mx_message/header/
bah_camt_058_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
19use crate::parse_result::{ErrorCollector, ParserConfig};
20use crate::validation::{Validate, helpers};
21use serde::{Deserialize, Serialize};
22
23// BranchAndFinancialInstitutionIdentification62: 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 BranchAndFinancialInstitutionIdentification62 {
26    #[serde(rename = "FinInstnId")]
27    pub fin_instn_id: FinancialInstitutionIdentification182,
28}
29
30impl Validate for BranchAndFinancialInstitutionIdentification62 {
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<Vec<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 vec) = self.rltd
221            && config.validate_optional_fields
222        {
223            for item in vec {
224                item.validate(&helpers::child_path(path, "Rltd"), config, collector);
225            }
226        }
227    }
228}
229
230// ClearingSystemIdentification2Choice: Identification code for a clearing system, that has not yet been identified in the list of clearing systems.
231#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
232pub struct ClearingSystemIdentification2Choice {
233    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
234    pub cd: Option<String>,
235    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
236    pub prtry: Option<String>,
237}
238
239impl Validate for ClearingSystemIdentification2Choice {
240    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
241        if let Some(ref val) = self.cd {
242            helpers::validate_length(
243                val,
244                "Cd",
245                Some(1),
246                Some(5),
247                &helpers::child_path(path, "Cd"),
248                config,
249                collector,
250            );
251        }
252        if let Some(ref val) = self.prtry {
253            helpers::validate_length(
254                val,
255                "Prtry",
256                Some(1),
257                Some(35),
258                &helpers::child_path(path, "Prtry"),
259                config,
260                collector,
261            );
262        }
263    }
264}
265
266// ClearingSystemIdentification2Choice1: Identification of a clearing system, in a coded form as published in an external list.
267#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
268pub struct ClearingSystemIdentification2Choice1 {
269    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
270    pub cd: Option<String>,
271}
272
273impl Validate for ClearingSystemIdentification2Choice1 {
274    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
275        if let Some(ref val) = self.cd {
276            helpers::validate_length(
277                val,
278                "Cd",
279                Some(1),
280                Some(5),
281                &helpers::child_path(path, "Cd"),
282                config,
283                collector,
284            );
285        }
286    }
287}
288
289// ClearingSystemMemberIdentification2: Identification of a member of a clearing system.
290#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
291pub struct ClearingSystemMemberIdentification2 {
292    #[serde(rename = "ClrSysId", skip_serializing_if = "Option::is_none")]
293    pub clr_sys_id: Option<ClearingSystemIdentification2Choice>,
294    #[serde(rename = "MmbId")]
295    pub mmb_id: String,
296}
297
298impl Validate for ClearingSystemMemberIdentification2 {
299    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
300        if let Some(ref val) = self.clr_sys_id
301            && config.validate_optional_fields
302        {
303            val.validate(&helpers::child_path(path, "ClrSysId"), config, collector);
304        }
305        helpers::validate_length(
306            &self.mmb_id,
307            "MmbId",
308            Some(1),
309            Some(35),
310            &helpers::child_path(path, "MmbId"),
311            config,
312            collector,
313        );
314    }
315}
316
317// ClearingSystemMemberIdentification21: Identification of a member of a clearing system.
318#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
319pub struct ClearingSystemMemberIdentification21 {
320    #[serde(rename = "ClrSysId")]
321    pub clr_sys_id: ClearingSystemIdentification2Choice1,
322    #[serde(rename = "MmbId")]
323    pub mmb_id: String,
324}
325
326impl Validate for ClearingSystemMemberIdentification21 {
327    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
328        self.clr_sys_id
329            .validate(&helpers::child_path(path, "ClrSysId"), config, collector);
330        helpers::validate_length(
331            &self.mmb_id,
332            "MmbId",
333            Some(1),
334            Some(28),
335            &helpers::child_path(path, "MmbId"),
336            config,
337            collector,
338        );
339        helpers::validate_pattern(
340            &self.mmb_id,
341            "MmbId",
342            "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+",
343            &helpers::child_path(path, "MmbId"),
344            config,
345            collector,
346        );
347    }
348}
349
350// CopyDuplicate1Code: Message is for information/confirmation purposes. It is a duplicate of a message previously sent.
351#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
352pub enum CopyDuplicate1Code {
353    #[default]
354    #[serde(rename = "CODU")]
355    CodeCODU,
356    #[serde(rename = "COPY")]
357    CodeCOPY,
358    #[serde(rename = "DUPL")]
359    CodeDUPL,
360}
361
362impl Validate for CopyDuplicate1Code {
363    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
364        // Enum validation is typically empty
365    }
366}
367
368// FinancialInstitutionIdentification182: Legal entity identifier of the financial institution.
369#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
370pub struct FinancialInstitutionIdentification182 {
371    #[serde(rename = "BICFI")]
372    pub bicfi: String,
373    #[serde(rename = "ClrSysMmbId", skip_serializing_if = "Option::is_none")]
374    pub clr_sys_mmb_id: Option<ClearingSystemMemberIdentification21>,
375    #[serde(rename = "LEI", skip_serializing_if = "Option::is_none")]
376    pub lei: Option<String>,
377}
378
379impl Validate for FinancialInstitutionIdentification182 {
380    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
381        helpers::validate_pattern(
382            &self.bicfi,
383            "BICFI",
384            "[A-Z0-9]{4,4}[A-Z]{2,2}[A-Z0-9]{2,2}([A-Z0-9]{3,3}){0,1}",
385            &helpers::child_path(path, "BICFI"),
386            config,
387            collector,
388        );
389        if let Some(ref val) = self.clr_sys_mmb_id
390            && config.validate_optional_fields
391        {
392            val.validate(&helpers::child_path(path, "ClrSysMmbId"), config, collector);
393        }
394        if let Some(ref val) = self.lei {
395            helpers::validate_pattern(
396                val,
397                "LEI",
398                "[A-Z0-9]{18,18}[0-9]{2,2}",
399                &helpers::child_path(path, "LEI"),
400                config,
401                collector,
402            );
403        }
404    }
405}
406
407// FinancialInstitutionIdentification183: Legal entity identifier of the financial institution.
408#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
409pub struct FinancialInstitutionIdentification183 {
410    #[serde(rename = "BICFI", skip_serializing_if = "Option::is_none")]
411    pub bicfi: Option<String>,
412    #[serde(rename = "ClrSysMmbId", skip_serializing_if = "Option::is_none")]
413    pub clr_sys_mmb_id: Option<ClearingSystemMemberIdentification2>,
414    #[serde(rename = "LEI", skip_serializing_if = "Option::is_none")]
415    pub lei: Option<String>,
416}
417
418impl Validate for FinancialInstitutionIdentification183 {
419    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
420        if let Some(ref val) = self.bicfi {
421            helpers::validate_pattern(
422                val,
423                "BICFI",
424                "[A-Z0-9]{4,4}[A-Z]{2,2}[A-Z0-9]{2,2}([A-Z0-9]{3,3}){0,1}",
425                &helpers::child_path(path, "BICFI"),
426                config,
427                collector,
428            );
429        }
430        if let Some(ref val) = self.clr_sys_mmb_id
431            && config.validate_optional_fields
432        {
433            val.validate(&helpers::child_path(path, "ClrSysMmbId"), config, collector);
434        }
435        if let Some(ref val) = self.lei {
436            helpers::validate_pattern(
437                val,
438                "LEI",
439                "[A-Z0-9]{18,18}[0-9]{2,2}",
440                &helpers::child_path(path, "LEI"),
441                config,
442                collector,
443            );
444        }
445    }
446}
447
448// 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.
449// For instance, "2018-01-01 – Version 2" or "urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66".
450#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
451pub struct ImplementationSpecification1 {
452    #[serde(rename = "Regy")]
453    pub regy: String,
454    #[serde(rename = "Id")]
455    pub id: String,
456}
457
458impl Validate for ImplementationSpecification1 {
459    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
460        helpers::validate_length(
461            &self.regy,
462            "Regy",
463            Some(1),
464            Some(350),
465            &helpers::child_path(path, "Regy"),
466            config,
467            collector,
468        );
469        helpers::validate_length(
470            &self.id,
471            "Id",
472            Some(1),
473            Some(2048),
474            &helpers::child_path(path, "Id"),
475            config,
476            collector,
477        );
478    }
479}
480
481// Party44Choice1: Identification of a financial institution.
482#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
483pub struct Party44Choice1 {
484    #[serde(rename = "FIId", skip_serializing_if = "Option::is_none")]
485    pub fi_id: Option<BranchAndFinancialInstitutionIdentification62>,
486}
487
488impl Validate for Party44Choice1 {
489    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
490        if let Some(ref val) = self.fi_id
491            && config.validate_optional_fields
492        {
493            val.validate(&helpers::child_path(path, "FIId"), config, collector);
494        }
495    }
496}
497
498// Party44Choice2: Identification of a financial institution.
499#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
500pub struct Party44Choice2 {
501    #[serde(rename = "FIId", skip_serializing_if = "Option::is_none")]
502    pub fi_id: Option<BranchAndFinancialInstitutionIdentification63>,
503}
504
505impl Validate for Party44Choice2 {
506    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
507        if let Some(ref val) = self.fi_id
508            && config.validate_optional_fields
509        {
510            val.validate(&helpers::child_path(path, "FIId"), config, collector);
511        }
512    }
513}
514
515// Priority2Code: Priority level is normal.
516#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
517pub enum Priority2Code {
518    #[default]
519    #[serde(rename = "HIGH")]
520    CodeHIGH,
521    #[serde(rename = "NORM")]
522    CodeNORM,
523}
524
525impl Validate for Priority2Code {
526    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
527        // Enum validation is typically empty
528    }
529}