Files
wyndham-ARR/tests/test_monthly_reports_xlsx.py
2026-08-04 14:49:38 +08:00

191 lines
6.9 KiB
Python

from __future__ import annotations
import tempfile
import unittest
from datetime import date, timedelta
from decimal import Decimal
from pathlib import Path
from openpyxl import load_workbook
from monthly_reports.contracts import (
ChannelObservation,
DailyVersionPin,
MonthlyFact,
MonthlySnapshot,
STANDARD_SHEETS,
)
from monthly_reports.core import build_monthly_report
from monthly_reports.publishing import OpenpyxlWorkbookBuilder
def report_fixture():
source = MonthlyFact(
daily_record_id=1,
daily_version_id=100,
business_date=date(2026, 7, 8),
channel_key="QBD",
arrival=date(2026, 7, 8),
departure=date(2026, 7, 10),
nights=2,
adults=2,
children=0,
block_code="=SYN-FORMULA-LIKE",
no_of_rooms=1,
company_name="SYN-COMPANY",
confirmation_no="SYN-CONFIRMATION",
disp_room_no="SYN-ROOM",
effective_rate_amount=Decimal("450.50"),
full_name="SYN-GUEST",
res_comment="SYN-COMMENT",
trace_text="",
products="",
rate_code="SYN-RATE",
room_category_label="SYN-TYPE",
real_price=Decimal("450.50"),
total_price=Decimal("901.00"),
kb_amount=None,
)
return build_monthly_report(
2026,
7,
date(2026, 7, 8),
MonthlySnapshot(
(source,),
(DailyVersionPin(date(2026, 7, 8), 100),),
(ChannelObservation(date(2026, 7, 8), 100, "QBD", 1, 1),),
),
)
def large_decimal_report_fixture():
facts = []
daily_versions = []
channel_observations = []
record_id = 1000
daily_plan = (
(date(2026, 8, 1), 501, 28),
(date(2026, 8, 2), 502, 30),
(date(2026, 8, 3), 503, 30),
)
for business_date, daily_version_id, rows_per_sheet in daily_plan:
daily_versions.append(DailyVersionPin(business_date, daily_version_id))
for channel_index, channel_key in enumerate(STANDARD_SHEETS, start=1):
channel_observations.append(
ChannelObservation(
business_date,
daily_version_id,
channel_key,
channel_index,
rows_per_sheet,
)
)
for row_index in range(rows_per_sheet):
nights = 1 + (row_index % 3)
no_of_rooms = 1 + (row_index % 2)
real_price = Decimal("321.17") + Decimal(row_index % 19) / Decimal("100")
sequence = record_id
facts.append(
MonthlyFact(
daily_record_id=sequence,
daily_version_id=daily_version_id,
business_date=business_date,
channel_key=channel_key,
arrival=business_date,
departure=business_date + timedelta(days=nights),
nights=nights,
adults=2,
children=row_index % 2,
block_code=f"BLOCK-{sequence}",
no_of_rooms=no_of_rooms,
company_name=f"COMPANY-{channel_index}",
confirmation_no=f"CONF-{sequence}",
disp_room_no=f"ROOM-{sequence}",
effective_rate_amount=Decimal("247.35")
+ Decimal((row_index + channel_index) % 7) / Decimal("100"),
full_name=f"GUEST-{sequence}",
res_comment=f"COMMENT-{sequence}",
trace_text="TRACE",
products="ROOM",
rate_code="BAR",
room_category_label="STD",
real_price=real_price,
total_price=real_price * no_of_rooms * nights,
kb_amount=Decimal(no_of_rooms * 100)
if channel_key == "DY-AI-Easy-KB"
else None,
)
)
record_id += 1
return build_monthly_report(
2026,
8,
date(2026, 8, 3),
MonthlySnapshot(
tuple(facts),
tuple(daily_versions),
tuple(channel_observations),
),
)
class MonthlyReportsXlsxTests(unittest.TestCase):
def test_openpyxl_builder_reopens_checks_formulas_and_semantic_identity(self):
report = report_fixture()
with tempfile.TemporaryDirectory(prefix="monthly-report-xlsx-") as temp_dir:
built = OpenpyxlWorkbookBuilder().build(report, Path(temp_dir))
self.assertTrue(built.path.is_file())
self.assertEqual(built.path.stat().st_mode & 0o777, 0o600)
self.assertEqual(built.summary["sheet_names"][:5], [
"LIANTAI-GROUP", "LIANTAI-FIT", "QBD", "DY-AI-Easy-KB", "FENGRUN"
])
self.assertEqual(built.summary["row_counts"], [0, 0, 1, 0, 0])
self.assertEqual(built.summary["formula_count"], 1)
self.assertEqual(built.summary["preview_count"], 5)
self.assertEqual(len(built.summary["semantic_sha256"]), 64)
workbook = load_workbook(built.path, data_only=False, read_only=True)
try:
self.assertEqual(workbook["QBD"]["S2"].value, "=R2*C2*G2")
self.assertEqual(workbook["QBD"]["F2"].value, "'=SYN-FORMULA-LIKE")
formulas = [
cell.value
for sheet in workbook.worksheets
for row in sheet.iter_rows()
for cell in row
if cell.data_type == "f"
]
self.assertEqual(formulas, ["=R2*C2*G2"])
finally:
workbook.close()
def test_openpyxl_builder_validates_440_decimal_rows_across_multiple_sheets(self):
report = large_decimal_report_fixture()
self.assertEqual(report.row_count, 440)
with tempfile.TemporaryDirectory(prefix="monthly-report-xlsx-large-") as temp_dir:
built = OpenpyxlWorkbookBuilder().build(report, Path(temp_dir))
self.assertEqual(built.summary["sheet_names"], list(STANDARD_SHEETS))
self.assertEqual(built.summary["row_counts"], [88, 88, 88, 88, 88])
self.assertEqual(built.summary["formula_count"], 440)
self.assertTrue(
OpenpyxlWorkbookBuilder._decimal_matches("321.1700005", "321.17")
)
self.assertFalse(
OpenpyxlWorkbookBuilder._decimal_matches("321.1700011", "321.17")
)
self.assertEqual(
OpenpyxlWorkbookBuilder._validate_workbook(
built.path,
report,
report.to_workbook_payload(),
),
440,
)
if __name__ == "__main__":
unittest.main()