from __future__ import annotations import unittest from booking_ingestion.excel import BookingExcelError from booking_ingestion.excel_review import ( BookingDraftItem, BookingDraftPage, BookingDraftSummary, validate_draft_id, validate_review_item_id, validate_review_item_ids, validate_review_quantity, validate_review_room_type, ) class BookingExcelReviewContractTests(unittest.TestCase): def test_review_inputs_are_strict_and_normalized(self) -> None: draft_id = "bookingdraft-" + "a" * 32 self.assertEqual(validate_draft_id(draft_id), draft_id) self.assertEqual(validate_review_item_id(7), 7) self.assertEqual(validate_review_item_ids([7, 8]), (7, 8)) self.assertEqual(validate_review_room_type(" U-TWN\nVIP "), "U-TWN VIP") self.assertEqual(validate_review_quantity(2), 2) for invalid in ("draft-1", "", None): with self.subTest(draft_id=invalid), self.assertRaises(BookingExcelError): validate_draft_id(invalid) for invalid in (True, 0, -1, "2"): with self.subTest(item_id=invalid), self.assertRaises(BookingExcelError): validate_review_item_id(invalid) for invalid in (None, [], [1, 1], [True], list(range(1, 52))): with self.subTest(item_ids=invalid), self.assertRaises(BookingExcelError): validate_review_item_ids(invalid) for invalid in (True, 0, 10_000, 1.5, "2"): with self.subTest(quantity=invalid), self.assertRaises(BookingExcelError): validate_review_quantity(invalid) def test_page_contract_exposes_review_state_without_hotel_detail(self) -> None: draft_id = "bookingdraft-" + "b" * 32 summary = BookingDraftSummary( draft_id=draft_id, filename="Booking.xlsx", status="reviewing", source_rows=1, worksheet_count=1, distinct_group_codes=1, extracted_items=1, confirmed_items=0, pending_items=1, deleted_items=0, confirmed_room_quantity=0, created_at=None, updated_at=None, ) item = BookingDraftItem( item_id=3, draft_id=draft_id, worksheet="Booking", row_no=9, item_no=1, tour_code="TOUR-1", room_type_raw="拼จU-4ค24", room_type_code=None, quantity=2, review_status="pending", automatic=False, source_fragment="【拼จU-4ค24】 2", updated_at=None, ) payload = BookingDraftPage(summary, (item,), 1, 50, 0).to_dict() self.assertEqual(payload["summary"]["pending_items"], 1) self.assertEqual(payload["items"][0]["tour_code"], "TOUR-1") self.assertIsNone(payload["items"][0]["room_type"]) self.assertEqual(payload["items"][0]["quantity"], 2) self.assertNotIn("hotel_raw", payload["items"][0]) if __name__ == "__main__": unittest.main(verbosity=2)