mx_message/header/
bah_pacs_010_001_03_mc.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
19use crate::parse_result::{ErrorCollector, ParserConfig};
20use crate::validation::{Validate, helpers};
21use serde::{Deserialize, Serialize};
22
23// BranchAndFinancialInstitutionIdentification61: Unique and unambiguous identification of a financial institution, as assigned under an internationally recognised or proprietary identification scheme.
24#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
25pub struct BranchAndFinancialInstitutionIdentification61 {
26    #[serde(rename = "FinInstnId")]
27    pub fin_instn_id: FinancialInstitutionIdentification181,
28}
29
30impl Validate for BranchAndFinancialInstitutionIdentification61 {
31    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
32        self.fin_instn_id
33            .validate(&helpers::child_path(path, "FinInstnId"), config, collector);
34    }
35}
36
37// BranchAndFinancialInstitutionIdentification63: Unique and unambiguous identification of a financial institution, as assigned under an internationally recognised or proprietary identification scheme.
38#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
39pub struct BranchAndFinancialInstitutionIdentification63 {
40    #[serde(rename = "FinInstnId")]
41    pub fin_instn_id: FinancialInstitutionIdentification183,
42}
43
44impl Validate for BranchAndFinancialInstitutionIdentification63 {
45    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
46        self.fin_instn_id
47            .validate(&helpers::child_path(path, "FinInstnId"), config, collector);
48    }
49}
50
51// BusinessApplicationHeader51: Relative indication of the processing precedence of the message over a (set of) Business Messages with assigned priorities.
52#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
53pub struct BusinessApplicationHeader51 {
54    #[serde(rename = "CharSet", skip_serializing_if = "Option::is_none")]
55    pub char_set: Option<String>,
56    #[serde(rename = "Fr")]
57    pub fr: Party44Choice2,
58    #[serde(rename = "To")]
59    pub to: Party44Choice2,
60    #[serde(rename = "BizMsgIdr")]
61    pub biz_msg_idr: String,
62    #[serde(rename = "MsgDefIdr")]
63    pub msg_def_idr: String,
64    #[serde(rename = "BizSvc", skip_serializing_if = "Option::is_none")]
65    pub biz_svc: Option<String>,
66    #[serde(rename = "CreDt")]
67    pub cre_dt: String,
68    #[serde(rename = "CpyDplct", skip_serializing_if = "Option::is_none")]
69    pub cpy_dplct: Option<CopyDuplicate1Code>,
70    #[serde(rename = "Prty", skip_serializing_if = "Option::is_none")]
71    pub prty: Option<String>,
72}
73
74impl Validate for BusinessApplicationHeader51 {
75    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
76        self.fr
77            .validate(&helpers::child_path(path, "Fr"), config, collector);
78        self.to
79            .validate(&helpers::child_path(path, "To"), config, collector);
80        helpers::validate_length(
81            &self.biz_msg_idr,
82            "BizMsgIdr",
83            Some(1),
84            Some(35),
85            &helpers::child_path(path, "BizMsgIdr"),
86            config,
87            collector,
88        );
89        helpers::validate_length(
90            &self.msg_def_idr,
91            "MsgDefIdr",
92            Some(1),
93            Some(35),
94            &helpers::child_path(path, "MsgDefIdr"),
95            config,
96            collector,
97        );
98        if let Some(ref val) = self.biz_svc {
99            helpers::validate_length(
100                val,
101                "BizSvc",
102                Some(1),
103                Some(35),
104                &helpers::child_path(path, "BizSvc"),
105                config,
106                collector,
107            );
108        }
109        helpers::validate_pattern(
110            &self.cre_dt,
111            "CreDt",
112            ".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]",
113            &helpers::child_path(path, "CreDt"),
114            config,
115            collector,
116        );
117        if let Some(ref val) = self.cpy_dplct
118            && config.validate_optional_fields
119        {
120            val.validate(&helpers::child_path(path, "CpyDplct"), config, collector);
121        }
122    }
123}
124
125// BusinessApplicationHeaderV02: Specifies the Business Application Header(s) of the Business Message(s) to which this Business Message relates.
126// Can be used when replying to a query; can also be used when canceling or amending.
127#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
128#[serde(rename = "AppHdr")]
129pub struct BusinessApplicationHeaderV02 {
130    #[serde(rename = "CharSet", skip_serializing_if = "Option::is_none")]
131    pub char_set: Option<String>,
132    #[serde(rename = "Fr")]
133    pub fr: Party44Choice1,
134    #[serde(rename = "To")]
135    pub to: Party44Choice1,
136    #[serde(rename = "BizMsgIdr")]
137    pub biz_msg_idr: String,
138    #[serde(rename = "MsgDefIdr")]
139    pub msg_def_idr: String,
140    #[serde(rename = "BizSvc")]
141    pub biz_svc: String,
142    #[serde(rename = "MktPrctc", skip_serializing_if = "Option::is_none")]
143    pub mkt_prctc: Option<ImplementationSpecification1>,
144    #[serde(rename = "CreDt")]
145    pub cre_dt: String,
146    #[serde(rename = "CpyDplct", skip_serializing_if = "Option::is_none")]
147    pub cpy_dplct: Option<CopyDuplicate1Code>,
148    #[serde(rename = "PssblDplct", skip_serializing_if = "Option::is_none")]
149    pub pssbl_dplct: Option<bool>,
150    #[serde(rename = "Prty", skip_serializing_if = "Option::is_none")]
151    pub prty: Option<Priority2Code>,
152    #[serde(rename = "Rltd", skip_serializing_if = "Option::is_none")]
153    pub rltd: Option<BusinessApplicationHeader51>,
154}
155
156impl Validate for BusinessApplicationHeaderV02 {
157    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
158        self.fr
159            .validate(&helpers::child_path(path, "Fr"), config, collector);
160        self.to
161            .validate(&helpers::child_path(path, "To"), config, collector);
162        helpers::validate_length(
163            &self.biz_msg_idr,
164            "BizMsgIdr",
165            Some(1),
166            Some(35),
167            &helpers::child_path(path, "BizMsgIdr"),
168            config,
169            collector,
170        );
171        helpers::validate_length(
172            &self.msg_def_idr,
173            "MsgDefIdr",
174            Some(1),
175            Some(35),
176            &helpers::child_path(path, "MsgDefIdr"),
177            config,
178            collector,
179        );
180        helpers::validate_length(
181            &self.biz_svc,
182            "BizSvc",
183            Some(6),
184            Some(35),
185            &helpers::child_path(path, "BizSvc"),
186            config,
187            collector,
188        );
189        helpers::validate_pattern(
190            &self.biz_svc,
191            "BizSvc",
192            "[a-z0-9]{1,10}\\.([a-z0-9]{1,10}\\.)+\\d\\d",
193            &helpers::child_path(path, "BizSvc"),
194            config,
195            collector,
196        );
197        if let Some(ref val) = self.mkt_prctc
198            && config.validate_optional_fields
199        {
200            val.validate(&helpers::child_path(path, "MktPrctc"), config, collector);
201        }
202        helpers::validate_pattern(
203            &self.cre_dt,
204            "CreDt",
205            ".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]",
206            &helpers::child_path(path, "CreDt"),
207            config,
208            collector,
209        );
210        if let Some(ref val) = self.cpy_dplct
211            && config.validate_optional_fields
212        {
213            val.validate(&helpers::child_path(path, "CpyDplct"), config, collector);
214        }
215        if let Some(ref val) = self.prty
216            && config.validate_optional_fields
217        {
218            val.validate(&helpers::child_path(path, "Prty"), config, collector);
219        }
220        if let Some(ref val) = self.rltd
221            && config.validate_optional_fields
222        {
223            val.validate(&helpers::child_path(path, "Rltd"), config, collector);
224        }
225    }
226}
227
228// ClearingSystemIdentification2Choice: Identification code for a clearing system, that has not yet been identified in the list of clearing systems.
229#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
230pub struct ClearingSystemIdentification2Choice {
231    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
232    pub cd: Option<String>,
233    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
234    pub prtry: Option<String>,
235}
236
237impl Validate for ClearingSystemIdentification2Choice {
238    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
239        if let Some(ref val) = self.cd {
240            helpers::validate_length(
241                val,
242                "Cd",
243                Some(1),
244                Some(5),
245                &helpers::child_path(path, "Cd"),
246                config,
247                collector,
248            );
249        }
250        if let Some(ref val) = self.prtry {
251            helpers::validate_length(
252                val,
253                "Prtry",
254                Some(1),
255                Some(35),
256                &helpers::child_path(path, "Prtry"),
257                config,
258                collector,
259            );
260        }
261    }
262}
263
264// ClearingSystemIdentification2Choice1: Identification of a clearing system, in a coded form as published in an external list.
265#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
266pub struct ClearingSystemIdentification2Choice1 {
267    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
268    pub cd: Option<String>,
269}
270
271impl Validate for ClearingSystemIdentification2Choice1 {
272    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
273        if let Some(ref val) = self.cd {
274            helpers::validate_length(
275                val,
276                "Cd",
277                Some(1),
278                Some(5),
279                &helpers::child_path(path, "Cd"),
280                config,
281                collector,
282            );
283        }
284    }
285}
286
287// ClearingSystemMemberIdentification2: Identification of a member of a clearing system.
288#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
289pub struct ClearingSystemMemberIdentification2 {
290    #[serde(rename = "ClrSysId", skip_serializing_if = "Option::is_none")]
291    pub clr_sys_id: Option<ClearingSystemIdentification2Choice>,
292    #[serde(rename = "MmbId")]
293    pub mmb_id: String,
294}
295
296impl Validate for ClearingSystemMemberIdentification2 {
297    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
298        if let Some(ref val) = self.clr_sys_id
299            && config.validate_optional_fields
300        {
301            val.validate(&helpers::child_path(path, "ClrSysId"), config, collector);
302        }
303        helpers::validate_length(
304            &self.mmb_id,
305            "MmbId",
306            Some(1),
307            Some(35),
308            &helpers::child_path(path, "MmbId"),
309            config,
310            collector,
311        );
312    }
313}
314
315// ClearingSystemMemberIdentification21: Identification of a member of a clearing system.
316#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
317pub struct ClearingSystemMemberIdentification21 {
318    #[serde(rename = "ClrSysId")]
319    pub clr_sys_id: ClearingSystemIdentification2Choice1,
320    #[serde(rename = "MmbId")]
321    pub mmb_id: String,
322}
323
324impl Validate for ClearingSystemMemberIdentification21 {
325    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
326        self.clr_sys_id
327            .validate(&helpers::child_path(path, "ClrSysId"), config, collector);
328        helpers::validate_length(
329            &self.mmb_id,
330            "MmbId",
331            Some(1),
332            Some(28),
333            &helpers::child_path(path, "MmbId"),
334            config,
335            collector,
336        );
337        helpers::validate_pattern(
338            &self.mmb_id,
339            "MmbId",
340            "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+",
341            &helpers::child_path(path, "MmbId"),
342            config,
343            collector,
344        );
345    }
346}
347
348// CopyDuplicate1Code: Message is for information/confirmation purposes. It is a duplicate of a message previously sent.
349#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
350pub enum CopyDuplicate1Code {
351    #[default]
352    #[serde(rename = "CODU")]
353    CodeCODU,
354    #[serde(rename = "COPY")]
355    CodeCOPY,
356    #[serde(rename = "DUPL")]
357    CodeDUPL,
358}
359
360impl Validate for CopyDuplicate1Code {
361    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
362        // Enum validation is typically empty
363    }
364}
365
366// FinancialInstitutionIdentification181: Legal entity identifier of the financial institution.
367#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
368pub struct FinancialInstitutionIdentification181 {
369    #[serde(rename = "BICFI")]
370    pub bicfi: String,
371    #[serde(rename = "ClrSysMmbId", skip_serializing_if = "Option::is_none")]
372    pub clr_sys_mmb_id: Option<ClearingSystemMemberIdentification21>,
373    #[serde(rename = "LEI", skip_serializing_if = "Option::is_none")]
374    pub lei: Option<String>,
375}
376
377impl Validate for FinancialInstitutionIdentification181 {
378    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
379        helpers::validate_pattern(
380            &self.bicfi,
381            "BICFI",
382            "[A-Z0-9]{4,4}[A-Z]{2,2}[A-Z0-9]{2,2}([A-Z0-9]{3,3}){0,1}",
383            &helpers::child_path(path, "BICFI"),
384            config,
385            collector,
386        );
387        if let Some(ref val) = self.clr_sys_mmb_id
388            && config.validate_optional_fields
389        {
390            val.validate(&helpers::child_path(path, "ClrSysMmbId"), config, collector);
391        }
392        if let Some(ref val) = self.lei {
393            helpers::validate_pattern(
394                val,
395                "LEI",
396                "[A-Z0-9]{18,18}[0-9]{2,2}",
397                &helpers::child_path(path, "LEI"),
398                config,
399                collector,
400            );
401        }
402    }
403}
404
405// FinancialInstitutionIdentification183: Legal entity identifier of the financial institution.
406#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
407pub struct FinancialInstitutionIdentification183 {
408    #[serde(rename = "BICFI")]
409    pub bicfi: String,
410    #[serde(rename = "ClrSysMmbId", skip_serializing_if = "Option::is_none")]
411    pub clr_sys_mmb_id: Option<ClearingSystemMemberIdentification2>,
412    #[serde(rename = "LEI", skip_serializing_if = "Option::is_none")]
413    pub lei: Option<String>,
414}
415
416impl Validate for FinancialInstitutionIdentification183 {
417    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
418        helpers::validate_pattern(
419            &self.bicfi,
420            "BICFI",
421            "[A-Z0-9]{4,4}[A-Z]{2,2}[A-Z0-9]{2,2}([A-Z0-9]{3,3}){0,1}",
422            &helpers::child_path(path, "BICFI"),
423            config,
424            collector,
425        );
426        if let Some(ref val) = self.clr_sys_mmb_id
427            && config.validate_optional_fields
428        {
429            val.validate(&helpers::child_path(path, "ClrSysMmbId"), config, collector);
430        }
431        if let Some(ref val) = self.lei {
432            helpers::validate_pattern(
433                val,
434                "LEI",
435                "[A-Z0-9]{18,18}[0-9]{2,2}",
436                &helpers::child_path(path, "LEI"),
437                config,
438                collector,
439            );
440        }
441    }
442}
443
444// ImplementationSpecification1: Identifier which unambiguously identifies, within the implementation specification registry, the implementation specification to which the ISO 20022 message is compliant. This can be done via a URN. It can also contain a version number or date.
445// For instance, "2018-01-01 – Version 2" or "urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66".
446#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
447pub struct ImplementationSpecification1 {
448    #[serde(rename = "Regy")]
449    pub regy: String,
450    #[serde(rename = "Id")]
451    pub id: String,
452}
453
454impl Validate for ImplementationSpecification1 {
455    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
456        helpers::validate_length(
457            &self.regy,
458            "Regy",
459            Some(1),
460            Some(350),
461            &helpers::child_path(path, "Regy"),
462            config,
463            collector,
464        );
465        helpers::validate_length(
466            &self.id,
467            "Id",
468            Some(1),
469            Some(2048),
470            &helpers::child_path(path, "Id"),
471            config,
472            collector,
473        );
474    }
475}
476
477// Party44Choice1: Identification of a financial institution.
478#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
479pub struct Party44Choice1 {
480    #[serde(rename = "FIId", skip_serializing_if = "Option::is_none")]
481    pub fi_id: Option<BranchAndFinancialInstitutionIdentification61>,
482}
483
484impl Validate for Party44Choice1 {
485    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
486        if let Some(ref val) = self.fi_id
487            && config.validate_optional_fields
488        {
489            val.validate(&helpers::child_path(path, "FIId"), config, collector);
490        }
491    }
492}
493
494// Party44Choice2: Identification of a financial institution.
495#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
496pub struct Party44Choice2 {
497    #[serde(rename = "FIId", skip_serializing_if = "Option::is_none")]
498    pub fi_id: Option<BranchAndFinancialInstitutionIdentification63>,
499}
500
501impl Validate for Party44Choice2 {
502    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
503        if let Some(ref val) = self.fi_id
504            && config.validate_optional_fields
505        {
506            val.validate(&helpers::child_path(path, "FIId"), config, collector);
507        }
508    }
509}
510
511// Priority2Code: Priority level is normal.
512#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
513pub enum Priority2Code {
514    #[default]
515    #[serde(rename = "HIGH")]
516    CodeHIGH,
517    #[serde(rename = "NORM")]
518    CodeNORM,
519}
520
521impl Validate for Priority2Code {
522    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
523        // Enum validation is typically empty
524    }
525}