1use mig_assembly::assembler::AssembledSegment;
10use mig_types::segment::OwnedSegment;
11use serde::{Deserialize, Serialize};
12use std::collections::{BTreeMap, HashMap};
13
14pub use bo4e_edifact_types::{
16 is_wrapped_transaktion, DynamicInterchange, DynamicNachricht, DynamicTransaktion, Interchange,
17 Interchangedaten, Nachricht, Nachrichtendaten, Transaktion, Uebermittlungsabschnitt,
18};
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct MappedTransaktion {
27 pub stammdaten: serde_json::Value,
30
31 #[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
38 pub transaktionsdaten: serde_json::Value,
39
40 #[serde(skip)]
47 pub nesting_info: HashMap<String, Vec<usize>>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct MappedMessage {
57 pub stammdaten: serde_json::Value,
59
60 #[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
66 pub nachricht_meta: serde_json::Value,
67
68 pub transaktionen: Vec<MappedTransaktion>,
70
71 #[serde(skip)]
77 pub nesting_info: HashMap<String, Vec<usize>>,
78
79 #[serde(skip)]
89 pub inter_group_segments: BTreeMap<usize, Vec<AssembledSegment>>,
90}
91
92impl MappedMessage {
93 pub fn into_dynamic_nachricht(self, nachrichtendaten: Nachrichtendaten) -> DynamicNachricht {
98 let mut nachrichtendaten = nachrichtendaten;
102 if let serde_json::Value::Object(fields) = self.nachricht_meta {
103 nachrichtendaten.nachricht = fields;
104 }
105
106 Nachricht {
107 nachrichtendaten,
108 stammdaten: self.stammdaten,
109 transaktionen: self
110 .transaktionen
111 .into_iter()
112 .map(|t| Transaktion {
113 transaktionsdaten: t.transaktionsdaten,
114 stammdaten: t.stammdaten,
115 })
116 .collect(),
117 }
118 }
119}
120
121pub const TX_METADATA_ENTITY: &str = "prozessdaten";
128
129pub const MSG_METADATA_ENTITY: &str = "nachricht";
131
132pub fn take_entity(from: &mut serde_json::Value, key: &str) -> serde_json::Value {
134 from.as_object_mut()
135 .and_then(|m| m.remove(key))
136 .unwrap_or(serde_json::Value::Null)
137}
138
139pub fn restore_entity(into: &mut serde_json::Value, key: &str, value: &serde_json::Value) {
144 if value.is_null() {
145 return;
146 }
147 if let Some(m) = into.as_object_mut() {
148 m.insert(key.to_string(), value.clone());
149 }
150}
151
152pub fn restore_message_metadata(msg_stammdaten: &mut serde_json::Value, nd: &Nachrichtendaten) {
159 if nd.nachricht.is_empty() {
160 return;
161 }
162 let value = serde_json::Value::Object(nd.nachricht.clone());
163 restore_entity(msg_stammdaten, MSG_METADATA_ENTITY, &value);
164}
165
166pub fn extract_unh_fields(unh: &OwnedSegment) -> (String, String) {
168 let referenz = unh.get_element(0).to_string();
169 let typ = unh.get_component(1, 0).to_string();
170 (referenz, typ)
171}
172
173pub fn extract_message_header(unh: &OwnedSegment) -> Nachrichtendaten {
182 let (unh_referenz, nachrichten_typ) = extract_unh_fields(unh);
183 let non_empty = |s: &str| (!s.is_empty()).then(|| s.to_string());
184 Nachrichtendaten {
185 unh_referenz,
186 nachrichten_typ,
187 zuordnungsreferenz: non_empty(unh.get_element(2)),
188 uebermittlungsfolgenummer: non_empty(unh.get_component(3, 0)),
189 uebermittlungsabschnitt: Uebermittlungsabschnitt::from_code(unh.get_component(3, 1)),
190 nachricht: Default::default(),
191 }
192}
193
194pub fn extract_interchangedaten(envelope: &[OwnedSegment]) -> Interchangedaten {
196 let mut result = Interchangedaten::default();
197
198 for seg in envelope {
199 if seg.is("UNB") {
200 let val = |s: &str| {
201 if s.is_empty() {
202 None
203 } else {
204 Some(s.to_string())
205 }
206 };
207 result.syntax_kennung = val(seg.get_component(0, 0));
208 result.absender_code = val(seg.get_component(1, 0));
209 result.empfaenger_code = val(seg.get_component(2, 0));
210 result.datum = val(seg.get_component(3, 0));
211 result.zeit = val(seg.get_component(3, 1));
212 result.interchange_ref = val(seg.get_element(4));
213 result.absender_qualifier = val(seg.get_component(1, 1));
214 result.empfaenger_qualifier = val(seg.get_component(2, 1));
215 result.anwendungsreferenz = val(seg.get_element(6));
216 }
217 }
218
219 result
220}
221
222pub fn extract_nachrichtendaten(envelope: &[OwnedSegment]) -> serde_json::Value {
226 let data = extract_interchangedaten(envelope);
227 serde_json::to_value(&data).unwrap_or_default()
228}
229
230fn normalize_unb_datum(datum: &str) -> &str {
235 if datum.len() == 8 && datum.as_bytes().iter().all(|b| b.is_ascii_digit()) {
236 &datum[2..]
237 } else {
238 datum
239 }
240}
241
242pub fn rebuild_unb_from_interchangedaten(data: &Interchangedaten) -> OwnedSegment {
248 let syntax = data.syntax_kennung.as_deref().unwrap_or("UNOC");
249 let sender = data.absender_code.as_deref().unwrap_or("");
250 let receiver = data.empfaenger_code.as_deref().unwrap_or("");
251 let datum = normalize_unb_datum(data.datum.as_deref().unwrap_or(""));
252 let zeit = data.zeit.as_deref().unwrap_or("");
253 let interchange_ref = data.interchange_ref.as_deref().unwrap_or("00000");
254
255 OwnedSegment {
256 id: "UNB".to_string(),
257 elements: vec![
258 vec![syntax.to_string(), "3".to_string()],
259 vec![sender.to_string(), "500".to_string()],
260 vec![receiver.to_string(), "500".to_string()],
261 vec![datum.to_string(), zeit.to_string()],
262 vec![interchange_ref.to_string()],
263 ],
264 segment_number: 0,
265 }
266}
267
268pub fn rebuild_unb(nachrichtendaten: &serde_json::Value) -> OwnedSegment {
274 let syntax = nachrichtendaten
275 .get("syntaxKennung")
276 .and_then(|v| v.as_str())
277 .unwrap_or("UNOC");
278 let sender = nachrichtendaten
279 .get("absenderCode")
280 .and_then(|v| v.as_str())
281 .unwrap_or("");
282 let receiver = nachrichtendaten
283 .get("empfaengerCode")
284 .and_then(|v| v.as_str())
285 .unwrap_or("");
286 let datum_raw = nachrichtendaten
287 .get("datum")
288 .and_then(|v| v.as_str())
289 .unwrap_or("");
290 let datum = normalize_unb_datum(datum_raw);
291 let zeit = nachrichtendaten
292 .get("zeit")
293 .and_then(|v| v.as_str())
294 .unwrap_or("");
295 let interchange_ref = nachrichtendaten
296 .get("interchangeRef")
297 .and_then(|v| v.as_str())
298 .unwrap_or("00000");
299
300 OwnedSegment {
301 id: "UNB".to_string(),
302 elements: vec![
303 vec![syntax.to_string(), "3".to_string()],
304 vec![sender.to_string(), "500".to_string()],
305 vec![receiver.to_string(), "500".to_string()],
306 vec![datum.to_string(), zeit.to_string()],
307 vec![interchange_ref.to_string()],
308 ],
309 segment_number: 0,
310 }
311}
312
313pub fn rebuild_unh(header: &Nachrichtendaten, release: &str, association: &str) -> OwnedSegment {
325 let mut elements = vec![
326 vec![header.unh_referenz.clone()],
327 vec![
328 header.nachrichten_typ.clone(),
329 "D".to_string(),
330 release.to_string(),
331 "UN".to_string(),
332 association.to_string(),
333 ],
334 ];
335
336 let s010: Vec<String> = match (
340 &header.uebermittlungsfolgenummer,
341 header.uebermittlungsabschnitt,
342 ) {
343 (None, None) => Vec::new(),
344 (folge, abschnitt) => vec![
345 folge.clone().unwrap_or_default(),
346 abschnitt.map(|a| a.code().to_string()).unwrap_or_default(),
347 ],
348 };
349 if header.zuordnungsreferenz.is_some() || !s010.is_empty() {
350 elements.push(vec![header.zuordnungsreferenz.clone().unwrap_or_default()]);
351 }
352 if !s010.is_empty() {
353 elements.push(s010);
354 }
355
356 OwnedSegment {
357 id: "UNH".to_string(),
358 elements,
359 segment_number: 0,
360 }
361}
362
363pub fn release_code_for_message_type(msg_type: &str) -> &'static str {
370 match msg_type {
371 "APERAK" => "07B",
372 "COMDIS" => "17A",
373 "CONTRL" => "3",
375 "IFTSTA" => "18A",
376 "INSRPT" => "10A",
377 "INVOIC" => "06A",
378 "MSCONS" => "04B",
379 "ORDCHG" => "20B",
380 "ORDERS" => "09B",
381 "ORDRSP" => "10A",
382 "PARTIN" => "20B",
383 "PRICAT" => "20B",
384 "QUOTES" => "10A",
385 "REMADV" => "05A",
386 "REQOTE" => "10A",
387 "UTILMD" => "11A",
388 "UTILTS" => "18A",
389 _ => "04B", }
391}
392
393pub fn rebuild_unt(segment_count: usize, referenz: &str) -> OwnedSegment {
398 OwnedSegment {
399 id: "UNT".to_string(),
400 elements: vec![vec![segment_count.to_string()], vec![referenz.to_string()]],
401 segment_number: 0,
402 }
403}
404
405pub fn rebuild_unz(message_count: usize, interchange_ref: &str) -> OwnedSegment {
409 OwnedSegment {
410 id: "UNZ".to_string(),
411 elements: vec![
412 vec![message_count.to_string()],
413 vec![interchange_ref.to_string()],
414 ],
415 segment_number: 0,
416 }
417}
418
419#[cfg(test)]
420mod tests {
421 use super::*;
422
423 #[test]
424 fn test_mapped_transaktion_serde_roundtrip() {
425 let tx = MappedTransaktion {
426 transaktionsdaten: serde_json::Value::Null,
427 stammdaten: serde_json::json!({
428 "prozessdaten": {
429 "vorgangId": "TX001",
430 "transaktionsgrund": "E01"
431 },
432 "marktlokation": { "marktlokationsId": "DE000111222333" }
433 }),
434 nesting_info: Default::default(),
435 };
436
437 let json = serde_json::to_string(&tx).unwrap();
438 let de: MappedTransaktion = serde_json::from_str(&json).unwrap();
439 assert_eq!(
440 de.stammdaten["prozessdaten"]["vorgangId"].as_str().unwrap(),
441 "TX001"
442 );
443 assert!(de.stammdaten["marktlokation"].is_object());
444 }
445
446 #[test]
447 fn test_dynamic_nachricht_serde_roundtrip() {
448 let msg: DynamicNachricht = Nachricht {
449 nachrichtendaten: Nachrichtendaten {
450 unh_referenz: "00001".to_string(),
451 nachrichten_typ: "UTILMD".to_string(),
452 nachricht: Default::default(),
453 ..Default::default()
454 },
455 stammdaten: serde_json::json!({
456 "marktteilnehmer": [
457 { "marktrolle": "MS", "rollencodenummer": "9900123" }
458 ]
459 }),
460 transaktionen: vec![Transaktion {
461 transaktionsdaten: serde_json::Value::Null,
462 stammdaten: serde_json::json!({}),
463 }],
464 };
465
466 let json = serde_json::to_string(&msg).unwrap();
467 let de: DynamicNachricht = serde_json::from_str(&json).unwrap();
468 assert_eq!(de.nachrichtendaten.unh_referenz, "00001");
469 assert_eq!(de.nachrichtendaten.nachrichten_typ, "UTILMD");
470 assert_eq!(de.transaktionen.len(), 1);
471 }
472
473 #[test]
474 fn test_dynamic_interchange_serde_roundtrip() {
475 let interchange: DynamicInterchange = Interchange {
476 interchangedaten: Interchangedaten {
477 absender_code: Some("9900123456789".to_string()),
478 empfaenger_code: Some("9900987654321".to_string()),
479 ..Default::default()
480 },
481 nachrichten: vec![Nachricht {
482 nachrichtendaten: Nachrichtendaten {
483 unh_referenz: "00001".to_string(),
484 nachrichten_typ: "UTILMD".to_string(),
485 nachricht: Default::default(),
486 ..Default::default()
487 },
488 stammdaten: serde_json::json!({}),
489 transaktionen: vec![],
490 }],
491 };
492
493 let json = serde_json::to_string_pretty(&interchange).unwrap();
494 let de: DynamicInterchange = serde_json::from_str(&json).unwrap();
495 assert_eq!(de.nachrichten.len(), 1);
496 assert_eq!(de.nachrichten[0].nachrichtendaten.unh_referenz, "00001");
497 }
498
499 #[test]
500 fn test_extract_interchangedaten_from_segments() {
501 let envelope = vec![OwnedSegment {
502 id: "UNB".to_string(),
503 elements: vec![
504 vec!["UNOC".to_string(), "3".to_string()],
505 vec!["9900123456789".to_string(), "500".to_string()],
506 vec!["9900987654321".to_string(), "500".to_string()],
507 vec!["210101".to_string(), "1200".to_string()],
508 vec!["REF001".to_string()],
509 ],
510 segment_number: 0,
511 }];
512
513 let data = extract_interchangedaten(&envelope);
514 assert_eq!(data.absender_code.as_deref(), Some("9900123456789"));
515 assert_eq!(data.empfaenger_code.as_deref(), Some("9900987654321"));
516 assert_eq!(data.interchange_ref.as_deref(), Some("REF001"));
517 assert_eq!(data.syntax_kennung.as_deref(), Some("UNOC"));
518 assert_eq!(data.datum.as_deref(), Some("210101"));
519 assert_eq!(data.zeit.as_deref(), Some("1200"));
520 }
521
522 #[test]
523 fn test_extract_envelope_from_segments_json() {
524 let envelope = vec![OwnedSegment {
525 id: "UNB".to_string(),
526 elements: vec![
527 vec!["UNOC".to_string(), "3".to_string()],
528 vec!["9900123456789".to_string(), "500".to_string()],
529 vec!["9900987654321".to_string(), "500".to_string()],
530 vec!["210101".to_string(), "1200".to_string()],
531 vec!["REF001".to_string()],
532 ],
533 segment_number: 0,
534 }];
535
536 let nd = extract_nachrichtendaten(&envelope);
537 assert_eq!(nd["absenderCode"].as_str().unwrap(), "9900123456789");
538 assert_eq!(nd["empfaengerCode"].as_str().unwrap(), "9900987654321");
539 assert_eq!(nd["interchangeRef"].as_str().unwrap(), "REF001");
540 assert_eq!(nd["syntaxKennung"].as_str().unwrap(), "UNOC");
541 assert_eq!(nd["datum"].as_str().unwrap(), "210101");
542 assert_eq!(nd["zeit"].as_str().unwrap(), "1200");
543 }
544
545 #[test]
546 fn test_extract_unh_fields() {
547 let unh = OwnedSegment {
548 id: "UNH".to_string(),
549 elements: vec![
550 vec!["MSG001".to_string()],
551 vec![
552 "UTILMD".to_string(),
553 "D".to_string(),
554 "11A".to_string(),
555 "UN".to_string(),
556 "S2.1".to_string(),
557 ],
558 ],
559 segment_number: 0,
560 };
561
562 let (referenz, typ) = extract_unh_fields(&unh);
563 assert_eq!(referenz, "MSG001");
564 assert_eq!(typ, "UTILMD");
565 }
566
567 #[test]
568 fn test_rebuild_unb_from_interchangedaten_typed() {
569 let data = Interchangedaten {
570 syntax_kennung: Some("UNOC".to_string()),
571 absender_code: Some("9900123456789".to_string()),
572 empfaenger_code: Some("9900987654321".to_string()),
573 datum: Some("210101".to_string()),
574 zeit: Some("1200".to_string()),
575 interchange_ref: Some("REF001".to_string()),
576 absender_qualifier: None,
577 empfaenger_qualifier: None,
578 anwendungsreferenz: None,
579 };
580
581 let unb = rebuild_unb_from_interchangedaten(&data);
582 assert_eq!(unb.id, "UNB");
583 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
584 assert_eq!(unb.elements[1][0], "9900123456789");
585 assert_eq!(unb.elements[2][0], "9900987654321");
586 assert_eq!(unb.elements[3], vec!["210101", "1200"]);
587 assert_eq!(unb.elements[4], vec!["REF001"]);
588 }
589
590 #[test]
591 fn test_rebuild_unb_from_nachrichtendaten() {
592 let nd = serde_json::json!({
593 "syntaxKennung": "UNOC",
594 "absenderCode": "9900123456789",
595 "empfaengerCode": "9900987654321",
596 "datum": "210101",
597 "zeit": "1200",
598 "interchangeRef": "REF001"
599 });
600
601 let unb = rebuild_unb(&nd);
602 assert_eq!(unb.id, "UNB");
603 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
604 assert_eq!(unb.elements[1][0], "9900123456789");
605 assert_eq!(unb.elements[2][0], "9900987654321");
606 assert_eq!(unb.elements[3], vec!["210101", "1200"]);
607 assert_eq!(unb.elements[4], vec!["REF001"]);
608 }
609
610 #[test]
611 fn test_rebuild_unb_defaults() {
612 let nd = serde_json::json!({});
613 let unb = rebuild_unb(&nd);
614 assert_eq!(unb.id, "UNB");
615 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
616 }
617
618 fn header(referenz: &str, typ: &str) -> Nachrichtendaten {
620 Nachrichtendaten {
621 unh_referenz: referenz.to_string(),
622 nachrichten_typ: typ.to_string(),
623 ..Default::default()
624 }
625 }
626
627 #[test]
633 fn the_optional_unh_elements_survive_extraction_and_rebuild() {
634 let original = OwnedSegment {
635 id: "UNH".to_string(),
636 elements: vec![
637 vec!["GENERATED00001".to_string()],
638 vec![
639 "MSCONS".to_string(),
640 "D".to_string(),
641 "04B".to_string(),
642 "UN".to_string(),
643 "2.4c".to_string(),
644 ],
645 vec!["ZUORDNUNG1".to_string()],
646 vec!["3".to_string(), "C".to_string()],
647 ],
648 segment_number: 0,
649 };
650
651 let header = extract_message_header(&original);
652 assert_eq!(header.zuordnungsreferenz.as_deref(), Some("ZUORDNUNG1"));
653 assert_eq!(header.uebermittlungsfolgenummer.as_deref(), Some("3"));
654 assert_eq!(
655 header.uebermittlungsabschnitt,
656 Some(Uebermittlungsabschnitt::Beginn),
657 "the BO4E carries the MIG's name for C, not the code"
658 );
659
660 let rebuilt = rebuild_unh(&header, "04B", "2.4c");
661 assert_eq!(rebuilt.elements, original.elements);
662 }
663
664 #[test]
666 fn a_header_without_the_optional_elements_renders_as_before() {
667 let unh = rebuild_unh(&header("00001", "UTILMD"), "11A", "S2.1");
668 assert_eq!(unh.elements.len(), 2, "no empty trailing elements: {unh:?}");
669 }
670
671 #[test]
673 fn s010_without_0068_keeps_its_position() {
674 let mut h = header("00001", "UTILMD");
675 h.uebermittlungsfolgenummer = Some("2".to_string());
676 let unh = rebuild_unh(&h, "11A", "S2.1");
677 assert_eq!(unh.elements[2], vec![""], "0068 holds S010's position");
678 assert_eq!(unh.elements[3], vec!["2", ""]);
679 }
680
681 #[test]
682 fn test_rebuild_unh() {
683 let unh = rebuild_unh(&header("00001", "UTILMD"), "11A", "S2.1");
684 assert_eq!(unh.id, "UNH");
685 assert_eq!(unh.elements[0], vec!["00001"]);
686 assert_eq!(unh.elements[1][0], "UTILMD");
687 assert_eq!(unh.elements[1][1], "D");
688 assert_eq!(unh.elements[1][2], "11A");
689 assert_eq!(unh.elements[1][3], "UN");
690 assert_eq!(unh.elements[1][4], "S2.1");
691 }
692
693 #[test]
694 fn test_rebuild_unh_uses_the_given_release_and_association() {
695 let unh = rebuild_unh(&header("00001", "UTILMD"), "11A", "G1.0a");
698 assert_eq!(unh.elements[1], vec!["UTILMD", "D", "11A", "UN", "G1.0a"]);
699
700 let unh = rebuild_unh(
701 &header("00001", "MSCONS"),
702 release_code_for_message_type("MSCONS"),
703 "2.4c",
704 );
705 assert_eq!(unh.elements[1], vec!["MSCONS", "D", "04B", "UN", "2.4c"]);
706 }
707
708 #[test]
709 fn test_rebuild_unt() {
710 let unt = rebuild_unt(25, "00001");
711 assert_eq!(unt.id, "UNT");
712 assert_eq!(unt.elements[0], vec!["25"]);
713 assert_eq!(unt.elements[1], vec!["00001"]);
714 }
715
716 #[test]
717 fn test_rebuild_unz() {
718 let unz = rebuild_unz(1, "REF001");
719 assert_eq!(unz.id, "UNZ");
720 assert_eq!(unz.elements[0], vec!["1"]);
721 assert_eq!(unz.elements[1], vec!["REF001"]);
722 }
723
724 #[test]
725 fn test_roundtrip_interchangedaten_rebuild() {
726 let original = OwnedSegment {
727 id: "UNB".to_string(),
728 elements: vec![
729 vec!["UNOC".to_string(), "3".to_string()],
730 vec!["9900123456789".to_string(), "500".to_string()],
731 vec!["9900987654321".to_string(), "500".to_string()],
732 vec!["210101".to_string(), "1200".to_string()],
733 vec!["REF001".to_string()],
734 ],
735 segment_number: 0,
736 };
737
738 let data = extract_interchangedaten(&[original]);
739 let rebuilt = rebuild_unb_from_interchangedaten(&data);
740 assert_eq!(rebuilt.elements[0], vec!["UNOC", "3"]);
741 assert_eq!(rebuilt.elements[1][0], "9900123456789");
742 assert_eq!(rebuilt.elements[2][0], "9900987654321");
743 assert_eq!(rebuilt.elements[3], vec!["210101", "1200"]);
744 assert_eq!(rebuilt.elements[4], vec!["REF001"]);
745 }
746
747 #[test]
748 fn test_roundtrip_nachrichtendaten_rebuild() {
749 let original = OwnedSegment {
750 id: "UNB".to_string(),
751 elements: vec![
752 vec!["UNOC".to_string(), "3".to_string()],
753 vec!["9900123456789".to_string(), "500".to_string()],
754 vec!["9900987654321".to_string(), "500".to_string()],
755 vec!["210101".to_string(), "1200".to_string()],
756 vec!["REF001".to_string()],
757 ],
758 segment_number: 0,
759 };
760
761 let nd = extract_nachrichtendaten(&[original]);
762 let rebuilt = rebuild_unb(&nd);
763 assert_eq!(rebuilt.elements[0], vec!["UNOC", "3"]);
764 assert_eq!(rebuilt.elements[1][0], "9900123456789");
765 assert_eq!(rebuilt.elements[2][0], "9900987654321");
766 assert_eq!(rebuilt.elements[3], vec!["210101", "1200"]);
767 assert_eq!(rebuilt.elements[4], vec!["REF001"]);
768 }
769
770 #[test]
771 fn test_rebuild_unb_normalizes_ccyymmdd_to_yymmdd() {
772 let data = Interchangedaten {
774 syntax_kennung: Some("UNOC".to_string()),
775 absender_code: Some("9900000000003".to_string()),
776 empfaenger_code: Some("9900000000001".to_string()),
777 datum: Some("20260409".to_string()), zeit: Some("0725".to_string()),
779 interchange_ref: Some("00004".to_string()),
780 absender_qualifier: None,
781 empfaenger_qualifier: None,
782 anwendungsreferenz: None,
783 };
784
785 let unb = rebuild_unb_from_interchangedaten(&data);
786 assert_eq!(unb.elements[3], vec!["260409", "0725"]); let nd = serde_json::json!({
790 "syntaxKennung": "UNOC",
791 "absenderCode": "9900000000003",
792 "empfaengerCode": "9900000000001",
793 "datum": "20260409",
794 "zeit": "0725",
795 "interchangeRef": "00004"
796 });
797 let unb_json = rebuild_unb(&nd);
798 assert_eq!(unb_json.elements[3], vec!["260409", "0725"]);
799 }
800
801 #[test]
802 fn test_rebuild_unb_preserves_yymmdd() {
803 let data = Interchangedaten {
805 datum: Some("260409".to_string()),
806 zeit: Some("0725".to_string()),
807 ..Default::default()
808 };
809 let unb = rebuild_unb_from_interchangedaten(&data);
810 assert_eq!(unb.elements[3], vec!["260409", "0725"]);
811 }
812
813 #[test]
814 fn test_into_dynamic_nachricht() {
815 let mapped = MappedMessage {
816 nachricht_meta: serde_json::Value::Null,
817 stammdaten: serde_json::json!({"marktteilnehmer": []}),
818 transaktionen: vec![MappedTransaktion {
819 transaktionsdaten: serde_json::json!({"vorgangId": "1"}),
820 stammdaten: serde_json::json!({}),
821 nesting_info: Default::default(),
822 }],
823 nesting_info: Default::default(),
824 inter_group_segments: Default::default(),
825 };
826
827 let nd = Nachrichtendaten {
828 unh_referenz: "00001".to_string(),
829 nachrichten_typ: "UTILMD".to_string(),
830 nachricht: Default::default(),
831 ..Default::default()
832 };
833
834 let nachricht = mapped.into_dynamic_nachricht(nd);
835 assert_eq!(nachricht.nachrichtendaten.unh_referenz, "00001");
836 assert_eq!(nachricht.transaktionen.len(), 1);
837 assert_eq!(
839 nachricht.transaktionen[0].transaktionsdaten["vorgangId"],
840 "1"
841 );
842 }
843}