swift_mt_message/fields/
field59.rs

1use serde::{Deserialize, Serialize};
2use swift_mt_message_macros::SwiftField;
3
4/// Field 59F: Beneficiary Customer (Option F)
5///
6/// Beneficiary customer with party identifier and name/address.
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftField)]
8pub struct Field59F {
9    /// Party identifier
10    #[component("34x", validate = ["party_identifier_format"])]
11    pub party_identifier: String,
12    /// Name and address lines
13    #[component("4*35x", validate = ["line_count", "line_length", "structured_address"])]
14    pub name_and_address: Vec<String>,
15}
16
17/// Field 59A: Beneficiary Customer (Option A)
18///
19/// Beneficiary customer with BIC-based identification.
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftField)]
21pub struct Field59A {
22    /// Account line indicator (optional)
23    #[component("[1!a]", optional)]
24    pub account_line_indicator: Option<String>,
25    /// Account number (optional)
26    #[component("[34x]", optional)]
27    pub account_number: Option<String>,
28    /// BIC code
29    #[component("4!a2!a2!c[3!c]", validate = ["bic"])]
30    pub bic: String,
31}
32
33/// Field 59: Beneficiary Customer
34///
35/// Multi-option field with different format specifications per option.
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37pub enum Field59 {
38    /// Option A: BIC-based identification
39    A(Field59A),
40    /// Option F: Party identifier with name/address
41    F(Field59F),
42    /// No option: Name and address only
43    NoOption(Field59Basic),
44}
45
46/// Type alias for Field 59 Basic: Beneficiary Customer (Basic)
47pub type Field59Basic = crate::fields::common::GenericMultiLine4x35;
48
49impl crate::SwiftField for Field59 {
50    fn parse(value: &str) -> crate::Result<Self> {
51        let content = value.trim();
52
53        // Determine option based on format pattern
54        if content.contains('\n') || content.lines().count() > 1 {
55            // Option F or NoOption - multiple lines
56            if content.starts_with('/') {
57                // Option F - has party identifier
58                let field_59f = Field59F::parse(value)?;
59                Ok(Field59::F(field_59f))
60            } else {
61                // NoOption - name and address only
62                let field_59_basic = Field59Basic::parse(value)?;
63                Ok(Field59::NoOption(field_59_basic))
64            }
65        } else {
66            // Option A - BIC format
67            let field_59a = Field59A::parse(value)?;
68            Ok(Field59::A(field_59a))
69        }
70    }
71
72    fn to_swift_string(&self) -> String {
73        match self {
74            Field59::A(field_59a) => field_59a.to_swift_string(),
75            Field59::F(field_59f) => field_59f.to_swift_string(),
76            Field59::NoOption(field_59_basic) => field_59_basic.to_swift_string(),
77        }
78    }
79
80    fn validate(&self) -> crate::ValidationResult {
81        match self {
82            Field59::A(field_59a) => field_59a.validate(),
83            Field59::F(field_59f) => field_59f.validate(),
84            Field59::NoOption(field_59_basic) => field_59_basic.validate(),
85        }
86    }
87
88    fn format_spec() -> &'static str {
89        "multi_option"
90    }
91}