Files
ARR-2.0-0918/integrations/ohip/arr_xml.py
T

41 lines
2.0 KiB
Python

"""Serialize explicit ordered rows to the existing ARR processor XML format.
No API selection, report semantics, filtering, deduplication or pricing occurs
here. Output is a processing projection, not a native Opera report replica.
"""
from __future__ import annotations
import xml.etree.ElementTree as ET
from .arr_xml_contract import MAX_BYTES, SCALARS, SourceDocument, validate_document
from .collect_arr_source import require
def serialize(document: SourceDocument) -> bytes:
validate_document(document)
root = ET.Element("RES_DETAIL")
groups = ET.SubElement(root, "LIST_G_GROUP_BY1")
group = ET.SubElement(groups, "G_GROUP_BY1")
day = document.report_date
ET.SubElement(group, "GROUPBY1_SORT_COL").text = f"{day.year:04d}{day.month:02d}{day.day:02d}"
# Use the full-year ISO representation accepted by the existing processor.
# A two-digit display year can silently map historical dates to another century.
ET.SubElement(group, "GROUPBY1_COL").text = document.report_date.isoformat()
rows = ET.SubElement(group, "LIST_G_RESERVATION")
for row in document.rows:
node = ET.SubElement(rows, "G_RESERVATION")
ET.SubElement(node, "RESORT").text = document.hotel_id
ET.SubElement(node, "RESV_NAME_ID").text = row.reservation_id
for attribute, tag in SCALARS:
ET.SubElement(node, tag).text = getattr(row, attribute)
comments = ET.SubElement(node, "LIST_G_COMMENT_RESV_NAME_ID")
for text in row.notes:
ET.SubElement(ET.SubElement(comments, "G_COMMENT_RESV_NAME_ID"), "RES_COMMENT").text = text
traces = ET.SubElement(node, "LIST_G_DEPT_ID")
for text in row.traces:
ET.SubElement(ET.SubElement(traces, "G_DEPT_ID"), "TRACE_TEXT").text = text
# XML parsers normalize literal CR; character references preserve it exactly.
raw = ET.tostring(root, encoding="utf-8", xml_declaration=True).replace(b"\r", b"
") + b"\n"
require(len(raw) <= MAX_BYTES, "arr_xml_output_budget_exceeded")
return raw