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)]
109pub struct Field50A {
110 pub account: Option<String>,
112 #[serde(flatten)]
114 pub bic: BIC,
115}
116
117impl Field50A {
118 pub fn new(account: Option<String>, bic: impl Into<String>) -> Result<Self, ParseError> {
120 let bic = BIC::parse(&bic.into(), Some("50A"))?;
122
123 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 pub fn account(&self) -> Option<&str> {
145 self.account.as_deref()
146 }
147
148 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#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
167pub struct Field50F {
168 pub party_identifier: String,
170 pub name_and_address: Vec<String>,
172}
173
174impl Field50F {
175 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 pub fn party_identifier(&self) -> &str {
220 &self.party_identifier
221 }
222
223 pub fn name_and_address(&self) -> &[String] {
225 &self.name_and_address
226 }
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
233pub struct Field50K {
234 pub name_and_address: Vec<String>,
236}
237
238impl Field50K {
239 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 pub fn name_and_address(&self) -> &[String] {
269 &self.name_and_address
270 }
271}
272
273#[derive(Debug, Clone, PartialEq, Eq)]
275pub enum Field50 {
276 A(Field50A),
277 F(Field50F),
278 K(Field50K),
279}
280
281impl Field50 {
282 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 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
320impl 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
334impl<'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 if fields.contains_key("bic") {
361 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 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 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 let bic_validation = self.bic.validate();
456 if !bic_validation.is_valid {
457 errors.extend(bic_validation.errors);
458 }
459
460 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 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 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 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 assert!(json.contains("\"name_and_address\""));
758 assert!(!json.contains("\"K\""));
759
760 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 assert!(json.contains("\"account\""));
769 assert!(json.contains("\"bic\""));
770 assert!(!json.contains("\"A\""));
771
772 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 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 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 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 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}