swift_mt_message/fields/
field50.rs

1use serde::{Deserialize, Serialize};
2use swift_mt_message_macros::SwiftField;
3
4/// Field 50F: Ordering Customer (Option F)
5///
6/// Ordering customer with party identifier and name/address.
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftField)]
8pub struct Field50F {
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 50A: Ordering Customer (Option A)
18///
19/// Ordering customer with BIC-based identification.
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftField)]
21pub struct Field50A {
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 50: Ordering Customer
34///
35/// Multi-option field with different format specifications per option.
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37pub enum Field50 {
38    /// Option A: BIC-based identification
39    A(Field50A),
40    /// Option F: Party identifier with name/address
41    F(Field50F),
42    /// Option K: Name and address only
43    K(Field50K),
44}
45
46/// Type alias for Field 50K: Ordering Customer (Option K)
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftField)]
48pub struct Field50K {
49    /// Account number (optional)
50    #[component("[34x]", optional)]
51    pub account_number: Option<String>,
52
53    /// Name and address lines
54    #[component("4*35x", validate = ["line_count", "line_length", "structured_address"])]
55    pub name_and_address: Vec<String>,
56}
57
58impl crate::SwiftField for Field50 {
59    fn parse(value: &str) -> crate::Result<Self> {
60        let content = value.trim();
61
62        // Determine option based on format pattern
63        if content.contains('\n') || content.lines().count() > 1 {
64            // Option K or F - multiple lines
65            if content.starts_with('/') {
66                // Option F - has party identifier
67                let field_50f = Field50F::parse(value)?;
68                Ok(Field50::F(field_50f))
69            } else {
70                // Option K - name and address only
71                let field_50k = Field50K::parse(value)?;
72                Ok(Field50::K(field_50k))
73            }
74        } else {
75            // Option A - BIC format
76            let field_50a = Field50A::parse(value)?;
77            Ok(Field50::A(field_50a))
78        }
79    }
80
81    fn to_swift_string(&self) -> String {
82        match self {
83            Field50::A(field_50a) => field_50a.to_swift_string(),
84            Field50::F(field_50f) => field_50f.to_swift_string(),
85            Field50::K(field_50k) => field_50k.to_swift_string(),
86        }
87    }
88
89    fn validate(&self) -> crate::ValidationResult {
90        match self {
91            Field50::A(field_50a) => field_50a.validate(),
92            Field50::F(field_50f) => field_50f.validate(),
93            Field50::K(field_50k) => field_50k.validate(),
94        }
95    }
96
97    fn format_spec() -> &'static str {
98        "multi_option"
99    }
100
101    fn sample() -> Self {
102        use rand::Rng;
103        let mut rng = rand::thread_rng();
104
105        // Randomly choose between the three variants
106        match rng.gen_range(0..3) {
107            0 => Field50::A(Field50A::sample()),
108            1 => Field50::F(Field50F::sample()),
109            _ => Field50::K(Field50K::sample()),
110        }
111    }
112
113    fn sample_with_config(_config: &crate::sample::FieldConfig) -> Self {
114        // For now, just delegate to sample()
115        // Could be enhanced to use config to determine variant choice
116        Self::sample()
117    }
118}