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 }
214 }
215
216 result
217}
218
219pub fn extract_nachrichtendaten(envelope: &[OwnedSegment]) -> serde_json::Value {
223 let data = extract_interchangedaten(envelope);
224 serde_json::to_value(&data).unwrap_or_default()
225}
226
227fn normalize_unb_datum(datum: &str) -> &str {
232 if datum.len() == 8 && datum.as_bytes().iter().all(|b| b.is_ascii_digit()) {
233 &datum[2..]
234 } else {
235 datum
236 }
237}
238
239pub fn rebuild_unb_from_interchangedaten(data: &Interchangedaten) -> OwnedSegment {
245 let syntax = data.syntax_kennung.as_deref().unwrap_or("UNOC");
246 let sender = data.absender_code.as_deref().unwrap_or("");
247 let receiver = data.empfaenger_code.as_deref().unwrap_or("");
248 let datum = normalize_unb_datum(data.datum.as_deref().unwrap_or(""));
249 let zeit = data.zeit.as_deref().unwrap_or("");
250 let interchange_ref = data.interchange_ref.as_deref().unwrap_or("00000");
251
252 OwnedSegment {
253 id: "UNB".to_string(),
254 elements: vec![
255 vec![syntax.to_string(), "3".to_string()],
256 vec![sender.to_string(), "500".to_string()],
257 vec![receiver.to_string(), "500".to_string()],
258 vec![datum.to_string(), zeit.to_string()],
259 vec![interchange_ref.to_string()],
260 ],
261 segment_number: 0,
262 }
263}
264
265pub fn rebuild_unb(nachrichtendaten: &serde_json::Value) -> OwnedSegment {
271 let syntax = nachrichtendaten
272 .get("syntaxKennung")
273 .and_then(|v| v.as_str())
274 .unwrap_or("UNOC");
275 let sender = nachrichtendaten
276 .get("absenderCode")
277 .and_then(|v| v.as_str())
278 .unwrap_or("");
279 let receiver = nachrichtendaten
280 .get("empfaengerCode")
281 .and_then(|v| v.as_str())
282 .unwrap_or("");
283 let datum_raw = nachrichtendaten
284 .get("datum")
285 .and_then(|v| v.as_str())
286 .unwrap_or("");
287 let datum = normalize_unb_datum(datum_raw);
288 let zeit = nachrichtendaten
289 .get("zeit")
290 .and_then(|v| v.as_str())
291 .unwrap_or("");
292 let interchange_ref = nachrichtendaten
293 .get("interchangeRef")
294 .and_then(|v| v.as_str())
295 .unwrap_or("00000");
296
297 OwnedSegment {
298 id: "UNB".to_string(),
299 elements: vec![
300 vec![syntax.to_string(), "3".to_string()],
301 vec![sender.to_string(), "500".to_string()],
302 vec![receiver.to_string(), "500".to_string()],
303 vec![datum.to_string(), zeit.to_string()],
304 vec![interchange_ref.to_string()],
305 ],
306 segment_number: 0,
307 }
308}
309
310pub fn rebuild_unh(header: &Nachrichtendaten, release: &str, association: &str) -> OwnedSegment {
322 let mut elements = vec![
323 vec![header.unh_referenz.clone()],
324 vec![
325 header.nachrichten_typ.clone(),
326 "D".to_string(),
327 release.to_string(),
328 "UN".to_string(),
329 association.to_string(),
330 ],
331 ];
332
333 let s010: Vec<String> = match (
337 &header.uebermittlungsfolgenummer,
338 header.uebermittlungsabschnitt,
339 ) {
340 (None, None) => Vec::new(),
341 (folge, abschnitt) => vec![
342 folge.clone().unwrap_or_default(),
343 abschnitt.map(|a| a.code().to_string()).unwrap_or_default(),
344 ],
345 };
346 if header.zuordnungsreferenz.is_some() || !s010.is_empty() {
347 elements.push(vec![header.zuordnungsreferenz.clone().unwrap_or_default()]);
348 }
349 if !s010.is_empty() {
350 elements.push(s010);
351 }
352
353 OwnedSegment {
354 id: "UNH".to_string(),
355 elements,
356 segment_number: 0,
357 }
358}
359
360pub fn release_code_for_message_type(msg_type: &str) -> &'static str {
367 match msg_type {
368 "APERAK" => "07B",
369 "COMDIS" => "17A",
370 "CONTRL" => "3",
372 "IFTSTA" => "18A",
373 "INSRPT" => "10A",
374 "INVOIC" => "06A",
375 "MSCONS" => "04B",
376 "ORDCHG" => "20B",
377 "ORDERS" => "09B",
378 "ORDRSP" => "10A",
379 "PARTIN" => "20B",
380 "PRICAT" => "20B",
381 "QUOTES" => "10A",
382 "REMADV" => "05A",
383 "REQOTE" => "10A",
384 "UTILMD" => "11A",
385 "UTILTS" => "18A",
386 _ => "04B", }
388}
389
390pub fn rebuild_unt(segment_count: usize, referenz: &str) -> OwnedSegment {
395 OwnedSegment {
396 id: "UNT".to_string(),
397 elements: vec![vec![segment_count.to_string()], vec![referenz.to_string()]],
398 segment_number: 0,
399 }
400}
401
402pub fn rebuild_unz(message_count: usize, interchange_ref: &str) -> OwnedSegment {
406 OwnedSegment {
407 id: "UNZ".to_string(),
408 elements: vec![
409 vec![message_count.to_string()],
410 vec![interchange_ref.to_string()],
411 ],
412 segment_number: 0,
413 }
414}
415
416#[cfg(test)]
417mod tests {
418 use super::*;
419
420 #[test]
421 fn test_mapped_transaktion_serde_roundtrip() {
422 let tx = MappedTransaktion {
423 transaktionsdaten: serde_json::Value::Null,
424 stammdaten: serde_json::json!({
425 "prozessdaten": {
426 "vorgangId": "TX001",
427 "transaktionsgrund": "E01"
428 },
429 "marktlokation": { "marktlokationsId": "DE000111222333" }
430 }),
431 nesting_info: Default::default(),
432 };
433
434 let json = serde_json::to_string(&tx).unwrap();
435 let de: MappedTransaktion = serde_json::from_str(&json).unwrap();
436 assert_eq!(
437 de.stammdaten["prozessdaten"]["vorgangId"].as_str().unwrap(),
438 "TX001"
439 );
440 assert!(de.stammdaten["marktlokation"].is_object());
441 }
442
443 #[test]
444 fn test_dynamic_nachricht_serde_roundtrip() {
445 let msg: DynamicNachricht = Nachricht {
446 nachrichtendaten: Nachrichtendaten {
447 unh_referenz: "00001".to_string(),
448 nachrichten_typ: "UTILMD".to_string(),
449 nachricht: Default::default(),
450 ..Default::default()
451 },
452 stammdaten: serde_json::json!({
453 "marktteilnehmer": [
454 { "marktrolle": "MS", "rollencodenummer": "9900123" }
455 ]
456 }),
457 transaktionen: vec![Transaktion {
458 transaktionsdaten: serde_json::Value::Null,
459 stammdaten: serde_json::json!({}),
460 }],
461 };
462
463 let json = serde_json::to_string(&msg).unwrap();
464 let de: DynamicNachricht = serde_json::from_str(&json).unwrap();
465 assert_eq!(de.nachrichtendaten.unh_referenz, "00001");
466 assert_eq!(de.nachrichtendaten.nachrichten_typ, "UTILMD");
467 assert_eq!(de.transaktionen.len(), 1);
468 }
469
470 #[test]
471 fn test_dynamic_interchange_serde_roundtrip() {
472 let interchange: DynamicInterchange = Interchange {
473 interchangedaten: Interchangedaten {
474 absender_code: Some("9900123456789".to_string()),
475 empfaenger_code: Some("9900987654321".to_string()),
476 ..Default::default()
477 },
478 nachrichten: vec![Nachricht {
479 nachrichtendaten: Nachrichtendaten {
480 unh_referenz: "00001".to_string(),
481 nachrichten_typ: "UTILMD".to_string(),
482 nachricht: Default::default(),
483 ..Default::default()
484 },
485 stammdaten: serde_json::json!({}),
486 transaktionen: vec![],
487 }],
488 };
489
490 let json = serde_json::to_string_pretty(&interchange).unwrap();
491 let de: DynamicInterchange = serde_json::from_str(&json).unwrap();
492 assert_eq!(de.nachrichten.len(), 1);
493 assert_eq!(de.nachrichten[0].nachrichtendaten.unh_referenz, "00001");
494 }
495
496 #[test]
497 fn test_extract_interchangedaten_from_segments() {
498 let envelope = vec![OwnedSegment {
499 id: "UNB".to_string(),
500 elements: vec![
501 vec!["UNOC".to_string(), "3".to_string()],
502 vec!["9900123456789".to_string(), "500".to_string()],
503 vec!["9900987654321".to_string(), "500".to_string()],
504 vec!["210101".to_string(), "1200".to_string()],
505 vec!["REF001".to_string()],
506 ],
507 segment_number: 0,
508 }];
509
510 let data = extract_interchangedaten(&envelope);
511 assert_eq!(data.absender_code.as_deref(), Some("9900123456789"));
512 assert_eq!(data.empfaenger_code.as_deref(), Some("9900987654321"));
513 assert_eq!(data.interchange_ref.as_deref(), Some("REF001"));
514 assert_eq!(data.syntax_kennung.as_deref(), Some("UNOC"));
515 assert_eq!(data.datum.as_deref(), Some("210101"));
516 assert_eq!(data.zeit.as_deref(), Some("1200"));
517 }
518
519 #[test]
520 fn test_extract_envelope_from_segments_json() {
521 let envelope = vec![OwnedSegment {
522 id: "UNB".to_string(),
523 elements: vec![
524 vec!["UNOC".to_string(), "3".to_string()],
525 vec!["9900123456789".to_string(), "500".to_string()],
526 vec!["9900987654321".to_string(), "500".to_string()],
527 vec!["210101".to_string(), "1200".to_string()],
528 vec!["REF001".to_string()],
529 ],
530 segment_number: 0,
531 }];
532
533 let nd = extract_nachrichtendaten(&envelope);
534 assert_eq!(nd["absenderCode"].as_str().unwrap(), "9900123456789");
535 assert_eq!(nd["empfaengerCode"].as_str().unwrap(), "9900987654321");
536 assert_eq!(nd["interchangeRef"].as_str().unwrap(), "REF001");
537 assert_eq!(nd["syntaxKennung"].as_str().unwrap(), "UNOC");
538 assert_eq!(nd["datum"].as_str().unwrap(), "210101");
539 assert_eq!(nd["zeit"].as_str().unwrap(), "1200");
540 }
541
542 #[test]
543 fn test_extract_unh_fields() {
544 let unh = OwnedSegment {
545 id: "UNH".to_string(),
546 elements: vec![
547 vec!["MSG001".to_string()],
548 vec![
549 "UTILMD".to_string(),
550 "D".to_string(),
551 "11A".to_string(),
552 "UN".to_string(),
553 "S2.1".to_string(),
554 ],
555 ],
556 segment_number: 0,
557 };
558
559 let (referenz, typ) = extract_unh_fields(&unh);
560 assert_eq!(referenz, "MSG001");
561 assert_eq!(typ, "UTILMD");
562 }
563
564 #[test]
565 fn test_rebuild_unb_from_interchangedaten_typed() {
566 let data = Interchangedaten {
567 syntax_kennung: Some("UNOC".to_string()),
568 absender_code: Some("9900123456789".to_string()),
569 empfaenger_code: Some("9900987654321".to_string()),
570 datum: Some("210101".to_string()),
571 zeit: Some("1200".to_string()),
572 interchange_ref: Some("REF001".to_string()),
573 };
574
575 let unb = rebuild_unb_from_interchangedaten(&data);
576 assert_eq!(unb.id, "UNB");
577 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
578 assert_eq!(unb.elements[1][0], "9900123456789");
579 assert_eq!(unb.elements[2][0], "9900987654321");
580 assert_eq!(unb.elements[3], vec!["210101", "1200"]);
581 assert_eq!(unb.elements[4], vec!["REF001"]);
582 }
583
584 #[test]
585 fn test_rebuild_unb_from_nachrichtendaten() {
586 let nd = serde_json::json!({
587 "syntaxKennung": "UNOC",
588 "absenderCode": "9900123456789",
589 "empfaengerCode": "9900987654321",
590 "datum": "210101",
591 "zeit": "1200",
592 "interchangeRef": "REF001"
593 });
594
595 let unb = rebuild_unb(&nd);
596 assert_eq!(unb.id, "UNB");
597 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
598 assert_eq!(unb.elements[1][0], "9900123456789");
599 assert_eq!(unb.elements[2][0], "9900987654321");
600 assert_eq!(unb.elements[3], vec!["210101", "1200"]);
601 assert_eq!(unb.elements[4], vec!["REF001"]);
602 }
603
604 #[test]
605 fn test_rebuild_unb_defaults() {
606 let nd = serde_json::json!({});
607 let unb = rebuild_unb(&nd);
608 assert_eq!(unb.id, "UNB");
609 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
610 }
611
612 fn header(referenz: &str, typ: &str) -> Nachrichtendaten {
614 Nachrichtendaten {
615 unh_referenz: referenz.to_string(),
616 nachrichten_typ: typ.to_string(),
617 ..Default::default()
618 }
619 }
620
621 #[test]
627 fn the_optional_unh_elements_survive_extraction_and_rebuild() {
628 let original = OwnedSegment {
629 id: "UNH".to_string(),
630 elements: vec![
631 vec!["GENERATED00001".to_string()],
632 vec![
633 "MSCONS".to_string(),
634 "D".to_string(),
635 "04B".to_string(),
636 "UN".to_string(),
637 "2.4c".to_string(),
638 ],
639 vec!["ZUORDNUNG1".to_string()],
640 vec!["3".to_string(), "C".to_string()],
641 ],
642 segment_number: 0,
643 };
644
645 let header = extract_message_header(&original);
646 assert_eq!(header.zuordnungsreferenz.as_deref(), Some("ZUORDNUNG1"));
647 assert_eq!(header.uebermittlungsfolgenummer.as_deref(), Some("3"));
648 assert_eq!(
649 header.uebermittlungsabschnitt,
650 Some(Uebermittlungsabschnitt::Beginn),
651 "the BO4E carries the MIG's name for C, not the code"
652 );
653
654 let rebuilt = rebuild_unh(&header, "04B", "2.4c");
655 assert_eq!(rebuilt.elements, original.elements);
656 }
657
658 #[test]
660 fn a_header_without_the_optional_elements_renders_as_before() {
661 let unh = rebuild_unh(&header("00001", "UTILMD"), "11A", "S2.1");
662 assert_eq!(unh.elements.len(), 2, "no empty trailing elements: {unh:?}");
663 }
664
665 #[test]
667 fn s010_without_0068_keeps_its_position() {
668 let mut h = header("00001", "UTILMD");
669 h.uebermittlungsfolgenummer = Some("2".to_string());
670 let unh = rebuild_unh(&h, "11A", "S2.1");
671 assert_eq!(unh.elements[2], vec![""], "0068 holds S010's position");
672 assert_eq!(unh.elements[3], vec!["2", ""]);
673 }
674
675 #[test]
676 fn test_rebuild_unh() {
677 let unh = rebuild_unh(&header("00001", "UTILMD"), "11A", "S2.1");
678 assert_eq!(unh.id, "UNH");
679 assert_eq!(unh.elements[0], vec!["00001"]);
680 assert_eq!(unh.elements[1][0], "UTILMD");
681 assert_eq!(unh.elements[1][1], "D");
682 assert_eq!(unh.elements[1][2], "11A");
683 assert_eq!(unh.elements[1][3], "UN");
684 assert_eq!(unh.elements[1][4], "S2.1");
685 }
686
687 #[test]
688 fn test_rebuild_unh_uses_the_given_release_and_association() {
689 let unh = rebuild_unh(&header("00001", "UTILMD"), "11A", "G1.0a");
692 assert_eq!(unh.elements[1], vec!["UTILMD", "D", "11A", "UN", "G1.0a"]);
693
694 let unh = rebuild_unh(
695 &header("00001", "MSCONS"),
696 release_code_for_message_type("MSCONS"),
697 "2.4c",
698 );
699 assert_eq!(unh.elements[1], vec!["MSCONS", "D", "04B", "UN", "2.4c"]);
700 }
701
702 #[test]
703 fn test_rebuild_unt() {
704 let unt = rebuild_unt(25, "00001");
705 assert_eq!(unt.id, "UNT");
706 assert_eq!(unt.elements[0], vec!["25"]);
707 assert_eq!(unt.elements[1], vec!["00001"]);
708 }
709
710 #[test]
711 fn test_rebuild_unz() {
712 let unz = rebuild_unz(1, "REF001");
713 assert_eq!(unz.id, "UNZ");
714 assert_eq!(unz.elements[0], vec!["1"]);
715 assert_eq!(unz.elements[1], vec!["REF001"]);
716 }
717
718 #[test]
719 fn test_roundtrip_interchangedaten_rebuild() {
720 let original = OwnedSegment {
721 id: "UNB".to_string(),
722 elements: vec![
723 vec!["UNOC".to_string(), "3".to_string()],
724 vec!["9900123456789".to_string(), "500".to_string()],
725 vec!["9900987654321".to_string(), "500".to_string()],
726 vec!["210101".to_string(), "1200".to_string()],
727 vec!["REF001".to_string()],
728 ],
729 segment_number: 0,
730 };
731
732 let data = extract_interchangedaten(&[original]);
733 let rebuilt = rebuild_unb_from_interchangedaten(&data);
734 assert_eq!(rebuilt.elements[0], vec!["UNOC", "3"]);
735 assert_eq!(rebuilt.elements[1][0], "9900123456789");
736 assert_eq!(rebuilt.elements[2][0], "9900987654321");
737 assert_eq!(rebuilt.elements[3], vec!["210101", "1200"]);
738 assert_eq!(rebuilt.elements[4], vec!["REF001"]);
739 }
740
741 #[test]
742 fn test_roundtrip_nachrichtendaten_rebuild() {
743 let original = OwnedSegment {
744 id: "UNB".to_string(),
745 elements: vec![
746 vec!["UNOC".to_string(), "3".to_string()],
747 vec!["9900123456789".to_string(), "500".to_string()],
748 vec!["9900987654321".to_string(), "500".to_string()],
749 vec!["210101".to_string(), "1200".to_string()],
750 vec!["REF001".to_string()],
751 ],
752 segment_number: 0,
753 };
754
755 let nd = extract_nachrichtendaten(&[original]);
756 let rebuilt = rebuild_unb(&nd);
757 assert_eq!(rebuilt.elements[0], vec!["UNOC", "3"]);
758 assert_eq!(rebuilt.elements[1][0], "9900123456789");
759 assert_eq!(rebuilt.elements[2][0], "9900987654321");
760 assert_eq!(rebuilt.elements[3], vec!["210101", "1200"]);
761 assert_eq!(rebuilt.elements[4], vec!["REF001"]);
762 }
763
764 #[test]
765 fn test_rebuild_unb_normalizes_ccyymmdd_to_yymmdd() {
766 let data = Interchangedaten {
768 syntax_kennung: Some("UNOC".to_string()),
769 absender_code: Some("9900000000003".to_string()),
770 empfaenger_code: Some("9900000000001".to_string()),
771 datum: Some("20260409".to_string()), zeit: Some("0725".to_string()),
773 interchange_ref: Some("00004".to_string()),
774 };
775
776 let unb = rebuild_unb_from_interchangedaten(&data);
777 assert_eq!(unb.elements[3], vec!["260409", "0725"]); let nd = serde_json::json!({
781 "syntaxKennung": "UNOC",
782 "absenderCode": "9900000000003",
783 "empfaengerCode": "9900000000001",
784 "datum": "20260409",
785 "zeit": "0725",
786 "interchangeRef": "00004"
787 });
788 let unb_json = rebuild_unb(&nd);
789 assert_eq!(unb_json.elements[3], vec!["260409", "0725"]);
790 }
791
792 #[test]
793 fn test_rebuild_unb_preserves_yymmdd() {
794 let data = Interchangedaten {
796 datum: Some("260409".to_string()),
797 zeit: Some("0725".to_string()),
798 ..Default::default()
799 };
800 let unb = rebuild_unb_from_interchangedaten(&data);
801 assert_eq!(unb.elements[3], vec!["260409", "0725"]);
802 }
803
804 #[test]
805 fn test_into_dynamic_nachricht() {
806 let mapped = MappedMessage {
807 nachricht_meta: serde_json::Value::Null,
808 stammdaten: serde_json::json!({"marktteilnehmer": []}),
809 transaktionen: vec![MappedTransaktion {
810 transaktionsdaten: serde_json::json!({"vorgangId": "1"}),
811 stammdaten: serde_json::json!({}),
812 nesting_info: Default::default(),
813 }],
814 nesting_info: Default::default(),
815 inter_group_segments: Default::default(),
816 };
817
818 let nd = Nachrichtendaten {
819 unh_referenz: "00001".to_string(),
820 nachrichten_typ: "UTILMD".to_string(),
821 nachricht: Default::default(),
822 ..Default::default()
823 };
824
825 let nachricht = mapped.into_dynamic_nachricht(nd);
826 assert_eq!(nachricht.nachrichtendaten.unh_referenz, "00001");
827 assert_eq!(nachricht.transaktionen.len(), 1);
828 assert_eq!(
830 nachricht.transaktionen[0].transaktionsdaten["vorgangId"],
831 "1"
832 );
833 }
834}