use chrono::{DateTime, NaiveDate, Utc};
use serde::{Deserialize, Serialize};
use super::{
AccountId, InstrumentId, MerchantId, ReminderId, ReminderMarkerId, ReminderMarkerState, TagId,
UserId,
};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReminderMarker {
pub id: ReminderMarkerId,
#[serde(with = "chrono::serde::ts_seconds")]
pub changed: DateTime<Utc>,
pub user: UserId,
pub income_instrument: InstrumentId,
pub income_account: AccountId,
pub income: f64,
pub outcome_instrument: InstrumentId,
pub outcome_account: AccountId,
pub outcome: f64,
pub tag: Option<Vec<TagId>>,
pub merchant: Option<MerchantId>,
pub payee: Option<String>,
pub comment: Option<String>,
pub date: NaiveDate,
pub reminder: ReminderId,
pub state: ReminderMarkerState,
pub notify: bool,
#[serde(default)]
pub is_forecast: Option<bool>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deserialize_planned_marker() {
let json = r#"{
"id": "rm-001",
"changed": 1700000000,
"user": 123,
"incomeInstrument": 1,
"incomeAccount": "acc-001",
"income": 0,
"outcomeInstrument": 1,
"outcomeAccount": "acc-001",
"outcome": 5000.0,
"tag": null,
"merchant": null,
"payee": null,
"comment": null,
"date": "2024-02-01",
"reminder": "rem-001",
"state": "planned",
"notify": true
}"#;
let marker: ReminderMarker = serde_json::from_str(json).unwrap();
assert_eq!(marker.state, ReminderMarkerState::Planned);
assert_eq!(marker.reminder, ReminderId::new("rem-001".to_owned()));
assert_eq!(marker.date, NaiveDate::from_ymd_opt(2024, 2, 1).unwrap());
}
#[test]
fn deserialize_processed_marker() {
let json = r#"{
"id": "rm-002",
"changed": 1700000000,
"user": 123,
"incomeInstrument": 1,
"incomeAccount": "acc-001",
"income": 0,
"outcomeInstrument": 1,
"outcomeAccount": "acc-001",
"outcome": 5000.0,
"tag": ["tag-001"],
"merchant": "m-001",
"payee": "Landlord",
"comment": "Rent paid",
"date": "2024-01-01",
"reminder": "rem-001",
"state": "processed",
"notify": false
}"#;
let marker: ReminderMarker = serde_json::from_str(json).unwrap();
assert_eq!(marker.state, ReminderMarkerState::Processed);
assert!(!marker.notify);
}
#[test]
fn serialize_roundtrip() {
let marker = ReminderMarker {
id: ReminderMarkerId::new("rm-1".to_owned()),
changed: DateTime::from_timestamp(1_700_000_000, 0).unwrap(),
user: UserId::new(1),
income_instrument: InstrumentId::new(1),
income_account: AccountId::new("a-1".to_owned()),
income: 0.0,
outcome_instrument: InstrumentId::new(1),
outcome_account: AccountId::new("a-1".to_owned()),
outcome: 100.0,
tag: None,
merchant: None,
payee: None,
comment: None,
date: NaiveDate::from_ymd_opt(2024, 1, 1).unwrap(),
reminder: ReminderId::new("r-1".to_owned()),
state: ReminderMarkerState::Deleted,
notify: false,
is_forecast: None,
};
let json = serde_json::to_string(&marker).unwrap();
let deserialized: ReminderMarker = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, marker);
}
}