fix: tolerate spreadsheet decimal roundoff

This commit is contained in:
Wyndham ARR
2026-08-04 14:49:38 +08:00
parent a2b86cdf10
commit aae3d8e1db
5 changed files with 144 additions and 7 deletions

View File

@@ -2,7 +2,7 @@ from __future__ import annotations
import tempfile
import unittest
from datetime import date
from datetime import date, timedelta
from decimal import Decimal
from pathlib import Path
@@ -13,6 +13,7 @@ from monthly_reports.contracts import (
DailyVersionPin,
MonthlyFact,
MonthlySnapshot,
STANDARD_SHEETS,
)
from monthly_reports.core import build_monthly_report
from monthly_reports.publishing import OpenpyxlWorkbookBuilder
@@ -57,6 +58,77 @@ def report_fixture():
)
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()
@@ -88,6 +160,31 @@ class MonthlyReportsXlsxTests(unittest.TestCase):
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()