2 Commits

Author SHA1 Message Date
Jonas Linter
13e404d07c Only update updated_at timestamps if something actually changes. 2025-12-09 14:06:00 +01:00
Jonas Linter
c4bb9c524d Disabled free_rooms for main branch
The respective tests fail but that is too be expected
2025-12-09 12:36:08 +01:00
2 changed files with 59 additions and 22 deletions

View File

@@ -842,4 +842,4 @@ class AlpineBitsServer:
# Ensure FreeRoomsAction is registered with ServerCapabilities discovery
from .free_rooms_action import FreeRoomsAction
#from .free_rooms_action import FreeRoomsAction

View File

@@ -119,6 +119,28 @@ class ConversionService:
f"session must be AsyncSession or SessionMaker, got {type(session)}"
)
@staticmethod
def _update_timestamp_if_modified(
obj: Conversion | ConversionRoom, session: AsyncSession
) -> bool:
"""Update the updated_at timestamp only if the object has been modified.
Uses SQLAlchemy's change tracking to determine if any scalar attributes
have changed. Only updates the timestamp if actual changes were detected.
Args:
obj: The ORM object to check and potentially update
session: The session managing this object
Returns:
True if the object was modified and timestamp was updated, False otherwise
"""
if session.is_modified(obj, include_collections=False):
obj.updated_at = datetime.now()
return True
return False
@staticmethod
def _parse_required_int(value: str | None, field_name: str) -> int:
"""Parse an integer attribute that must be present."""
@@ -897,26 +919,39 @@ class ConversionService:
existing_conversion = existing_result.scalar_one_or_none()
if existing_conversion:
# Update existing conversion - only update reservation metadata and advertising data
# Update existing conversion using Pydantic validation
# Guest info is stored in ConversionGuest table, not here
# Don't clear reservation/customer links (matching logic will update if needed)
existing_conversion.reservation_number = (
parsed_reservation.reservation_number
# Preserve reservation/customer links (matching logic will update if needed)
conversion_data = ConversionData(
hotel_id=hotel_id,
pms_reservation_id=pms_reservation_id,
guest_id=parsed_reservation.guest_id,
reservation_number=parsed_reservation.reservation_number,
reservation_date=parsed_reservation.reservation_date,
creation_time=parsed_reservation.creation_time,
reservation_type=parsed_reservation.reservation_type,
booking_channel=parsed_reservation.booking_channel,
advertising_medium=parsed_reservation.advertising_medium,
advertising_partner=parsed_reservation.advertising_partner,
advertising_campagne=parsed_reservation.advertising_campagne,
# Preserve existing values (managed separately)
created_at=existing_conversion.created_at,
reservation_id=existing_conversion.reservation_id,
customer_id=existing_conversion.customer_id,
directly_attributable=existing_conversion.directly_attributable,
guest_matched=existing_conversion.guest_matched,
)
existing_conversion.reservation_date = parsed_reservation.reservation_date
existing_conversion.creation_time = parsed_reservation.creation_time
existing_conversion.reservation_type = parsed_reservation.reservation_type
existing_conversion.booking_channel = parsed_reservation.booking_channel
existing_conversion.advertising_medium = (
parsed_reservation.advertising_medium
# Apply validated data, excluding managed fields
validated_dict = conversion_data.model_dump(
exclude={'created_at', 'updated_at', 'reservation_id', 'customer_id',
'directly_attributable', 'guest_matched'}
)
existing_conversion.advertising_partner = (
parsed_reservation.advertising_partner
)
existing_conversion.advertising_campagne = (
parsed_reservation.advertising_campagne
)
existing_conversion.updated_at = datetime.now()
for key, value in validated_dict.items():
setattr(existing_conversion, key, value)
# Only update timestamp if something actually changed
self._update_timestamp_if_modified(existing_conversion, session)
conversion = existing_conversion
_LOGGER.debug(
"Updated conversion %s (pms_id=%s)",
@@ -998,7 +1033,8 @@ class ConversionService:
else None
)
existing_room_reservation.total_revenue = room_reservation.total_revenue
existing_room_reservation.updated_at = datetime.now()
# Only update timestamp if something actually changed
self._update_timestamp_if_modified(existing_room_reservation, session)
_LOGGER.debug(
"Updated room reservation %s (pms_id=%s, room=%s)",
existing_room_reservation.id,
@@ -1358,8 +1394,8 @@ class ConversionService:
# ID-based matches are always directly attributable
conversion.directly_attributable = True
conversion.guest_matched = False
conversion.updated_at = datetime.now()
# Only update timestamp if something actually changed
self._update_timestamp_if_modified(conversion, session)
# Update stats if provided
if stats is not None:
@@ -1506,7 +1542,8 @@ class ConversionService:
elif conversion.reservation_id is None:
conversion.directly_attributable = False
conversion.updated_at = datetime.now()
# Only update timestamp if something actually changed
self._update_timestamp_if_modified(conversion, session)
return matched_reservation, matched_customer