from __future__ import annotations import os import shutil import tempfile import unittest from pathlib import Path from company_reports.contracts import COMPANY_NAMES, REPORT_HEADERS, WarningCode from company_reports.core import build_all_company_reports from company_reports.publishing import ArtifactToolBuilder from tests.company_reports_acceptance_fixture import ( AS_OF_DATE, REPORT_MONTH, REPORT_YEAR, acceptance_snapshot, ) PROJECT_ROOT = Path(__file__).resolve().parents[1] BUILDER_SCRIPT = PROJECT_ROOT / "company_reports" / "xlsx" / "build_workbook.mjs" ARTIFACT_PACKAGE = ( PROJECT_ROOT / "company_reports" / "xlsx" / "node_modules" / "@oai" / "artifact-tool" ) def acceptance_reports(): return build_all_company_reports( REPORT_YEAR, REPORT_MONTH, AS_OF_DATE, acceptance_snapshot(), ) def artifact_tool_available() -> bool: configured = os.environ.get("COMPANY_REPORT_ARTIFACT_TOOL_MODULE", "").strip() return ARTIFACT_PACKAGE.exists() or bool(configured and Path(configured).is_file()) def node_binary() -> str: configured = os.environ.get("COMPANY_REPORT_NODE_BINARY", "").strip() return configured or shutil.which("node") or "" class CompanyReportAcceptanceCoreTests(unittest.TestCase): def test_all_five_companies_have_contract_complete_month_end_reports(self): reports = acceptance_reports() self.assertEqual(tuple(report.company for report in reports), COMPANY_NAMES) self.assertTrue(all(report.valid for report in reports)) self.assertTrue(all(len(report.periods) == 3 for report in reports)) self.assertTrue(all(all(period.active for period in report.periods) for report in reports)) self.assertTrue( all(report.to_workbook_payload()["headers"] == list(REPORT_HEADERS) for report in reports) ) self.assertEqual( {report.company: [len(period.rows) for period in report.periods] for report in reports}, { "LianTai": [1, 0, 0], "QBD": [1, 1, 0], "DY-AI-Easy-KB": [0, 1, 0], "FengRun": [0, 0, 1], "HanaTour": [0, 0, 1], }, ) self.assertEqual( {report.filename for report in reports}, {f"{company}-July-2026.xlsx" for company in COMPANY_NAMES}, ) def test_acceptance_rows_exercise_aggregation_duplicate_and_review_rules(self): reports = {report.company: report for report in acceptance_reports()} lian_tai = reports["LianTai"].periods[0].rows[0] self.assertEqual( lian_tai.booking_room, "【SYN-SUP-TWN-BF】2;【SYN-SUP-TRP-BF】1", ) self.assertEqual( lian_tai.total_booking_price, "【SYN-RM2】900×2 + 【SYN-RM3】3,400×1 = 5,200", ) qbd_report = reports["QBD"] qbd_rows = [row for period in qbd_report.periods for row in period.rows] self.assertEqual(len(qbd_rows), 2) self.assertTrue(all(row.duplicate_group for row in qbd_rows)) self.assertTrue(qbd_rows[0].multi_price_review) self.assertFalse(qbd_rows[1].multi_price_review) self.assertEqual( qbd_rows[0].total_booking_price, "【SYN-RM2】900×1 + 【SYN-RM2】1,800×1 = 2,700", ) self.assertEqual( [warning.code for warning in qbd_report.warnings], [WarningCode.MULTI_PRICE_REVIEW], ) dy_row = reports["DY-AI-Easy-KB"].periods[1].rows[0] self.assertEqual(dy_row.res_comment, "SYN-DY-0720") self.assertEqual(dy_row.departure.day, 20) @unittest.skipUnless(artifact_tool_available(), "artifact-tool dependency is not installed") class CompanyReportAcceptanceWorkbookTests(unittest.TestCase): def test_real_builder_exports_reopens_and_renders_all_five_workbooks(self): node = node_binary() if not node: self.skipTest("Node.js is unavailable") builder = ArtifactToolBuilder( BUILDER_SCRIPT, node_binary=node, timeout_seconds=180, ) with tempfile.TemporaryDirectory(prefix="company-report-acceptance-") as temp_dir: root = Path(temp_dir) for report in acceptance_reports(): with self.subTest(company=report.company): built = builder.build(report, root / report.company) self.assertTrue(built.path.is_file()) self.assertEqual(built.path.name, report.filename) self.assertEqual(built.summary["formula_count"], 0) self.assertEqual(built.summary["preview_count"], 3) self.assertEqual( built.summary["row_counts"], [len(period.rows) for period in report.periods], ) self.assertEqual( len(list((root / report.company / "previews").glob("sheet-*.png"))), 3, ) if __name__ == "__main__": unittest.main()