swift_mt_message/
json.rs

1//! JSON conversion utilities for SWIFT MT messages
2//!
3//! This module provides bidirectional conversion between SWIFT MT messages
4//! and JSON format, supporting both message-level and field-level serialization.
5
6use serde::{Deserialize, Serialize};
7use serde_json::{Map, Value};
8use std::collections::HashMap;
9
10use crate::errors::{ParseError, Result};
11use crate::field_parser::{SwiftFieldContainer, SwiftMessage};
12use crate::mt_models::fields::beneficiary::Field59;
13use crate::mt_models::fields::institutions::{
14    Field52, Field53, Field54, Field55, Field56, Field57,
15};
16use crate::mt_models::fields::ordering_customer::Field50;
17use crate::mt_models::mt103::MT103;
18use crate::tokenizer::SwiftMessageBlocks;
19
20/// JSON representation of a SWIFT message
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct JsonMessage {
23    /// Message type (e.g., "103", "202")
24    pub message_type: String,
25
26    /// Message header blocks
27    pub blocks: JsonBlocks,
28
29    /// Message fields with their values
30    pub fields: Map<String, Value>,
31
32    /// Original field order for faithful reconstruction
33    pub field_order: Vec<String>,
34}
35
36/// JSON representation of SWIFT message blocks
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct JsonBlocks {
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub block1: Option<String>,
41
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub block2: Option<String>,
44
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub block3: Option<String>,
47
48    pub block4: String,
49
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub block5: Option<String>,
52}
53
54/// Optional metadata for enhanced JSON representation
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct MessageMetadata {
57    /// Parsing timestamp
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub parsed_at: Option<chrono::DateTime<chrono::Utc>>,
60
61    /// Validation status
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub validation_status: Option<String>,
64
65    /// Additional custom metadata
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub custom: Option<Map<String, Value>>,
68}
69
70/// Convert SWIFT message to JSON
71pub trait ToJson {
72    /// Convert to JSON Value
73    fn to_json(&self) -> Result<Value>;
74
75    /// Convert to JSON string
76    fn to_json_string(&self) -> Result<String> {
77        let json_value = self.to_json()?;
78        serde_json::to_string_pretty(&json_value).map_err(|e| ParseError::JsonError {
79            message: format!("Failed to serialize to JSON: {}", e),
80        })
81    }
82
83    /// Convert to compact JSON string
84    fn to_json_compact(&self) -> Result<String> {
85        let json_value = self.to_json()?;
86        serde_json::to_string(&json_value).map_err(|e| ParseError::JsonError {
87            message: format!("Failed to serialize to JSON: {}", e),
88        })
89    }
90}
91
92/// Convert from JSON to SWIFT message
93pub trait FromJson<T> {
94    /// Parse from JSON Value
95    fn from_json(json: &Value) -> Result<T>;
96
97    /// Parse from JSON string
98    fn from_json_string(json_str: &str) -> Result<T> {
99        let json_value: Value =
100            serde_json::from_str(json_str).map_err(|e| ParseError::JsonError {
101                message: format!("Invalid JSON: {}", e),
102            })?;
103        Self::from_json(&json_value)
104    }
105}
106
107impl ToJson for SwiftMessage {
108    fn to_json(&self) -> Result<Value> {
109        let mut fields_map = Map::new();
110
111        // Convert each field to JSON based on its type
112        for (tag, field) in &self.fields {
113            // Extract the inner field data without the container wrapper
114            let field_value = extract_field_data(field)?;
115            fields_map.insert(tag.clone(), field_value);
116        }
117
118        let json_message = JsonMessage {
119            message_type: self.message_type.clone(),
120            blocks: JsonBlocks {
121                block1: self.blocks.block_1.clone(),
122                block2: self.blocks.block_2.clone(),
123                block3: self.blocks.block_3.clone(),
124                block4: self.blocks.block_4.clone().unwrap_or_default(),
125                block5: self.blocks.block_5.clone(),
126            },
127            fields: fields_map,
128            field_order: self.field_order.clone(),
129        };
130
131        serde_json::to_value(json_message).map_err(|e| ParseError::JsonError {
132            message: format!("Failed to convert to JSON: {}", e),
133        })
134    }
135}
136
137impl FromJson<SwiftMessage> for SwiftMessage {
138    fn from_json(json: &Value) -> Result<SwiftMessage> {
139        let json_message: JsonMessage =
140            serde_json::from_value(json.clone()).map_err(|e| ParseError::JsonError {
141                message: format!("Invalid JSON message format: {}", e),
142            })?;
143
144        let mut fields = HashMap::new();
145
146        // Convert JSON fields back to SwiftFieldContainer
147        for (tag, field_value) in &json_message.fields {
148            // Recreate the field container from the simplified structure
149            let field_container = recreate_field_container(tag, field_value)?;
150            fields.insert(tag.clone(), field_container);
151        }
152
153        let blocks = SwiftMessageBlocks {
154            block_1: json_message.blocks.block1,
155            block_2: json_message.blocks.block2,
156            block_3: json_message.blocks.block3,
157            block_4: Some(json_message.blocks.block4),
158            block_5: json_message.blocks.block5,
159        };
160
161        Ok(SwiftMessage {
162            message_type: json_message.message_type,
163            blocks,
164            fields,
165            field_order: json_message.field_order,
166        })
167    }
168}
169
170impl ToJson for MT103 {
171    fn to_json(&self) -> Result<Value> {
172        // Convert to SwiftMessage first, then to JSON
173        let swift_message = self.to_swift_message();
174        swift_message.to_json()
175    }
176}
177
178impl FromJson<MT103> for MT103 {
179    fn from_json(json: &Value) -> Result<MT103> {
180        let swift_message = SwiftMessage::from_json(json)?;
181        MT103::from_swift_message(swift_message)
182    }
183}
184
185/// Extract the inner field data without the SwiftFieldContainer wrapper
186fn extract_field_data(field: &SwiftFieldContainer) -> Result<Value> {
187    let result = match field {
188        SwiftFieldContainer::Field20(f) => serde_json::to_value(f),
189        SwiftFieldContainer::Field23B(f) => serde_json::to_value(f),
190        SwiftFieldContainer::Field32A(f) => serde_json::to_value(f),
191        SwiftFieldContainer::Field50(f) => return extract_field50_data(f),
192        SwiftFieldContainer::Field59(f) => return extract_field59_data(f),
193        SwiftFieldContainer::Field71A(f) => serde_json::to_value(f),
194        SwiftFieldContainer::Field13C(f) => serde_json::to_value(f),
195        SwiftFieldContainer::Field23E(f) => serde_json::to_value(f),
196        SwiftFieldContainer::Field26T(f) => serde_json::to_value(f),
197        SwiftFieldContainer::Field33B(f) => serde_json::to_value(f),
198        SwiftFieldContainer::Field36(f) => serde_json::to_value(f),
199        SwiftFieldContainer::Field51A(f) => serde_json::to_value(f),
200        SwiftFieldContainer::Field52(f) => return extract_field52_data(f),
201        SwiftFieldContainer::Field53(f) => return extract_field53_data(f),
202        SwiftFieldContainer::Field54(f) => return extract_field54_data(f),
203        SwiftFieldContainer::Field55(f) => return extract_field55_data(f),
204        SwiftFieldContainer::Field56(f) => return extract_field56_data(f),
205        SwiftFieldContainer::Field57(f) => return extract_field57_data(f),
206        SwiftFieldContainer::Field70(f) => serde_json::to_value(f),
207        SwiftFieldContainer::Field71F(f) => serde_json::to_value(f),
208        SwiftFieldContainer::Field71G(f) => serde_json::to_value(f),
209        SwiftFieldContainer::Field72(f) => serde_json::to_value(f),
210        SwiftFieldContainer::Field77B(f) => serde_json::to_value(f),
211        SwiftFieldContainer::Unknown(f) => {
212            let mut map = Map::new();
213            map.insert("tag".to_string(), Value::String(f.tag.clone()));
214            map.insert("content".to_string(), Value::String(f.content.clone()));
215            return Ok(Value::Object(map));
216        }
217    };
218
219    result.map_err(|e| ParseError::JsonError {
220        message: format!("Failed to serialize field: {}", e),
221    })
222}
223
224/// Extract Field50 data and flatten enum structure
225fn extract_field50_data(field: &Field50) -> Result<Value> {
226    match field {
227        Field50::A(f) => serde_json::to_value(f),
228        Field50::F(f) => serde_json::to_value(f),
229        Field50::K(f) => serde_json::to_value(f),
230    }
231    .map_err(|e| ParseError::JsonError {
232        message: format!("Failed to serialize Field50: {}", e),
233    })
234}
235
236/// Extract Field59 data and flatten enum structure  
237fn extract_field59_data(field: &Field59) -> Result<Value> {
238    match field {
239        Field59::A(f) => serde_json::to_value(f),
240        Field59::NoOption(f) => serde_json::to_value(f),
241    }
242    .map_err(|e| ParseError::JsonError {
243        message: format!("Failed to serialize Field59: {}", e),
244    })
245}
246
247/// Extract Field52 data and flatten enum structure
248fn extract_field52_data(field: &Field52) -> Result<Value> {
249    match field {
250        Field52::A(f) => serde_json::to_value(f),
251        Field52::D(f) => serde_json::to_value(f),
252    }
253    .map_err(|e| ParseError::JsonError {
254        message: format!("Failed to serialize Field52: {}", e),
255    })
256}
257
258/// Extract Field53 data and flatten enum structure
259fn extract_field53_data(field: &Field53) -> Result<Value> {
260    match field {
261        Field53::A(f) => serde_json::to_value(f),
262        Field53::B(f) => serde_json::to_value(f),
263        Field53::D(f) => serde_json::to_value(f),
264    }
265    .map_err(|e| ParseError::JsonError {
266        message: format!("Failed to serialize Field53: {}", e),
267    })
268}
269
270/// Extract Field54 data and flatten enum structure
271fn extract_field54_data(field: &Field54) -> Result<Value> {
272    match field {
273        Field54::A(f) => serde_json::to_value(f),
274        Field54::B(f) => serde_json::to_value(f),
275        Field54::D(f) => serde_json::to_value(f),
276    }
277    .map_err(|e| ParseError::JsonError {
278        message: format!("Failed to serialize Field54: {}", e),
279    })
280}
281
282/// Extract Field55 data and flatten enum structure
283fn extract_field55_data(field: &Field55) -> Result<Value> {
284    match field {
285        Field55::A(f) => serde_json::to_value(f),
286        Field55::B(f) => serde_json::to_value(f),
287        Field55::D(f) => serde_json::to_value(f),
288    }
289    .map_err(|e| ParseError::JsonError {
290        message: format!("Failed to serialize Field55: {}", e),
291    })
292}
293
294/// Extract Field56 data and flatten enum structure
295fn extract_field56_data(field: &Field56) -> Result<Value> {
296    match field {
297        Field56::A(f) => serde_json::to_value(f),
298        Field56::C(f) => serde_json::to_value(f),
299        Field56::D(f) => serde_json::to_value(f),
300    }
301    .map_err(|e| ParseError::JsonError {
302        message: format!("Failed to serialize Field56: {}", e),
303    })
304}
305
306/// Extract Field57 data and flatten enum structure
307fn extract_field57_data(field: &Field57) -> Result<Value> {
308    match field {
309        Field57::A(f) => serde_json::to_value(f),
310        Field57::B(f) => serde_json::to_value(f),
311        Field57::C(f) => serde_json::to_value(f),
312        Field57::D(f) => serde_json::to_value(f),
313    }
314    .map_err(|e| ParseError::JsonError {
315        message: format!("Failed to serialize Field57: {}", e),
316    })
317}
318
319/// Recreate Field50 from flattened JSON structure
320fn recreate_field50(tag: &str, value: &Value) -> Result<Field50> {
321    use crate::mt_models::fields::ordering_customer::{Field50A, Field50F, Field50K};
322
323    match tag {
324        "50A" => {
325            let field: Field50A =
326                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
327                    message: format!("Failed to parse Field50A: {}", e),
328                })?;
329            Ok(Field50::A(field))
330        }
331        "50F" => {
332            let field: Field50F =
333                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
334                    message: format!("Failed to parse Field50F: {}", e),
335                })?;
336            Ok(Field50::F(field))
337        }
338        "50K" => {
339            let field: Field50K =
340                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
341                    message: format!("Failed to parse Field50K: {}", e),
342                })?;
343            Ok(Field50::K(field))
344        }
345        _ => Err(ParseError::JsonError {
346            message: format!("Unknown Field50 variant: {}", tag),
347        }),
348    }
349}
350
351/// Recreate Field52 from flattened JSON structure
352fn recreate_field52(tag: &str, value: &Value) -> Result<Field52> {
353    use crate::mt_models::fields::institutions::{Field52A, Field52D};
354
355    match tag {
356        "52A" => {
357            let field: Field52A =
358                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
359                    message: format!("Failed to parse Field52A: {}", e),
360                })?;
361            Ok(Field52::A(field))
362        }
363        "52D" => {
364            let field: Field52D =
365                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
366                    message: format!("Failed to parse Field52D: {}", e),
367                })?;
368            Ok(Field52::D(field))
369        }
370        _ => Err(ParseError::JsonError {
371            message: format!("Unknown Field52 variant: {}", tag),
372        }),
373    }
374}
375
376/// Recreate Field53 from flattened JSON structure
377fn recreate_field53(tag: &str, value: &Value) -> Result<Field53> {
378    use crate::mt_models::fields::institutions::{Field53A, Field53B, Field53D};
379
380    match tag {
381        "53A" => {
382            let field: Field53A =
383                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
384                    message: format!("Failed to parse Field53A: {}", e),
385                })?;
386            Ok(Field53::A(field))
387        }
388        "53B" => {
389            let field: Field53B =
390                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
391                    message: format!("Failed to parse Field53B: {}", e),
392                })?;
393            Ok(Field53::B(field))
394        }
395        "53D" => {
396            let field: Field53D =
397                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
398                    message: format!("Failed to parse Field53D: {}", e),
399                })?;
400            Ok(Field53::D(field))
401        }
402        _ => Err(ParseError::JsonError {
403            message: format!("Unknown Field53 variant: {}", tag),
404        }),
405    }
406}
407
408/// Recreate Field54 from flattened JSON structure
409fn recreate_field54(tag: &str, value: &Value) -> Result<Field54> {
410    use crate::mt_models::fields::institutions::{Field54A, Field54B, Field54D};
411
412    match tag {
413        "54A" => {
414            let field: Field54A =
415                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
416                    message: format!("Failed to parse Field54A: {}", e),
417                })?;
418            Ok(Field54::A(field))
419        }
420        "54B" => {
421            let field: Field54B =
422                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
423                    message: format!("Failed to parse Field54B: {}", e),
424                })?;
425            Ok(Field54::B(field))
426        }
427        "54D" => {
428            let field: Field54D =
429                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
430                    message: format!("Failed to parse Field54D: {}", e),
431                })?;
432            Ok(Field54::D(field))
433        }
434        _ => Err(ParseError::JsonError {
435            message: format!("Unknown Field54 variant: {}", tag),
436        }),
437    }
438}
439
440/// Recreate Field55 from flattened JSON structure
441fn recreate_field55(tag: &str, value: &Value) -> Result<Field55> {
442    use crate::mt_models::fields::institutions::{Field55A, Field55B, Field55D};
443
444    match tag {
445        "55A" => {
446            let field: Field55A =
447                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
448                    message: format!("Failed to parse Field55A: {}", e),
449                })?;
450            Ok(Field55::A(field))
451        }
452        "55B" => {
453            let field: Field55B =
454                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
455                    message: format!("Failed to parse Field55B: {}", e),
456                })?;
457            Ok(Field55::B(field))
458        }
459        "55D" => {
460            let field: Field55D =
461                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
462                    message: format!("Failed to parse Field55D: {}", e),
463                })?;
464            Ok(Field55::D(field))
465        }
466        _ => Err(ParseError::JsonError {
467            message: format!("Unknown Field55 variant: {}", tag),
468        }),
469    }
470}
471
472/// Recreate Field56 from flattened JSON structure
473fn recreate_field56(tag: &str, value: &Value) -> Result<Field56> {
474    use crate::mt_models::fields::institutions::{Field56A, Field56C, Field56D};
475
476    match tag {
477        "56A" => {
478            let field: Field56A =
479                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
480                    message: format!("Failed to parse Field56A: {}", e),
481                })?;
482            Ok(Field56::A(field))
483        }
484        "56C" => {
485            let field: Field56C =
486                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
487                    message: format!("Failed to parse Field56C: {}", e),
488                })?;
489            Ok(Field56::C(field))
490        }
491        "56D" => {
492            let field: Field56D =
493                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
494                    message: format!("Failed to parse Field56D: {}", e),
495                })?;
496            Ok(Field56::D(field))
497        }
498        _ => Err(ParseError::JsonError {
499            message: format!("Unknown Field56 variant: {}", tag),
500        }),
501    }
502}
503
504/// Recreate Field57 from flattened JSON structure
505fn recreate_field57(tag: &str, value: &Value) -> Result<Field57> {
506    use crate::mt_models::fields::institutions::{Field57A, Field57B, Field57C, Field57D};
507
508    match tag {
509        "57A" => {
510            let field: Field57A =
511                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
512                    message: format!("Failed to parse Field57A: {}", e),
513                })?;
514            Ok(Field57::A(field))
515        }
516        "57B" => {
517            let field: Field57B =
518                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
519                    message: format!("Failed to parse Field57B: {}", e),
520                })?;
521            Ok(Field57::B(field))
522        }
523        "57C" => {
524            let field: Field57C =
525                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
526                    message: format!("Failed to parse Field57C: {}", e),
527                })?;
528            Ok(Field57::C(field))
529        }
530        "57D" => {
531            let field: Field57D =
532                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
533                    message: format!("Failed to parse Field57D: {}", e),
534                })?;
535            Ok(Field57::D(field))
536        }
537        _ => Err(ParseError::JsonError {
538            message: format!("Unknown Field57 variant: {}", tag),
539        }),
540    }
541}
542
543/// Recreate Field59 from flattened JSON structure
544fn recreate_field59(tag: &str, value: &Value) -> Result<Field59> {
545    use crate::mt_models::fields::beneficiary::{Field59A, Field59Basic};
546
547    match tag {
548        "59A" => {
549            let field: Field59A =
550                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
551                    message: format!("Failed to parse Field59A: {}", e),
552                })?;
553            Ok(Field59::A(field))
554        }
555        "59" => {
556            let field: Field59Basic =
557                serde_json::from_value(value.clone()).map_err(|e| ParseError::JsonError {
558                    message: format!("Failed to parse Field59: {}", e),
559                })?;
560            Ok(Field59::NoOption(field))
561        }
562        _ => Err(ParseError::JsonError {
563            message: format!("Unknown Field59 variant: {}", tag),
564        }),
565    }
566}
567
568/// Recreate a SwiftFieldContainer from simplified JSON structure
569fn recreate_field_container(tag: &str, value: &Value) -> Result<SwiftFieldContainer> {
570    // For unknown fields, handle special case
571    if value.is_object() && value.get("tag").is_some() && value.get("content").is_some() {
572        if let Some(obj) = value.as_object() {
573            if let (Some(tag_val), Some(content_val)) = (obj.get("tag"), obj.get("content")) {
574                if let (Some(tag_str), Some(content_str)) = (tag_val.as_str(), content_val.as_str())
575                {
576                    return Ok(SwiftFieldContainer::Unknown(
577                        crate::field_parser::UnknownField {
578                            tag: tag_str.to_string(),
579                            content: content_str.to_string(),
580                        },
581                    ));
582                }
583            }
584        }
585    }
586
587    // Convert simplified JSON back to appropriate field type
588    match tag {
589        "13C" => {
590            let field = serde_json::from_value(value.clone())?;
591            Ok(SwiftFieldContainer::Field13C(field))
592        }
593        "20" => {
594            let field = serde_json::from_value(value.clone())?;
595            Ok(SwiftFieldContainer::Field20(field))
596        }
597        "23B" => {
598            let field = serde_json::from_value(value.clone())?;
599            Ok(SwiftFieldContainer::Field23B(field))
600        }
601        "23E" => {
602            let field = serde_json::from_value(value.clone())?;
603            Ok(SwiftFieldContainer::Field23E(field))
604        }
605        "26T" => {
606            let field = serde_json::from_value(value.clone())?;
607            Ok(SwiftFieldContainer::Field26T(field))
608        }
609        "32A" => {
610            let field = serde_json::from_value(value.clone())?;
611            Ok(SwiftFieldContainer::Field32A(field))
612        }
613        "33B" => {
614            let field = serde_json::from_value(value.clone())?;
615            Ok(SwiftFieldContainer::Field33B(field))
616        }
617        "36" => {
618            let field = serde_json::from_value(value.clone())?;
619            Ok(SwiftFieldContainer::Field36(field))
620        }
621        tag if tag.starts_with("50") => {
622            let field = recreate_field50(tag, value)?;
623            Ok(SwiftFieldContainer::Field50(field))
624        }
625        "51A" => {
626            let field = serde_json::from_value(value.clone())?;
627            Ok(SwiftFieldContainer::Field51A(field))
628        }
629        tag if tag.starts_with("52") => {
630            let field = recreate_field52(tag, value)?;
631            Ok(SwiftFieldContainer::Field52(field))
632        }
633        tag if tag.starts_with("53") => {
634            let field = recreate_field53(tag, value)?;
635            Ok(SwiftFieldContainer::Field53(field))
636        }
637        tag if tag.starts_with("54") => {
638            let field = recreate_field54(tag, value)?;
639            Ok(SwiftFieldContainer::Field54(field))
640        }
641        tag if tag.starts_with("55") => {
642            let field = recreate_field55(tag, value)?;
643            Ok(SwiftFieldContainer::Field55(field))
644        }
645        tag if tag.starts_with("56") => {
646            let field = recreate_field56(tag, value)?;
647            Ok(SwiftFieldContainer::Field56(field))
648        }
649        tag if tag.starts_with("57") => {
650            let field = recreate_field57(tag, value)?;
651            Ok(SwiftFieldContainer::Field57(field))
652        }
653        tag if tag.starts_with("59") => {
654            let field = recreate_field59(tag, value)?;
655            Ok(SwiftFieldContainer::Field59(field))
656        }
657        "70" => {
658            let field = serde_json::from_value(value.clone())?;
659            Ok(SwiftFieldContainer::Field70(field))
660        }
661        "71A" => {
662            let field = serde_json::from_value(value.clone())?;
663            Ok(SwiftFieldContainer::Field71A(field))
664        }
665        "71F" => {
666            let field = serde_json::from_value(value.clone())?;
667            Ok(SwiftFieldContainer::Field71F(field))
668        }
669        "71G" => {
670            let field = serde_json::from_value(value.clone())?;
671            Ok(SwiftFieldContainer::Field71G(field))
672        }
673        "72" => {
674            let field = serde_json::from_value(value.clone())?;
675            Ok(SwiftFieldContainer::Field72(field))
676        }
677        "77B" => {
678            let field = serde_json::from_value(value.clone())?;
679            Ok(SwiftFieldContainer::Field77B(field))
680        }
681        _ => {
682            // Fallback to unknown field
683            Ok(SwiftFieldContainer::Unknown(
684                crate::field_parser::UnknownField {
685                    tag: tag.to_string(),
686                    content: value.to_string(),
687                },
688            ))
689        }
690    }
691    .map_err(|e: serde_json::Error| ParseError::JsonError {
692        message: format!("Failed to parse field {}: {}", tag, e),
693    })
694}
695
696/// High-level utility functions for common use cases
697pub mod utils {
698    use super::*;
699
700    /// Parse MT message from SWIFT format and convert to JSON
701    pub fn swift_to_json(swift_message: &str) -> Result<String> {
702        let message = SwiftMessage::parse(swift_message)?;
703        message.to_json_string()
704    }
705
706    /// Parse JSON and convert to SWIFT format (basic implementation)
707    pub fn json_to_swift(json_str: &str) -> Result<String> {
708        let message = SwiftMessage::from_json_string(json_str)?;
709
710        // Build a basic SWIFT message format
711        let mut swift_content = String::new();
712
713        // Add blocks if available
714        if let Some(block1) = &message.blocks.block_1 {
715            swift_content.push_str(&format!("{{1:{}}}", block1));
716        }
717        if let Some(block2) = &message.blocks.block_2 {
718            swift_content.push_str(&format!("{{2:{}}}", block2));
719        }
720        if let Some(block3) = &message.blocks.block_3 {
721            swift_content.push_str(&format!("{{3:{}}}", block3));
722        }
723
724        // Add Block 4 with fields
725        swift_content.push_str("{4:\n");
726        for tag in &message.field_order {
727            if let Some(field) = message.fields.get(tag) {
728                swift_content.push_str(&format!(":{}:{}\n", tag, field.to_swift_string()));
729            }
730        }
731        swift_content.push_str("-}");
732
733        if let Some(block5) = &message.blocks.block_5 {
734            swift_content.push_str(&format!("{{5:{}}}", block5));
735        }
736
737        Ok(swift_content)
738    }
739
740    /// Parse specific MT103 from JSON
741    pub fn json_to_mt103(json_str: &str) -> Result<MT103> {
742        MT103::from_json_string(json_str)
743    }
744
745    /// Convert MT103 to JSON
746    pub fn mt103_to_json(mt103: &MT103) -> Result<String> {
747        mt103.to_json_string()
748    }
749}
750
751#[cfg(test)]
752mod tests {
753    use super::*;
754    use pretty_assertions::assert_eq;
755
756    #[test]
757    fn test_swift_message_json_roundtrip() {
758        let swift_text = r#"{1:F01DEUTDEFFAXXX0123456789}{2:I103CHASUS33AXXXU3003}{4:
759:20:FT21234567890
760:23B:CRED
761:32A:210315EUR1234567,89
762:50K:JOHN DOE
763:59:JANE SMITH
764:71A:OUR
765-}"#;
766
767        // Parse SWIFT -> JSON -> SWIFT
768        let message = SwiftMessage::parse(swift_text).unwrap();
769        let json_str = message.to_json_string().unwrap();
770        let parsed_back = SwiftMessage::from_json_string(&json_str).unwrap();
771
772        assert_eq!(message.message_type, parsed_back.message_type);
773        assert_eq!(message.fields.len(), parsed_back.fields.len());
774    }
775
776    #[test]
777    fn test_json_utility_functions() {
778        let swift_text = r#"{1:F01DEUTDEFFAXXX0123456789}{2:I103CHASUS33AXXXU3003}{4:
779:20:FT21234567890
780:23B:CRED
781:32A:210315EUR1234567,89
782:50K:JOHN DOE
783:59:JANE SMITH
784:71A:OUR
785-}"#;
786
787        // Test utility functions
788        let json_str = utils::swift_to_json(swift_text).unwrap();
789        assert!(json_str.contains("\"message_type\": \"103\""));
790        assert!(json_str.contains("\"transaction_reference\": \"FT21234567890\""));
791
792        // Test round-trip conversion
793        let swift_reconstructed = utils::json_to_swift(&json_str).unwrap();
794        assert!(swift_reconstructed.contains("103"));
795        assert!(swift_reconstructed.contains("FT21234567890"));
796    }
797}