mx_message/header/
bah_camt_052_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// BranchAndFinancialInstitutionIdentification65: 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 BranchAndFinancialInstitutionIdentification65 {
26    #[serde(rename = "FinInstnId")]
27    pub fin_instn_id: FinancialInstitutionIdentification183,
28}
29
30impl Validate for BranchAndFinancialInstitutionIdentification65 {
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: String,
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        helpers::validate_length(
167            &self.biz_svc,
168            "BizSvc",
169            Some(6),
170            Some(35),
171            &helpers::child_path(path, "BizSvc"),
172            config,
173            collector,
174        );
175        helpers::validate_pattern(
176            &self.biz_svc,
177            "BizSvc",
178            "[a-z0-9]{1,10}\\.([a-z0-9]{1,10}\\.)+\\d\\d",
179            &helpers::child_path(path, "BizSvc"),
180            config,
181            collector,
182        );
183        if let Some(ref val) = self.mkt_prctc
184            && config.validate_optional_fields
185        {
186            val.validate(&helpers::child_path(path, "MktPrctc"), config, collector);
187        }
188        helpers::validate_pattern(
189            &self.cre_dt,
190            "CreDt",
191            ".*(\\+|-)((0[0-9])|(1[0-4])):[0-5][0-9]",
192            &helpers::child_path(path, "CreDt"),
193            config,
194            collector,
195        );
196        if let Some(ref val) = self.cpy_dplct
197            && config.validate_optional_fields
198        {
199            val.validate(&helpers::child_path(path, "CpyDplct"), config, collector);
200        }
201        if let Some(ref val) = self.prty
202            && config.validate_optional_fields
203        {
204            val.validate(&helpers::child_path(path, "Prty"), config, collector);
205        }
206        if let Some(ref val) = self.rltd
207            && config.validate_optional_fields
208        {
209            val.validate(&helpers::child_path(path, "Rltd"), config, collector);
210        }
211    }
212}
213
214// ClearingSystemIdentification2Choice1: Identification of a clearing system, in a coded form as published in an external list.
215#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
216pub struct ClearingSystemIdentification2Choice1 {
217    #[serde(rename = "Cd", skip_serializing_if = "Option::is_none")]
218    pub cd: Option<String>,
219}
220
221impl Validate for ClearingSystemIdentification2Choice1 {
222    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
223        if let Some(ref val) = self.cd {
224            helpers::validate_length(
225                val,
226                "Cd",
227                Some(1),
228                Some(5),
229                &helpers::child_path(path, "Cd"),
230                config,
231                collector,
232            );
233        }
234    }
235}
236
237// ClearingSystemMemberIdentification21: Identification of a member of a clearing system.
238#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
239pub struct ClearingSystemMemberIdentification21 {
240    #[serde(rename = "ClrSysId")]
241    pub clr_sys_id: ClearingSystemIdentification2Choice1,
242    #[serde(rename = "MmbId")]
243    pub mmb_id: String,
244}
245
246impl Validate for ClearingSystemMemberIdentification21 {
247    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
248        self.clr_sys_id
249            .validate(&helpers::child_path(path, "ClrSysId"), config, collector);
250        helpers::validate_length(
251            &self.mmb_id,
252            "MmbId",
253            Some(1),
254            Some(28),
255            &helpers::child_path(path, "MmbId"),
256            config,
257            collector,
258        );
259        helpers::validate_pattern(
260            &self.mmb_id,
261            "MmbId",
262            "[0-9a-zA-Z/\\-\\?:\\(\\)\\.,'\\+ ]+",
263            &helpers::child_path(path, "MmbId"),
264            config,
265            collector,
266        );
267    }
268}
269
270// CopyDuplicate1Code: Message is for information/confirmation purposes. It is a duplicate of a message previously sent.
271#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
272pub enum CopyDuplicate1Code {
273    #[default]
274    #[serde(rename = "CODU")]
275    CodeCODU,
276    #[serde(rename = "COPY")]
277    CodeCOPY,
278    #[serde(rename = "DUPL")]
279    CodeDUPL,
280}
281
282impl Validate for CopyDuplicate1Code {
283    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
284        // Enum validation is typically empty
285    }
286}
287
288// FinancialInstitutionIdentification183: Legal entity identifier of the financial institution.
289#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
290pub struct FinancialInstitutionIdentification183 {
291    #[serde(rename = "BICFI")]
292    pub bicfi: String,
293    #[serde(rename = "ClrSysMmbId", skip_serializing_if = "Option::is_none")]
294    pub clr_sys_mmb_id: Option<ClearingSystemMemberIdentification21>,
295    #[serde(rename = "LEI", skip_serializing_if = "Option::is_none")]
296    pub lei: Option<String>,
297}
298
299impl Validate for FinancialInstitutionIdentification183 {
300    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
301        helpers::validate_pattern(
302            &self.bicfi,
303            "BICFI",
304            "[A-Z0-9]{4,4}[A-Z]{2,2}[A-Z0-9]{2,2}([A-Z0-9]{3,3}){0,1}",
305            &helpers::child_path(path, "BICFI"),
306            config,
307            collector,
308        );
309        if let Some(ref val) = self.clr_sys_mmb_id
310            && config.validate_optional_fields
311        {
312            val.validate(&helpers::child_path(path, "ClrSysMmbId"), config, collector);
313        }
314        if let Some(ref val) = self.lei {
315            helpers::validate_pattern(
316                val,
317                "LEI",
318                "[A-Z0-9]{18,18}[0-9]{2,2}",
319                &helpers::child_path(path, "LEI"),
320                config,
321                collector,
322            );
323        }
324    }
325}
326
327// 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.
328// For instance, "2018-01-01 – Version 2" or "urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66".
329#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
330pub struct ImplementationSpecification1 {
331    #[serde(rename = "Regy")]
332    pub regy: String,
333    #[serde(rename = "Id")]
334    pub id: String,
335}
336
337impl Validate for ImplementationSpecification1 {
338    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
339        helpers::validate_length(
340            &self.regy,
341            "Regy",
342            Some(1),
343            Some(350),
344            &helpers::child_path(path, "Regy"),
345            config,
346            collector,
347        );
348        helpers::validate_length(
349            &self.id,
350            "Id",
351            Some(1),
352            Some(2048),
353            &helpers::child_path(path, "Id"),
354            config,
355            collector,
356        );
357    }
358}
359
360// Party44Choice1: Identification of a financial institution.
361#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
362pub struct Party44Choice1 {
363    #[serde(rename = "FIId", skip_serializing_if = "Option::is_none")]
364    pub fi_id: Option<BranchAndFinancialInstitutionIdentification65>,
365}
366
367impl Validate for Party44Choice1 {
368    fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector) {
369        if let Some(ref val) = self.fi_id
370            && config.validate_optional_fields
371        {
372            val.validate(&helpers::child_path(path, "FIId"), config, collector);
373        }
374    }
375}
376
377// Priority2Code: Priority level is normal.
378#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
379pub enum Priority2Code {
380    #[default]
381    #[serde(rename = "HIGH")]
382    CodeHIGH,
383    #[serde(rename = "NORM")]
384    CodeNORM,
385}
386
387impl Validate for Priority2Code {
388    fn validate(&self, _path: &str, _config: &ParserConfig, _collector: &mut ErrorCollector) {
389        // Enum validation is typically empty
390    }
391}