Done but not really complete
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
"""Service for handling conversion data from hotel PMS XML files."""
|
||||
|
||||
import json
|
||||
import xml.etree.ElementTree as ET
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import or_, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from .db import Conversion, Customer, HashedCustomer, Reservation
|
||||
from .db import Conversion, RoomReservation, Customer, HashedCustomer, Reservation
|
||||
from .logging_config import get_logger
|
||||
|
||||
_LOGGER = get_logger(__name__)
|
||||
@@ -199,6 +201,48 @@ class ConversionService:
|
||||
)
|
||||
return stats
|
||||
|
||||
# Create Conversion entry first (once per PMS reservation)
|
||||
conversion = Conversion(
|
||||
# Links to existing entities (nullable)
|
||||
reservation_id=matched_reservation.id if matched_reservation else None,
|
||||
customer_id=matched_customer.id if matched_customer else None,
|
||||
hashed_customer_id=matched_hashed_customer.id
|
||||
if matched_hashed_customer
|
||||
else None,
|
||||
# Reservation metadata
|
||||
hotel_id=hotel_id,
|
||||
pms_reservation_id=pms_reservation_id,
|
||||
reservation_number=reservation_number,
|
||||
reservation_date=reservation_date,
|
||||
creation_time=creation_time,
|
||||
reservation_type=reservation_type,
|
||||
booking_channel=booking_channel,
|
||||
# Guest information
|
||||
guest_first_name=guest_first_name,
|
||||
guest_last_name=guest_last_name,
|
||||
guest_email=guest_email,
|
||||
guest_country_code=guest_country_code,
|
||||
# Advertising data
|
||||
advertising_medium=advertising_medium,
|
||||
advertising_partner=advertising_partner,
|
||||
advertising_campagne=advertising_campagne,
|
||||
# Metadata
|
||||
created_at=datetime.now(),
|
||||
updated_at=datetime.now(),
|
||||
)
|
||||
self.session.add(conversion)
|
||||
|
||||
# Update stats for the conversion record itself
|
||||
if matched_reservation:
|
||||
stats["matched_to_reservation"] += 1
|
||||
if matched_customer:
|
||||
stats["matched_to_customer"] += 1
|
||||
if matched_hashed_customer:
|
||||
stats["matched_to_hashed_customer"] += 1
|
||||
if not any([matched_reservation, matched_customer, matched_hashed_customer]):
|
||||
stats["unmatched"] += 1
|
||||
|
||||
# Process room reservations
|
||||
for room_reservation in room_reservations.findall("roomReservation"):
|
||||
# Extract room reservation details
|
||||
arrival_str = room_reservation.get("arrival")
|
||||
@@ -208,6 +252,7 @@ class ConversionService:
|
||||
room_number = room_reservation.get("roomNumber")
|
||||
adults_str = room_reservation.get("adults")
|
||||
rate_plan_code = room_reservation.get("ratePlanCode")
|
||||
connected_room_type = room_reservation.get("connectedRoomType")
|
||||
|
||||
arrival_date = None
|
||||
if arrival_str:
|
||||
@@ -232,53 +277,80 @@ class ConversionService:
|
||||
except ValueError:
|
||||
_LOGGER.warning("Invalid adults value: %s", adults_str)
|
||||
|
||||
# Process daily sales
|
||||
daily_sales = room_reservation.find("dailySales")
|
||||
if daily_sales is None:
|
||||
continue
|
||||
# Create composite ID for upsert: pms_reservation_id + room_number
|
||||
# This allows updating the same room reservation if it appears again
|
||||
pms_hotel_reservation_id = f"{pms_reservation_id}_{room_number}"
|
||||
|
||||
for daily_sale in daily_sales.findall("dailySale"):
|
||||
stats["daily_sales_count"] += 1
|
||||
# Process daily sales and extract total revenue
|
||||
daily_sales_elem = room_reservation.find("dailySales")
|
||||
daily_sales_list = []
|
||||
total_revenue = Decimal("0")
|
||||
|
||||
# Extract daily sale data
|
||||
sale_date_str = daily_sale.get("date")
|
||||
sale_date = None
|
||||
if sale_date_str:
|
||||
try:
|
||||
sale_date = datetime.strptime(
|
||||
sale_date_str, "%Y-%m-%d"
|
||||
).date()
|
||||
except ValueError:
|
||||
_LOGGER.warning("Invalid sale date format: %s", sale_date_str)
|
||||
if daily_sales_elem is not None:
|
||||
for daily_sale in daily_sales_elem.findall("dailySale"):
|
||||
stats["daily_sales_count"] += 1
|
||||
|
||||
# Create conversion record
|
||||
conversion = Conversion(
|
||||
# Links to existing entities (nullable)
|
||||
reservation_id=matched_reservation.id
|
||||
if matched_reservation
|
||||
else None,
|
||||
customer_id=matched_customer.id if matched_customer else None,
|
||||
hashed_customer_id=matched_hashed_customer.id
|
||||
if matched_hashed_customer
|
||||
else None,
|
||||
# Reservation metadata
|
||||
hotel_id=hotel_id,
|
||||
pms_reservation_id=pms_reservation_id,
|
||||
reservation_number=reservation_number,
|
||||
reservation_date=reservation_date,
|
||||
creation_time=creation_time,
|
||||
reservation_type=reservation_type,
|
||||
booking_channel=booking_channel,
|
||||
# Guest information
|
||||
guest_first_name=guest_first_name,
|
||||
guest_last_name=guest_last_name,
|
||||
guest_email=guest_email,
|
||||
guest_country_code=guest_country_code,
|
||||
# Advertising data
|
||||
advertising_medium=advertising_medium,
|
||||
advertising_partner=advertising_partner,
|
||||
advertising_campagne=advertising_campagne,
|
||||
# Room reservation details
|
||||
# Extract daily sale data
|
||||
sale_date_str = daily_sale.get("date")
|
||||
daily_sale_obj = {}
|
||||
|
||||
if sale_date_str:
|
||||
daily_sale_obj["date"] = sale_date_str
|
||||
|
||||
# Extract all revenue fields
|
||||
revenue_total_str = daily_sale.get("revenueTotal")
|
||||
if revenue_total_str:
|
||||
daily_sale_obj["revenueTotal"] = revenue_total_str
|
||||
try:
|
||||
total_revenue += Decimal(revenue_total_str)
|
||||
except (ValueError, TypeError):
|
||||
_LOGGER.warning(
|
||||
"Invalid revenueTotal value: %s", revenue_total_str
|
||||
)
|
||||
|
||||
# Add other revenue fields if present
|
||||
if daily_sale.get("revenueLogis"):
|
||||
daily_sale_obj["revenueLogis"] = daily_sale.get("revenueLogis")
|
||||
if daily_sale.get("revenueBoard"):
|
||||
daily_sale_obj["revenueBoard"] = daily_sale.get("revenueBoard")
|
||||
if daily_sale.get("revenueFB"):
|
||||
daily_sale_obj["revenueFB"] = daily_sale.get("revenueFB")
|
||||
if daily_sale.get("revenueSpa"):
|
||||
daily_sale_obj["revenueSpa"] = daily_sale.get("revenueSpa")
|
||||
if daily_sale.get("revenueOther"):
|
||||
daily_sale_obj["revenueOther"] = daily_sale.get("revenueOther")
|
||||
|
||||
if daily_sale_obj: # Only add if has data
|
||||
daily_sales_list.append(daily_sale_obj)
|
||||
|
||||
# Try to find existing room reservation for upsert
|
||||
existing_result = await self.session.execute(
|
||||
select(RoomReservation).where(
|
||||
RoomReservation.pms_hotel_reservation_id == pms_hotel_reservation_id
|
||||
)
|
||||
)
|
||||
existing_room_reservation = existing_result.scalar_one_or_none()
|
||||
|
||||
if existing_room_reservation:
|
||||
# Update existing room reservation
|
||||
existing_room_reservation.room_status = room_status
|
||||
existing_room_reservation.num_adults = num_adults
|
||||
existing_room_reservation.daily_sales = daily_sales_list if daily_sales_list else None
|
||||
existing_room_reservation.total_revenue = (
|
||||
str(total_revenue) if total_revenue > 0 else None
|
||||
)
|
||||
existing_room_reservation.updated_at = datetime.now()
|
||||
_LOGGER.debug(
|
||||
"Updated room reservation %s (pms_id=%s, room=%s)",
|
||||
existing_room_reservation.id,
|
||||
pms_reservation_id,
|
||||
room_number,
|
||||
)
|
||||
else:
|
||||
# Create new room reservation
|
||||
room_reservation_record = RoomReservation(
|
||||
conversion_id=conversion.id,
|
||||
pms_hotel_reservation_id=pms_hotel_reservation_id,
|
||||
arrival_date=arrival_date,
|
||||
departure_date=departure_date,
|
||||
room_status=room_status,
|
||||
@@ -286,31 +358,19 @@ class ConversionService:
|
||||
room_number=room_number,
|
||||
num_adults=num_adults,
|
||||
rate_plan_code=rate_plan_code,
|
||||
# Daily sale data
|
||||
sale_date=sale_date,
|
||||
revenue_total=daily_sale.get("revenueTotal"),
|
||||
revenue_logis=daily_sale.get("revenueLogis"),
|
||||
revenue_board=daily_sale.get("revenueBoard"),
|
||||
revenue_fb=daily_sale.get("revenueFB"),
|
||||
revenue_spa=daily_sale.get("revenueSpa"),
|
||||
revenue_other=daily_sale.get("revenueOther"),
|
||||
# Metadata
|
||||
connected_room_type=connected_room_type,
|
||||
daily_sales=daily_sales_list if daily_sales_list else None,
|
||||
total_revenue=str(total_revenue) if total_revenue > 0 else None,
|
||||
created_at=datetime.now(),
|
||||
updated_at=datetime.now(),
|
||||
)
|
||||
self.session.add(room_reservation_record)
|
||||
_LOGGER.debug(
|
||||
"Created room reservation (pms_id=%s, room=%s, adults=%s)",
|
||||
pms_reservation_id,
|
||||
room_number,
|
||||
num_adults,
|
||||
)
|
||||
|
||||
self.session.add(conversion)
|
||||
|
||||
# Update stats
|
||||
if matched_reservation:
|
||||
stats["matched_to_reservation"] += 1
|
||||
if matched_customer:
|
||||
stats["matched_to_customer"] += 1
|
||||
if matched_hashed_customer:
|
||||
stats["matched_to_hashed_customer"] += 1
|
||||
if not any(
|
||||
[matched_reservation, matched_customer, matched_hashed_customer]
|
||||
):
|
||||
stats["unmatched"] += 1
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
Reference in New Issue
Block a user