1use crate::error::{Error, Result};
7use crate::person::{LegalPerson, NaturalPerson};
8use crate::types::*;
9use serde::{Deserialize, Serialize};
10use tap_msg::utils::NameHashable;
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub enum Person {
16 NaturalPerson(NaturalPerson),
18 LegalPerson(LegalPerson),
20}
21
22impl Person {
23 pub fn validate(&self) -> Result<()> {
25 match self {
26 Person::NaturalPerson(person) => person.validate(),
27 Person::LegalPerson(person) => person.validate(),
28 }
29 }
30
31 pub fn is_natural_person(&self) -> bool {
33 matches!(self, Person::NaturalPerson(_))
34 }
35
36 pub fn is_legal_person(&self) -> bool {
38 matches!(self, Person::LegalPerson(_))
39 }
40
41 pub fn get_full_name(&self) -> Option<String> {
43 match self {
44 Person::NaturalPerson(person) => person.name.get_full_name(),
45 Person::LegalPerson(person) => person.name.get_full_name(),
46 }
47 }
48}
49
50impl NameHashable for Person {}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct Originator {
57 pub originator_persons: Vec<Person>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub account_numbers: Option<Vec<String>>,
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub bic: Option<BicCode>,
65}
66
67impl Originator {
68 pub fn new(originator_persons: Vec<Person>) -> Self {
70 Self {
71 originator_persons,
72 account_numbers: None,
73 bic: None,
74 }
75 }
76
77 pub fn validate(&self) -> Result<()> {
79 if self.originator_persons.is_empty() {
80 return Err(Error::MissingRequiredField(
81 "At least one originator person is required".to_string(),
82 ));
83 }
84
85 for person in &self.originator_persons {
86 person.validate()?;
87 }
88
89 if let Some(ref bic) = self.bic {
90 if bic.len() != 8 && bic.len() != 11 {
91 return Err(Error::InvalidBic(format!(
92 "BIC must be 8 or 11 characters: {}",
93 bic
94 )));
95 }
96 }
97
98 Ok(())
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
104#[serde(rename_all = "camelCase")]
105pub struct Beneficiary {
106 pub beneficiary_persons: Vec<Person>,
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub account_numbers: Option<Vec<String>>,
111}
112
113impl Beneficiary {
114 pub fn new(beneficiary_persons: Vec<Person>) -> Self {
116 Self {
117 beneficiary_persons,
118 account_numbers: None,
119 }
120 }
121
122 pub fn validate(&self) -> Result<()> {
124 if self.beneficiary_persons.is_empty() {
125 return Err(Error::MissingRequiredField(
126 "At least one beneficiary person is required".to_string(),
127 ));
128 }
129
130 for person in &self.beneficiary_persons {
131 person.validate()?;
132 }
133
134 Ok(())
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
140#[serde(rename_all = "camelCase")]
141pub struct OriginatingVasp {
142 pub originating_vasp: Person,
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub bic: Option<BicCode>,
147}
148
149impl OriginatingVasp {
150 pub fn new(originating_vasp: Person) -> Self {
152 Self {
153 originating_vasp,
154 bic: None,
155 }
156 }
157
158 pub fn validate(&self) -> Result<()> {
160 self.originating_vasp.validate()?;
161
162 if let Some(ref bic) = self.bic {
163 if bic.len() != 8 && bic.len() != 11 {
164 return Err(Error::InvalidBic(format!(
165 "BIC must be 8 or 11 characters: {}",
166 bic
167 )));
168 }
169 }
170
171 Ok(())
172 }
173}
174
175#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
177#[serde(rename_all = "camelCase")]
178pub struct BeneficiaryVasp {
179 pub beneficiary_vasp: Person,
181}
182
183impl BeneficiaryVasp {
184 pub fn new(beneficiary_vasp: Person) -> Self {
186 Self { beneficiary_vasp }
187 }
188
189 pub fn validate(&self) -> Result<()> {
191 self.beneficiary_vasp.validate()
192 }
193}
194
195#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
197#[serde(rename_all = "camelCase")]
198pub struct TransactionData {
199 pub amount: String,
201 pub currency: CurrencyCode,
203 pub direction: TransactionDirection,
205 #[serde(skip_serializing_if = "Option::is_none")]
207 pub payment_type: Option<PaymentType>,
208 pub transaction_identifier: String,
210 pub transaction_datetime: String,
212 #[serde(skip_serializing_if = "Option::is_none")]
214 pub transaction_network: Option<TransactionNetworkType>,
215 #[serde(skip_serializing_if = "Option::is_none")]
217 pub transaction_hash: Option<String>,
218}
219
220impl TransactionData {
221 pub fn validate(&self) -> Result<()> {
223 if self.amount.is_empty() {
224 return Err(Error::MissingRequiredField(
225 "Transaction amount is required".to_string(),
226 ));
227 }
228
229 if self.currency.len() != 3 {
230 return Err(Error::InvalidCurrencyCode(format!(
231 "Currency code must be 3 characters: {}",
232 self.currency
233 )));
234 }
235
236 if self.transaction_identifier.is_empty() {
237 return Err(Error::MissingRequiredField(
238 "Transaction identifier is required".to_string(),
239 ));
240 }
241
242 if chrono::DateTime::parse_from_rfc3339(&self.transaction_datetime).is_err() {
244 return Err(Error::InvalidDate(format!(
245 "Invalid transaction datetime format: {}",
246 self.transaction_datetime
247 )));
248 }
249
250 Ok(())
251 }
252}
253
254#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
256#[serde(rename_all = "camelCase")]
257pub struct IvmsMessage {
258 pub originator: Originator,
260 pub beneficiary: Beneficiary,
262 pub originating_vasp: OriginatingVasp,
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub beneficiary_vasp: Option<BeneficiaryVasp>,
267 pub transaction: TransactionData,
269}
270
271impl IvmsMessage {
272 pub fn new(
274 originator: Originator,
275 beneficiary: Beneficiary,
276 originating_vasp: OriginatingVasp,
277 transaction: TransactionData,
278 ) -> Self {
279 Self {
280 originator,
281 beneficiary,
282 originating_vasp,
283 beneficiary_vasp: None,
284 transaction,
285 }
286 }
287
288 pub fn validate(&self) -> Result<()> {
290 let mut issues = Vec::new();
291
292 if let Err(e) = self.originator.validate() {
293 issues.push(format!("Originator: {}", e));
294 }
295
296 if let Err(e) = self.beneficiary.validate() {
297 issues.push(format!("Beneficiary: {}", e));
298 }
299
300 if let Err(e) = self.originating_vasp.validate() {
301 issues.push(format!("Originating VASP: {}", e));
302 }
303
304 if let Some(ref beneficiary_vasp) = self.beneficiary_vasp {
305 if let Err(e) = beneficiary_vasp.validate() {
306 issues.push(format!("Beneficiary VASP: {}", e));
307 }
308 }
309
310 if let Err(e) = self.transaction.validate() {
311 issues.push(format!("Transaction: {}", e));
312 }
313
314 if !issues.is_empty() {
315 return Err(Error::ValidationFailed { issues });
316 }
317
318 Ok(())
319 }
320
321 pub fn to_json(&self) -> Result<String> {
323 serde_json::to_string(self).map_err(Error::from)
324 }
325
326 pub fn to_json_pretty(&self) -> Result<String> {
328 serde_json::to_string_pretty(self).map_err(Error::from)
329 }
330
331 pub fn from_json(json: &str) -> Result<Self> {
333 serde_json::from_str(json).map_err(Error::from)
334 }
335}