mx_message/header/
bah_camt_105_001_02_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// BusinessApplicationHeader51: Relative indication of the processing precedence of the message over a (set of) Business Messages with assigned priorities.
38#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
39pub struct BusinessApplicationHeader51 {
40    #[serde(rename = "CharSet", skip_serializing_if = "Option::is_none")]
41    pub char_set: Option<String>,
42    #[serde(rename = "Fr")]
43    pub fr: Party44Choice1,
44    #[serde(rename = "To")]
45    pub to: Party44Choice1,
46    #[serde(rename = "BizMsgIdr")]
47    pub biz_msg_idr: String,
48    #[serde(rename = "MsgDefIdr")]
49    pub msg_def_idr: String,
50    #[serde(rename = "BizSvc", skip_serializing_if = "Option::is_none")]
51    pub biz_svc: Option<String>,
52    #[serde(rename = "CreDt")]
53    pub cre_dt: String,
54    #[serde(rename = "CpyDplct", skip_serializing_if = "Option::is_none")]
55    pub cpy_dplct: Option<CopyDuplicate1Code>,
56    #[serde(rename = "Prty", skip_serializing_if = "Option::is_none")]
57    pub prty: Option<String>,
58}
59
60impl Validate for BusinessApplicationHeader51 {
61    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
62        self.fr
63            .validate(&helpers::child_path(path, "Fr"), config, collector);
64        self.to
65            .validate(&helpers::child_path(path, "To"), config, collector);
66        helpers::validate_length(
67            &self.biz_msg_idr,
68            "BizMsgIdr",
69            Some(1),
70            Some(35),
71            &helpers::child_path(path, "BizMsgIdr"),
72            config,
73            collector,
74        );
75        helpers::validate_length(
76            &self.msg_def_idr,
77            "MsgDefIdr",
78            Some(1),
79            Some(35),
80            &helpers::child_path(path, "MsgDefIdr"),
81            config,
82            collector,
83        );
84        if let Some(ref val) = self.biz_svc {
85            helpers::validate_length(
86                val,
87                "BizSvc",
88                Some(1),
89                Some(35),
90                &helpers::child_path(path, "BizSvc"),
91                config,
92                collector,
93            );
94        }
95        helpers::validate_pattern(
96            &self.cre_dt,
97            "CreDt",
98            ".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]",
99            &helpers::child_path(path, "CreDt"),
100            config,
101            collector,
102        );
103        if let Some(ref val) = self.cpy_dplct
104            && config.validate_optional_fields
105        {
106            val.validate(&helpers::child_path(path, "CpyDplct"), config, collector);
107        }
108    }
109}
110
111// BusinessApplicationHeaderV02: Specifies the Business Application Header(s) of the Business Message(s) to which this Business Message relates.
112// Can be used when replying to a query; can also be used when canceling or amending.
113#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
114#[serde(rename = "AppHdr")]
115pub struct BusinessApplicationHeaderV02 {
116    #[serde(rename = "CharSet", skip_serializing_if = "Option::is_none")]
117    pub char_set: Option<String>,
118    #[serde(rename = "Fr")]
119    pub fr: Party44Choice1,
120    #[serde(rename = "To")]
121    pub to: Party44Choice1,
122    #[serde(rename = "BizMsgIdr")]
123    pub biz_msg_idr: String,
124    #[serde(rename = "MsgDefIdr")]
125    pub msg_def_idr: String,
126    #[serde(rename = "BizSvc")]
127    pub biz_svc: Max35Textfixed,
128    #[serde(rename = "MktPrctc", skip_serializing_if = "Option::is_none")]
129    pub mkt_prctc: Option<ImplementationSpecification1>,
130    #[serde(rename = "CreDt")]
131    pub cre_dt: String,
132    #[serde(rename = "CpyDplct", skip_serializing_if = "Option::is_none")]
133    pub cpy_dplct: Option<CopyDuplicate1Code>,
134    #[serde(rename = "PssblDplct", skip_serializing_if = "Option::is_none")]
135    pub pssbl_dplct: Option<bool>,
136    #[serde(rename = "Prty", skip_serializing_if = "Option::is_none")]
137    pub prty: Option<Priority2Code>,
138    #[serde(rename = "Rltd", skip_serializing_if = "Option::is_none")]
139    pub rltd: Option<BusinessApplicationHeader51>,
140}
141
142impl Validate for BusinessApplicationHeaderV02 {
143    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
144        self.fr
145            .validate(&helpers::child_path(path, "Fr"), config, collector);
146        self.to
147            .validate(&helpers::child_path(path, "To"), config, collector);
148        helpers::validate_length(
149            &self.biz_msg_idr,
150            "BizMsgIdr",
151            Some(1),
152            Some(35),
153            &helpers::child_path(path, "BizMsgIdr"),
154            config,
155            collector,
156        );
157        helpers::validate_length(
158            &self.msg_def_idr,
159            "MsgDefIdr",
160            Some(1),
161            Some(35),
162            &helpers::child_path(path, "MsgDefIdr"),
163            config,
164            collector,
165        );
166        self.biz_svc
167            .validate(&helpers::child_path(path, "BizSvc"), config, collector);
168        if let Some(ref val) = self.mkt_prctc
169            && config.validate_optional_fields
170        {
171            val.validate(&helpers::child_path(path, "MktPrctc"), config, collector);
172        }
173        helpers::validate_pattern(
174            &self.cre_dt,
175            "CreDt",
176            ".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]",
177            &helpers::child_path(path, "CreDt"),
178            config,
179            collector,
180        );
181        if let Some(ref val) = self.cpy_dplct
182            && config.validate_optional_fields
183        {
184            val.validate(&helpers::child_path(path, "CpyDplct"), config, collector);
185        }
186        if let Some(ref val) = self.prty
187            && config.validate_optional_fields
188        {
189            val.validate(&helpers::child_path(path, "Prty"), config, collector);
190        }
191        if let Some(ref val) = self.rltd
192            && config.validate_optional_fields
193        {
194            val.validate(&helpers::child_path(path, "Rltd"), config, collector);
195        }
196    }
197}
198
199// ClearingSystemIdentification2Choice: Identification code for a clearing system, that has not yet been identified in the list of clearing systems.
200#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
201pub struct ClearingSystemIdentification2Choice {
202    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
203    pub cd: Option<String>,
204    #[serde(rename = "Prtry", skip_serializing_if = "Option::is_none")]
205    pub prtry: Option<String>,
206}
207
208impl Validate for ClearingSystemIdentification2Choice {
209    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
210        if let Some(ref val) = self.cd {
211            helpers::validate_length(
212                val,
213                "Cd",
214                Some(1),
215                Some(5),
216                &helpers::child_path(path, "Cd"),
217                config,
218                collector,
219            );
220        }
221        if let Some(ref val) = self.prtry {
222            helpers::validate_length(
223                val,
224                "Prtry",
225                Some(1),
226                Some(35),
227                &helpers::child_path(path, "Prtry"),
228                config,
229                collector,
230            );
231        }
232    }
233}
234
235// ClearingSystemMemberIdentification22: Identification of a member of a clearing system.
236#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
237pub struct ClearingSystemMemberIdentification22 {
238    #[serde(rename = "ClrSysId", skip_serializing_if = "Option::is_none")]
239    pub clr_sys_id: Option<ClearingSystemIdentification2Choice>,
240    #[serde(rename = "MmbId")]
241    pub mmb_id: String,
242}
243
244impl Validate for ClearingSystemMemberIdentification22 {
245    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
246        if let Some(ref val) = self.clr_sys_id
247            && config.validate_optional_fields
248        {
249            val.validate(&helpers::child_path(path, "ClrSysId"), config, collector);
250        }
251        helpers::validate_length(
252            &self.mmb_id,
253            "MmbId",
254            Some(1),
255            Some(28),
256            &helpers::child_path(path, "MmbId"),
257            config,
258            collector,
259        );
260        helpers::validate_pattern(
261            &self.mmb_id,
262            "MmbId",
263            "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+",
264            &helpers::child_path(path, "MmbId"),
265            config,
266            collector,
267        );
268    }
269}
270
271// CopyDuplicate1Code: Message is for information/confirmation purposes. It is a duplicate of a message previously sent.
272#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
273pub enum CopyDuplicate1Code {
274    #[default]
275    #[serde(rename = "CODU")]
276    CodeCODU,
277    #[serde(rename = "COPY")]
278    CodeCOPY,
279    #[serde(rename = "DUPL")]
280    CodeDUPL,
281}
282
283impl Validate for CopyDuplicate1Code {
284    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
285        // Enum validation is typically empty
286    }
287}
288
289// FinancialInstitutionIdentification181: Legal entity identifier of the financial institution.
290#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
291pub struct FinancialInstitutionIdentification181 {
292    #[serde(rename = "BICFI")]
293    pub bicfi: String,
294    #[serde(rename = "ClrSysMmbId", skip_serializing_if = "Option::is_none")]
295    pub clr_sys_mmb_id: Option<ClearingSystemMemberIdentification22>,
296    #[serde(rename = "LEI", skip_serializing_if = "Option::is_none")]
297    pub lei: Option<String>,
298}
299
300impl Validate for FinancialInstitutionIdentification181 {
301    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
302        helpers::validate_pattern(
303            &self.bicfi,
304            "BICFI",
305            "[A-Z0-9]{4,4}[A-Z]{2,2}[A-Z0-9]{2,2}([A-Z0-9]{3,3}){0,1}",
306            &helpers::child_path(path, "BICFI"),
307            config,
308            collector,
309        );
310        if let Some(ref val) = self.clr_sys_mmb_id
311            && config.validate_optional_fields
312        {
313            val.validate(&helpers::child_path(path, "ClrSysMmbId"), config, collector);
314        }
315        if let Some(ref val) = self.lei {
316            helpers::validate_pattern(
317                val,
318                "LEI",
319                "[A-Z0-9]{18,18}[0-9]{2,2}",
320                &helpers::child_path(path, "LEI"),
321                config,
322                collector,
323            );
324        }
325    }
326}
327
328// 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.
329// For instance, "2018-01-01 – Version 2" or "urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66".
330#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
331pub struct ImplementationSpecification1 {
332    #[serde(rename = "Regy")]
333    pub regy: String,
334    #[serde(rename = "Id")]
335    pub id: String,
336}
337
338impl Validate for ImplementationSpecification1 {
339    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
340        helpers::validate_length(
341            &self.regy,
342            "Regy",
343            Some(1),
344            Some(350),
345            &helpers::child_path(path, "Regy"),
346            config,
347            collector,
348        );
349        helpers::validate_length(
350            &self.id,
351            "Id",
352            Some(1),
353            Some(2048),
354            &helpers::child_path(path, "Id"),
355            config,
356            collector,
357        );
358    }
359}
360
361// Max35Text_fixed: swift.cbprplus.mlp.02
362#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
363pub enum Max35Textfixed {
364    #[default]
365    #[serde(rename = "swift.cbprplus.mlp.02")]
366    CodeSWIFTCBPRPLUSMLP02,
367}
368
369impl Validate for Max35Textfixed {
370    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
371        // Enum validation is typically empty
372    }
373}
374
375// Party44Choice1: Identification of a financial institution.
376#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
377pub struct Party44Choice1 {
378    #[serde(rename = "FIId", skip_serializing_if = "Option::is_none")]
379    pub fi_id: Option<BranchAndFinancialInstitutionIdentification61>,
380}
381
382impl Validate for Party44Choice1 {
383    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
384        if let Some(ref val) = self.fi_id
385            && config.validate_optional_fields
386        {
387            val.validate(&helpers::child_path(path, "FIId"), config, collector);
388        }
389    }
390}
391
392// Priority2Code: Priority level is normal.
393#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
394pub enum Priority2Code {
395    #[default]
396    #[serde(rename = "HIGH")]
397    CodeHIGH,
398    #[serde(rename = "NORM")]
399    CodeNORM,
400}
401
402impl Validate for Priority2Code {
403    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
404        // Enum validation is typically empty
405    }
406}