Fixed removing hashed_customer
This commit is contained in:
@@ -471,7 +471,6 @@ class ConversionService:
|
|||||||
"total_daily_sales": 0,
|
"total_daily_sales": 0,
|
||||||
"matched_to_reservation": 0,
|
"matched_to_reservation": 0,
|
||||||
"matched_to_customer": 0,
|
"matched_to_customer": 0,
|
||||||
"matched_to_hashed_customer": 0,
|
|
||||||
"unmatched": 0,
|
"unmatched": 0,
|
||||||
"errors": 0,
|
"errors": 0,
|
||||||
}
|
}
|
||||||
@@ -1471,41 +1470,40 @@ class ConversionService:
|
|||||||
session: AsyncSession for database queries
|
session: AsyncSession for database queries
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Get all ConversionGuests that have ANY customer link
|
# Collect every guest/customer pair derived from conversions.
|
||||||
# This includes:
|
|
||||||
# 1. Guests matched via guest-details (hashed_customer_id is not null)
|
|
||||||
# 2. Guests matched via ID-based matching (customer_id is not null via conversion)
|
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
select(ConversionGuest).where(
|
select(Conversion.guest_id, Conversion.customer_id).where(
|
||||||
ConversionGuest.hashed_customer_id.isnot(None)
|
Conversion.guest_id.isnot(None), Conversion.customer_id.isnot(None)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
matched_guests = result.scalars().all()
|
guest_customer_rows = result.all()
|
||||||
|
|
||||||
if not matched_guests:
|
if not guest_customer_rows:
|
||||||
_LOGGER.debug("Phase 3d: No matched guests to check for regularity")
|
_LOGGER.debug("Phase 3d: No matched guests to check for regularity")
|
||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug(
|
# Deduplicate by guest_id to avoid recalculating when multiple conversions share the same guest.
|
||||||
"Phase 3d: Checking regularity for %d matched guests", len(matched_guests)
|
guest_to_customer: dict[int, int] = {}
|
||||||
)
|
for guest_id, customer_id in guest_customer_rows:
|
||||||
|
if guest_id is None or customer_id is None:
|
||||||
for conversion_guest in matched_guests:
|
|
||||||
if not conversion_guest.hashed_customer_id:
|
|
||||||
continue
|
continue
|
||||||
|
if guest_id not in guest_to_customer:
|
||||||
|
guest_to_customer[guest_id] = customer_id
|
||||||
|
elif guest_to_customer[guest_id] != customer_id:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Guest %s linked to multiple customers (%s, %s); keeping first match",
|
||||||
|
guest_id,
|
||||||
|
guest_to_customer[guest_id],
|
||||||
|
customer_id,
|
||||||
|
)
|
||||||
|
|
||||||
# Get the customer ID from the hashed_customer
|
_LOGGER.debug(
|
||||||
hashed_customer_result = await session.execute(
|
"Phase 3d: Checking regularity for %d matched guests",
|
||||||
select(Customer).where(
|
len(guest_to_customer),
|
||||||
Customer.id == conversion_guest.hashed_customer_id
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
hashed_customer = hashed_customer_result.scalar_one_or_none()
|
|
||||||
|
|
||||||
if hashed_customer and hashed_customer.id:
|
for guest_id, customer_id in guest_to_customer.items():
|
||||||
await self._check_if_guest_is_regular(
|
await self._check_if_guest_is_regular(guest_id, customer_id, session)
|
||||||
conversion_guest.guest_id, hashed_customer.id, session
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _match_conversions_from_db_sequential(
|
async def _match_conversions_from_db_sequential(
|
||||||
self, pms_reservation_ids: list[str], stats: dict[str, int]
|
self, pms_reservation_ids: list[str], stats: dict[str, int]
|
||||||
@@ -1721,7 +1719,6 @@ class ConversionService:
|
|||||||
# Guest detail matching is deferred to Phase 3b/3c
|
# Guest detail matching is deferred to Phase 3b/3c
|
||||||
matched_reservation = None
|
matched_reservation = None
|
||||||
matched_customer = None
|
matched_customer = None
|
||||||
matched_hashed_customer = None
|
|
||||||
|
|
||||||
if conversion.advertising_campagne:
|
if conversion.advertising_campagne:
|
||||||
matched_reservation = await self._match_by_advertising(
|
matched_reservation = await self._match_by_advertising(
|
||||||
@@ -1755,10 +1752,6 @@ class ConversionService:
|
|||||||
conversion.directly_attributable = True
|
conversion.directly_attributable = True
|
||||||
conversion.guest_matched = False
|
conversion.guest_matched = False
|
||||||
|
|
||||||
# Update conversion_guest with hashed_customer reference if matched
|
|
||||||
if conversion_guest and matched_hashed_customer:
|
|
||||||
conversion_guest.hashed_customer_id = matched_hashed_customer.id
|
|
||||||
|
|
||||||
conversion.updated_at = datetime.now()
|
conversion.updated_at = datetime.now()
|
||||||
|
|
||||||
# Update stats if provided
|
# Update stats if provided
|
||||||
@@ -1767,8 +1760,6 @@ class ConversionService:
|
|||||||
stats["matched_to_reservation"] += 1
|
stats["matched_to_reservation"] += 1
|
||||||
elif matched_customer:
|
elif matched_customer:
|
||||||
stats["matched_to_customer"] += 1
|
stats["matched_to_customer"] += 1
|
||||||
elif matched_hashed_customer:
|
|
||||||
stats["matched_to_hashed_customer"] += 1
|
|
||||||
else:
|
else:
|
||||||
stats["unmatched"] += 1
|
stats["unmatched"] += 1
|
||||||
|
|
||||||
|
|||||||
@@ -562,7 +562,6 @@ class ConversionData(BaseModel):
|
|||||||
# Foreign key references (nullable - matched after creation)
|
# Foreign key references (nullable - matched after creation)
|
||||||
reservation_id: int | None = Field(None, gt=0)
|
reservation_id: int | None = Field(None, gt=0)
|
||||||
customer_id: int | None = Field(None, gt=0)
|
customer_id: int | None = Field(None, gt=0)
|
||||||
hashed_customer_id: int | None = Field(None, gt=0)
|
|
||||||
|
|
||||||
# Required reservation metadata from PMS
|
# Required reservation metadata from PMS
|
||||||
hotel_id: str = Field(..., min_length=1, max_length=50)
|
hotel_id: str = Field(..., min_length=1, max_length=50)
|
||||||
@@ -591,7 +590,7 @@ class ConversionData(BaseModel):
|
|||||||
|
|
||||||
@field_validator(
|
@field_validator(
|
||||||
"pms_reservation_id", "guest_id", "reservation_id", "customer_id",
|
"pms_reservation_id", "guest_id", "reservation_id", "customer_id",
|
||||||
"hashed_customer_id", mode="before"
|
mode="before"
|
||||||
)
|
)
|
||||||
@classmethod
|
@classmethod
|
||||||
def convert_int_fields(cls, v: Any) -> int | None:
|
def convert_int_fields(cls, v: Any) -> int | None:
|
||||||
|
|||||||
Reference in New Issue
Block a user