Skip to content

Commit 2f17435

Browse files
authored
feat: Support <Uebertragungsdatei> in MigReader (adds flag is_on_uebertragungsdatei_level to MIG Segment model) (#133)
feat: Support `<Uebertragungsdatei>` in `MigReader` (adds flag is_on_uebertragungsdatei_level to Segment model) We decided AGAINST modeling this as an extra level in our data model because it adds no value and makes the models less uniform than they are right now (see e.g. PR #130 ). This is because some MIGs do contain an Übertragungsdatei on root level, some don't and the distinction is more pain than the value gained (at least for our usecases). Feel free to report back in issues if this doesn't suit your needs.
1 parent 3a999b2 commit 2f17435

File tree

4 files changed

+54
-13
lines changed

4 files changed

+54
-13
lines changed

src/fundamend/models/messageimplementationguide.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@ class Segment(FundamendBaseModel):
121121
status_specification: MigStatus # e.g. M
122122
example: str | None #: e.g. "NAD+MS+9900259000002::293'"
123123
data_elements: tuple[DataElement | DataElementGroup, ...]
124+
is_on_uebertragungsdatei_level: bool = False
125+
"""
126+
true only for those segments that are on the 'UEBERTRAGUNGSDATEI' level (meaning, outside the <M_FORMAT> tag).
127+
Similar to the corresponding AHB tag, we decided against replicating this XML level in the fundamend data model.
128+
This is the case for the UNA and UNZ segments in UTILMD, REMADV or INVOIC.
129+
But other formats like UTILTS or ORDERS have no such level at all.
130+
Basically this flag describes on which level you may aggregate single "Geschäftsvorfälle"/transactions in a single
131+
Übertragungsdatei.
132+
You may, for example, send multiple UTILMDs oR MSCONS messages batched/aggregated in one file, but not multiple
133+
ORDERs.
134+
"""
124135

125136

126137
class SegmentGroup(FundamendBaseModel):

src/fundamend/reader/migreader.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def _to_data_element_group(element: ET.Element) -> DataElementGroup:
7171
)
7272

7373

74-
def _to_segment(element: ET.Element) -> Segment:
74+
def _to_segment(element: ET.Element, is_on_uebertragungsdatei_level: bool = False) -> Segment:
7575
assert _is_segment(element)
7676
data_elements: list[DataElement | DataElementGroup] = []
7777
for child in element:
@@ -94,6 +94,7 @@ def _to_segment(element: ET.Element) -> Segment:
9494
example=element.attrib["Example"] or None,
9595
number=element.attrib["Number"],
9696
data_elements=tuple(data_elements),
97+
is_on_uebertragungsdatei_level=is_on_uebertragungsdatei_level,
9798
)
9899

99100

@@ -180,18 +181,22 @@ def _iter_segments_and_segment_groups(self, element: ET.Element) -> list[Segment
180181

181182
def read(self) -> MessageImplementationGuide:
182183
"""
183-
read the entire file and convert it to a MessageImplementationGuid instance
184+
read the entire file and convert it to a MessageImplementationGuide instance
184185
"""
185-
segments_and_groups = []
186+
segments_and_groups: list[Segment | SegmentGroup] = []
186187
root = self._element_tree.getroot()
187188
if _is_uebertragungsdatei(root):
188-
for elem in root.iter():
189-
if elem.tag.startswith("M_"):
190-
root = elem
191-
break
192-
for element in root:
193-
segments_and_groups.extend(self._iter_segments_and_segment_groups(element))
194-
189+
for elem in root:
190+
if _is_segment(elem):
191+
segments_and_groups.append(_to_segment(elem, is_on_uebertragungsdatei_level=True))
192+
elif elem.tag.startswith("M_"):
193+
for element in elem:
194+
segments_and_groups.extend(self._iter_segments_and_segment_groups(element))
195+
else:
196+
raise ValueError(f"unexpected element: {elem.tag}")
197+
else:
198+
for element in root:
199+
segments_and_groups.extend(self._iter_segments_and_segment_groups(element))
195200
result = MessageImplementationGuide(
196201
veroeffentlichungsdatum=self.get_publishing_date(),
197202
autor=self.get_author(),

unittests/__snapshots__/test_migreader.ambr

Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

unittests/test_ahb_serialisierung.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import pytest
55

6+
from fundamend.models.messageimplementationguide import Segment as MigSegment
67
from fundamend.reader import AhbReader, MigReader
78

89
from .conftest import is_private_submodule_checked_out
@@ -58,3 +59,27 @@ def test_deserializing_all_migs() -> None:
5859
for mig_file_path in data_path.rglob("**/*MIG*.xml"):
5960
reader = MigReader(mig_file_path)
6061
_ = reader.read() # must not crash
62+
63+
64+
def test_uebertragungsdatei_flag_is_set() -> None:
65+
if not is_private_submodule_checked_out():
66+
pytest.skip("Skipping test because of missing private submodule")
67+
mig_file_path = data_path / "FV2504" / "UTILMD_MIG_Strom_S2_1_Fehlerkorrektur_20250320.xml"
68+
reader = MigReader(mig_file_path)
69+
mig = reader.read()
70+
una_segment = [s for s in mig.elements if isinstance(s, MigSegment) and s.id == "UNA"][0]
71+
assert una_segment.is_on_uebertragungsdatei_level is True
72+
unh_segment = [s for s in mig.elements if isinstance(s, MigSegment) and s.id == "UNH"][0]
73+
assert unh_segment.is_on_uebertragungsdatei_level is False
74+
unz_segment = [s for s in mig.elements if isinstance(s, MigSegment) and s.id == "UNZ"][0]
75+
assert unz_segment.is_on_uebertragungsdatei_level is True
76+
77+
78+
def test_uebertragungsdatei_flag_is_not_set_outside_uebertragungsdatei() -> None:
79+
if not is_private_submodule_checked_out():
80+
pytest.skip("Skipping test because of missing private submodule")
81+
mig_file_path = data_path / "FV2504" / "UTILTS_MIG_1_1e_Fehlerkorrektur_20241018.xml" # has no uebertragungsdatei
82+
reader = MigReader(mig_file_path)
83+
mig = reader.read()
84+
unh_segment = [s for s in mig.elements if isinstance(s, MigSegment) and s.id == "UNH"][0]
85+
assert unh_segment.is_on_uebertragungsdatei_level is False

0 commit comments

Comments
 (0)