mx_message/document/
pacs_009_001_08.rs

1// Plasmatic MX Message Parsing Library
2// https://github.com/GoPlasmatic/MXMessage
3//
4// Copyright (c) 2025 Plasmatic
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9//     http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17// You may obtain a copy of this library at
18// https://github.com/GoPlasmatic/MXMessage
19
20use crate::error::*;
21use regex::Regex;
22use serde::{Deserialize, Serialize};
23
24// AccountIdentification4Choice1: Unique identification of an account, as assigned by the account servicer, using an identification scheme.
25#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
26pub struct AccountIdentification4Choice1 {
27    #[serde(rename = "IBAN", skip_serializing_if = "Option::is_none")]
28    pub iban: Option<String>,
29    #[serde(rename = "Othr", skip_serializing_if = "Option::is_none")]
30    pub othr: Option<GenericAccountIdentification11>,
31}
32
33impl AccountIdentification4Choice1 {
34    pub fn validate(&self) -> Result<(), ValidationError> {
35        if let Some(ref val) = self.iban {
36            let pattern = Regex::new("[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}").unwrap();
37            if !pattern.is_match(val) {
38                return Err(ValidationError::new(
39                    1005,
40                    "iban does not match the required pattern".to_string(),
41                ));
42            }
43        }
44        if let Some(ref val) = self.othr {
45            val.validate()?
46        }
47        Ok(())
48    }
49}
50
51// AccountSchemeName1Choice1: Name of the identification scheme, in a free text form.
52#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
53pub struct AccountSchemeName1Choice1 {
54    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
55    pub cd: Option<String>,
56    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
57    pub prtry: Option<String>,
58}
59
60impl AccountSchemeName1Choice1 {
61    pub fn validate(&self) -> Result<(), ValidationError> {
62        if let Some(ref val) = self.cd {
63            if val.chars().count() < 1 {
64                return Err(ValidationError::new(
65                    1001,
66                    "cd is shorter than the minimum length of 1".to_string(),
67                ));
68            }
69            if val.chars().count() > 4 {
70                return Err(ValidationError::new(
71                    1002,
72                    "cd exceeds the maximum length of 4".to_string(),
73                ));
74            }
75        }
76        if let Some(ref val) = self.prtry {
77            if val.chars().count() < 1 {
78                return Err(ValidationError::new(
79                    1001,
80                    "prtry is shorter than the minimum length of 1".to_string(),
81                ));
82            }
83            if val.chars().count() > 35 {
84                return Err(ValidationError::new(
85                    1002,
86                    "prtry exceeds the maximum length of 35".to_string(),
87                ));
88            }
89            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
90            if !pattern.is_match(val) {
91                return Err(ValidationError::new(
92                    1005,
93                    "prtry does not match the required pattern".to_string(),
94                ));
95            }
96        }
97        Ok(())
98    }
99}
100
101// BranchAndFinancialInstitutionIdentification61: Unique and unambiguous identification of a financial institution, as assigned under an internationally recognised or proprietary identification scheme.
102#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
103pub struct BranchAndFinancialInstitutionIdentification61 {
104    #[serde(rename = "FinInstnId")]
105    pub fin_instn_id: FinancialInstitutionIdentification181,
106}
107
108impl BranchAndFinancialInstitutionIdentification61 {
109    pub fn validate(&self) -> Result<(), ValidationError> {
110        self.fin_instn_id.validate()?;
111        Ok(())
112    }
113}
114
115// BranchAndFinancialInstitutionIdentification62: Unique and unambiguous identification of a financial institution, as assigned under an internationally recognised or proprietary identification scheme.
116#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
117pub struct BranchAndFinancialInstitutionIdentification62 {
118    #[serde(rename = "FinInstnId")]
119    pub fin_instn_id: FinancialInstitutionIdentification182,
120}
121
122impl BranchAndFinancialInstitutionIdentification62 {
123    pub fn validate(&self) -> Result<(), ValidationError> {
124        self.fin_instn_id.validate()?;
125        Ok(())
126    }
127}
128
129// CBPRAmount: CBPR_Amount
130#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
131pub struct CBPRAmount {
132    #[serde(rename = "@Ccy")]
133    pub ccy: String,
134    #[serde(rename = "$value")]
135    pub value: f64,
136}
137
138impl CBPRAmount {
139    pub fn validate(&self) -> Result<(), ValidationError> {
140        Ok(())
141    }
142}
143
144// CashAccount381: Specifies an alternate assumed name for the identification of the account.
145#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
146pub struct CashAccount381 {
147    #[serde(rename = "Id")]
148    pub id: AccountIdentification4Choice1,
149    #[serde(rename = "Tp", skip_serializing_if = "Option::is_none")]
150    pub tp: Option<CashAccountType2Choice1>,
151    #[serde(rename = "Ccy", skip_serializing_if = "Option::is_none")]
152    pub ccy: Option<String>,
153    #[serde(rename = "Nm", skip_serializing_if = "Option::is_none")]
154    pub nm: Option<String>,
155    #[serde(rename = "Prxy", skip_serializing_if = "Option::is_none")]
156    pub prxy: Option<ProxyAccountIdentification11>,
157}
158
159impl CashAccount381 {
160    pub fn validate(&self) -> Result<(), ValidationError> {
161        self.id.validate()?;
162        if let Some(ref val) = self.tp {
163            val.validate()?
164        }
165        if let Some(ref val) = self.ccy {
166            let pattern = Regex::new("[A-Z]{3,3}").unwrap();
167            if !pattern.is_match(val) {
168                return Err(ValidationError::new(
169                    1005,
170                    "ccy does not match the required pattern".to_string(),
171                ));
172            }
173        }
174        if let Some(ref val) = self.nm {
175            if val.chars().count() < 1 {
176                return Err(ValidationError::new(
177                    1001,
178                    "nm is shorter than the minimum length of 1".to_string(),
179                ));
180            }
181            if val.chars().count() > 70 {
182                return Err(ValidationError::new(
183                    1002,
184                    "nm exceeds the maximum length of 70".to_string(),
185                ));
186            }
187            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
188            if !pattern.is_match(val) {
189                return Err(ValidationError::new(
190                    1005,
191                    "nm does not match the required pattern".to_string(),
192                ));
193            }
194        }
195        if let Some(ref val) = self.prxy {
196            val.validate()?
197        }
198        Ok(())
199    }
200}
201
202// CashAccountType2Choice1: Nature or use of the account in a proprietary form.
203#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
204pub struct CashAccountType2Choice1 {
205    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
206    pub cd: Option<String>,
207    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
208    pub prtry: Option<String>,
209}
210
211impl CashAccountType2Choice1 {
212    pub fn validate(&self) -> Result<(), ValidationError> {
213        if let Some(ref val) = self.cd {
214            if val.chars().count() < 1 {
215                return Err(ValidationError::new(
216                    1001,
217                    "cd is shorter than the minimum length of 1".to_string(),
218                ));
219            }
220            if val.chars().count() > 4 {
221                return Err(ValidationError::new(
222                    1002,
223                    "cd exceeds the maximum length of 4".to_string(),
224                ));
225            }
226        }
227        if let Some(ref val) = self.prtry {
228            if val.chars().count() < 1 {
229                return Err(ValidationError::new(
230                    1001,
231                    "prtry is shorter than the minimum length of 1".to_string(),
232                ));
233            }
234            if val.chars().count() > 35 {
235                return Err(ValidationError::new(
236                    1002,
237                    "prtry exceeds the maximum length of 35".to_string(),
238                ));
239            }
240            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
241            if !pattern.is_match(val) {
242                return Err(ValidationError::new(
243                    1005,
244                    "prtry does not match the required pattern".to_string(),
245                ));
246            }
247        }
248        Ok(())
249    }
250}
251
252// CategoryPurpose1Choice1: Category purpose, in a proprietary form.
253#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
254pub struct CategoryPurpose1Choice1 {
255    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
256    pub cd: Option<String>,
257    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
258    pub prtry: Option<String>,
259}
260
261impl CategoryPurpose1Choice1 {
262    pub fn validate(&self) -> Result<(), ValidationError> {
263        if let Some(ref val) = self.cd {
264            if val.chars().count() < 1 {
265                return Err(ValidationError::new(
266                    1001,
267                    "cd is shorter than the minimum length of 1".to_string(),
268                ));
269            }
270            if val.chars().count() > 4 {
271                return Err(ValidationError::new(
272                    1002,
273                    "cd exceeds the maximum length of 4".to_string(),
274                ));
275            }
276        }
277        if let Some(ref val) = self.prtry {
278            if val.chars().count() < 1 {
279                return Err(ValidationError::new(
280                    1001,
281                    "prtry is shorter than the minimum length of 1".to_string(),
282                ));
283            }
284            if val.chars().count() > 35 {
285                return Err(ValidationError::new(
286                    1002,
287                    "prtry exceeds the maximum length of 35".to_string(),
288                ));
289            }
290            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
291            if !pattern.is_match(val) {
292                return Err(ValidationError::new(
293                    1005,
294                    "prtry does not match the required pattern".to_string(),
295                ));
296            }
297        }
298        Ok(())
299    }
300}
301
302// ClearingChannel2Code: Payment through internal book transfer.
303#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
304pub enum ClearingChannel2Code {
305    #[default]
306    #[serde(rename = "RTGS")]
307    CodeRTGS,
308    #[serde(rename = "RTNS")]
309    CodeRTNS,
310    #[serde(rename = "MPNS")]
311    CodeMPNS,
312    #[serde(rename = "BOOK")]
313    CodeBOOK,
314}
315
316impl ClearingChannel2Code {
317    pub fn validate(&self) -> Result<(), ValidationError> {
318        Ok(())
319    }
320}
321
322// ClearingSystemIdentification2Choice1: Identification of a clearing system, in a coded form as published in an external list.
323#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
324pub struct ClearingSystemIdentification2Choice1 {
325    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
326    pub cd: Option<String>,
327}
328
329impl ClearingSystemIdentification2Choice1 {
330    pub fn validate(&self) -> Result<(), ValidationError> {
331        if let Some(ref val) = self.cd {
332            if val.chars().count() < 1 {
333                return Err(ValidationError::new(
334                    1001,
335                    "cd is shorter than the minimum length of 1".to_string(),
336                ));
337            }
338            if val.chars().count() > 5 {
339                return Err(ValidationError::new(
340                    1002,
341                    "cd exceeds the maximum length of 5".to_string(),
342                ));
343            }
344        }
345        Ok(())
346    }
347}
348
349// ClearingSystemMemberIdentification21: Identification of a member of a clearing system.
350#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
351pub struct ClearingSystemMemberIdentification21 {
352    #[serde(rename = "ClrSysId")]
353    pub clr_sys_id: ClearingSystemIdentification2Choice1,
354    #[serde(rename = "MmbId")]
355    pub mmb_id: String,
356}
357
358impl ClearingSystemMemberIdentification21 {
359    pub fn validate(&self) -> Result<(), ValidationError> {
360        self.clr_sys_id.validate()?;
361        if self.mmb_id.chars().count() < 1 {
362            return Err(ValidationError::new(
363                1001,
364                "mmb_id is shorter than the minimum length of 1".to_string(),
365            ));
366        }
367        if self.mmb_id.chars().count() > 28 {
368            return Err(ValidationError::new(
369                1002,
370                "mmb_id exceeds the maximum length of 28".to_string(),
371            ));
372        }
373        let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
374        if !pattern.is_match(&self.mmb_id) {
375            return Err(ValidationError::new(
376                1005,
377                "mmb_id does not match the required pattern".to_string(),
378            ));
379        }
380        Ok(())
381    }
382}
383
384// CreditTransferTransaction361: Information supplied to enable the matching of an entry with the items that the transfer is intended to settle, such as commercial invoices in an accounts' receivable system.
385#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
386pub struct CreditTransferTransaction361 {
387    #[serde(rename = "PmtId")]
388    pub pmt_id: PaymentIdentification71,
389    #[serde(rename = "PmtTpInf", skip_serializing_if = "Option::is_none")]
390    pub pmt_tp_inf: Option<PaymentTypeInformation281>,
391    #[serde(rename = "IntrBkSttlmAmt")]
392    pub intr_bk_sttlm_amt: CBPRAmount,
393    #[serde(rename = "IntrBkSttlmDt")]
394    pub intr_bk_sttlm_dt: String,
395    #[serde(rename = "SttlmPrty", skip_serializing_if = "Option::is_none")]
396    pub sttlm_prty: Option<Priority3Code>,
397    #[serde(rename = "SttlmTmIndctn", skip_serializing_if = "Option::is_none")]
398    pub sttlm_tm_indctn: Option<SettlementDateTimeIndication11>,
399    #[serde(rename = "SttlmTmReq", skip_serializing_if = "Option::is_none")]
400    pub sttlm_tm_req: Option<SettlementTimeRequest21>,
401    #[serde(rename = "PrvsInstgAgt1", skip_serializing_if = "Option::is_none")]
402    pub prvs_instg_agt1: Option<BranchAndFinancialInstitutionIdentification61>,
403    #[serde(rename = "PrvsInstgAgt1Acct", skip_serializing_if = "Option::is_none")]
404    pub prvs_instg_agt1_acct: Option<CashAccount381>,
405    #[serde(rename = "PrvsInstgAgt2", skip_serializing_if = "Option::is_none")]
406    pub prvs_instg_agt2: Option<BranchAndFinancialInstitutionIdentification61>,
407    #[serde(rename = "PrvsInstgAgt2Acct", skip_serializing_if = "Option::is_none")]
408    pub prvs_instg_agt2_acct: Option<CashAccount381>,
409    #[serde(rename = "PrvsInstgAgt3", skip_serializing_if = "Option::is_none")]
410    pub prvs_instg_agt3: Option<BranchAndFinancialInstitutionIdentification61>,
411    #[serde(rename = "PrvsInstgAgt3Acct", skip_serializing_if = "Option::is_none")]
412    pub prvs_instg_agt3_acct: Option<CashAccount381>,
413    #[serde(rename = "InstgAgt")]
414    pub instg_agt: BranchAndFinancialInstitutionIdentification62,
415    #[serde(rename = "InstdAgt")]
416    pub instd_agt: BranchAndFinancialInstitutionIdentification62,
417    #[serde(rename = "IntrmyAgt1", skip_serializing_if = "Option::is_none")]
418    pub intrmy_agt1: Option<BranchAndFinancialInstitutionIdentification61>,
419    #[serde(rename = "IntrmyAgt1Acct", skip_serializing_if = "Option::is_none")]
420    pub intrmy_agt1_acct: Option<CashAccount381>,
421    #[serde(rename = "IntrmyAgt2", skip_serializing_if = "Option::is_none")]
422    pub intrmy_agt2: Option<BranchAndFinancialInstitutionIdentification61>,
423    #[serde(rename = "IntrmyAgt2Acct", skip_serializing_if = "Option::is_none")]
424    pub intrmy_agt2_acct: Option<CashAccount381>,
425    #[serde(rename = "IntrmyAgt3", skip_serializing_if = "Option::is_none")]
426    pub intrmy_agt3: Option<BranchAndFinancialInstitutionIdentification61>,
427    #[serde(rename = "IntrmyAgt3Acct", skip_serializing_if = "Option::is_none")]
428    pub intrmy_agt3_acct: Option<CashAccount381>,
429    #[serde(rename = "Dbtr")]
430    pub dbtr: BranchAndFinancialInstitutionIdentification61,
431    #[serde(rename = "DbtrAcct", skip_serializing_if = "Option::is_none")]
432    pub dbtr_acct: Option<CashAccount381>,
433    #[serde(rename = "DbtrAgt", skip_serializing_if = "Option::is_none")]
434    pub dbtr_agt: Option<BranchAndFinancialInstitutionIdentification61>,
435    #[serde(rename = "DbtrAgtAcct", skip_serializing_if = "Option::is_none")]
436    pub dbtr_agt_acct: Option<CashAccount381>,
437    #[serde(rename = "CdtrAgt", skip_serializing_if = "Option::is_none")]
438    pub cdtr_agt: Option<BranchAndFinancialInstitutionIdentification61>,
439    #[serde(rename = "CdtrAgtAcct", skip_serializing_if = "Option::is_none")]
440    pub cdtr_agt_acct: Option<CashAccount381>,
441    #[serde(rename = "Cdtr")]
442    pub cdtr: BranchAndFinancialInstitutionIdentification61,
443    #[serde(rename = "CdtrAcct", skip_serializing_if = "Option::is_none")]
444    pub cdtr_acct: Option<CashAccount381>,
445    #[serde(rename = "InstrForCdtrAgt", skip_serializing_if = "Option::is_none")]
446    pub instr_for_cdtr_agt: Option<Vec<InstructionForCreditorAgent21>>,
447    #[serde(rename = "InstrForNxtAgt", skip_serializing_if = "Option::is_none")]
448    pub instr_for_nxt_agt: Option<Vec<InstructionForNextAgent11>>,
449    #[serde(rename = "Purp", skip_serializing_if = "Option::is_none")]
450    pub purp: Option<Purpose2Choice1>,
451    #[serde(rename = "RmtInf", skip_serializing_if = "Option::is_none")]
452    pub rmt_inf: Option<RemittanceInformation21>,
453}
454
455impl CreditTransferTransaction361 {
456    pub fn validate(&self) -> Result<(), ValidationError> {
457        self.pmt_id.validate()?;
458        if let Some(ref val) = self.pmt_tp_inf {
459            val.validate()?
460        }
461        self.intr_bk_sttlm_amt.validate()?;
462        if let Some(ref val) = self.sttlm_prty {
463            val.validate()?
464        }
465        if let Some(ref val) = self.sttlm_tm_indctn {
466            val.validate()?
467        }
468        if let Some(ref val) = self.sttlm_tm_req {
469            val.validate()?
470        }
471        if let Some(ref val) = self.prvs_instg_agt1 {
472            val.validate()?
473        }
474        if let Some(ref val) = self.prvs_instg_agt1_acct {
475            val.validate()?
476        }
477        if let Some(ref val) = self.prvs_instg_agt2 {
478            val.validate()?
479        }
480        if let Some(ref val) = self.prvs_instg_agt2_acct {
481            val.validate()?
482        }
483        if let Some(ref val) = self.prvs_instg_agt3 {
484            val.validate()?
485        }
486        if let Some(ref val) = self.prvs_instg_agt3_acct {
487            val.validate()?
488        }
489        self.instg_agt.validate()?;
490        self.instd_agt.validate()?;
491        if let Some(ref val) = self.intrmy_agt1 {
492            val.validate()?
493        }
494        if let Some(ref val) = self.intrmy_agt1_acct {
495            val.validate()?
496        }
497        if let Some(ref val) = self.intrmy_agt2 {
498            val.validate()?
499        }
500        if let Some(ref val) = self.intrmy_agt2_acct {
501            val.validate()?
502        }
503        if let Some(ref val) = self.intrmy_agt3 {
504            val.validate()?
505        }
506        if let Some(ref val) = self.intrmy_agt3_acct {
507            val.validate()?
508        }
509        self.dbtr.validate()?;
510        if let Some(ref val) = self.dbtr_acct {
511            val.validate()?
512        }
513        if let Some(ref val) = self.dbtr_agt {
514            val.validate()?
515        }
516        if let Some(ref val) = self.dbtr_agt_acct {
517            val.validate()?
518        }
519        if let Some(ref val) = self.cdtr_agt {
520            val.validate()?
521        }
522        if let Some(ref val) = self.cdtr_agt_acct {
523            val.validate()?
524        }
525        self.cdtr.validate()?;
526        if let Some(ref val) = self.cdtr_acct {
527            val.validate()?
528        }
529        if let Some(ref vec) = self.instr_for_cdtr_agt {
530            for item in vec {
531                item.validate()?
532            }
533        }
534        if let Some(ref vec) = self.instr_for_nxt_agt {
535            for item in vec {
536                item.validate()?
537            }
538        }
539        if let Some(ref val) = self.purp {
540            val.validate()?
541        }
542        if let Some(ref val) = self.rmt_inf {
543            val.validate()?
544        }
545        Ok(())
546    }
547}
548
549// FinancialInstitutionCreditTransferV08: Set of elements providing information specific to the individual credit transfer(s).
550#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
551pub struct FinancialInstitutionCreditTransferV08 {
552    #[serde(rename = "GrpHdr")]
553    pub grp_hdr: GroupHeader931,
554    #[serde(rename = "CdtTrfTxInf")]
555    pub cdt_trf_tx_inf: CreditTransferTransaction361,
556}
557
558impl FinancialInstitutionCreditTransferV08 {
559    pub fn validate(&self) -> Result<(), ValidationError> {
560        self.grp_hdr.validate()?;
561        self.cdt_trf_tx_inf.validate()?;
562        Ok(())
563    }
564}
565
566// FinancialInstitutionIdentification181: Information that locates and identifies a specific address, as defined by postal services.
567#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
568pub struct FinancialInstitutionIdentification181 {
569    #[serde(rename = "BICFI", skip_serializing_if = "Option::is_none")]
570    pub bicfi: Option<String>,
571    #[serde(rename = "ClrSysMmbId", skip_serializing_if = "Option::is_none")]
572    pub clr_sys_mmb_id: Option<ClearingSystemMemberIdentification21>,
573    #[serde(rename = "LEI", skip_serializing_if = "Option::is_none")]
574    pub lei: Option<String>,
575    #[serde(rename = "Nm", skip_serializing_if = "Option::is_none")]
576    pub nm: Option<String>,
577    #[serde(rename = "PstlAdr", skip_serializing_if = "Option::is_none")]
578    pub pstl_adr: Option<PostalAddress241>,
579}
580
581impl FinancialInstitutionIdentification181 {
582    pub fn validate(&self) -> Result<(), ValidationError> {
583        if let Some(ref val) = self.bicfi {
584            let pattern =
585                Regex::new("[A-Z0-9]{4,4}[A-Z]{2,2}[A-Z0-9]{2,2}([A-Z0-9]{3,3}){0,1}").unwrap();
586            if !pattern.is_match(val) {
587                return Err(ValidationError::new(
588                    1005,
589                    "bicfi does not match the required pattern".to_string(),
590                ));
591            }
592        }
593        if let Some(ref val) = self.clr_sys_mmb_id {
594            val.validate()?
595        }
596        if let Some(ref val) = self.lei {
597            let pattern = Regex::new("[A-Z0-9]{18,18}[0-9]{2,2}").unwrap();
598            if !pattern.is_match(val) {
599                return Err(ValidationError::new(
600                    1005,
601                    "lei does not match the required pattern".to_string(),
602                ));
603            }
604        }
605        if let Some(ref val) = self.nm {
606            if val.chars().count() < 1 {
607                return Err(ValidationError::new(
608                    1001,
609                    "nm is shorter than the minimum length of 1".to_string(),
610                ));
611            }
612            if val.chars().count() > 140 {
613                return Err(ValidationError::new(
614                    1002,
615                    "nm exceeds the maximum length of 140".to_string(),
616                ));
617            }
618            let pattern = Regex::new(
619                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
620            )
621            .unwrap();
622            if !pattern.is_match(val) {
623                return Err(ValidationError::new(
624                    1005,
625                    "nm does not match the required pattern".to_string(),
626                ));
627            }
628        }
629        if let Some(ref val) = self.pstl_adr {
630            val.validate()?
631        }
632        Ok(())
633    }
634}
635
636// FinancialInstitutionIdentification182: Legal entity identifier of the financial institution.
637#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
638pub struct FinancialInstitutionIdentification182 {
639    #[serde(rename = "BICFI")]
640    pub bicfi: String,
641    #[serde(rename = "ClrSysMmbId", skip_serializing_if = "Option::is_none")]
642    pub clr_sys_mmb_id: Option<ClearingSystemMemberIdentification21>,
643    #[serde(rename = "LEI", skip_serializing_if = "Option::is_none")]
644    pub lei: Option<String>,
645}
646
647impl FinancialInstitutionIdentification182 {
648    pub fn validate(&self) -> Result<(), ValidationError> {
649        let pattern =
650            Regex::new("[A-Z0-9]{4,4}[A-Z]{2,2}[A-Z0-9]{2,2}([A-Z0-9]{3,3}){0,1}").unwrap();
651        if !pattern.is_match(&self.bicfi) {
652            return Err(ValidationError::new(
653                1005,
654                "bicfi does not match the required pattern".to_string(),
655            ));
656        }
657        if let Some(ref val) = self.clr_sys_mmb_id {
658            val.validate()?
659        }
660        if let Some(ref val) = self.lei {
661            let pattern = Regex::new("[A-Z0-9]{18,18}[0-9]{2,2}").unwrap();
662            if !pattern.is_match(val) {
663                return Err(ValidationError::new(
664                    1005,
665                    "lei does not match the required pattern".to_string(),
666                ));
667            }
668        }
669        Ok(())
670    }
671}
672
673// GenericAccountIdentification11: Entity that assigns the identification.
674#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
675pub struct GenericAccountIdentification11 {
676    #[serde(rename = "Id")]
677    pub id: String,
678    #[serde(rename = "SchmeNm", skip_serializing_if = "Option::is_none")]
679    pub schme_nm: Option<AccountSchemeName1Choice1>,
680    #[serde(rename = "Issr", skip_serializing_if = "Option::is_none")]
681    pub issr: Option<String>,
682}
683
684impl GenericAccountIdentification11 {
685    pub fn validate(&self) -> Result<(), ValidationError> {
686        if self.id.chars().count() < 1 {
687            return Err(ValidationError::new(
688                1001,
689                "id is shorter than the minimum length of 1".to_string(),
690            ));
691        }
692        if self.id.chars().count() > 34 {
693            return Err(ValidationError::new(
694                1002,
695                "id exceeds the maximum length of 34".to_string(),
696            ));
697        }
698        let pattern = Regex::new("([0-9a-zA-Z\\-\\?:\\(\\)\\.,'\\+ ]([0-9a-zA-Z\\-\\?:\\(\\)\\.,'\\+ ]*(/[0-9a-zA-Z\\-\\?:\\(\\)\\.,'\\+ ])?)*)").unwrap();
699        if !pattern.is_match(&self.id) {
700            return Err(ValidationError::new(
701                1005,
702                "id does not match the required pattern".to_string(),
703            ));
704        }
705        if let Some(ref val) = self.schme_nm {
706            val.validate()?
707        }
708        if let Some(ref val) = self.issr {
709            if val.chars().count() < 1 {
710                return Err(ValidationError::new(
711                    1001,
712                    "issr is shorter than the minimum length of 1".to_string(),
713                ));
714            }
715            if val.chars().count() > 35 {
716                return Err(ValidationError::new(
717                    1002,
718                    "issr exceeds the maximum length of 35".to_string(),
719                ));
720            }
721            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
722            if !pattern.is_match(val) {
723                return Err(ValidationError::new(
724                    1005,
725                    "issr does not match the required pattern".to_string(),
726                ));
727            }
728        }
729        Ok(())
730    }
731}
732
733// GroupHeader931: Specifies the details on how the settlement of the transaction(s) between the instructing agent and the instructed agent is completed.
734#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
735pub struct GroupHeader931 {
736    #[serde(rename = "MsgId")]
737    pub msg_id: String,
738    #[serde(rename = "CreDtTm")]
739    pub cre_dt_tm: String,
740    #[serde(rename = "NbOfTxs")]
741    pub nb_of_txs: Max15NumericTextfixed,
742    #[serde(rename = "SttlmInf")]
743    pub sttlm_inf: SettlementInstruction71,
744}
745
746impl GroupHeader931 {
747    pub fn validate(&self) -> Result<(), ValidationError> {
748        if self.msg_id.chars().count() < 1 {
749            return Err(ValidationError::new(
750                1001,
751                "msg_id is shorter than the minimum length of 1".to_string(),
752            ));
753        }
754        if self.msg_id.chars().count() > 35 {
755            return Err(ValidationError::new(
756                1002,
757                "msg_id exceeds the maximum length of 35".to_string(),
758            ));
759        }
760        let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
761        if !pattern.is_match(&self.msg_id) {
762            return Err(ValidationError::new(
763                1005,
764                "msg_id does not match the required pattern".to_string(),
765            ));
766        }
767        let pattern = Regex::new(".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]").unwrap();
768        if !pattern.is_match(&self.cre_dt_tm) {
769            return Err(ValidationError::new(
770                1005,
771                "cre_dt_tm does not match the required pattern".to_string(),
772            ));
773        }
774        self.nb_of_txs.validate()?;
775        self.sttlm_inf.validate()?;
776        Ok(())
777    }
778}
779
780// Instruction5Code: Please advise/contact (ultimate) creditor/claimant by the most efficient means of telecommunication.
781#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
782pub enum Instruction5Code {
783    #[default]
784    #[serde(rename = "PHOB")]
785    CodePHOB,
786    #[serde(rename = "TELB")]
787    CodeTELB,
788}
789
790impl Instruction5Code {
791    pub fn validate(&self) -> Result<(), ValidationError> {
792        Ok(())
793    }
794}
795
796// InstructionForCreditorAgent21: Further information complementing the coded instruction or instruction to the creditor's agent that is bilaterally agreed or specific to a user community.
797#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
798pub struct InstructionForCreditorAgent21 {
799    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
800    pub cd: Option<Instruction5Code>,
801    #[serde(rename = "InstrInf", skip_serializing_if = "Option::is_none")]
802    pub instr_inf: Option<String>,
803}
804
805impl InstructionForCreditorAgent21 {
806    pub fn validate(&self) -> Result<(), ValidationError> {
807        if let Some(ref val) = self.cd {
808            val.validate()?
809        }
810        if let Some(ref val) = self.instr_inf {
811            if val.chars().count() < 1 {
812                return Err(ValidationError::new(
813                    1001,
814                    "instr_inf is shorter than the minimum length of 1".to_string(),
815                ));
816            }
817            if val.chars().count() > 140 {
818                return Err(ValidationError::new(
819                    1002,
820                    "instr_inf exceeds the maximum length of 140".to_string(),
821                ));
822            }
823            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
824            if !pattern.is_match(val) {
825                return Err(ValidationError::new(
826                    1005,
827                    "instr_inf does not match the required pattern".to_string(),
828                ));
829            }
830        }
831        Ok(())
832    }
833}
834
835// InstructionForNextAgent11: Further information complementing the coded instruction or instruction to the next agent that is bilaterally agreed or specific to a user community.
836#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
837pub struct InstructionForNextAgent11 {
838    #[serde(rename = "InstrInf", skip_serializing_if = "Option::is_none")]
839    pub instr_inf: Option<String>,
840}
841
842impl InstructionForNextAgent11 {
843    pub fn validate(&self) -> Result<(), ValidationError> {
844        if let Some(ref val) = self.instr_inf {
845            if val.chars().count() < 1 {
846                return Err(ValidationError::new(
847                    1001,
848                    "instr_inf is shorter than the minimum length of 1".to_string(),
849                ));
850            }
851            if val.chars().count() > 35 {
852                return Err(ValidationError::new(
853                    1002,
854                    "instr_inf exceeds the maximum length of 35".to_string(),
855                ));
856            }
857            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
858            if !pattern.is_match(val) {
859                return Err(ValidationError::new(
860                    1005,
861                    "instr_inf does not match the required pattern".to_string(),
862                ));
863            }
864        }
865        Ok(())
866    }
867}
868
869// LocalInstrument2Choice1: Specifies the local instrument, as a proprietary code.
870#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
871pub struct LocalInstrument2Choice1 {
872    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
873    pub cd: Option<String>,
874    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
875    pub prtry: Option<String>,
876}
877
878impl LocalInstrument2Choice1 {
879    pub fn validate(&self) -> Result<(), ValidationError> {
880        if let Some(ref val) = self.cd {
881            if val.chars().count() < 1 {
882                return Err(ValidationError::new(
883                    1001,
884                    "cd is shorter than the minimum length of 1".to_string(),
885                ));
886            }
887            if val.chars().count() > 35 {
888                return Err(ValidationError::new(
889                    1002,
890                    "cd exceeds the maximum length of 35".to_string(),
891                ));
892            }
893        }
894        if let Some(ref val) = self.prtry {
895            if val.chars().count() < 1 {
896                return Err(ValidationError::new(
897                    1001,
898                    "prtry is shorter than the minimum length of 1".to_string(),
899                ));
900            }
901            if val.chars().count() > 35 {
902                return Err(ValidationError::new(
903                    1002,
904                    "prtry exceeds the maximum length of 35".to_string(),
905                ));
906            }
907            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
908            if !pattern.is_match(val) {
909                return Err(ValidationError::new(
910                    1005,
911                    "prtry does not match the required pattern".to_string(),
912                ));
913            }
914        }
915        Ok(())
916    }
917}
918
919// Max15NumericText_fixed: 1
920#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
921pub enum Max15NumericTextfixed {
922    #[default]
923    #[serde(rename = "1")]
924    Code1,
925}
926
927impl Max15NumericTextfixed {
928    pub fn validate(&self) -> Result<(), ValidationError> {
929        Ok(())
930    }
931}
932
933// PaymentIdentification71: Unique reference, as assigned by a clearing system, to unambiguously identify the instruction.
934#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
935pub struct PaymentIdentification71 {
936    #[serde(rename = "InstrId")]
937    pub instr_id: String,
938    #[serde(rename = "EndToEndId")]
939    pub end_to_end_id: String,
940    #[serde(rename = "TxId", skip_serializing_if = "Option::is_none")]
941    pub tx_id: Option<String>,
942    #[serde(rename = "UETR")]
943    pub uetr: String,
944    #[serde(rename = "ClrSysRef", skip_serializing_if = "Option::is_none")]
945    pub clr_sys_ref: Option<String>,
946}
947
948impl PaymentIdentification71 {
949    pub fn validate(&self) -> Result<(), ValidationError> {
950        if self.instr_id.chars().count() < 1 {
951            return Err(ValidationError::new(
952                1001,
953                "instr_id is shorter than the minimum length of 1".to_string(),
954            ));
955        }
956        if self.instr_id.chars().count() > 16 {
957            return Err(ValidationError::new(
958                1002,
959                "instr_id exceeds the maximum length of 16".to_string(),
960            ));
961        }
962        let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
963        if !pattern.is_match(&self.instr_id) {
964            return Err(ValidationError::new(
965                1005,
966                "instr_id does not match the required pattern".to_string(),
967            ));
968        }
969        if self.end_to_end_id.chars().count() < 1 {
970            return Err(ValidationError::new(
971                1001,
972                "end_to_end_id is shorter than the minimum length of 1".to_string(),
973            ));
974        }
975        if self.end_to_end_id.chars().count() > 35 {
976            return Err(ValidationError::new(
977                1002,
978                "end_to_end_id exceeds the maximum length of 35".to_string(),
979            ));
980        }
981        let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
982        if !pattern.is_match(&self.end_to_end_id) {
983            return Err(ValidationError::new(
984                1005,
985                "end_to_end_id does not match the required pattern".to_string(),
986            ));
987        }
988        if let Some(ref val) = self.tx_id {
989            if val.chars().count() < 1 {
990                return Err(ValidationError::new(
991                    1001,
992                    "tx_id is shorter than the minimum length of 1".to_string(),
993                ));
994            }
995            if val.chars().count() > 35 {
996                return Err(ValidationError::new(
997                    1002,
998                    "tx_id exceeds the maximum length of 35".to_string(),
999                ));
1000            }
1001            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
1002            if !pattern.is_match(val) {
1003                return Err(ValidationError::new(
1004                    1005,
1005                    "tx_id does not match the required pattern".to_string(),
1006                ));
1007            }
1008        }
1009        let pattern =
1010            Regex::new("[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}")
1011                .unwrap();
1012        if !pattern.is_match(&self.uetr) {
1013            return Err(ValidationError::new(
1014                1005,
1015                "uetr does not match the required pattern".to_string(),
1016            ));
1017        }
1018        if let Some(ref val) = self.clr_sys_ref {
1019            if val.chars().count() < 1 {
1020                return Err(ValidationError::new(
1021                    1001,
1022                    "clr_sys_ref is shorter than the minimum length of 1".to_string(),
1023                ));
1024            }
1025            if val.chars().count() > 35 {
1026                return Err(ValidationError::new(
1027                    1002,
1028                    "clr_sys_ref exceeds the maximum length of 35".to_string(),
1029                ));
1030            }
1031            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
1032            if !pattern.is_match(val) {
1033                return Err(ValidationError::new(
1034                    1005,
1035                    "clr_sys_ref does not match the required pattern".to_string(),
1036                ));
1037            }
1038        }
1039        Ok(())
1040    }
1041}
1042
1043// PaymentTypeInformation281: Specifies the high level purpose of the instruction based on a set of pre-defined categories.
1044// Usage: This is used by the initiating party to provide information concerning the processing of the payment. It is likely to trigger special processing by any of the agents involved in the payment chain.
1045#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1046pub struct PaymentTypeInformation281 {
1047    #[serde(rename = "InstrPrty", skip_serializing_if = "Option::is_none")]
1048    pub instr_prty: Option<Priority2Code>,
1049    #[serde(rename = "ClrChanl", skip_serializing_if = "Option::is_none")]
1050    pub clr_chanl: Option<ClearingChannel2Code>,
1051    #[serde(rename = "SvcLvl", skip_serializing_if = "Option::is_none")]
1052    pub svc_lvl: Option<Vec<ServiceLevel8Choice1>>,
1053    #[serde(rename = "LclInstrm", skip_serializing_if = "Option::is_none")]
1054    pub lcl_instrm: Option<LocalInstrument2Choice1>,
1055    #[serde(rename = "CtgyPurp", skip_serializing_if = "Option::is_none")]
1056    pub ctgy_purp: Option<CategoryPurpose1Choice1>,
1057}
1058
1059impl PaymentTypeInformation281 {
1060    pub fn validate(&self) -> Result<(), ValidationError> {
1061        if let Some(ref val) = self.instr_prty {
1062            val.validate()?
1063        }
1064        if let Some(ref val) = self.clr_chanl {
1065            val.validate()?
1066        }
1067        if let Some(ref vec) = self.svc_lvl {
1068            for item in vec {
1069                item.validate()?
1070            }
1071        }
1072        if let Some(ref val) = self.lcl_instrm {
1073            val.validate()?
1074        }
1075        if let Some(ref val) = self.ctgy_purp {
1076            val.validate()?
1077        }
1078        Ok(())
1079    }
1080}
1081
1082// PostalAddress241: Information that locates and identifies a specific address, as defined by postal services, presented in free format text.
1083#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1084pub struct PostalAddress241 {
1085    #[serde(rename = "Dept", skip_serializing_if = "Option::is_none")]
1086    pub dept: Option<String>,
1087    #[serde(rename = "SubDept", skip_serializing_if = "Option::is_none")]
1088    pub sub_dept: Option<String>,
1089    #[serde(rename = "StrtNm", skip_serializing_if = "Option::is_none")]
1090    pub strt_nm: Option<String>,
1091    #[serde(rename = "BldgNb", skip_serializing_if = "Option::is_none")]
1092    pub bldg_nb: Option<String>,
1093    #[serde(rename = "BldgNm", skip_serializing_if = "Option::is_none")]
1094    pub bldg_nm: Option<String>,
1095    #[serde(rename = "Flr", skip_serializing_if = "Option::is_none")]
1096    pub flr: Option<String>,
1097    #[serde(rename = "PstBx", skip_serializing_if = "Option::is_none")]
1098    pub pst_bx: Option<String>,
1099    #[serde(rename = "Room", skip_serializing_if = "Option::is_none")]
1100    pub room: Option<String>,
1101    #[serde(rename = "PstCd", skip_serializing_if = "Option::is_none")]
1102    pub pst_cd: Option<String>,
1103    #[serde(rename = "TwnNm", skip_serializing_if = "Option::is_none")]
1104    pub twn_nm: Option<String>,
1105    #[serde(rename = "TwnLctnNm", skip_serializing_if = "Option::is_none")]
1106    pub twn_lctn_nm: Option<String>,
1107    #[serde(rename = "DstrctNm", skip_serializing_if = "Option::is_none")]
1108    pub dstrct_nm: Option<String>,
1109    #[serde(rename = "CtrySubDvsn", skip_serializing_if = "Option::is_none")]
1110    pub ctry_sub_dvsn: Option<String>,
1111    #[serde(rename = "Ctry", skip_serializing_if = "Option::is_none")]
1112    pub ctry: Option<String>,
1113    #[serde(rename = "AdrLine", skip_serializing_if = "Option::is_none")]
1114    pub adr_line: Option<Vec<String>>,
1115}
1116
1117impl PostalAddress241 {
1118    pub fn validate(&self) -> Result<(), ValidationError> {
1119        if let Some(ref val) = self.dept {
1120            if val.chars().count() < 1 {
1121                return Err(ValidationError::new(
1122                    1001,
1123                    "dept is shorter than the minimum length of 1".to_string(),
1124                ));
1125            }
1126            if val.chars().count() > 70 {
1127                return Err(ValidationError::new(
1128                    1002,
1129                    "dept exceeds the maximum length of 70".to_string(),
1130                ));
1131            }
1132            let pattern = Regex::new(
1133                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1134            )
1135            .unwrap();
1136            if !pattern.is_match(val) {
1137                return Err(ValidationError::new(
1138                    1005,
1139                    "dept does not match the required pattern".to_string(),
1140                ));
1141            }
1142        }
1143        if let Some(ref val) = self.sub_dept {
1144            if val.chars().count() < 1 {
1145                return Err(ValidationError::new(
1146                    1001,
1147                    "sub_dept is shorter than the minimum length of 1".to_string(),
1148                ));
1149            }
1150            if val.chars().count() > 70 {
1151                return Err(ValidationError::new(
1152                    1002,
1153                    "sub_dept exceeds the maximum length of 70".to_string(),
1154                ));
1155            }
1156            let pattern = Regex::new(
1157                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1158            )
1159            .unwrap();
1160            if !pattern.is_match(val) {
1161                return Err(ValidationError::new(
1162                    1005,
1163                    "sub_dept does not match the required pattern".to_string(),
1164                ));
1165            }
1166        }
1167        if let Some(ref val) = self.strt_nm {
1168            if val.chars().count() < 1 {
1169                return Err(ValidationError::new(
1170                    1001,
1171                    "strt_nm is shorter than the minimum length of 1".to_string(),
1172                ));
1173            }
1174            if val.chars().count() > 70 {
1175                return Err(ValidationError::new(
1176                    1002,
1177                    "strt_nm exceeds the maximum length of 70".to_string(),
1178                ));
1179            }
1180            let pattern = Regex::new(
1181                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1182            )
1183            .unwrap();
1184            if !pattern.is_match(val) {
1185                return Err(ValidationError::new(
1186                    1005,
1187                    "strt_nm does not match the required pattern".to_string(),
1188                ));
1189            }
1190        }
1191        if let Some(ref val) = self.bldg_nb {
1192            if val.chars().count() < 1 {
1193                return Err(ValidationError::new(
1194                    1001,
1195                    "bldg_nb is shorter than the minimum length of 1".to_string(),
1196                ));
1197            }
1198            if val.chars().count() > 16 {
1199                return Err(ValidationError::new(
1200                    1002,
1201                    "bldg_nb exceeds the maximum length of 16".to_string(),
1202                ));
1203            }
1204            let pattern = Regex::new(
1205                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1206            )
1207            .unwrap();
1208            if !pattern.is_match(val) {
1209                return Err(ValidationError::new(
1210                    1005,
1211                    "bldg_nb does not match the required pattern".to_string(),
1212                ));
1213            }
1214        }
1215        if let Some(ref val) = self.bldg_nm {
1216            if val.chars().count() < 1 {
1217                return Err(ValidationError::new(
1218                    1001,
1219                    "bldg_nm is shorter than the minimum length of 1".to_string(),
1220                ));
1221            }
1222            if val.chars().count() > 35 {
1223                return Err(ValidationError::new(
1224                    1002,
1225                    "bldg_nm exceeds the maximum length of 35".to_string(),
1226                ));
1227            }
1228            let pattern = Regex::new(
1229                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1230            )
1231            .unwrap();
1232            if !pattern.is_match(val) {
1233                return Err(ValidationError::new(
1234                    1005,
1235                    "bldg_nm does not match the required pattern".to_string(),
1236                ));
1237            }
1238        }
1239        if let Some(ref val) = self.flr {
1240            if val.chars().count() < 1 {
1241                return Err(ValidationError::new(
1242                    1001,
1243                    "flr is shorter than the minimum length of 1".to_string(),
1244                ));
1245            }
1246            if val.chars().count() > 70 {
1247                return Err(ValidationError::new(
1248                    1002,
1249                    "flr exceeds the maximum length of 70".to_string(),
1250                ));
1251            }
1252            let pattern = Regex::new(
1253                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1254            )
1255            .unwrap();
1256            if !pattern.is_match(val) {
1257                return Err(ValidationError::new(
1258                    1005,
1259                    "flr does not match the required pattern".to_string(),
1260                ));
1261            }
1262        }
1263        if let Some(ref val) = self.pst_bx {
1264            if val.chars().count() < 1 {
1265                return Err(ValidationError::new(
1266                    1001,
1267                    "pst_bx is shorter than the minimum length of 1".to_string(),
1268                ));
1269            }
1270            if val.chars().count() > 16 {
1271                return Err(ValidationError::new(
1272                    1002,
1273                    "pst_bx exceeds the maximum length of 16".to_string(),
1274                ));
1275            }
1276            let pattern = Regex::new(
1277                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1278            )
1279            .unwrap();
1280            if !pattern.is_match(val) {
1281                return Err(ValidationError::new(
1282                    1005,
1283                    "pst_bx does not match the required pattern".to_string(),
1284                ));
1285            }
1286        }
1287        if let Some(ref val) = self.room {
1288            if val.chars().count() < 1 {
1289                return Err(ValidationError::new(
1290                    1001,
1291                    "room is shorter than the minimum length of 1".to_string(),
1292                ));
1293            }
1294            if val.chars().count() > 70 {
1295                return Err(ValidationError::new(
1296                    1002,
1297                    "room exceeds the maximum length of 70".to_string(),
1298                ));
1299            }
1300            let pattern = Regex::new(
1301                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1302            )
1303            .unwrap();
1304            if !pattern.is_match(val) {
1305                return Err(ValidationError::new(
1306                    1005,
1307                    "room does not match the required pattern".to_string(),
1308                ));
1309            }
1310        }
1311        if let Some(ref val) = self.pst_cd {
1312            if val.chars().count() < 1 {
1313                return Err(ValidationError::new(
1314                    1001,
1315                    "pst_cd is shorter than the minimum length of 1".to_string(),
1316                ));
1317            }
1318            if val.chars().count() > 16 {
1319                return Err(ValidationError::new(
1320                    1002,
1321                    "pst_cd exceeds the maximum length of 16".to_string(),
1322                ));
1323            }
1324            let pattern = Regex::new(
1325                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1326            )
1327            .unwrap();
1328            if !pattern.is_match(val) {
1329                return Err(ValidationError::new(
1330                    1005,
1331                    "pst_cd does not match the required pattern".to_string(),
1332                ));
1333            }
1334        }
1335        if let Some(ref val) = self.twn_nm {
1336            if val.chars().count() < 1 {
1337                return Err(ValidationError::new(
1338                    1001,
1339                    "twn_nm is shorter than the minimum length of 1".to_string(),
1340                ));
1341            }
1342            if val.chars().count() > 35 {
1343                return Err(ValidationError::new(
1344                    1002,
1345                    "twn_nm exceeds the maximum length of 35".to_string(),
1346                ));
1347            }
1348            let pattern = Regex::new(
1349                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1350            )
1351            .unwrap();
1352            if !pattern.is_match(val) {
1353                return Err(ValidationError::new(
1354                    1005,
1355                    "twn_nm does not match the required pattern".to_string(),
1356                ));
1357            }
1358        }
1359        if let Some(ref val) = self.twn_lctn_nm {
1360            if val.chars().count() < 1 {
1361                return Err(ValidationError::new(
1362                    1001,
1363                    "twn_lctn_nm is shorter than the minimum length of 1".to_string(),
1364                ));
1365            }
1366            if val.chars().count() > 35 {
1367                return Err(ValidationError::new(
1368                    1002,
1369                    "twn_lctn_nm exceeds the maximum length of 35".to_string(),
1370                ));
1371            }
1372            let pattern = Regex::new(
1373                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1374            )
1375            .unwrap();
1376            if !pattern.is_match(val) {
1377                return Err(ValidationError::new(
1378                    1005,
1379                    "twn_lctn_nm does not match the required pattern".to_string(),
1380                ));
1381            }
1382        }
1383        if let Some(ref val) = self.dstrct_nm {
1384            if val.chars().count() < 1 {
1385                return Err(ValidationError::new(
1386                    1001,
1387                    "dstrct_nm is shorter than the minimum length of 1".to_string(),
1388                ));
1389            }
1390            if val.chars().count() > 35 {
1391                return Err(ValidationError::new(
1392                    1002,
1393                    "dstrct_nm exceeds the maximum length of 35".to_string(),
1394                ));
1395            }
1396            let pattern = Regex::new(
1397                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1398            )
1399            .unwrap();
1400            if !pattern.is_match(val) {
1401                return Err(ValidationError::new(
1402                    1005,
1403                    "dstrct_nm does not match the required pattern".to_string(),
1404                ));
1405            }
1406        }
1407        if let Some(ref val) = self.ctry_sub_dvsn {
1408            if val.chars().count() < 1 {
1409                return Err(ValidationError::new(
1410                    1001,
1411                    "ctry_sub_dvsn is shorter than the minimum length of 1".to_string(),
1412                ));
1413            }
1414            if val.chars().count() > 35 {
1415                return Err(ValidationError::new(
1416                    1002,
1417                    "ctry_sub_dvsn exceeds the maximum length of 35".to_string(),
1418                ));
1419            }
1420            let pattern = Regex::new(
1421                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1422            )
1423            .unwrap();
1424            if !pattern.is_match(val) {
1425                return Err(ValidationError::new(
1426                    1005,
1427                    "ctry_sub_dvsn does not match the required pattern".to_string(),
1428                ));
1429            }
1430        }
1431        if let Some(ref val) = self.ctry {
1432            let pattern = Regex::new("[A-Z]{2,2}").unwrap();
1433            if !pattern.is_match(val) {
1434                return Err(ValidationError::new(
1435                    1005,
1436                    "ctry does not match the required pattern".to_string(),
1437                ));
1438            }
1439        }
1440        if let Some(ref vec) = self.adr_line {
1441            for item in vec {
1442                if item.chars().count() < 1 {
1443                    return Err(ValidationError::new(
1444                        1001,
1445                        "adr_line is shorter than the minimum length of 1".to_string(),
1446                    ));
1447                }
1448                if item.chars().count() > 70 {
1449                    return Err(ValidationError::new(
1450                        1002,
1451                        "adr_line exceeds the maximum length of 70".to_string(),
1452                    ));
1453                }
1454                let pattern = Regex::new(
1455                    "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1456                )
1457                .unwrap();
1458                if !pattern.is_match(&item) {
1459                    return Err(ValidationError::new(
1460                        1005,
1461                        "adr_line does not match the required pattern".to_string(),
1462                    ));
1463                }
1464            }
1465        }
1466        Ok(())
1467    }
1468}
1469
1470// Priority2Code: Priority level is normal.
1471#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1472pub enum Priority2Code {
1473    #[default]
1474    #[serde(rename = "HIGH")]
1475    CodeHIGH,
1476    #[serde(rename = "NORM")]
1477    CodeNORM,
1478}
1479
1480impl Priority2Code {
1481    pub fn validate(&self) -> Result<(), ValidationError> {
1482        Ok(())
1483    }
1484}
1485
1486// Priority3Code: Priority level is normal.
1487#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1488pub enum Priority3Code {
1489    #[default]
1490    #[serde(rename = "URGT")]
1491    CodeURGT,
1492    #[serde(rename = "HIGH")]
1493    CodeHIGH,
1494    #[serde(rename = "NORM")]
1495    CodeNORM,
1496}
1497
1498impl Priority3Code {
1499    pub fn validate(&self) -> Result<(), ValidationError> {
1500        Ok(())
1501    }
1502}
1503
1504// ProxyAccountIdentification11: Identification used to indicate the account identification under another specified name.
1505#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1506pub struct ProxyAccountIdentification11 {
1507    #[serde(rename = "Tp", skip_serializing_if = "Option::is_none")]
1508    pub tp: Option<ProxyAccountType1Choice1>,
1509    #[serde(rename = "Id")]
1510    pub id: String,
1511}
1512
1513impl ProxyAccountIdentification11 {
1514    pub fn validate(&self) -> Result<(), ValidationError> {
1515        if let Some(ref val) = self.tp {
1516            val.validate()?
1517        }
1518        if self.id.chars().count() < 1 {
1519            return Err(ValidationError::new(
1520                1001,
1521                "id is shorter than the minimum length of 1".to_string(),
1522            ));
1523        }
1524        if self.id.chars().count() > 320 {
1525            return Err(ValidationError::new(
1526                1002,
1527                "id exceeds the maximum length of 320".to_string(),
1528            ));
1529        }
1530        let pattern =
1531            Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+")
1532                .unwrap();
1533        if !pattern.is_match(&self.id) {
1534            return Err(ValidationError::new(
1535                1005,
1536                "id does not match the required pattern".to_string(),
1537            ));
1538        }
1539        Ok(())
1540    }
1541}
1542
1543// ProxyAccountType1Choice1: Name of the identification scheme, in a free text form.
1544#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1545pub struct ProxyAccountType1Choice1 {
1546    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
1547    pub cd: Option<String>,
1548    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
1549    pub prtry: Option<String>,
1550}
1551
1552impl ProxyAccountType1Choice1 {
1553    pub fn validate(&self) -> Result<(), ValidationError> {
1554        if let Some(ref val) = self.cd {
1555            if val.chars().count() < 1 {
1556                return Err(ValidationError::new(
1557                    1001,
1558                    "cd is shorter than the minimum length of 1".to_string(),
1559                ));
1560            }
1561            if val.chars().count() > 4 {
1562                return Err(ValidationError::new(
1563                    1002,
1564                    "cd exceeds the maximum length of 4".to_string(),
1565                ));
1566            }
1567        }
1568        if let Some(ref val) = self.prtry {
1569            if val.chars().count() < 1 {
1570                return Err(ValidationError::new(
1571                    1001,
1572                    "prtry is shorter than the minimum length of 1".to_string(),
1573                ));
1574            }
1575            if val.chars().count() > 35 {
1576                return Err(ValidationError::new(
1577                    1002,
1578                    "prtry exceeds the maximum length of 35".to_string(),
1579                ));
1580            }
1581            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
1582            if !pattern.is_match(val) {
1583                return Err(ValidationError::new(
1584                    1005,
1585                    "prtry does not match the required pattern".to_string(),
1586                ));
1587            }
1588        }
1589        Ok(())
1590    }
1591}
1592
1593// Purpose2Choice1: Purpose, in a proprietary form.
1594#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1595pub struct Purpose2Choice1 {
1596    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
1597    pub cd: Option<String>,
1598    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
1599    pub prtry: Option<String>,
1600}
1601
1602impl Purpose2Choice1 {
1603    pub fn validate(&self) -> Result<(), ValidationError> {
1604        if let Some(ref val) = self.cd {
1605            if val.chars().count() < 1 {
1606                return Err(ValidationError::new(
1607                    1001,
1608                    "cd is shorter than the minimum length of 1".to_string(),
1609                ));
1610            }
1611            if val.chars().count() > 4 {
1612                return Err(ValidationError::new(
1613                    1002,
1614                    "cd exceeds the maximum length of 4".to_string(),
1615                ));
1616            }
1617        }
1618        if let Some(ref val) = self.prtry {
1619            if val.chars().count() < 1 {
1620                return Err(ValidationError::new(
1621                    1001,
1622                    "prtry is shorter than the minimum length of 1".to_string(),
1623                ));
1624            }
1625            if val.chars().count() > 35 {
1626                return Err(ValidationError::new(
1627                    1002,
1628                    "prtry exceeds the maximum length of 35".to_string(),
1629                ));
1630            }
1631            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
1632            if !pattern.is_match(val) {
1633                return Err(ValidationError::new(
1634                    1005,
1635                    "prtry does not match the required pattern".to_string(),
1636                ));
1637            }
1638        }
1639        Ok(())
1640    }
1641}
1642
1643// RemittanceInformation21: Information supplied to enable the matching of an entry with the items that the transfer is intended to settle, for example, commercial invoices in an accounts' receivable system in an unstructured form.
1644#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1645pub struct RemittanceInformation21 {
1646    #[serde(rename = "Ustrd", skip_serializing_if = "Option::is_none")]
1647    pub ustrd: Option<String>,
1648}
1649
1650impl RemittanceInformation21 {
1651    pub fn validate(&self) -> Result<(), ValidationError> {
1652        if let Some(ref val) = self.ustrd {
1653            if val.chars().count() < 1 {
1654                return Err(ValidationError::new(
1655                    1001,
1656                    "ustrd is shorter than the minimum length of 1".to_string(),
1657                ));
1658            }
1659            if val.chars().count() > 140 {
1660                return Err(ValidationError::new(
1661                    1002,
1662                    "ustrd exceeds the maximum length of 140".to_string(),
1663                ));
1664            }
1665            let pattern = Regex::new(
1666                "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ !#$%&\\*=^_`\\{\\|\\}~\";<>@\\[\\\\\\]]+",
1667            )
1668            .unwrap();
1669            if !pattern.is_match(val) {
1670                return Err(ValidationError::new(
1671                    1005,
1672                    "ustrd does not match the required pattern".to_string(),
1673                ));
1674            }
1675        }
1676        Ok(())
1677    }
1678}
1679
1680// ServiceLevel8Choice1: Specifies a pre-agreed service or level of service between the parties, as a proprietary code.
1681#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1682pub struct ServiceLevel8Choice1 {
1683    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
1684    pub cd: Option<String>,
1685    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
1686    pub prtry: Option<String>,
1687}
1688
1689impl ServiceLevel8Choice1 {
1690    pub fn validate(&self) -> Result<(), ValidationError> {
1691        if let Some(ref val) = self.cd {
1692            if val.chars().count() < 1 {
1693                return Err(ValidationError::new(
1694                    1001,
1695                    "cd is shorter than the minimum length of 1".to_string(),
1696                ));
1697            }
1698            if val.chars().count() > 4 {
1699                return Err(ValidationError::new(
1700                    1002,
1701                    "cd exceeds the maximum length of 4".to_string(),
1702                ));
1703            }
1704        }
1705        if let Some(ref val) = self.prtry {
1706            if val.chars().count() < 1 {
1707                return Err(ValidationError::new(
1708                    1001,
1709                    "prtry is shorter than the minimum length of 1".to_string(),
1710                ));
1711            }
1712            if val.chars().count() > 35 {
1713                return Err(ValidationError::new(
1714                    1002,
1715                    "prtry exceeds the maximum length of 35".to_string(),
1716                ));
1717            }
1718            let pattern = Regex::new("[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+").unwrap();
1719            if !pattern.is_match(val) {
1720                return Err(ValidationError::new(
1721                    1005,
1722                    "prtry does not match the required pattern".to_string(),
1723                ));
1724            }
1725        }
1726        Ok(())
1727    }
1728}
1729
1730// SettlementDateTimeIndication11: Date and time at which a payment has been credited at the transaction administrator. In the case of TARGET, the date and time at which the payment has been credited at the receiving central bank, expressed in Central European Time (CET).
1731#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1732pub struct SettlementDateTimeIndication11 {
1733    #[serde(rename = "DbtDtTm", skip_serializing_if = "Option::is_none")]
1734    pub dbt_dt_tm: Option<String>,
1735    #[serde(rename = "CdtDtTm", skip_serializing_if = "Option::is_none")]
1736    pub cdt_dt_tm: Option<String>,
1737}
1738
1739impl SettlementDateTimeIndication11 {
1740    pub fn validate(&self) -> Result<(), ValidationError> {
1741        if let Some(ref val) = self.dbt_dt_tm {
1742            let pattern = Regex::new(".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]").unwrap();
1743            if !pattern.is_match(val) {
1744                return Err(ValidationError::new(
1745                    1005,
1746                    "dbt_dt_tm does not match the required pattern".to_string(),
1747                ));
1748            }
1749        }
1750        if let Some(ref val) = self.cdt_dt_tm {
1751            let pattern = Regex::new(".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]").unwrap();
1752            if !pattern.is_match(val) {
1753                return Err(ValidationError::new(
1754                    1005,
1755                    "cdt_dt_tm does not match the required pattern".to_string(),
1756                ));
1757            }
1758        }
1759        Ok(())
1760    }
1761}
1762
1763// SettlementInstruction71: A specific purpose account used to post debit and credit entries as a result of the transaction.
1764#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1765pub struct SettlementInstruction71 {
1766    #[serde(rename = "SttlmMtd")]
1767    pub sttlm_mtd: SettlementMethod1Code1,
1768    #[serde(rename = "SttlmAcct", skip_serializing_if = "Option::is_none")]
1769    pub sttlm_acct: Option<CashAccount381>,
1770}
1771
1772impl SettlementInstruction71 {
1773    pub fn validate(&self) -> Result<(), ValidationError> {
1774        self.sttlm_mtd.validate()?;
1775        if let Some(ref val) = self.sttlm_acct {
1776            val.validate()?
1777        }
1778        Ok(())
1779    }
1780}
1781
1782// SettlementMethod1Code__1: Settlement is done by the agent instructing and forwarding the payment to the next party in the payment chain.
1783#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1784pub enum SettlementMethod1Code1 {
1785    #[default]
1786    #[serde(rename = "INDA")]
1787    CodeINDA,
1788    #[serde(rename = "INGA")]
1789    CodeINGA,
1790}
1791
1792impl SettlementMethod1Code1 {
1793    pub fn validate(&self) -> Result<(), ValidationError> {
1794        Ok(())
1795    }
1796}
1797
1798// SettlementTimeRequest21: Time by when the payment must be settled to avoid rejection.
1799#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
1800pub struct SettlementTimeRequest21 {
1801    #[serde(rename = "CLSTm", skip_serializing_if = "Option::is_none")]
1802    pub cls_tm: Option<String>,
1803    #[serde(rename = "TillTm", skip_serializing_if = "Option::is_none")]
1804    pub till_tm: Option<String>,
1805    #[serde(rename = "FrTm", skip_serializing_if = "Option::is_none")]
1806    pub fr_tm: Option<String>,
1807    #[serde(rename = "RjctTm", skip_serializing_if = "Option::is_none")]
1808    pub rjct_tm: Option<String>,
1809}
1810
1811impl SettlementTimeRequest21 {
1812    pub fn validate(&self) -> Result<(), ValidationError> {
1813        if let Some(ref val) = self.cls_tm {
1814            let pattern = Regex::new(".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]").unwrap();
1815            if !pattern.is_match(val) {
1816                return Err(ValidationError::new(
1817                    1005,
1818                    "cls_tm does not match the required pattern".to_string(),
1819                ));
1820            }
1821        }
1822        if let Some(ref val) = self.till_tm {
1823            let pattern = Regex::new(".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]").unwrap();
1824            if !pattern.is_match(val) {
1825                return Err(ValidationError::new(
1826                    1005,
1827                    "till_tm does not match the required pattern".to_string(),
1828                ));
1829            }
1830        }
1831        if let Some(ref val) = self.fr_tm {
1832            let pattern = Regex::new(".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]").unwrap();
1833            if !pattern.is_match(val) {
1834                return Err(ValidationError::new(
1835                    1005,
1836                    "fr_tm does not match the required pattern".to_string(),
1837                ));
1838            }
1839        }
1840        if let Some(ref val) = self.rjct_tm {
1841            let pattern = Regex::new(".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]").unwrap();
1842            if !pattern.is_match(val) {
1843                return Err(ValidationError::new(
1844                    1005,
1845                    "rjct_tm does not match the required pattern".to_string(),
1846                ));
1847            }
1848        }
1849        Ok(())
1850    }
1851}