3 Commits

Author SHA1 Message Date
Jonas Linter
95b17b8776 I think acknowledgments work just fine now 2025-10-09 09:38:54 +02:00
Jonas Linter
1b3ebb3cad Mucking around with the tests 2025-10-09 09:29:01 +02:00
Jonas Linter
18d30a140f Fixed SelectionCriteria Filtering. Date wasn't added to pydantic model 2025-10-09 09:22:52 +02:00
4 changed files with 55 additions and 16 deletions

View File

@@ -1,7 +1,7 @@
import logging import logging
import traceback import traceback
from dataclasses import dataclass from dataclasses import dataclass
from datetime import UTC, datetime from datetime import UTC
from enum import Enum from enum import Enum
from typing import Any from typing import Any
@@ -786,7 +786,7 @@ def _process_single_reservation(
) )
hotel_reservation = HotelReservation( hotel_reservation = HotelReservation(
create_date_time=datetime.now(UTC).isoformat(), create_date_time=reservation.created_at.replace(tzinfo=UTC).isoformat(),
res_status=HotelReservationResStatus.REQUESTED, res_status=HotelReservationResStatus.REQUESTED,
room_stay_reservation="true", room_stay_reservation="true",
unique_id=unique_id, unique_id=unique_id,

View File

@@ -505,6 +505,9 @@ class ReadAction(AlpineBitsAction):
start_date = None start_date = None
"""When given, the server will send only inquiries generated after the Start timestamp, regardless
whether the client has retrieved them before or not."""
if hotel_read_request.selection_criteria is not None: if hotel_read_request.selection_criteria is not None:
start_date = datetime.fromisoformat( start_date = datetime.fromisoformat(
hotel_read_request.selection_criteria.start hotel_read_request.selection_criteria.start
@@ -518,7 +521,8 @@ class ReadAction(AlpineBitsAction):
.filter(Reservation.hotel_code == hotelid) .filter(Reservation.hotel_code == hotelid)
) )
if start_date: if start_date:
stmt = stmt.filter(Reservation.start_date >= start_date) _LOGGER.info("Filtering reservations from start date %s", start_date)
stmt = stmt.filter(Reservation.created_at >= start_date)
# remove reservations that have been acknowledged via client_id # remove reservations that have been acknowledged via client_id
elif client_info.client_id: elif client_info.client_id:
subquery = ( subquery = (

View File

@@ -10,7 +10,7 @@ from XML generation (xsdata) follows clean architecture principles.
""" """
import hashlib import hashlib
from datetime import date from datetime import date, datetime
from enum import Enum from enum import Enum
from pydantic import BaseModel, EmailStr, Field, field_validator, model_validator from pydantic import BaseModel, EmailStr, Field, field_validator, model_validator
@@ -43,6 +43,7 @@ class ReservationData(BaseModel):
md5_unique_id: str | None = Field(None, min_length=1, max_length=32) md5_unique_id: str | None = Field(None, min_length=1, max_length=32)
start_date: date start_date: date
end_date: date end_date: date
created_at: datetime = Field(default_factory=datetime.now)
num_adults: int = Field(..., ge=1) num_adults: int = Field(..., ge=1)
num_children: int = Field(0, ge=0, le=10) num_children: int = Field(0, ge=0, le=10)
children_ages: list[int] = Field(default_factory=list) children_ages: list[int] = Field(default_factory=list)

View File

@@ -91,7 +91,7 @@ def sample_reservation(sample_customer):
num_children=1, num_children=1,
children_ages=[8], children_ages=[8],
offer="Christmas Special", offer="Christmas Special",
created_at=datetime.now(UTC), created_at=datetime(2024, 11, 1, 12, 0, 0, tzinfo=UTC),
utm_source="google", utm_source="google",
utm_medium="cpc", utm_medium="cpc",
utm_campaign="winter2024", utm_campaign="winter2024",
@@ -109,8 +109,6 @@ def sample_reservation(sample_customer):
children_csv = ",".join(str(int(a)) for a in children_list) if children_list else "" children_csv = ",".join(str(int(a)) for a in children_list) if children_list else ""
data["children_ages"] = children_csv data["children_ages"] = children_csv
print(data)
return Reservation( return Reservation(
id=1, id=1,
customer_id=1, customer_id=1,
@@ -141,7 +139,7 @@ def minimal_reservation(minimal_customer):
num_children=0, num_children=0,
children_ages=[], children_ages=[],
hotel_code="HOTEL123", hotel_code="HOTEL123",
created_at=datetime.now(UTC), created_at=datetime(2024, 12, 2, 12, 0, 0, tzinfo=UTC),
hotel_name="Alpine Paradise Resort", hotel_name="Alpine Paradise Resort",
) )
@@ -169,7 +167,7 @@ def read_request_xml():
Version="8.000"> Version="8.000">
<ReadRequests> <ReadRequests>
<HotelReadRequest HotelCode="HOTEL123" HotelName="Alpine Paradise Resort"> <HotelReadRequest HotelCode="HOTEL123" HotelName="Alpine Paradise Resort">
<SelectionCriteria Start="2024-12-01" End="2025-01-31"/> <SelectionCriteria Start="2024-10-01" End="2025-01-31"/>
</HotelReadRequest> </HotelReadRequest>
</ReadRequests> </ReadRequests>
</OTA_ReadRQ>""" </OTA_ReadRQ>"""
@@ -334,7 +332,7 @@ class TestXMLParsing:
assert hotel_req.hotel_code == "HOTEL123" assert hotel_req.hotel_code == "HOTEL123"
assert hotel_req.hotel_name == "Alpine Paradise Resort" assert hotel_req.hotel_name == "Alpine Paradise Resort"
assert hotel_req.selection_criteria is not None assert hotel_req.selection_criteria is not None
assert hotel_req.selection_criteria.start == "2024-12-01" assert hotel_req.selection_criteria.start == "2024-10-01"
def test_parse_read_request_no_date(self, read_request_xml_no_date_filter): def test_parse_read_request_no_date(self, read_request_xml_no_date_filter):
"""Test parsing of OTA_ReadRQ without date filter.""" """Test parsing of OTA_ReadRQ without date filter."""
@@ -715,7 +713,11 @@ class TestAcknowledgments:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_acknowledgments_work_with_date_filters( async def test_acknowledgments_work_with_date_filters(
self, alpinebits_server, populated_db_session, client_info self,
alpinebits_server,
populated_db_session,
client_info,
read_request_xml_no_date_filter,
): ):
"""Test 5: Verify acknowledgments still work when SelectionCriteria date filters are applied.""" """Test 5: Verify acknowledgments still work when SelectionCriteria date filters are applied."""
# Read request with date filter # Read request with date filter
@@ -726,7 +728,7 @@ class TestAcknowledgments:
Version="8.000"> Version="8.000">
<ReadRequests> <ReadRequests>
<HotelReadRequest HotelCode="HOTEL123" HotelName="Alpine Paradise Resort"> <HotelReadRequest HotelCode="HOTEL123" HotelName="Alpine Paradise Resort">
<SelectionCriteria Start="2024-12-01" End="2025-02-01"/> <SelectionCriteria Start="2024-12-01"/>
</HotelReadRequest> </HotelReadRequest>
</ReadRequests> </ReadRequests>
</OTA_ReadRQ>""" </OTA_ReadRQ>"""
@@ -751,9 +753,14 @@ class TestAcknowledgments:
): ):
initial_count = len(initial_parsed.reservations_list.hotel_reservation) initial_count = len(initial_parsed.reservations_list.hotel_reservation)
assert initial_count > 0, "Initial count with date filter should be > 0"
assert initial_count == 1, (
"Should only return one reservation with this date filter"
)
# Acknowledge one reservation that falls within the date range # Acknowledge one reservation that falls within the date range
# The sample_reservation has dates 2024-12-25 to 2024-12-31, which should be in range # The sample_reservation was created at 2024-11-01 and thus falls out of range
sample_unique_id = "RES-2024-001" sample_unique_id = "RES-2024-002"
md5_hash = hashlib.md5(sample_unique_id.encode()).hexdigest() md5_hash = hashlib.md5(sample_unique_id.encode()).hexdigest()
acked_request = AckedRequest( acked_request = AckedRequest(
@@ -764,6 +771,31 @@ class TestAcknowledgments:
populated_db_session.add(acked_request) populated_db_session.add(acked_request)
await populated_db_session.commit() await populated_db_session.commit()
without_filter_read = await alpinebits_server.handle_request(
request_action_name="OTA_Read:GuestRequests",
request_xml=read_request_xml_no_date_filter,
client_info=client_info,
version="2024-10",
dbsession=populated_db_session,
)
without_filter_parsed = parser.from_string(
without_filter_read.xml_content, OtaResRetrieveRs
)
without_filter_count = 0
if (
without_filter_parsed.reservations_list
and without_filter_parsed.reservations_list.hotel_reservation
):
without_filter_count = len(
without_filter_parsed.reservations_list.hotel_reservation
)
assert without_filter_count == 1, (
"Without date filter, should return one reservation after acknowledgment"
)
# Second read with same date filter # Second read with same date filter
second_response = await alpinebits_server.handle_request( second_response = await alpinebits_server.handle_request(
request_action_name="OTA_Read:GuestRequests", request_action_name="OTA_Read:GuestRequests",
@@ -783,8 +815,10 @@ class TestAcknowledgments:
): ):
second_count = len(second_parsed.reservations_list.hotel_reservation) second_count = len(second_parsed.reservations_list.hotel_reservation)
# Should have fewer reservations even with date filter # Should have exactly the same amount of reservations
assert second_count < initial_count assert second_count == initial_count, (
"Acknowledgment should not affect count when date filter is applied"
)
if __name__ == "__main__": if __name__ == "__main__":