1use mig_types::segment::OwnedSegment;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13pub use bo4e_edifact_types::{
15 DynamicInterchange, DynamicNachricht, Interchange, Interchangedaten, Nachricht,
16 Nachrichtendaten,
17};
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase")]
25pub struct MappedTransaktion {
26 pub stammdaten: serde_json::Value,
29
30 #[serde(skip)]
37 pub nesting_info: HashMap<String, Vec<usize>>,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub struct MappedMessage {
47 pub stammdaten: serde_json::Value,
49
50 pub transaktionen: Vec<MappedTransaktion>,
52
53 #[serde(skip)]
59 pub nesting_info: HashMap<String, Vec<usize>>,
60}
61
62impl MappedMessage {
63 pub fn into_dynamic_nachricht(self, nachrichtendaten: Nachrichtendaten) -> DynamicNachricht {
68 Nachricht {
69 nachrichtendaten,
70 stammdaten: self.stammdaten,
71 transaktionen: self
72 .transaktionen
73 .into_iter()
74 .map(|t| t.stammdaten)
75 .collect(),
76 }
77 }
78}
79
80pub fn extract_unh_fields(unh: &OwnedSegment) -> (String, String) {
82 let referenz = unh.get_element(0).to_string();
83 let typ = unh.get_component(1, 0).to_string();
84 (referenz, typ)
85}
86
87pub fn extract_interchangedaten(envelope: &[OwnedSegment]) -> Interchangedaten {
89 let mut result = Interchangedaten::default();
90
91 for seg in envelope {
92 if seg.is("UNB") {
93 let val = |s: &str| {
94 if s.is_empty() {
95 None
96 } else {
97 Some(s.to_string())
98 }
99 };
100 result.syntax_kennung = val(seg.get_component(0, 0));
101 result.absender_code = val(seg.get_component(1, 0));
102 result.empfaenger_code = val(seg.get_component(2, 0));
103 result.datum = val(seg.get_component(3, 0));
104 result.zeit = val(seg.get_component(3, 1));
105 result.interchange_ref = val(seg.get_element(4));
106 }
107 }
108
109 result
110}
111
112pub fn extract_nachrichtendaten(envelope: &[OwnedSegment]) -> serde_json::Value {
116 let data = extract_interchangedaten(envelope);
117 serde_json::to_value(&data).unwrap_or_default()
118}
119
120pub fn rebuild_unb_from_interchangedaten(data: &Interchangedaten) -> OwnedSegment {
125 let syntax = data.syntax_kennung.as_deref().unwrap_or("UNOC");
126 let sender = data.absender_code.as_deref().unwrap_or("");
127 let receiver = data.empfaenger_code.as_deref().unwrap_or("");
128 let datum = data.datum.as_deref().unwrap_or("");
129 let zeit = data.zeit.as_deref().unwrap_or("");
130 let interchange_ref = data.interchange_ref.as_deref().unwrap_or("00000");
131
132 OwnedSegment {
133 id: "UNB".to_string(),
134 elements: vec![
135 vec![syntax.to_string(), "3".to_string()],
136 vec![sender.to_string(), "500".to_string()],
137 vec![receiver.to_string(), "500".to_string()],
138 vec![datum.to_string(), zeit.to_string()],
139 vec![interchange_ref.to_string()],
140 ],
141 segment_number: 0,
142 }
143}
144
145pub fn rebuild_unb(nachrichtendaten: &serde_json::Value) -> OwnedSegment {
150 let syntax = nachrichtendaten
151 .get("syntaxKennung")
152 .and_then(|v| v.as_str())
153 .unwrap_or("UNOC");
154 let sender = nachrichtendaten
155 .get("absenderCode")
156 .and_then(|v| v.as_str())
157 .unwrap_or("");
158 let receiver = nachrichtendaten
159 .get("empfaengerCode")
160 .and_then(|v| v.as_str())
161 .unwrap_or("");
162 let datum = nachrichtendaten
163 .get("datum")
164 .and_then(|v| v.as_str())
165 .unwrap_or("");
166 let zeit = nachrichtendaten
167 .get("zeit")
168 .and_then(|v| v.as_str())
169 .unwrap_or("");
170 let interchange_ref = nachrichtendaten
171 .get("interchangeRef")
172 .and_then(|v| v.as_str())
173 .unwrap_or("00000");
174
175 OwnedSegment {
176 id: "UNB".to_string(),
177 elements: vec![
178 vec![syntax.to_string(), "3".to_string()],
179 vec![sender.to_string(), "500".to_string()],
180 vec![receiver.to_string(), "500".to_string()],
181 vec![datum.to_string(), zeit.to_string()],
182 vec![interchange_ref.to_string()],
183 ],
184 segment_number: 0,
185 }
186}
187
188pub fn rebuild_unh(referenz: &str, nachrichten_typ: &str) -> OwnedSegment {
192 OwnedSegment {
193 id: "UNH".to_string(),
194 elements: vec![
195 vec![referenz.to_string()],
196 vec![
197 nachrichten_typ.to_string(),
198 "D".to_string(),
199 "11A".to_string(),
200 "UN".to_string(),
201 "S2.1".to_string(),
202 ],
203 ],
204 segment_number: 0,
205 }
206}
207
208pub fn rebuild_unt(segment_count: usize, referenz: &str) -> OwnedSegment {
213 OwnedSegment {
214 id: "UNT".to_string(),
215 elements: vec![vec![segment_count.to_string()], vec![referenz.to_string()]],
216 segment_number: 0,
217 }
218}
219
220pub fn rebuild_unz(message_count: usize, interchange_ref: &str) -> OwnedSegment {
224 OwnedSegment {
225 id: "UNZ".to_string(),
226 elements: vec![
227 vec![message_count.to_string()],
228 vec![interchange_ref.to_string()],
229 ],
230 segment_number: 0,
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237
238 #[test]
239 fn test_mapped_transaktion_serde_roundtrip() {
240 let tx = MappedTransaktion {
241 stammdaten: serde_json::json!({
242 "prozessdaten": {
243 "vorgangId": "TX001",
244 "transaktionsgrund": "E01"
245 },
246 "marktlokation": { "marktlokationsId": "DE000111222333" }
247 }),
248 nesting_info: Default::default(),
249 };
250
251 let json = serde_json::to_string(&tx).unwrap();
252 let de: MappedTransaktion = serde_json::from_str(&json).unwrap();
253 assert_eq!(
254 de.stammdaten["prozessdaten"]["vorgangId"].as_str().unwrap(),
255 "TX001"
256 );
257 assert!(de.stammdaten["marktlokation"].is_object());
258 }
259
260 #[test]
261 fn test_dynamic_nachricht_serde_roundtrip() {
262 let msg: DynamicNachricht = Nachricht {
263 nachrichtendaten: Nachrichtendaten {
264 unh_referenz: "00001".to_string(),
265 nachrichten_typ: "UTILMD".to_string(),
266 },
267 stammdaten: serde_json::json!({
268 "marktteilnehmer": [
269 { "marktrolle": "MS", "rollencodenummer": "9900123" }
270 ]
271 }),
272 transaktionen: vec![serde_json::json!({})],
273 };
274
275 let json = serde_json::to_string(&msg).unwrap();
276 let de: DynamicNachricht = serde_json::from_str(&json).unwrap();
277 assert_eq!(de.nachrichtendaten.unh_referenz, "00001");
278 assert_eq!(de.nachrichtendaten.nachrichten_typ, "UTILMD");
279 assert_eq!(de.transaktionen.len(), 1);
280 }
281
282 #[test]
283 fn test_dynamic_interchange_serde_roundtrip() {
284 let interchange: DynamicInterchange = Interchange {
285 interchangedaten: Interchangedaten {
286 absender_code: Some("9900123456789".to_string()),
287 empfaenger_code: Some("9900987654321".to_string()),
288 ..Default::default()
289 },
290 nachrichten: vec![Nachricht {
291 nachrichtendaten: Nachrichtendaten {
292 unh_referenz: "00001".to_string(),
293 nachrichten_typ: "UTILMD".to_string(),
294 },
295 stammdaten: serde_json::json!({}),
296 transaktionen: vec![],
297 }],
298 };
299
300 let json = serde_json::to_string_pretty(&interchange).unwrap();
301 let de: DynamicInterchange = serde_json::from_str(&json).unwrap();
302 assert_eq!(de.nachrichten.len(), 1);
303 assert_eq!(de.nachrichten[0].nachrichtendaten.unh_referenz, "00001");
304 }
305
306 #[test]
307 fn test_extract_interchangedaten_from_segments() {
308 let envelope = vec![OwnedSegment {
309 id: "UNB".to_string(),
310 elements: vec![
311 vec!["UNOC".to_string(), "3".to_string()],
312 vec!["9900123456789".to_string(), "500".to_string()],
313 vec!["9900987654321".to_string(), "500".to_string()],
314 vec!["210101".to_string(), "1200".to_string()],
315 vec!["REF001".to_string()],
316 ],
317 segment_number: 0,
318 }];
319
320 let data = extract_interchangedaten(&envelope);
321 assert_eq!(data.absender_code.as_deref(), Some("9900123456789"));
322 assert_eq!(data.empfaenger_code.as_deref(), Some("9900987654321"));
323 assert_eq!(data.interchange_ref.as_deref(), Some("REF001"));
324 assert_eq!(data.syntax_kennung.as_deref(), Some("UNOC"));
325 assert_eq!(data.datum.as_deref(), Some("210101"));
326 assert_eq!(data.zeit.as_deref(), Some("1200"));
327 }
328
329 #[test]
330 fn test_extract_envelope_from_segments_json() {
331 let envelope = vec![OwnedSegment {
332 id: "UNB".to_string(),
333 elements: vec![
334 vec!["UNOC".to_string(), "3".to_string()],
335 vec!["9900123456789".to_string(), "500".to_string()],
336 vec!["9900987654321".to_string(), "500".to_string()],
337 vec!["210101".to_string(), "1200".to_string()],
338 vec!["REF001".to_string()],
339 ],
340 segment_number: 0,
341 }];
342
343 let nd = extract_nachrichtendaten(&envelope);
344 assert_eq!(nd["absenderCode"].as_str().unwrap(), "9900123456789");
345 assert_eq!(nd["empfaengerCode"].as_str().unwrap(), "9900987654321");
346 assert_eq!(nd["interchangeRef"].as_str().unwrap(), "REF001");
347 assert_eq!(nd["syntaxKennung"].as_str().unwrap(), "UNOC");
348 assert_eq!(nd["datum"].as_str().unwrap(), "210101");
349 assert_eq!(nd["zeit"].as_str().unwrap(), "1200");
350 }
351
352 #[test]
353 fn test_extract_unh_fields() {
354 let unh = OwnedSegment {
355 id: "UNH".to_string(),
356 elements: vec![
357 vec!["MSG001".to_string()],
358 vec![
359 "UTILMD".to_string(),
360 "D".to_string(),
361 "11A".to_string(),
362 "UN".to_string(),
363 "S2.1".to_string(),
364 ],
365 ],
366 segment_number: 0,
367 };
368
369 let (referenz, typ) = extract_unh_fields(&unh);
370 assert_eq!(referenz, "MSG001");
371 assert_eq!(typ, "UTILMD");
372 }
373
374 #[test]
375 fn test_rebuild_unb_from_interchangedaten_typed() {
376 let data = Interchangedaten {
377 syntax_kennung: Some("UNOC".to_string()),
378 absender_code: Some("9900123456789".to_string()),
379 empfaenger_code: Some("9900987654321".to_string()),
380 datum: Some("210101".to_string()),
381 zeit: Some("1200".to_string()),
382 interchange_ref: Some("REF001".to_string()),
383 };
384
385 let unb = rebuild_unb_from_interchangedaten(&data);
386 assert_eq!(unb.id, "UNB");
387 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
388 assert_eq!(unb.elements[1][0], "9900123456789");
389 assert_eq!(unb.elements[2][0], "9900987654321");
390 assert_eq!(unb.elements[3], vec!["210101", "1200"]);
391 assert_eq!(unb.elements[4], vec!["REF001"]);
392 }
393
394 #[test]
395 fn test_rebuild_unb_from_nachrichtendaten() {
396 let nd = serde_json::json!({
397 "syntaxKennung": "UNOC",
398 "absenderCode": "9900123456789",
399 "empfaengerCode": "9900987654321",
400 "datum": "210101",
401 "zeit": "1200",
402 "interchangeRef": "REF001"
403 });
404
405 let unb = rebuild_unb(&nd);
406 assert_eq!(unb.id, "UNB");
407 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
408 assert_eq!(unb.elements[1][0], "9900123456789");
409 assert_eq!(unb.elements[2][0], "9900987654321");
410 assert_eq!(unb.elements[3], vec!["210101", "1200"]);
411 assert_eq!(unb.elements[4], vec!["REF001"]);
412 }
413
414 #[test]
415 fn test_rebuild_unb_defaults() {
416 let nd = serde_json::json!({});
417 let unb = rebuild_unb(&nd);
418 assert_eq!(unb.id, "UNB");
419 assert_eq!(unb.elements[0], vec!["UNOC", "3"]);
420 }
421
422 #[test]
423 fn test_rebuild_unh() {
424 let unh = rebuild_unh("00001", "UTILMD");
425 assert_eq!(unh.id, "UNH");
426 assert_eq!(unh.elements[0], vec!["00001"]);
427 assert_eq!(unh.elements[1][0], "UTILMD");
428 assert_eq!(unh.elements[1][1], "D");
429 assert_eq!(unh.elements[1][2], "11A");
430 assert_eq!(unh.elements[1][3], "UN");
431 assert_eq!(unh.elements[1][4], "S2.1");
432 }
433
434 #[test]
435 fn test_rebuild_unt() {
436 let unt = rebuild_unt(25, "00001");
437 assert_eq!(unt.id, "UNT");
438 assert_eq!(unt.elements[0], vec!["25"]);
439 assert_eq!(unt.elements[1], vec!["00001"]);
440 }
441
442 #[test]
443 fn test_rebuild_unz() {
444 let unz = rebuild_unz(1, "REF001");
445 assert_eq!(unz.id, "UNZ");
446 assert_eq!(unz.elements[0], vec!["1"]);
447 assert_eq!(unz.elements[1], vec!["REF001"]);
448 }
449
450 #[test]
451 fn test_roundtrip_interchangedaten_rebuild() {
452 let original = OwnedSegment {
453 id: "UNB".to_string(),
454 elements: vec![
455 vec!["UNOC".to_string(), "3".to_string()],
456 vec!["9900123456789".to_string(), "500".to_string()],
457 vec!["9900987654321".to_string(), "500".to_string()],
458 vec!["210101".to_string(), "1200".to_string()],
459 vec!["REF001".to_string()],
460 ],
461 segment_number: 0,
462 };
463
464 let data = extract_interchangedaten(&[original]);
465 let rebuilt = rebuild_unb_from_interchangedaten(&data);
466 assert_eq!(rebuilt.elements[0], vec!["UNOC", "3"]);
467 assert_eq!(rebuilt.elements[1][0], "9900123456789");
468 assert_eq!(rebuilt.elements[2][0], "9900987654321");
469 assert_eq!(rebuilt.elements[3], vec!["210101", "1200"]);
470 assert_eq!(rebuilt.elements[4], vec!["REF001"]);
471 }
472
473 #[test]
474 fn test_roundtrip_nachrichtendaten_rebuild() {
475 let original = OwnedSegment {
476 id: "UNB".to_string(),
477 elements: vec![
478 vec!["UNOC".to_string(), "3".to_string()],
479 vec!["9900123456789".to_string(), "500".to_string()],
480 vec!["9900987654321".to_string(), "500".to_string()],
481 vec!["210101".to_string(), "1200".to_string()],
482 vec!["REF001".to_string()],
483 ],
484 segment_number: 0,
485 };
486
487 let nd = extract_nachrichtendaten(&[original]);
488 let rebuilt = rebuild_unb(&nd);
489 assert_eq!(rebuilt.elements[0], vec!["UNOC", "3"]);
490 assert_eq!(rebuilt.elements[1][0], "9900123456789");
491 assert_eq!(rebuilt.elements[2][0], "9900987654321");
492 assert_eq!(rebuilt.elements[3], vec!["210101", "1200"]);
493 assert_eq!(rebuilt.elements[4], vec!["REF001"]);
494 }
495
496 #[test]
497 fn test_into_dynamic_nachricht() {
498 let mapped = MappedMessage {
499 stammdaten: serde_json::json!({"marktteilnehmer": []}),
500 transaktionen: vec![MappedTransaktion {
501 stammdaten: serde_json::json!({"prozessdaten": {"id": "1"}}),
502 nesting_info: Default::default(),
503 }],
504 nesting_info: Default::default(),
505 };
506
507 let nd = Nachrichtendaten {
508 unh_referenz: "00001".to_string(),
509 nachrichten_typ: "UTILMD".to_string(),
510 };
511
512 let nachricht = mapped.into_dynamic_nachricht(nd);
513 assert_eq!(nachricht.nachrichtendaten.unh_referenz, "00001");
514 assert_eq!(nachricht.transaktionen.len(), 1);
515 assert!(nachricht.transaktionen[0]["prozessdaten"].is_object());
516 }
517}