1pub mod money;
7pub mod tx;
8
9pub use money::{CurrencyCode, Money};
10pub use tx::{Transaction, TxType};
11
12use chrono::NaiveDate;
13use serde::{Deserialize, Serialize};
14
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[derive(Debug, Clone, PartialEq, Eq, Default)]
18pub struct OrgRef {
19 pub ref_id: Option<String>,
21 pub name: Option<String>,
23}
24
25#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27#[derive(Debug, Clone, PartialEq)]
28pub struct Activity {
29 pub iati_identifier: String,
31 pub default_currency: Option<CurrencyCode>,
34 pub transactions: Vec<Transaction>,
36 pub reporting_org: Option<OrgRef>,
38 pub activity_start: Option<NaiveDate>,
40 pub activity_end: Option<NaiveDate>,
41}
42
43impl Activity {
44 pub fn new<S: Into<String>>(iati_identifier: S) -> Self {
45 Self {
46 iati_identifier: iati_identifier.into(),
47 default_currency: None,
48 transactions: Vec::new(),
49 reporting_org: None,
50 activity_start: None,
51 activity_end: None,
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use crate::tx::{Transaction, TxType};
60 use rust_decimal::Decimal;
61
62 #[test]
63 fn tx_type_roundtrip() {
64 assert_eq!(TxType::from(1).code(), 1);
65 assert_eq!(TxType::from(13).code(), 13);
66 assert!(matches!(TxType::from(99), TxType::Unknown(99)));
67 assert_eq!("3".parse::<TxType>().unwrap().code(), 3);
68 }
69
70 #[test]
71 fn money_uppercases_currency() {
72 use crate::money::{CurrencyCode, Money};
73 let m = Money {
74 amount: Decimal::new(1000, 2),
75 currency: Some(CurrencyCode::from("usd")),
76 value_date: None,
77 };
78 assert_eq!(m.currency.unwrap().0, "USD");
79 }
80
81 #[test]
82 fn transaction_new_and_builders() {
83 use crate::money::{CurrencyCode, Money};
84 use chrono::NaiveDate;
85
86 let date = NaiveDate::from_ymd_opt(2023, 5, 1).unwrap();
87 let money = Money::new(Decimal::new(5000, 2));
88
89 let tx = Transaction::new(TxType::Disbursement, date, money.clone())
90 .with_provider(OrgRef {
91 ref_id: Some("AAA-111".into()),
92 name: Some("Donor Org".into()),
93 })
94 .with_receiver(OrgRef {
95 ref_id: Some("BBB-222".into()),
96 name: None,
97 })
98 .with_currency_hint(CurrencyCode::from("EUR"));
99
100 assert_eq!(tx.tx_type, TxType::Disbursement);
101 assert_eq!(tx.date, date);
102 assert_eq!(tx.value.amount, money.amount);
103 assert_eq!(
104 tx.provider_org.as_ref().unwrap().ref_id.as_deref(),
105 Some("AAA-111")
106 );
107 assert_eq!(
108 tx.receiver_org.as_ref().unwrap().ref_id.as_deref(),
109 Some("BBB-222")
110 );
111 assert_eq!(tx.currency_hint.as_ref().unwrap().0, "EUR");
112 }
113}