307 lines
8.8 KiB
Python
307 lines
8.8 KiB
Python
"""Privacy-safe five-company acceptance facts for the downstream processor."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
from typing import Dict, List
|
|
|
|
from company_reports.contracts import (
|
|
BatchSnapshot,
|
|
BookingRoomItem,
|
|
DailyVersionPin,
|
|
FinanceFact,
|
|
)
|
|
|
|
|
|
REPORT_YEAR = 2026
|
|
REPORT_MONTH = 7
|
|
AS_OF_DATE = date(2026, 7, 31)
|
|
|
|
|
|
def _fact(
|
|
record_id: int,
|
|
*,
|
|
business_date: date,
|
|
daily_version_id: int,
|
|
company_key: str,
|
|
channel_key: str,
|
|
group_code: str,
|
|
block_code: str,
|
|
arrival: date,
|
|
departure: date,
|
|
room_label: str,
|
|
total_price: str,
|
|
) -> FinanceFact:
|
|
return FinanceFact(
|
|
daily_record_id=record_id,
|
|
daily_version_id=daily_version_id,
|
|
business_date=business_date,
|
|
channel_key=channel_key,
|
|
company_key=company_key,
|
|
company_name=f"SYN-COMPANY-{company_key}",
|
|
block_code=block_code,
|
|
group_code_key=group_code,
|
|
res_comment=group_code,
|
|
room_category_label=room_label,
|
|
arrival=arrival,
|
|
departure=departure,
|
|
nights=(departure - arrival).days,
|
|
total_price=Decimal(total_price),
|
|
booking_source_match_status="matched",
|
|
)
|
|
|
|
|
|
def _room_item(
|
|
item_no: int,
|
|
*,
|
|
group_code: str,
|
|
parse_version_id: int,
|
|
segment_no: int,
|
|
arrival: date,
|
|
departure: date,
|
|
room_type: str,
|
|
quantity: int,
|
|
) -> BookingRoomItem:
|
|
return BookingRoomItem(
|
|
group_code_key=group_code,
|
|
parse_version_id=parse_version_id,
|
|
segment_no=segment_no,
|
|
arrival=arrival,
|
|
departure=departure,
|
|
nights=(departure - arrival).days,
|
|
item_no=item_no,
|
|
room_type_raw=room_type,
|
|
quantity=quantity,
|
|
)
|
|
|
|
|
|
def acceptance_snapshot() -> BatchSnapshot:
|
|
"""Return one synthetic month-end snapshot covering every accepted rule."""
|
|
|
|
facts: List[FinanceFact] = []
|
|
room_items: List[BookingRoomItem] = []
|
|
|
|
lt_arrival = date(2026, 7, 7)
|
|
lt_departure = date(2026, 7, 10)
|
|
for record_id, room_label, price, block_code in (
|
|
(101, "SYN-RM2", "900", "SYN-BLOCK-LT-A"),
|
|
(102, "SYN-RM2", "900", "SYN-BLOCK-LT-A"),
|
|
(103, "SYN-RM3", "3400", "SYN-BLOCK-LT-B"),
|
|
):
|
|
facts.append(
|
|
_fact(
|
|
record_id,
|
|
business_date=date(2026, 7, 8),
|
|
daily_version_id=1008,
|
|
company_key="LIAN TAI",
|
|
channel_key="SYN-CHANNEL-LT",
|
|
group_code="SYN-LT-0710",
|
|
block_code=block_code,
|
|
arrival=lt_arrival,
|
|
departure=lt_departure,
|
|
room_label=room_label,
|
|
total_price=price,
|
|
)
|
|
)
|
|
room_items.extend(
|
|
(
|
|
_room_item(
|
|
1,
|
|
group_code="SYN-LT-0710",
|
|
parse_version_id=7101,
|
|
segment_no=1,
|
|
arrival=lt_arrival,
|
|
departure=lt_departure,
|
|
room_type="SYN-SUP-TWN-BF",
|
|
quantity=2,
|
|
),
|
|
_room_item(
|
|
2,
|
|
group_code="SYN-LT-0710",
|
|
parse_version_id=7101,
|
|
segment_no=1,
|
|
arrival=lt_arrival,
|
|
departure=lt_departure,
|
|
room_type="SYN-SUP-TRP-BF",
|
|
quantity=1,
|
|
),
|
|
)
|
|
)
|
|
|
|
qbd_first_arrival = date(2026, 7, 7)
|
|
qbd_first_departure = date(2026, 7, 10)
|
|
for record_id, price in ((201, "900"), (202, "1800")):
|
|
facts.append(
|
|
_fact(
|
|
record_id,
|
|
business_date=date(2026, 7, 8),
|
|
daily_version_id=1008,
|
|
company_key="QBD",
|
|
channel_key="SYN-CHANNEL-QBD",
|
|
group_code="SYN-QBD-REPEAT",
|
|
block_code="SYN-BLOCK-QBD-A",
|
|
arrival=qbd_first_arrival,
|
|
departure=qbd_first_departure,
|
|
room_label="SYN-RM2",
|
|
total_price=price,
|
|
)
|
|
)
|
|
qbd_second_arrival = date(2026, 7, 17)
|
|
qbd_second_departure = date(2026, 7, 20)
|
|
for record_id in (203, 204, 205):
|
|
facts.append(
|
|
_fact(
|
|
record_id,
|
|
business_date=date(2026, 7, 18),
|
|
daily_version_id=1018,
|
|
company_key="QBD",
|
|
channel_key="SYN-CHANNEL-QBD",
|
|
group_code="SYN-QBD-REPEAT",
|
|
block_code="SYN-BLOCK-QBD-B",
|
|
arrival=qbd_second_arrival,
|
|
departure=qbd_second_departure,
|
|
room_label="SYN-RM2",
|
|
total_price="900",
|
|
)
|
|
)
|
|
room_items.extend(
|
|
(
|
|
_room_item(
|
|
1,
|
|
group_code="SYN-QBD-REPEAT",
|
|
parse_version_id=7201,
|
|
segment_no=1,
|
|
arrival=qbd_first_arrival,
|
|
departure=qbd_first_departure,
|
|
room_type="SYN-SUP-TWN-BF",
|
|
quantity=2,
|
|
),
|
|
_room_item(
|
|
1,
|
|
group_code="SYN-QBD-REPEAT",
|
|
parse_version_id=7201,
|
|
segment_no=2,
|
|
arrival=qbd_second_arrival,
|
|
departure=qbd_second_departure,
|
|
room_type="SYN-SUP-TWN-BF",
|
|
quantity=3,
|
|
),
|
|
)
|
|
)
|
|
|
|
dy_arrival = date(2026, 7, 18)
|
|
dy_departure = date(2026, 7, 20)
|
|
for record_id in (301, 302):
|
|
facts.append(
|
|
_fact(
|
|
record_id,
|
|
business_date=date(2026, 7, 18),
|
|
daily_version_id=1018,
|
|
company_key="SYN-UNMAPPED",
|
|
channel_key="DY-AI-EASY-KB",
|
|
group_code="SYN-DY-0720",
|
|
block_code="SYN-BLOCK-DY-A",
|
|
arrival=dy_arrival,
|
|
departure=dy_departure,
|
|
room_label="SYN-KB-RM",
|
|
total_price="800",
|
|
)
|
|
)
|
|
room_items.append(
|
|
_room_item(
|
|
1,
|
|
group_code="SYN-DY-0720",
|
|
parse_version_id=7301,
|
|
segment_no=1,
|
|
arrival=dy_arrival,
|
|
departure=dy_departure,
|
|
room_type="SYN-AI-EASY-TWN",
|
|
quantity=2,
|
|
)
|
|
)
|
|
|
|
fr_arrival = date(2026, 7, 27)
|
|
fr_departure = date(2026, 7, 31)
|
|
facts.append(
|
|
_fact(
|
|
401,
|
|
business_date=date(2026, 7, 28),
|
|
daily_version_id=1028,
|
|
company_key="FENGRUN",
|
|
channel_key="SYN-CHANNEL-FR",
|
|
group_code="SYN-FR-0731",
|
|
block_code="SYN-BLOCK-FR-A",
|
|
arrival=fr_arrival,
|
|
departure=fr_departure,
|
|
room_label="SYN-RM3",
|
|
total_price="3200",
|
|
)
|
|
)
|
|
room_items.append(
|
|
_room_item(
|
|
1,
|
|
group_code="SYN-FR-0731",
|
|
parse_version_id=7401,
|
|
segment_no=1,
|
|
arrival=fr_arrival,
|
|
departure=fr_departure,
|
|
room_type="SYN-SUP-TRP-BF",
|
|
quantity=1,
|
|
)
|
|
)
|
|
|
|
ht_arrival = date(2026, 7, 29)
|
|
ht_departure = date(2026, 7, 31)
|
|
for record_id in (501, 502):
|
|
facts.append(
|
|
_fact(
|
|
record_id,
|
|
business_date=date(2026, 7, 29),
|
|
daily_version_id=1029,
|
|
company_key="HANA TOUR",
|
|
channel_key="SYN-CHANNEL-HT",
|
|
group_code="SYN-HT-0731",
|
|
block_code="SYN-BLOCK-HT-A",
|
|
arrival=ht_arrival,
|
|
departure=ht_departure,
|
|
room_label="SYN-RM2",
|
|
total_price="1200",
|
|
)
|
|
)
|
|
room_items.append(
|
|
_room_item(
|
|
1,
|
|
group_code="SYN-HT-0731",
|
|
parse_version_id=7501,
|
|
segment_no=1,
|
|
arrival=ht_arrival,
|
|
departure=ht_departure,
|
|
room_type="SYN-SUP-TWN-BF",
|
|
quantity=2,
|
|
)
|
|
)
|
|
|
|
versions_by_date: Dict[date, int] = {}
|
|
for fact in facts:
|
|
existing = versions_by_date.get(fact.business_date)
|
|
if existing is not None and existing != fact.daily_version_id:
|
|
raise AssertionError("synthetic date has conflicting daily versions")
|
|
versions_by_date[fact.business_date] = fact.daily_version_id
|
|
|
|
return BatchSnapshot(
|
|
facts=tuple(facts),
|
|
room_items=tuple(room_items),
|
|
daily_versions=tuple(
|
|
DailyVersionPin(business_date, version_id)
|
|
for business_date, version_id in sorted(versions_by_date.items())
|
|
),
|
|
group_parse_versions={
|
|
"SYN-LT-0710": 7101,
|
|
"SYN-QBD-REPEAT": 7201,
|
|
"SYN-DY-0720": 7301,
|
|
"SYN-FR-0731": 7401,
|
|
"SYN-HT-0731": 7501,
|
|
},
|
|
)
|