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#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
122pub struct Field59A {
123 pub account: Option<String>,
125 #[serde(flatten)]
127 pub bic: BIC,
128}
129
130impl Field59A {
131 pub fn new(account: Option<String>, bic: impl Into<String>) -> Result<Self, ParseError> {
133 let bic_str = bic.into().trim().to_string();
134
135 let parsed_bic = BIC::parse(&bic_str, Some("59A"))?;
137
138 if let Some(ref acc) = account {
140 if acc.is_empty() {
141 return Err(ParseError::InvalidFieldFormat {
142 field_tag: "59A".to_string(),
143 message: "Account cannot be empty if specified".to_string(),
144 });
145 }
146
147 if acc.len() > 34 {
148 return Err(ParseError::InvalidFieldFormat {
149 field_tag: "59A".to_string(),
150 message: "Account number too long (max 34 characters)".to_string(),
151 });
152 }
153 }
154
155 Ok(Field59A {
156 account,
157 bic: parsed_bic,
158 })
159 }
160
161 pub fn account(&self) -> Option<&str> {
163 self.account.as_deref()
164 }
165
166 pub fn bic(&self) -> &str {
168 self.bic.value()
169 }
170}
171
172impl std::fmt::Display for Field59A {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 match &self.account {
175 Some(account) => write!(f, "Account: {}, BIC: {}", account, self.bic.value()),
176 None => write!(f, "BIC: {}", self.bic.value()),
177 }
178 }
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
187pub struct Field59F {
188 pub party_identifier: String,
190 pub name_and_address: Vec<String>,
192}
193
194impl Field59F {
195 pub fn new(
197 party_identifier: impl Into<String>,
198 name_and_address: Vec<String>,
199 ) -> Result<Self, ParseError> {
200 let party_identifier = party_identifier.into().trim().to_string();
201
202 if party_identifier.is_empty() {
203 return Err(ParseError::InvalidFieldFormat {
204 field_tag: "59F".to_string(),
205 message: "Party identifier cannot be empty".to_string(),
206 });
207 }
208
209 if party_identifier.len() > 35 {
210 return Err(ParseError::InvalidFieldFormat {
211 field_tag: "59F".to_string(),
212 message: "Party identifier cannot exceed 35 characters".to_string(),
213 });
214 }
215
216 if !party_identifier
217 .chars()
218 .all(|c| c.is_ascii() && !c.is_control())
219 {
220 return Err(ParseError::InvalidFieldFormat {
221 field_tag: "59F".to_string(),
222 message: "Party identifier contains invalid characters".to_string(),
223 });
224 }
225
226 if name_and_address.is_empty() {
227 return Err(ParseError::InvalidFieldFormat {
228 field_tag: "59F".to_string(),
229 message: "Name and address cannot be empty".to_string(),
230 });
231 }
232
233 if name_and_address.len() > 4 {
234 return Err(ParseError::InvalidFieldFormat {
235 field_tag: "59F".to_string(),
236 message: "Cannot exceed 4 name and address lines".to_string(),
237 });
238 }
239
240 for (i, line) in name_and_address.iter().enumerate() {
241 let trimmed = line.trim();
242 if trimmed.is_empty() {
243 return Err(ParseError::InvalidFieldFormat {
244 field_tag: "59F".to_string(),
245 message: format!("Name and address line {} cannot be empty", i + 1),
246 });
247 }
248
249 if !trimmed.starts_with(char::is_numeric) || !trimmed.contains('/') {
251 return Err(ParseError::InvalidFieldFormat {
252 field_tag: "59F".to_string(),
253 message: format!("Name and address line {} must be in format 'n/text'", i + 1),
254 });
255 }
256
257 let parts: Vec<&str> = trimmed.splitn(2, '/').collect();
258 if parts.len() != 2 {
259 return Err(ParseError::InvalidFieldFormat {
260 field_tag: "59F".to_string(),
261 message: format!(
262 "Name and address line {} must contain exactly one '/'",
263 i + 1
264 ),
265 });
266 }
267
268 let line_number: u8 = parts[0]
269 .parse()
270 .map_err(|_| ParseError::InvalidFieldFormat {
271 field_tag: "59F".to_string(),
272 message: format!(
273 "Name and address line {} must start with a number 1-4",
274 i + 1
275 ),
276 })?;
277
278 if !(1..=4).contains(&line_number) {
279 return Err(ParseError::InvalidFieldFormat {
280 field_tag: "59F".to_string(),
281 message: format!(
282 "Name and address line {} number must be between 1 and 4",
283 i + 1
284 ),
285 });
286 }
287
288 if parts[1].is_empty() {
289 return Err(ParseError::InvalidFieldFormat {
290 field_tag: "59F".to_string(),
291 message: format!("Name and address line {} content cannot be empty", i + 1),
292 });
293 }
294
295 if parts[1].len() > 33 {
296 return Err(ParseError::InvalidFieldFormat {
297 field_tag: "59F".to_string(),
298 message: format!(
299 "Name and address line {} content cannot exceed 33 characters",
300 i + 1
301 ),
302 });
303 }
304
305 if !parts[1].chars().all(|c| c.is_ascii() && !c.is_control()) {
306 return Err(ParseError::InvalidFieldFormat {
307 field_tag: "59F".to_string(),
308 message: format!(
309 "Name and address line {} contains invalid characters",
310 i + 1
311 ),
312 });
313 }
314 }
315
316 let trimmed_lines: Vec<String> = name_and_address
317 .iter()
318 .map(|line| line.trim().to_string())
319 .collect();
320
321 Ok(Field59F {
322 party_identifier,
323 name_and_address: trimmed_lines,
324 })
325 }
326
327 pub fn party_identifier(&self) -> &str {
329 &self.party_identifier
330 }
331
332 pub fn name_and_address(&self) -> &[String] {
334 &self.name_and_address
335 }
336
337 pub fn name_address_line(&self, line_number: u8) -> Option<&str> {
339 self.name_and_address
340 .iter()
341 .find(|line| line.starts_with(&format!("{}/", line_number)))
342 .map(|line| line.split_once('/').map(|x| x.1).unwrap_or(""))
343 }
344
345 pub fn description(&self) -> String {
347 format!(
348 "Beneficiary Customer (Party ID: {}, Name/Address: {})",
349 self.party_identifier,
350 self.name_and_address.join(", ")
351 )
352 }
353}
354
355impl std::fmt::Display for Field59F {
356 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357 write!(
358 f,
359 "Party: {}, Name/Address: {}",
360 self.party_identifier,
361 self.name_and_address.join(" / ")
362 )
363 }
364}
365
366impl SwiftField for Field59F {
367 fn parse(content: &str) -> Result<Self, ParseError> {
368 let content = if let Some(stripped) = content.strip_prefix(":59F:") {
369 stripped
370 } else if let Some(stripped) = content.strip_prefix("59F:") {
371 stripped
372 } else {
373 content
374 };
375
376 let lines: Vec<&str> = content.lines().collect();
377 if lines.is_empty() {
378 return Err(ParseError::InvalidFieldFormat {
379 field_tag: "59F".to_string(),
380 message: "No content provided".to_string(),
381 });
382 }
383
384 let party_identifier = lines[0].to_string();
385 let name_and_address = lines[1..].iter().map(|s| s.to_string()).collect();
386
387 Field59F::new(party_identifier, name_and_address)
388 }
389
390 fn to_swift_string(&self) -> String {
391 let mut content = self.party_identifier.clone();
392 for line in &self.name_and_address {
393 content.push('\n');
394 content.push_str(line);
395 }
396 format!(":59F:{}", content)
397 }
398
399 fn validate(&self) -> ValidationResult {
400 ValidationResult {
402 is_valid: true,
403 errors: Vec::new(),
404 warnings: Vec::new(),
405 }
406 }
407
408 fn format_spec() -> &'static str {
409 "party_identifier_and_name_address"
410 }
411}
412
413#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
417pub struct Field59Basic {
418 pub beneficiary_customer: Vec<String>,
420}
421
422impl Field59Basic {
423 pub fn new(beneficiary_customer: Vec<String>) -> Result<Self, ParseError> {
425 if beneficiary_customer.is_empty() {
426 return Err(ParseError::InvalidFieldFormat {
427 field_tag: "59".to_string(),
428 message: "Beneficiary customer information cannot be empty".to_string(),
429 });
430 }
431
432 if beneficiary_customer.len() > 4 {
433 return Err(ParseError::InvalidFieldFormat {
434 field_tag: "59".to_string(),
435 message: "Too many lines (max 4)".to_string(),
436 });
437 }
438
439 for (i, line) in beneficiary_customer.iter().enumerate() {
440 if line.len() > 35 {
441 return Err(ParseError::InvalidFieldFormat {
442 field_tag: "59".to_string(),
443 message: format!("Line {} too long (max 35 characters)", i + 1),
444 });
445 }
446 }
447
448 Ok(Field59Basic {
449 beneficiary_customer,
450 })
451 }
452
453 pub fn beneficiary_customer(&self) -> &[String] {
455 &self.beneficiary_customer
456 }
457}
458
459#[derive(Debug, Clone, PartialEq, Eq)]
461pub enum Field59 {
462 A(Field59A),
463 F(Field59F),
464 NoOption(Field59Basic),
465}
466
467impl Field59 {
468 pub fn parse_with_tag(tag: &str, content: &str) -> Result<Self, ParseError> {
470 match tag {
471 "59A" => Ok(Field59::A(Field59A::parse(content)?)),
472 "59F" => Ok(Field59::F(Field59F::parse(content)?)),
473 "59" => Ok(Field59::NoOption(Field59Basic::parse(content)?)),
474 _ => Err(ParseError::InvalidFieldFormat {
475 field_tag: "59".to_string(),
476 message: format!("Unknown Field59 option: {}", tag),
477 }),
478 }
479 }
480
481 pub fn tag(&self) -> &'static str {
483 match self {
484 Field59::A(_) => "59A",
485 Field59::F(_) => "59F",
486 Field59::NoOption(_) => "59",
487 }
488 }
489}
490
491impl std::fmt::Display for Field59 {
492 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
493 match self {
494 Field59::A(field) => write!(f, "59A: {}", field),
495 Field59::F(field) => write!(f, "59F: {}", field),
496 Field59::NoOption(field) => {
497 write!(f, "59: {}", field.beneficiary_customer.join(", "))
498 }
499 }
500 }
501}
502
503impl Serialize for Field59 {
505 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
506 where
507 S: Serializer,
508 {
509 match self {
510 Field59::A(field) => field.serialize(serializer),
511 Field59::F(field) => field.serialize(serializer),
512 Field59::NoOption(field) => field.serialize(serializer),
513 }
514 }
515}
516
517impl<'de> Deserialize<'de> for Field59 {
519 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
520 where
521 D: Deserializer<'de>,
522 {
523 struct Field59Visitor;
524
525 impl<'de> Visitor<'de> for Field59Visitor {
526 type Value = Field59;
527
528 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
529 formatter.write_str("a Field59 variant")
530 }
531
532 fn visit_map<V>(self, mut map: V) -> Result<Field59, V::Error>
533 where
534 V: MapAccess<'de>,
535 {
536 let mut fields = std::collections::HashMap::new();
537
538 while let Some((key, value)) = map.next_entry::<String, serde_json::Value>()? {
539 fields.insert(key, value);
540 }
541
542 if fields.contains_key("bic") {
544 let account = fields
546 .get("account")
547 .and_then(|v| v.as_str())
548 .map(|s| s.to_string());
549 let bic = fields
550 .get("bic")
551 .and_then(|v| v.as_str())
552 .ok_or_else(|| de::Error::missing_field("bic"))?
553 .to_string();
554
555 Field59A::new(account, bic)
556 .map(Field59::A)
557 .map_err(|e| de::Error::custom(format!("Field59A validation error: {}", e)))
558 } else if fields.contains_key("party_identifier")
559 && fields.contains_key("name_and_address")
560 {
561 let party_identifier = fields
563 .get("party_identifier")
564 .and_then(|v| v.as_str())
565 .ok_or_else(|| de::Error::missing_field("party_identifier"))?
566 .to_string();
567 let name_and_address = fields
568 .get("name_and_address")
569 .and_then(|v| v.as_array())
570 .ok_or_else(|| de::Error::missing_field("name_and_address"))?
571 .iter()
572 .map(|v| v.as_str().unwrap_or("").to_string())
573 .collect();
574
575 Field59F::new(party_identifier, name_and_address)
576 .map(Field59::F)
577 .map_err(|e| de::Error::custom(format!("Field59F validation error: {}", e)))
578 } else if fields.contains_key("beneficiary_customer") {
579 let beneficiary_customer = fields
581 .get("beneficiary_customer")
582 .and_then(|v| v.as_array())
583 .ok_or_else(|| de::Error::missing_field("beneficiary_customer"))?
584 .iter()
585 .map(|v| v.as_str().unwrap_or("").to_string())
586 .collect();
587
588 Field59Basic::new(beneficiary_customer)
589 .map(Field59::NoOption)
590 .map_err(|e| {
591 de::Error::custom(format!("Field59Basic validation error: {}", e))
592 })
593 } else {
594 Err(de::Error::custom("Unable to determine Field59 variant"))
595 }
596 }
597 }
598
599 deserializer.deserialize_map(Field59Visitor)
600 }
601}
602
603impl SwiftField for Field59A {
604 fn parse(content: &str) -> Result<Self, ParseError> {
605 let content = if let Some(stripped) = content.strip_prefix(":59A:") {
606 stripped
607 } else if let Some(stripped) = content.strip_prefix("59A:") {
608 stripped
609 } else {
610 content
611 };
612
613 let mut lines = content.lines();
614 let first_line = lines.next().unwrap_or_default();
615
616 let (account, bic_line) = if let Some(stripped) = first_line.strip_prefix('/') {
617 (Some(stripped.to_string()), lines.next().unwrap_or_default())
618 } else {
619 (None, first_line)
620 };
621
622 Field59A::new(account, bic_line)
623 }
624
625 fn to_swift_string(&self) -> String {
626 match &self.account {
627 Some(account) => format!(":59A:/{}\n{}", account, self.bic.value()),
628 None => format!(":59A:{}", self.bic.value()),
629 }
630 }
631
632 fn validate(&self) -> ValidationResult {
633 use crate::errors::ValidationError;
634
635 let mut errors = Vec::new();
636
637 let bic_validation = self.bic.validate();
639 if !bic_validation.is_valid {
640 errors.extend(bic_validation.errors);
641 }
642
643 if let Some(ref account) = self.account {
645 if account.len() > 34 {
646 errors.push(ValidationError::FormatValidation {
647 field_tag: "59A".to_string(),
648 message: "Account number too long (max 34 characters)".to_string(),
649 });
650 }
651 }
652
653 ValidationResult {
654 is_valid: errors.is_empty(),
655 errors,
656 warnings: vec![],
657 }
658 }
659
660 fn format_spec() -> &'static str {
661 "[/account]bic"
662 }
663}
664
665impl SwiftField for Field59Basic {
666 fn parse(content: &str) -> Result<Self, ParseError> {
667 let content = if let Some(stripped) = content.strip_prefix(":59:") {
668 stripped
669 } else if let Some(stripped) = content.strip_prefix("59:") {
670 stripped
671 } else {
672 content
673 };
674
675 let lines: Vec<String> = content.lines().map(|s| s.to_string()).collect();
676
677 Field59Basic::new(lines)
678 }
679
680 fn to_swift_string(&self) -> String {
681 format!(":59:{}", self.beneficiary_customer.join("\n"))
682 }
683
684 fn validate(&self) -> ValidationResult {
685 use crate::errors::ValidationError;
686
687 let mut errors = Vec::new();
688
689 if self.beneficiary_customer.is_empty() {
690 errors.push(ValidationError::FormatValidation {
691 field_tag: "59".to_string(),
692 message: "Beneficiary customer information cannot be empty".to_string(),
693 });
694 }
695
696 if self.beneficiary_customer.len() > 4 {
697 errors.push(ValidationError::FormatValidation {
698 field_tag: "59".to_string(),
699 message: "Too many lines (max 4)".to_string(),
700 });
701 }
702
703 for (i, line) in self.beneficiary_customer.iter().enumerate() {
704 if line.len() > 35 {
705 errors.push(ValidationError::FormatValidation {
706 field_tag: "59".to_string(),
707 message: format!("Line {} too long (max 35 characters)", i + 1),
708 });
709 }
710 }
711
712 ValidationResult {
713 is_valid: errors.is_empty(),
714 errors,
715 warnings: vec![],
716 }
717 }
718
719 fn format_spec() -> &'static str {
720 "4*35x"
721 }
722}
723
724impl SwiftField for Field59 {
725 fn parse(input: &str) -> Result<Self, ParseError> {
726 if input.starts_with(":59A:") || input.starts_with("59A:") {
728 Ok(Field59::A(Field59A::parse(input)?))
729 } else if input.starts_with(":59F:") || input.starts_with("59F:") {
730 Ok(Field59::F(Field59F::parse(input)?))
731 } else if input.starts_with(":59:") || input.starts_with("59:") {
732 Ok(Field59::NoOption(Field59Basic::parse(input)?))
733 } else {
734 Ok(Field59::NoOption(Field59Basic::parse(input)?))
736 }
737 }
738
739 fn to_swift_string(&self) -> String {
740 match self {
741 Field59::A(field) => field.to_swift_string(),
742 Field59::F(field) => field.to_swift_string(),
743 Field59::NoOption(field) => field.to_swift_string(),
744 }
745 }
746
747 fn validate(&self) -> ValidationResult {
748 match self {
749 Field59::A(field) => field.validate(),
750 Field59::F(field) => field.validate(),
751 Field59::NoOption(field) => field.validate(),
752 }
753 }
754
755 fn format_spec() -> &'static str {
756 "beneficiary_customer"
757 }
758}
759
760#[cfg(test)]
761mod tests {
762 use super::*;
763
764 #[test]
765 fn test_field59a_creation() {
766 let field = Field59A::new(Some("123456789".to_string()), "DEUTDEFFXXX").unwrap();
767 assert_eq!(field.account(), Some("123456789"));
768 assert_eq!(field.bic(), "DEUTDEFFXXX");
769 assert_eq!(field.to_swift_string(), ":59A:/123456789\nDEUTDEFFXXX");
770 }
771
772 #[test]
773 fn test_field59a_without_account() {
774 let field = Field59A::new(None, "DEUTDEFFXXX").unwrap();
775 assert_eq!(field.account(), None);
776 assert_eq!(field.bic(), "DEUTDEFFXXX");
777 assert_eq!(field.to_swift_string(), ":59A:DEUTDEFFXXX");
778 }
779
780 #[test]
781 fn test_field59a_parse() {
782 let field = Field59A::parse("/123456789\nDEUTDEFFXXX").unwrap();
783 assert_eq!(field.account(), Some("123456789"));
784 assert_eq!(field.bic(), "DEUTDEFFXXX");
785
786 let field = Field59A::parse("DEUTDEFFXXX").unwrap();
787 assert_eq!(field.account(), None);
788 assert_eq!(field.bic(), "DEUTDEFFXXX");
789 }
790
791 #[test]
792 fn test_field59a_invalid_bic() {
793 let result = Field59A::new(None, "INVALID"); assert!(result.is_err());
795
796 let result = Field59A::new(None, "TOOLONGBICCODE"); assert!(result.is_err());
798 }
799
800 #[test]
801 fn test_field59_basic_creation() {
802 let field = Field59Basic::new(vec![
803 "MUELLER GMBH".to_string(),
804 "HAUPTSTRASSE 1".to_string(),
805 ])
806 .unwrap();
807 assert_eq!(
808 field.beneficiary_customer(),
809 &["MUELLER GMBH", "HAUPTSTRASSE 1"]
810 );
811 }
812
813 #[test]
814 fn test_field59_basic_parse() {
815 let field = Field59Basic::parse("MUELLER GMBH\nHAUPTSTRASSE 1").unwrap();
816 assert_eq!(
817 field.beneficiary_customer(),
818 &["MUELLER GMBH", "HAUPTSTRASSE 1"]
819 );
820 }
821
822 #[test]
823 fn test_field59_basic_too_many_lines() {
824 let result = Field59Basic::new(vec![
825 "LINE1".to_string(),
826 "LINE2".to_string(),
827 "LINE3".to_string(),
828 "LINE4".to_string(),
829 "LINE5".to_string(), ]);
831 assert!(result.is_err());
832 }
833
834 #[test]
835 fn test_field59_enum_parse() {
836 let field = Field59::parse(":59A:DEUTDEFFXXX").unwrap();
837 assert!(matches!(field, Field59::A(_)));
838
839 let field = Field59::parse(":59:MUELLER GMBH\nHAUPTSTRASSE 1").unwrap();
840 assert!(matches!(field, Field59::NoOption(_)));
841 }
842
843 #[test]
844 fn test_field59_parse_with_tag() {
845 let field = Field59::parse_with_tag("59A", "DEUTDEFFXXX").unwrap();
846 assert!(matches!(field, Field59::A(_)));
847
848 let field = Field59::parse_with_tag("59", "MUELLER GMBH\nHAUPTSTRASSE 1").unwrap();
849 assert!(matches!(field, Field59::NoOption(_)));
850 }
851
852 #[test]
853 fn test_field59_tag() {
854 let field = Field59::A(Field59A::new(None, "DEUTDEFFXXX").unwrap());
855 assert_eq!(field.tag(), "59A");
856
857 let field = Field59::NoOption(Field59Basic::new(vec!["MUELLER GMBH".to_string()]).unwrap());
858 assert_eq!(field.tag(), "59");
859 }
860
861 #[test]
862 fn test_field59_validation() {
863 let field = Field59A::new(None, "DEUTDEFF").unwrap();
864 let result = field.validate();
865 assert!(result.is_valid);
866
867 let field = Field59Basic::new(vec!["MUELLER GMBH".to_string()]).unwrap();
868 let result = field.validate();
869 assert!(result.is_valid);
870 }
871
872 #[test]
873 fn test_field59_display() {
874 let field = Field59A::new(Some("123456".to_string()), "DEUTDEFF").unwrap();
875 assert_eq!(format!("{}", field), "Account: 123456, BIC: DEUTDEFF");
876
877 let field = Field59A::new(None, "DEUTDEFF").unwrap();
878 assert_eq!(format!("{}", field), "BIC: DEUTDEFF");
879
880 let field =
881 Field59Basic::new(vec!["MUELLER GMBH".to_string(), "BERLIN".to_string()]).unwrap();
882 let enum_field = Field59::NoOption(field);
883 assert_eq!(format!("{}", enum_field), "59: MUELLER GMBH, BERLIN");
884 }
885
886 #[test]
887 fn test_field59_json_serialization_flattened() {
888 let field59a = Field59::A(
890 Field59A::new(Some("DE89370400440532013000".to_string()), "DEUTDEFF").unwrap(),
891 );
892
893 let json = serde_json::to_string(&field59a).unwrap();
894 println!("Field59A JSON: {}", json);
895
896 assert!(json.contains("\"account\""));
898 assert!(json.contains("\"bic\""));
899 assert!(!json.contains("\"A\""));
900
901 let field59_basic = Field59::NoOption(
903 Field59Basic::new(vec![
904 "MUELLER GMBH".to_string(),
905 "HAUPTSTRASSE 1".to_string(),
906 ])
907 .unwrap(),
908 );
909
910 let json = serde_json::to_string(&field59_basic).unwrap();
911 println!("Field59Basic JSON: {}", json);
912
913 assert!(json.contains("\"beneficiary_customer\""));
915 assert!(!json.contains("\"NoOption\""));
916 }
917
918 #[test]
919 fn test_field59_json_deserialization() {
920 let json = r#"{"account":"DE89370400440532013000","bic":"DEUTDEFF"}"#;
922 let field: Field59 = serde_json::from_str(json).unwrap();
923 assert!(matches!(field, Field59::A(_)));
924
925 let json = r#"{"party_identifier":"PARTYID123","name_and_address":["1/JOHN DOE","2/123 MAIN ST"]}"#;
927 let field: Field59 = serde_json::from_str(json).unwrap();
928 assert!(matches!(field, Field59::F(_)));
929
930 let json = r#"{"beneficiary_customer":["MUELLER GMBH","HAUPTSTRASSE 1"]}"#;
932 let field: Field59 = serde_json::from_str(json).unwrap();
933 assert!(matches!(field, Field59::NoOption(_)));
934 }
935
936 #[test]
937 fn test_field59f_creation() {
938 let field = Field59F::new(
939 "PARTYID123",
940 vec!["1/JOHN DOE".to_string(), "2/123 MAIN ST".to_string()],
941 )
942 .unwrap();
943 assert_eq!(field.party_identifier(), "PARTYID123");
944 assert_eq!(field.name_and_address(), &["1/JOHN DOE", "2/123 MAIN ST"]);
945 assert_eq!(field.name_address_line(1), Some("JOHN DOE"));
946 assert_eq!(field.name_address_line(2), Some("123 MAIN ST"));
947 assert_eq!(field.name_address_line(3), None);
948 }
949
950 #[test]
951 fn test_field59f_parse() {
952 let field = Field59F::parse("PARTYID123\n1/JOHN DOE\n2/123 MAIN ST").unwrap();
953 assert_eq!(field.party_identifier(), "PARTYID123");
954 assert_eq!(field.name_and_address(), &["1/JOHN DOE", "2/123 MAIN ST"]);
955 }
956
957 #[test]
958 fn test_field59f_to_swift_string() {
959 let field = Field59F::new(
960 "PARTYID123",
961 vec!["1/JOHN DOE".to_string(), "2/123 MAIN ST".to_string()],
962 )
963 .unwrap();
964 assert_eq!(
965 field.to_swift_string(),
966 ":59F:PARTYID123\n1/JOHN DOE\n2/123 MAIN ST"
967 );
968 }
969
970 #[test]
971 fn test_field59f_validation_errors() {
972 let result = Field59F::new("", vec!["1/JOHN DOE".to_string()]);
974 assert!(result.is_err());
975
976 let result = Field59F::new("A".repeat(36), vec!["1/JOHN DOE".to_string()]);
978 assert!(result.is_err());
979
980 let result = Field59F::new("PARTYID123", vec![]);
982 assert!(result.is_err());
983
984 let result = Field59F::new(
986 "PARTYID123",
987 vec![
988 "1/JOHN DOE".to_string(),
989 "2/123 MAIN ST".to_string(),
990 "3/CITY".to_string(),
991 "4/COUNTRY".to_string(),
992 "5/EXTRA".to_string(), ],
994 );
995 assert!(result.is_err());
996
997 let result = Field59F::new("PARTYID123", vec!["INVALID FORMAT".to_string()]);
999 assert!(result.is_err());
1000
1001 let result = Field59F::new("PARTYID123", vec!["5/INVALID LINE NUMBER".to_string()]);
1003 assert!(result.is_err());
1004
1005 let result = Field59F::new(
1007 "PARTYID123",
1008 vec![format!("1/{}", "A".repeat(34))], );
1010 assert!(result.is_err());
1011 }
1012
1013 #[test]
1014 fn test_field59f_display() {
1015 let field = Field59F::new(
1016 "PARTYID123",
1017 vec!["1/JOHN DOE".to_string(), "2/123 MAIN ST".to_string()],
1018 )
1019 .unwrap();
1020 assert_eq!(
1021 format!("{}", field),
1022 "Party: PARTYID123, Name/Address: 1/JOHN DOE / 2/123 MAIN ST"
1023 );
1024 }
1025
1026 #[test]
1027 fn test_field59f_description() {
1028 let field = Field59F::new(
1029 "PARTYID123",
1030 vec!["1/JOHN DOE".to_string(), "2/123 MAIN ST".to_string()],
1031 )
1032 .unwrap();
1033 assert_eq!(
1034 field.description(),
1035 "Beneficiary Customer (Party ID: PARTYID123, Name/Address: 1/JOHN DOE, 2/123 MAIN ST)"
1036 );
1037 }
1038
1039 #[test]
1040 fn test_field59_enum_with_f_variant() {
1041 let field = Field59::F(
1042 Field59F::new(
1043 "PARTYID123",
1044 vec!["1/JOHN DOE".to_string(), "2/123 MAIN ST".to_string()],
1045 )
1046 .unwrap(),
1047 );
1048 assert_eq!(field.tag(), "59F");
1049 assert_eq!(
1050 format!("{}", field),
1051 "59F: Party: PARTYID123, Name/Address: 1/JOHN DOE / 2/123 MAIN ST"
1052 );
1053 }
1054
1055 #[test]
1056 fn test_field59_parse_with_tag_f() {
1057 let field =
1058 Field59::parse_with_tag("59F", "PARTYID123\n1/JOHN DOE\n2/123 MAIN ST").unwrap();
1059 assert!(matches!(field, Field59::F(_)));
1060 assert_eq!(field.tag(), "59F");
1061 }
1062
1063 #[test]
1064 fn test_field59_parse_f_variant() {
1065 let field = Field59::parse(":59F:PARTYID123\n1/JOHN DOE\n2/123 MAIN ST").unwrap();
1066 assert!(matches!(field, Field59::F(_)));
1067 assert_eq!(
1068 field.to_swift_string(),
1069 ":59F:PARTYID123\n1/JOHN DOE\n2/123 MAIN ST"
1070 );
1071 }
1072
1073 #[test]
1074 fn test_field59f_json_serialization() {
1075 let field = Field59::F(
1076 Field59F::new(
1077 "PARTYID123",
1078 vec!["1/JOHN DOE".to_string(), "2/123 MAIN ST".to_string()],
1079 )
1080 .unwrap(),
1081 );
1082
1083 let json = serde_json::to_string(&field).unwrap();
1084 println!("Field59F JSON: {}", json);
1085
1086 assert!(json.contains("\"party_identifier\""));
1088 assert!(json.contains("\"name_and_address\""));
1089 assert!(!json.contains("\"F\""));
1090 }
1091}