Small db improvements. Still needs migration for alembic
This commit is contained in:
@@ -37,7 +37,7 @@ class ConversionService:
|
|||||||
2. Concurrent mode: SessionMaker passed in, creates independent sessions per task
|
2. Concurrent mode: SessionMaker passed in, creates independent sessions per task
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, session: AsyncSession | SessionMaker | None = None):
|
def __init__(self, session: AsyncSession | SessionMaker | None = None, hotel_id: str | None = None):
|
||||||
"""Initialize the ConversionService.
|
"""Initialize the ConversionService.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -45,11 +45,13 @@ class ConversionService:
|
|||||||
- AsyncSession: Single session for sequential processing
|
- AsyncSession: Single session for sequential processing
|
||||||
- SessionMaker: Factory for creating sessions in concurrent mode
|
- SessionMaker: Factory for creating sessions in concurrent mode
|
||||||
- None: Not recommended, but allowed for subclassing
|
- None: Not recommended, but allowed for subclassing
|
||||||
|
hotel_id: Hotel ID for this conversion service context (from authenticated user)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.session = None
|
self.session = None
|
||||||
self.session_maker = None
|
self.session_maker = None
|
||||||
self.supports_concurrent = False
|
self.supports_concurrent = False
|
||||||
|
self.hotel_id = hotel_id
|
||||||
|
|
||||||
# Cache for reservation and customer data within a single XML processing run
|
# Cache for reservation and customer data within a single XML processing run
|
||||||
# Maps hotel_code -> list of (reservation, hashed_customer) tuples
|
# Maps hotel_code -> list of (reservation, hashed_customer) tuples
|
||||||
@@ -248,8 +250,12 @@ class ConversionService:
|
|||||||
# Process deleted reservations
|
# Process deleted reservations
|
||||||
for deleted_res in root.findall("Deletedreservation"):
|
for deleted_res in root.findall("Deletedreservation"):
|
||||||
stats["deleted_reservations"] += 1
|
stats["deleted_reservations"] += 1
|
||||||
pms_reservation_id = deleted_res.get("ID")
|
pms_reservation_id_str = deleted_res.get("ID")
|
||||||
try:
|
try:
|
||||||
|
pms_reservation_id = int(pms_reservation_id_str) if pms_reservation_id_str else None
|
||||||
|
if pms_reservation_id is None:
|
||||||
|
_LOGGER.warning("Deleted reservation missing ID attribute, skipping")
|
||||||
|
continue
|
||||||
await self._handle_deleted_reservation(pms_reservation_id, session)
|
await self._handle_deleted_reservation(pms_reservation_id, session)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -552,7 +558,7 @@ class ConversionService:
|
|||||||
await session.close()
|
await session.close()
|
||||||
|
|
||||||
async def _handle_deleted_reservation(
|
async def _handle_deleted_reservation(
|
||||||
self, pms_reservation_id: str, session: AsyncSession
|
self, pms_reservation_id: int, session: AsyncSession
|
||||||
):
|
):
|
||||||
"""Handle deleted reservation by marking conversions as deleted or removing them.
|
"""Handle deleted reservation by marking conversions as deleted or removing them.
|
||||||
|
|
||||||
@@ -561,13 +567,16 @@ class ConversionService:
|
|||||||
session: AsyncSession to use for the operation
|
session: AsyncSession to use for the operation
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# For now, we'll just log it. You could add a 'deleted' flag to the Conversion table
|
if not self.hotel_id:
|
||||||
# or actually delete the conversion records
|
_LOGGER.error("Cannot delete reservation: hotel_id not set in ConversionService")
|
||||||
_LOGGER.info("Processing deleted reservation: PMS ID %s", pms_reservation_id)
|
return
|
||||||
|
|
||||||
# Option 1: Delete conversion records
|
_LOGGER.info("Processing deleted reservation: Hotel %s, PMS ID %s", self.hotel_id, pms_reservation_id)
|
||||||
|
|
||||||
|
# Delete conversion records for this hotel + pms_reservation_id
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
select(Conversion).where(
|
select(Conversion).where(
|
||||||
|
Conversion.hotel_id == self.hotel_id,
|
||||||
Conversion.pms_reservation_id == pms_reservation_id
|
Conversion.pms_reservation_id == pms_reservation_id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -578,8 +587,9 @@ class ConversionService:
|
|||||||
|
|
||||||
if conversions:
|
if conversions:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"Deleted %d conversion records for PMS reservation %s",
|
"Deleted %d conversion records for hotel %s, PMS reservation %s",
|
||||||
len(conversions),
|
len(conversions),
|
||||||
|
self.hotel_id,
|
||||||
pms_reservation_id,
|
pms_reservation_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -673,6 +683,7 @@ class ConversionService:
|
|||||||
# Check if conversion already exists (upsert logic)
|
# Check if conversion already exists (upsert logic)
|
||||||
existing_result = await session.execute(
|
existing_result = await session.execute(
|
||||||
select(Conversion).where(
|
select(Conversion).where(
|
||||||
|
Conversion.hotel_id == hotel_id,
|
||||||
Conversion.pms_reservation_id == pms_reservation_id
|
Conversion.pms_reservation_id == pms_reservation_id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -1498,7 +1509,7 @@ class ConversionService:
|
|||||||
|
|
||||||
async def _match_conversion_using_db_data(
|
async def _match_conversion_using_db_data(
|
||||||
self,
|
self,
|
||||||
pms_reservation_id: str,
|
pms_reservation_id: int,
|
||||||
session: AsyncSession | None = None,
|
session: AsyncSession | None = None,
|
||||||
stats: dict[str, int] | None = None,
|
stats: dict[str, int] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -1521,10 +1532,17 @@ class ConversionService:
|
|||||||
if session is None:
|
if session is None:
|
||||||
session = self.session
|
session = self.session
|
||||||
|
|
||||||
|
if not self.hotel_id:
|
||||||
|
_LOGGER.error("Cannot match conversion: hotel_id not set in ConversionService")
|
||||||
|
return
|
||||||
|
|
||||||
# Get the conversion from the database with related data
|
# Get the conversion from the database with related data
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
select(Conversion)
|
select(Conversion)
|
||||||
.where(Conversion.pms_reservation_id == pms_reservation_id)
|
.where(
|
||||||
|
Conversion.hotel_id == self.hotel_id,
|
||||||
|
Conversion.pms_reservation_id == pms_reservation_id
|
||||||
|
)
|
||||||
.options(selectinload(Conversion.guest), selectinload(Conversion.conversion_rooms))
|
.options(selectinload(Conversion.guest), selectinload(Conversion.conversion_rooms))
|
||||||
)
|
)
|
||||||
conversion = result.scalar_one_or_none()
|
conversion = result.scalar_one_or_none()
|
||||||
|
|||||||
@@ -383,8 +383,8 @@ class ConversionGuest(Base):
|
|||||||
__tablename__ = "conversion_guests"
|
__tablename__ = "conversion_guests"
|
||||||
|
|
||||||
# Natural keys from PMS - composite primary key
|
# Natural keys from PMS - composite primary key
|
||||||
hotel_id = Column(String, nullable=False, primary_key=True, index=True)
|
hotel_id = Column(String(50), ForeignKey("hotels.hotel_id", ondelete="CASCADE"), nullable=False, primary_key=True, index=True)
|
||||||
guest_id = Column(String, nullable=False, primary_key=True, index=True)
|
guest_id = Column(Integer, nullable=False, primary_key=True, index=True)
|
||||||
|
|
||||||
# Unhashed guest information (for reference/transition period)
|
# Unhashed guest information (for reference/transition period)
|
||||||
guest_first_name = Column(String)
|
guest_first_name = Column(String)
|
||||||
@@ -578,9 +578,10 @@ class Conversion(Base):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Reservation metadata from XML
|
# Reservation metadata from XML
|
||||||
hotel_id = Column(String, index=True) # hotelID attribute
|
hotel_id = Column(String(50), ForeignKey("hotels.hotel_id", ondelete="CASCADE"), nullable=False, index=True) # hotelID attribute
|
||||||
guest_id = Column(String, nullable=True, index=True) # PMS guest ID, FK to conversion_guests
|
pms_reservation_id = Column(Integer, nullable=False, index=True) # id attribute from reservation
|
||||||
pms_reservation_id = Column(String, index=True) # id attribute from reservation
|
guest_id = Column(Integer, nullable=True, index=True) # PMS guest ID, FK to conversion_guests
|
||||||
|
|
||||||
reservation_number = Column(String) # number attribute
|
reservation_number = Column(String) # number attribute
|
||||||
reservation_date = Column(Date) # date attribute (when reservation was made)
|
reservation_date = Column(Date) # date attribute (when reservation was made)
|
||||||
creation_time = Column(DateTime(timezone=True)) # creationTime attribute
|
creation_time = Column(DateTime(timezone=True)) # creationTime attribute
|
||||||
@@ -616,6 +617,7 @@ class Conversion(Base):
|
|||||||
["conversion_guests.hotel_id", "conversion_guests.guest_id"],
|
["conversion_guests.hotel_id", "conversion_guests.guest_id"],
|
||||||
ondelete="SET NULL",
|
ondelete="SET NULL",
|
||||||
),
|
),
|
||||||
|
UniqueConstraint("hotel_id", "pms_reservation_id", name="uq_conversion_hotel_reservation"),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Relationships
|
# Relationships
|
||||||
|
|||||||
Reference in New Issue
Block a user