swift_mt_message/fields/
field50.rs

1use crate::common::BIC;
2use crate::{SwiftField, ValidationResult, errors::ParseError};
3use serde::de::{self, MapAccess, Visitor};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::fmt;
6
7/// # Field 50: Ordering Customer
8///
9/// ## Overview
10/// Field 50 identifies the ordering customer (originator) of a SWIFT payment message.
11/// This field is crucial for identifying the party who initiated the payment instruction
12/// and is used for compliance, audit, and customer relationship purposes. The field
13/// supports multiple format options (A, F, K) to accommodate different identification
14/// methods and regulatory requirements.
15///
16/// ## Format Specification
17/// Field 50 supports three format options:
18///
19/// ### Option A (50A): BIC-based Identification
20/// **Format**: `[/account]BIC`
21/// - **account**: Optional account number (max 34 characters, preceded by /)
22/// - **BIC**: Bank Identifier Code (8 or 11 characters)
23/// - **Structure**: Account and BIC on separate lines if account present
24///
25/// ### Option F (50F): Party Identifier with Name/Address
26/// **Format**: `party_identifier + 4*35x`
27/// - **party_identifier**: Unique party identifier (max 35 characters)
28/// - **name_and_address**: Up to 4 lines of 35 characters each
29/// - **Usage**: For structured party identification with full name/address
30///
31/// ### Option K (50K): Name and Address Only
32/// **Format**: `4*35x`
33/// - **name_and_address**: Up to 4 lines of 35 characters each
34/// - **Usage**: Simple name/address format without structured identifiers
35/// - **Most common**: Default option when no BIC or party ID available
36///
37/// ## Usage Context
38/// Field 50 is mandatory in most SWIFT payment messages:
39/// - **MT103**: Single Customer Credit Transfer
40/// - **MT200**: Financial Institution Transfer
41/// - **MT202**: General Financial Institution Transfer
42/// - **MT202COV**: Cover for customer credit transfer
43///
44/// ### Regulatory Applications
45/// - **AML/KYC**: Customer identification for anti-money laundering compliance
46/// - **Sanctions screening**: Identifying parties for sanctions compliance
47/// - **FATCA/CRS**: Tax reporting requirements
48/// - **Audit trails**: Maintaining originator information for investigations
49/// - **Customer due diligence**: Enhanced due diligence requirements
50///
51/// ## Examples
52/// ```text
53/// :50A:/1234567890
54/// DEUTDEFFXXX
55/// └─── Customer with account 1234567890 at Deutsche Bank Frankfurt
56///
57/// :50A:CHASUS33XXX
58/// └─── Customer identified by BIC only (JPMorgan Chase New York)
59///
60/// :50F:PARTY123456789
61/// JOHN DOE ENTERPRISES
62/// 123 BUSINESS AVENUE
63/// NEW YORK NY 10001
64/// UNITED STATES
65/// └─── Customer with party identifier and full address
66///
67/// :50K:ACME CORPORATION
68/// 456 INDUSTRIAL DRIVE
69/// CHICAGO IL 60601
70/// UNITED STATES
71/// └─── Customer with name and address only
72/// ```
73///
74/// ## Option Selection Guidelines
75/// - **Use 50A when**: Customer has account at known financial institution with BIC
76/// - **Use 50F when**: Structured party identification required (regulatory compliance)
77/// - **Use 50K when**: Simple name/address sufficient, no structured ID available
78/// - **Preference order**: 50A > 50F > 50K (from most to least structured)
79///
80/// ## Validation Rules
81/// ### Option A (50A):
82/// 1. **BIC validation**: Must be valid 8 or 11 character BIC format
83/// 2. **Account format**: If present, max 34 characters, must start with /
84/// 3. **BIC structure**: 4!a2!a2!c[3!c] format required
85///
86/// ### Option F (50F):
87/// 1. **Party identifier**: Cannot be empty, max 35 characters
88/// 2. **Address lines**: Minimum 1, maximum 4 lines
89/// 3. **Line length**: Each line max 35 characters
90/// 4. **Character set**: Printable ASCII characters only
91///
92/// ### Option K (50K):
93/// 1. **Address lines**: Minimum 1, maximum 4 lines
94/// 2. **Line length**: Each line max 35 characters
95/// 3. **Character set**: Printable ASCII characters only
96/// 4. **Content validation**: Must contain meaningful customer information
97///
98/// ## Network Validated Rules (SWIFT Standards)
99/// - Field 50 is mandatory in customer payment messages (Error: C23)
100/// - BIC in option A must be valid format (Error: T27)
101/// - Account number cannot exceed 34 characters (Error: T15)
102/// - Name/address lines cannot exceed 35 characters each (Error: T14)
103/// - Maximum 4 name/address lines allowed (Error: T16)
104/// - Characters must be from SWIFT character set (Error: T61)
105///
106///
107
108#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
109pub struct Field50A {
110    /// Optional account number (starting with /)
111    pub account: Option<String>,
112    /// BIC code
113    #[serde(flatten)]
114    pub bic: BIC,
115}
116
117impl Field50A {
118    /// Create a new Field50A with validation
119    pub fn new(account: Option<String>, bic: impl Into<String>) -> Result<Self, ParseError> {
120        // Parse and validate BIC using the common structure
121        let bic = BIC::parse(&bic.into(), Some("50A"))?;
122
123        // Validate account if present
124        if let Some(ref acc) = account {
125            if acc.is_empty() {
126                return Err(ParseError::InvalidFieldFormat {
127                    field_tag: "50A".to_string(),
128                    message: "Account cannot be empty if specified".to_string(),
129                });
130            }
131
132            if acc.len() > 34 {
133                return Err(ParseError::InvalidFieldFormat {
134                    field_tag: "50A".to_string(),
135                    message: "Account number too long (max 34 characters)".to_string(),
136                });
137            }
138        }
139
140        Ok(Field50A { account, bic })
141    }
142
143    /// Get the account number
144    pub fn account(&self) -> Option<&str> {
145        self.account.as_deref()
146    }
147
148    /// Get the BIC code
149    pub fn bic(&self) -> &str {
150        self.bic.value()
151    }
152}
153
154impl std::fmt::Display for Field50A {
155    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156        match &self.account {
157            Some(account) => write!(f, "Account: {}, BIC: {}", account, self.bic.value()),
158            None => write!(f, "BIC: {}", self.bic.value()),
159        }
160    }
161}
162
163/// Field 50F: Ordering Customer (Option F)
164///
165/// Format: Party identifier and name/address lines
166#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
167pub struct Field50F {
168    /// Party identifier
169    pub party_identifier: String,
170    /// Name and address lines (up to 4 lines)
171    pub name_and_address: Vec<String>,
172}
173
174impl Field50F {
175    /// Create a new Field50F with validation
176    pub fn new(
177        party_identifier: impl Into<String>,
178        name_and_address: Vec<String>,
179    ) -> Result<Self, ParseError> {
180        let party_identifier = party_identifier.into().trim().to_string();
181
182        if party_identifier.is_empty() {
183            return Err(ParseError::InvalidFieldFormat {
184                field_tag: "50F".to_string(),
185                message: "Party identifier cannot be empty".to_string(),
186            });
187        }
188
189        if name_and_address.is_empty() {
190            return Err(ParseError::InvalidFieldFormat {
191                field_tag: "50F".to_string(),
192                message: "Name and address cannot be empty".to_string(),
193            });
194        }
195
196        if name_and_address.len() > 4 {
197            return Err(ParseError::InvalidFieldFormat {
198                field_tag: "50F".to_string(),
199                message: "Too many name/address lines (max 4)".to_string(),
200            });
201        }
202
203        for (i, line) in name_and_address.iter().enumerate() {
204            if line.len() > 35 {
205                return Err(ParseError::InvalidFieldFormat {
206                    field_tag: "50F".to_string(),
207                    message: format!("Line {} too long (max 35 characters)", i + 1),
208                });
209            }
210        }
211
212        Ok(Field50F {
213            party_identifier,
214            name_and_address,
215        })
216    }
217
218    /// Get the party identifier
219    pub fn party_identifier(&self) -> &str {
220        &self.party_identifier
221    }
222
223    /// Get the name and address lines
224    pub fn name_and_address(&self) -> &[String] {
225        &self.name_and_address
226    }
227}
228
229/// Field 50K: Ordering Customer (Option K)
230///
231/// Format: Name and address lines (up to 4 lines)
232#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
233pub struct Field50K {
234    /// Name and address lines (up to 4 lines)
235    pub name_and_address: Vec<String>,
236}
237
238impl Field50K {
239    /// Create a new Field50K with validation
240    pub fn new(name_and_address: Vec<String>) -> Result<Self, ParseError> {
241        if name_and_address.is_empty() {
242            return Err(ParseError::InvalidFieldFormat {
243                field_tag: "50K".to_string(),
244                message: "Name and address cannot be empty".to_string(),
245            });
246        }
247
248        if name_and_address.len() > 4 {
249            return Err(ParseError::InvalidFieldFormat {
250                field_tag: "50K".to_string(),
251                message: "Too many name/address lines (max 4)".to_string(),
252            });
253        }
254
255        for (i, line) in name_and_address.iter().enumerate() {
256            if line.len() > 35 {
257                return Err(ParseError::InvalidFieldFormat {
258                    field_tag: "50K".to_string(),
259                    message: format!("Line {} too long (max 35 characters)", i + 1),
260                });
261            }
262        }
263
264        Ok(Field50K { name_and_address })
265    }
266
267    /// Get the name and address lines
268    pub fn name_and_address(&self) -> &[String] {
269        &self.name_and_address
270    }
271}
272
273/// Field 50: Ordering Customer (with options A, F, and K)
274#[derive(Debug, Clone, PartialEq, Eq)]
275pub enum Field50 {
276    A(Field50A),
277    F(Field50F),
278    K(Field50K),
279}
280
281impl Field50 {
282    /// Parse Field50 with a specific tag (50A, 50F, or 50K)
283    pub fn parse_with_tag(tag: &str, content: &str) -> Result<Self, ParseError> {
284        match tag {
285            "50A" => Ok(Field50::A(Field50A::parse(content)?)),
286            "50F" => Ok(Field50::F(Field50F::parse(content)?)),
287            "50K" => Ok(Field50::K(Field50K::parse(content)?)),
288            _ => Err(ParseError::InvalidFieldFormat {
289                field_tag: "50".to_string(),
290                message: format!("Unknown Field50 option: {}", tag),
291            }),
292        }
293    }
294
295    /// Get the tag for this field variant
296    pub fn tag(&self) -> &'static str {
297        match self {
298            Field50::A(_) => "50A",
299            Field50::F(_) => "50F",
300            Field50::K(_) => "50K",
301        }
302    }
303}
304
305impl std::fmt::Display for Field50 {
306    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307        match self {
308            Field50::A(field) => write!(f, "50A: {}", field),
309            Field50::F(field) => write!(
310                f,
311                "50F: {} - {}",
312                field.party_identifier,
313                field.name_and_address.join(", ")
314            ),
315            Field50::K(field) => write!(f, "50K: {}", field.name_and_address.join(", ")),
316        }
317    }
318}
319
320// Custom serialization for Field50 to flatten the JSON structure
321impl Serialize for Field50 {
322    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
323    where
324        S: Serializer,
325    {
326        match self {
327            Field50::A(field) => field.serialize(serializer),
328            Field50::F(field) => field.serialize(serializer),
329            Field50::K(field) => field.serialize(serializer),
330        }
331    }
332}
333
334// Custom deserialization for Field50
335impl<'de> Deserialize<'de> for Field50 {
336    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
337    where
338        D: Deserializer<'de>,
339    {
340        struct Field50Visitor;
341
342        impl<'de> Visitor<'de> for Field50Visitor {
343            type Value = Field50;
344
345            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
346                formatter.write_str("a Field50 variant")
347            }
348
349            fn visit_map<V>(self, mut map: V) -> Result<Field50, V::Error>
350            where
351                V: MapAccess<'de>,
352            {
353                let mut fields = std::collections::HashMap::new();
354
355                while let Some((key, value)) = map.next_entry::<String, serde_json::Value>()? {
356                    fields.insert(key, value);
357                }
358
359                // Try to determine the variant based on the fields present
360                if fields.contains_key("bic") {
361                    // Field50A variant
362                    let account = fields
363                        .get("account")
364                        .and_then(|v| v.as_str())
365                        .map(|s| s.to_string());
366                    let bic = fields
367                        .get("bic")
368                        .and_then(|v| v.as_str())
369                        .ok_or_else(|| de::Error::missing_field("bic"))?
370                        .to_string();
371
372                    Field50A::new(account, bic)
373                        .map(Field50::A)
374                        .map_err(|e| de::Error::custom(format!("Field50A validation error: {}", e)))
375                } else if fields.contains_key("party_identifier") {
376                    // Field50F variant
377                    let party_identifier = fields
378                        .get("party_identifier")
379                        .and_then(|v| v.as_str())
380                        .ok_or_else(|| de::Error::missing_field("party_identifier"))?
381                        .to_string();
382                    let name_and_address = fields
383                        .get("name_and_address")
384                        .and_then(|v| v.as_array())
385                        .ok_or_else(|| de::Error::missing_field("name_and_address"))?
386                        .iter()
387                        .map(|v| v.as_str().unwrap_or("").to_string())
388                        .collect();
389
390                    Field50F::new(party_identifier, name_and_address)
391                        .map(Field50::F)
392                        .map_err(|e| de::Error::custom(format!("Field50F validation error: {}", e)))
393                } else if fields.contains_key("name_and_address") {
394                    // Field50K variant
395                    let name_and_address = fields
396                        .get("name_and_address")
397                        .and_then(|v| v.as_array())
398                        .ok_or_else(|| de::Error::missing_field("name_and_address"))?
399                        .iter()
400                        .map(|v| v.as_str().unwrap_or("").to_string())
401                        .collect();
402
403                    Field50K::new(name_and_address)
404                        .map(Field50::K)
405                        .map_err(|e| de::Error::custom(format!("Field50K validation error: {}", e)))
406                } else {
407                    Err(de::Error::custom("Unable to determine Field50 variant"))
408                }
409            }
410        }
411
412        deserializer.deserialize_map(Field50Visitor)
413    }
414}
415
416impl SwiftField for Field50A {
417    fn parse(content: &str) -> Result<Self, ParseError> {
418        let content = if let Some(stripped) = content.strip_prefix(":50A:") {
419            stripped
420        } else if let Some(stripped) = content.strip_prefix("50A:") {
421            stripped
422        } else {
423            content
424        };
425
426        let mut lines = content.lines();
427        let first_line = lines.next().unwrap_or_default();
428
429        let (account, bic_line) = if let Some(stripped) = first_line.strip_prefix('/') {
430            (Some(stripped.to_string()), lines.next().unwrap_or_default())
431        } else {
432            (None, first_line)
433        };
434
435        let bic = BIC::parse(bic_line, Some("50A"))?;
436
437        Ok(Field50A { account, bic })
438    }
439
440    fn to_swift_string(&self) -> String {
441        let content = if let Some(ref account) = self.account {
442            format!("/{}\n{}", account, self.bic.value())
443        } else {
444            self.bic.value().to_string()
445        };
446        format!(":50A:{}", content)
447    }
448
449    fn validate(&self) -> ValidationResult {
450        use crate::errors::ValidationError;
451
452        let mut errors = Vec::new();
453
454        // Validate BIC format using the common BIC validation
455        let bic_validation = self.bic.validate();
456        if !bic_validation.is_valid {
457            errors.extend(bic_validation.errors);
458        }
459
460        // Validate account length if present
461        if let Some(ref account) = self.account {
462            if account.len() > 34 {
463                errors.push(ValidationError::FormatValidation {
464                    field_tag: "50A".to_string(),
465                    message: "Account number too long (max 34 characters)".to_string(),
466                });
467            }
468        }
469
470        ValidationResult {
471            is_valid: errors.is_empty(),
472            errors,
473            warnings: vec![],
474        }
475    }
476
477    fn format_spec() -> &'static str {
478        "[/account]bic"
479    }
480}
481
482impl SwiftField for Field50F {
483    fn parse(content: &str) -> Result<Self, ParseError> {
484        let content = if let Some(stripped) = content.strip_prefix(":50F:") {
485            stripped
486        } else if let Some(stripped) = content.strip_prefix("50F:") {
487            stripped
488        } else {
489            content
490        };
491
492        let lines: Vec<&str> = content.lines().collect();
493        if lines.is_empty() {
494            return Err(ParseError::InvalidFieldFormat {
495                field_tag: "50F".to_string(),
496                message: "No content provided".to_string(),
497            });
498        }
499
500        Field50F::new(
501            lines[0].to_string(),
502            lines[1..].iter().map(|s| s.to_string()).collect(),
503        )
504    }
505
506    fn to_swift_string(&self) -> String {
507        let mut content = self.party_identifier.clone();
508        for line in &self.name_and_address {
509            content.push('\n');
510            content.push_str(line);
511        }
512        format!(":50F:{}", content)
513    }
514
515    fn validate(&self) -> ValidationResult {
516        use crate::errors::ValidationError;
517
518        let errors = if self.party_identifier.is_empty() {
519            vec![ValidationError::FormatValidation {
520                field_tag: "50F".to_string(),
521                message: "Party identifier cannot be empty".to_string(),
522            }]
523        } else {
524            vec![]
525        };
526
527        ValidationResult {
528            is_valid: errors.is_empty(),
529            errors,
530            warnings: vec![],
531        }
532    }
533
534    fn format_spec() -> &'static str {
535        "party_identifier_and_name"
536    }
537}
538
539impl SwiftField for Field50K {
540    fn parse(content: &str) -> Result<Self, ParseError> {
541        let content = if let Some(stripped) = content.strip_prefix(":50K:") {
542            stripped
543        } else if let Some(stripped) = content.strip_prefix("50K:") {
544            stripped
545        } else {
546            content
547        };
548
549        let lines: Vec<String> = content.lines().map(|s| s.to_string()).collect();
550
551        Field50K::new(lines)
552    }
553
554    fn to_swift_string(&self) -> String {
555        format!(":50K:{}", self.name_and_address.join("\n"))
556    }
557
558    fn validate(&self) -> ValidationResult {
559        use crate::errors::ValidationError;
560
561        let mut errors = Vec::new();
562
563        if self.name_and_address.is_empty() {
564            errors.push(ValidationError::FormatValidation {
565                field_tag: "50K".to_string(),
566                message: "Name and address cannot be empty".to_string(),
567            });
568        }
569
570        if self.name_and_address.len() > 4 {
571            errors.push(ValidationError::FormatValidation {
572                field_tag: "50K".to_string(),
573                message: "Too many lines (max 4)".to_string(),
574            });
575        }
576
577        for (i, line) in self.name_and_address.iter().enumerate() {
578            if line.len() > 35 {
579                errors.push(ValidationError::FormatValidation {
580                    field_tag: "50K".to_string(),
581                    message: format!("Line {} too long (max 35 characters)", i + 1),
582                });
583            }
584        }
585
586        ValidationResult {
587            is_valid: errors.is_empty(),
588            errors,
589            warnings: vec![],
590        }
591    }
592
593    fn format_spec() -> &'static str {
594        "4*35x"
595    }
596}
597
598impl SwiftField for Field50 {
599    fn parse(input: &str) -> Result<Self, ParseError> {
600        // Try to determine the variant from the input
601        if input.starts_with(":50A:") || input.starts_with("50A:") {
602            Ok(Field50::A(Field50A::parse(input)?))
603        } else if input.starts_with(":50F:") || input.starts_with("50F:") {
604            Ok(Field50::F(Field50F::parse(input)?))
605        } else if input.starts_with(":50K:") || input.starts_with("50K:") {
606            Ok(Field50::K(Field50K::parse(input)?))
607        } else {
608            // Default to 50K if no clear indicator
609            Ok(Field50::K(Field50K::parse(input)?))
610        }
611    }
612
613    fn to_swift_string(&self) -> String {
614        match self {
615            Field50::A(field) => field.to_swift_string(),
616            Field50::F(field) => field.to_swift_string(),
617            Field50::K(field) => field.to_swift_string(),
618        }
619    }
620
621    fn validate(&self) -> ValidationResult {
622        match self {
623            Field50::A(field) => field.validate(),
624            Field50::F(field) => field.validate(),
625            Field50::K(field) => field.validate(),
626        }
627    }
628
629    fn format_spec() -> &'static str {
630        "ordering_customer"
631    }
632}
633
634#[cfg(test)]
635mod tests {
636    use super::*;
637
638    #[test]
639    fn test_field50a_creation() {
640        let field = Field50A::new(Some("123456789".to_string()), "DEUTDEFFXXX").unwrap();
641        assert_eq!(field.account(), Some("123456789"));
642        assert_eq!(field.bic(), "DEUTDEFFXXX");
643        assert_eq!(field.to_swift_string(), ":50A:/123456789\nDEUTDEFFXXX");
644    }
645
646    #[test]
647    fn test_field50a_without_account() {
648        let field = Field50A::new(None, "DEUTDEFFXXX").unwrap();
649        assert_eq!(field.account(), None);
650        assert_eq!(field.bic(), "DEUTDEFFXXX");
651        assert_eq!(field.to_swift_string(), ":50A:DEUTDEFFXXX");
652    }
653
654    #[test]
655    fn test_field50a_parse() {
656        let field = Field50A::parse("/123456789\nDEUTDEFFXXX").unwrap();
657        assert_eq!(field.account(), Some("123456789"));
658        assert_eq!(field.bic(), "DEUTDEFFXXX");
659
660        let field = Field50A::parse("DEUTDEFFXXX").unwrap();
661        assert_eq!(field.account(), None);
662        assert_eq!(field.bic(), "DEUTDEFFXXX");
663    }
664
665    #[test]
666    fn test_field50f_creation() {
667        let field = Field50F::new(
668            "PARTY123",
669            vec!["JOHN DOE".to_string(), "123 MAIN ST".to_string()],
670        )
671        .unwrap();
672        assert_eq!(field.party_identifier(), "PARTY123");
673        assert_eq!(field.name_and_address(), &["JOHN DOE", "123 MAIN ST"]);
674    }
675
676    #[test]
677    fn test_field50f_parse() {
678        let field = Field50F::parse("PARTY123\nJOHN DOE\n123 MAIN ST").unwrap();
679        assert_eq!(field.party_identifier(), "PARTY123");
680        assert_eq!(field.name_and_address(), &["JOHN DOE", "123 MAIN ST"]);
681    }
682
683    #[test]
684    fn test_field50k_creation() {
685        let field = Field50K::new(vec!["JOHN DOE".to_string(), "123 MAIN ST".to_string()]).unwrap();
686        assert_eq!(field.name_and_address(), &["JOHN DOE", "123 MAIN ST"]);
687    }
688
689    #[test]
690    fn test_field50k_parse() {
691        let field = Field50K::parse("JOHN DOE\n123 MAIN ST").unwrap();
692        assert_eq!(field.name_and_address(), &["JOHN DOE", "123 MAIN ST"]);
693    }
694
695    #[test]
696    fn test_field50_enum_parse() {
697        let field = Field50::parse(":50A:DEUTDEFFXXX").unwrap();
698        assert!(matches!(field, Field50::A(_)));
699
700        let field = Field50::parse(":50F:PARTY123\nJOHN DOE").unwrap();
701        assert!(matches!(field, Field50::F(_)));
702
703        let field = Field50::parse(":50K:JOHN DOE\n123 MAIN ST").unwrap();
704        assert!(matches!(field, Field50::K(_)));
705    }
706
707    #[test]
708    fn test_field50_parse_with_tag() {
709        let field = Field50::parse_with_tag("50A", "DEUTDEFFXXX").unwrap();
710        assert!(matches!(field, Field50::A(_)));
711
712        let field = Field50::parse_with_tag("50F", "PARTY123\nJOHN DOE").unwrap();
713        assert!(matches!(field, Field50::F(_)));
714
715        let field = Field50::parse_with_tag("50K", "JOHN DOE\n123 MAIN ST").unwrap();
716        assert!(matches!(field, Field50::K(_)));
717    }
718
719    #[test]
720    fn test_field50_tag() {
721        let field = Field50::A(Field50A::new(None, "DEUTDEFFXXX").unwrap());
722        assert_eq!(field.tag(), "50A");
723
724        let field = Field50::F(Field50F::new("PARTY123", vec!["JOHN DOE".to_string()]).unwrap());
725        assert_eq!(field.tag(), "50F");
726
727        let field = Field50::K(Field50K::new(vec!["JOHN DOE".to_string()]).unwrap());
728        assert_eq!(field.tag(), "50K");
729    }
730
731    #[test]
732    fn test_field50_validation() {
733        let field = Field50A::new(None, "DEUTDEFF").unwrap();
734        let result = field.validate();
735        assert!(result.is_valid);
736
737        let field = Field50F::new("PARTY123", vec!["JOHN DOE".to_string()]).unwrap();
738        let result = field.validate();
739        assert!(result.is_valid);
740
741        let field = Field50K::new(vec!["JOHN DOE".to_string()]).unwrap();
742        let result = field.validate();
743        assert!(result.is_valid);
744    }
745
746    #[test]
747    fn test_field50_json_serialization_flattened() {
748        // Test Field50K (most common case)
749        let field50k = Field50::K(
750            Field50K::new(vec!["JOHN DOE".to_string(), "123 MAIN ST".to_string()]).unwrap(),
751        );
752
753        let json = serde_json::to_string(&field50k).unwrap();
754        println!("Field50K JSON: {}", json);
755
756        // Should be flattened - no "K" wrapper
757        assert!(json.contains("\"name_and_address\""));
758        assert!(!json.contains("\"K\""));
759
760        // Test Field50A
761        let field50a =
762            Field50::A(Field50A::new(Some("123456789".to_string()), "DEUTDEFFXXX").unwrap());
763
764        let json = serde_json::to_string(&field50a).unwrap();
765        println!("Field50A JSON: {}", json);
766
767        // Should be flattened - no "A" wrapper
768        assert!(json.contains("\"account\""));
769        assert!(json.contains("\"bic\""));
770        assert!(!json.contains("\"A\""));
771
772        // Test Field50F
773        let field50f = Field50::F(Field50F::new("PARTY123", vec!["JOHN DOE".to_string()]).unwrap());
774
775        let json = serde_json::to_string(&field50f).unwrap();
776        println!("Field50F JSON: {}", json);
777
778        // Should be flattened - no "F" wrapper
779        assert!(json.contains("\"party_identifier\""));
780        assert!(json.contains("\"name_and_address\""));
781        assert!(!json.contains("\"F\""));
782    }
783
784    #[test]
785    fn test_field50_json_deserialization() {
786        // Test deserializing Field50K
787        let json = r#"{"name_and_address":["JOHN DOE","123 MAIN ST"]}"#;
788        let field: Field50 = serde_json::from_str(json).unwrap();
789        assert!(matches!(field, Field50::K(_)));
790
791        // Test deserializing Field50A
792        let json = r#"{"account":"123456789","bic":"DEUTDEFFXXX"}"#;
793        let field: Field50 = serde_json::from_str(json).unwrap();
794        assert!(matches!(field, Field50::A(_)));
795
796        // Test deserializing Field50F
797        let json = r#"{"party_identifier":"PARTY123","name_and_address":["JOHN DOE"]}"#;
798        let field: Field50 = serde_json::from_str(json).unwrap();
799        assert!(matches!(field, Field50::F(_)));
800    }
801}