From 79ceb72d129b4a5b141f5f1471aa7066cab258ab Mon Sep 17 00:00:00 2001 From: Jonas Linter Date: Wed, 24 Sep 2025 15:28:55 +0200 Subject: [PATCH] Before simplifying the factory --- src/main.py | 35 ++-- src/output.xml | 2 +- src/simplified_access.py | 314 ++++++++++++++++++++++++--------- test/test_simplified_access.py | 126 ++++++++++++- 4 files changed, 374 insertions(+), 103 deletions(-) diff --git a/src/main.py b/src/main.py index c2a4ade..5261bc9 100644 --- a/src/main.py +++ b/src/main.py @@ -6,8 +6,14 @@ from datetime import datetime, timezone import re from xsdata_pydantic.bindings import XmlSerializer -from simplified_access import CustomerData, CustomerFactory, PhoneTechType, ResGuestFactory - +from simplified_access import ( + CustomerData, + CustomerFactory, + HotelReservationIdData, + HotelReservationIdFactory, + PhoneTechType, + ResGuestFactory, +) def main(): @@ -45,7 +51,7 @@ def main(): name_prefix="Mr.", phone_numbers=[ ("+1234567890", PhoneTechType.MOBILE), # Phone number with type - ("+0987654321", None) # Phone number without type + ("+0987654321", None), # Phone number without type ], email_address="john.doe@example.com", email_newsletter=True, @@ -56,23 +62,25 @@ def main(): address_catalog=False, gender="Male", birth_date="1980-01-01", - language="en" + language="en", ) - - res_guests = ResGuestFactory.create_retrieve_res_guests(customer_data) - - + hotel_res_id_data = HotelReservationIdData( + res_id_type="13", + res_id_value=None, + res_id_source=None, + res_id_source_context="99tales", + ) + # Create HotelReservationId using the factory + hotel_res_id = HotelReservationIdFactory.create_retrieve_hotel_reservation_id( + hotel_res_id_data + ) # Use the actual nested HotelReservationIds class hotel_res_ids = ab.OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.HotelReservationIds( - hotel_reservation_id = [ - ab.OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.HotelReservationIds.HotelReservationId( - res_id_type="13", res_id_source_context="99tales" - ) - ] + hotel_reservation_id=[hotel_res_id] ) # Basic property info @@ -146,7 +154,6 @@ def main(): parsed_result = parser.from_string(xml_content, ab.OtaResRetrieveRs) - print("✅ Round-trip validation successful!") print( f"Parsed reservation status: {parsed_result.reservations_list.hotel_reservation[0].res_status}" diff --git a/src/output.xml b/src/output.xml index a54d587..07c6ec7 100644 --- a/src/output.xml +++ b/src/output.xml @@ -1,7 +1,7 @@ - + diff --git a/src/simplified_access.py b/src/simplified_access.py index 336c53a..b0c73bc 100644 --- a/src/simplified_access.py +++ b/src/simplified_access.py @@ -10,6 +10,10 @@ from generated.alpinebits import OtaHotelResNotifRq, OtaResRetrieveRs NotifCustomer = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGuests.ResGuest.Profiles.ProfileInfo.Profile.Customer RetrieveCustomer = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGuests.ResGuest.Profiles.ProfileInfo.Profile.Customer +# Define type aliases for HotelReservationId types +NotifHotelReservationId = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGlobalInfo.HotelReservationIds.HotelReservationId +RetrieveHotelReservationId = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.HotelReservationIds.HotelReservationId + # phonetechtype enum 1,3,5 voice, fax, mobile class PhoneTechType(Enum): @@ -18,23 +22,28 @@ class PhoneTechType(Enum): MOBILE = "5" - - @dataclass class CustomerData: """Simple data class to hold customer information without nested type constraints.""" + given_name: str surname: str name_prefix: None | str = None name_title: None | str = None - phone_numbers: list[tuple[str, None | PhoneTechType]] = None # (phone_number, phone_tech_type) + phone_numbers: list[tuple[str, None | PhoneTechType]] = ( + None # (phone_number, phone_tech_type) + ) email_address: None | str = None - email_newsletter: None | bool = None # True for "yes", False for "no", None for not specified + email_newsletter: None | bool = ( + None # True for "yes", False for "no", None for not specified + ) address_line: None | str = None city_name: None | str = None postal_code: None | str = None country_code: None | str = None # Two-letter country code - address_catalog: None | bool = None # True for "yes", False for "no", None for not specified + address_catalog: None | bool = ( + None # True for "yes", False for "no", None for not specified + ) gender: None | str = None # "Unknown", "Male", "Female" birth_date: None | str = None language: None | str = None # Two-letter language code @@ -46,69 +55,70 @@ class CustomerData: class CustomerFactory: """Factory class to create Customer instances for both OtaHotelResNotifRq and OtaResRetrieveRs.""" - + @staticmethod def create_notif_customer(data: CustomerData) -> NotifCustomer: """Create a Customer for OtaHotelResNotifRq.""" return CustomerFactory._create_customer(NotifCustomer, data) - + @staticmethod def create_retrieve_customer(data: CustomerData) -> RetrieveCustomer: """Create a Customer for OtaResRetrieveRs.""" return CustomerFactory._create_customer(RetrieveCustomer, data) - + @staticmethod def _create_customer(customer_class: type, data: CustomerData) -> Any: """Internal method to create a customer of the specified type.""" - + # Create PersonName person_name = customer_class.PersonName( given_name=data.given_name, surname=data.surname, name_prefix=data.name_prefix, - name_title=data.name_title + name_title=data.name_title, ) - + # Create telephone list telephones = [] for phone_number, phone_tech_type in data.phone_numbers: telephone = customer_class.Telephone( phone_number=phone_number, - phone_tech_type=phone_tech_type.value if phone_tech_type else None + phone_tech_type=phone_tech_type.value if phone_tech_type else None, ) telephones.append(telephone) - + # Create email if provided email = None if data.email_address: remark = None if data.email_newsletter is not None: remark = f"newsletter:{'yes' if data.email_newsletter else 'no'}" - - email = customer_class.Email( - value=data.email_address, - remark=remark - ) - + + email = customer_class.Email(value=data.email_address, remark=remark) + # Create address if any address fields are provided address = None - if any([data.address_line, data.city_name, data.postal_code, data.country_code]): + if any( + [data.address_line, data.city_name, data.postal_code, data.country_code] + ): country_name = None if data.country_code: - country_name = customer_class.Address.CountryName(code=data.country_code) - + country_name = customer_class.Address.CountryName( + code=data.country_code + ) + address_remark = None if data.address_catalog is not None: address_remark = f"catalog:{'yes' if data.address_catalog else 'no'}" - + address = customer_class.Address( address_line=data.address_line, city_name=data.city_name, postal_code=data.postal_code, country_name=country_name, - remark=address_remark + remark=address_remark, ) - + # Create the customer return customer_class( person_name=person_name, @@ -117,29 +127,36 @@ class CustomerFactory: address=address, gender=data.gender, birth_date=data.birth_date, - language=data.language + language=data.language, ) @staticmethod def from_notif_customer(customer: NotifCustomer) -> CustomerData: """Convert a NotifCustomer back to CustomerData.""" return CustomerFactory._customer_to_data(customer) - + @staticmethod def from_retrieve_customer(customer: RetrieveCustomer) -> CustomerData: """Convert a RetrieveCustomer back to CustomerData.""" return CustomerFactory._customer_to_data(customer) - + @staticmethod def _customer_to_data(customer: Any) -> CustomerData: """Internal method to convert any customer type to CustomerData.""" - + # Extract phone numbers phone_numbers = [] if customer.telephone: for tel in customer.telephone: - phone_numbers.append((tel.phone_number, PhoneTechType(tel.phone_tech_type) if tel.phone_tech_type else None)) - + phone_numbers.append( + ( + tel.phone_number, + PhoneTechType(tel.phone_tech_type) + if tel.phone_tech_type + else None, + ) + ) + # Extract email info email_address = None email_newsletter = None @@ -150,28 +167,28 @@ class CustomerFactory: email_newsletter = True elif "newsletter:no" in customer.email.remark: email_newsletter = False - + # Extract address info address_line = None city_name = None postal_code = None country_code = None address_catalog = None - + if customer.address: address_line = customer.address.address_line city_name = customer.address.city_name postal_code = customer.address.postal_code - + if customer.address.country_name: country_code = customer.address.country_name.code - + if customer.address.remark: if "catalog:yes" in customer.address.remark: address_catalog = True elif "catalog:no" in customer.address.remark: address_catalog = False - + return CustomerData( given_name=customer.person_name.given_name, surname=customer.person_name.surname, @@ -187,7 +204,81 @@ class CustomerFactory: address_catalog=address_catalog, gender=customer.gender, birth_date=customer.birth_date, - language=customer.language + language=customer.language, + ) + + +@dataclass +class HotelReservationIdData: + """Simple data class to hold hotel reservation ID information without nested type constraints.""" + + res_id_type: str # Required field - pattern: [0-9]+ + res_id_value: None | str = None # Max 64 characters + res_id_source: None | str = None # Max 64 characters + res_id_source_context: None | str = None # Max 64 characters + + +class HotelReservationIdFactory: + """Factory class to create HotelReservationId instances for both OtaHotelResNotifRq and OtaResRetrieveRs.""" + + @staticmethod + def create_notif_hotel_reservation_id( + data: HotelReservationIdData, + ) -> NotifHotelReservationId: + """Create a HotelReservationId for OtaHotelResNotifRq.""" + return HotelReservationIdFactory._create_hotel_reservation_id( + NotifHotelReservationId, data + ) + + @staticmethod + def create_retrieve_hotel_reservation_id( + data: HotelReservationIdData, + ) -> RetrieveHotelReservationId: + """Create a HotelReservationId for OtaResRetrieveRs.""" + return HotelReservationIdFactory._create_hotel_reservation_id( + RetrieveHotelReservationId, data + ) + + @staticmethod + def _create_hotel_reservation_id( + hotel_reservation_id_class: type, data: HotelReservationIdData + ) -> Any: + """Internal method to create a hotel reservation id of the specified type.""" + return hotel_reservation_id_class( + res_id_type=data.res_id_type, + res_id_value=data.res_id_value, + res_id_source=data.res_id_source, + res_id_source_context=data.res_id_source_context, + ) + + @staticmethod + def from_notif_hotel_reservation_id( + hotel_reservation_id: NotifHotelReservationId, + ) -> HotelReservationIdData: + """Convert a NotifHotelReservationId back to HotelReservationIdData.""" + return HotelReservationIdFactory._hotel_reservation_id_to_data( + hotel_reservation_id + ) + + @staticmethod + def from_retrieve_hotel_reservation_id( + hotel_reservation_id: RetrieveHotelReservationId, + ) -> HotelReservationIdData: + """Convert a RetrieveHotelReservationId back to HotelReservationIdData.""" + return HotelReservationIdFactory._hotel_reservation_id_to_data( + hotel_reservation_id + ) + + @staticmethod + def _hotel_reservation_id_to_data( + hotel_reservation_id: Any, + ) -> HotelReservationIdData: + """Internal method to convert any hotel reservation id type to HotelReservationIdData.""" + return HotelReservationIdData( + res_id_type=hotel_reservation_id.res_id_type, + res_id_value=hotel_reservation_id.res_id_value, + res_id_source=hotel_reservation_id.res_id_source, + res_id_source_context=hotel_reservation_id.res_id_source_context, ) @@ -198,64 +289,56 @@ RetrieveResGuests = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGuests class ResGuestFactory: """Factory class to create complete ResGuests structures with a primary customer.""" - + @staticmethod def create_notif_res_guests(customer_data: CustomerData) -> NotifResGuests: """Create a complete ResGuests structure for OtaHotelResNotifRq with primary customer.""" return ResGuestFactory._create_res_guests( - NotifResGuests, - NotifCustomer, - customer_data + NotifResGuests, NotifCustomer, customer_data ) - + @staticmethod def create_retrieve_res_guests(customer_data: CustomerData) -> RetrieveResGuests: """Create a complete ResGuests structure for OtaResRetrieveRs with primary customer.""" return ResGuestFactory._create_res_guests( - RetrieveResGuests, - RetrieveCustomer, - customer_data + RetrieveResGuests, RetrieveCustomer, customer_data ) - + @staticmethod - def _create_res_guests(res_guests_class: type, customer_class: type, customer_data: CustomerData) -> Any: + def _create_res_guests( + res_guests_class: type, customer_class: type, customer_data: CustomerData + ) -> Any: """Internal method to create complete ResGuests structure.""" - + # Create the customer using the existing CustomerFactory customer = CustomerFactory._create_customer(customer_class, customer_data) - + # Create Profile with the customer profile = res_guests_class.ResGuest.Profiles.ProfileInfo.Profile( customer=customer ) - + # Create ProfileInfo with the profile - profile_info = res_guests_class.ResGuest.Profiles.ProfileInfo( - profile=profile - ) - + profile_info = res_guests_class.ResGuest.Profiles.ProfileInfo(profile=profile) + # Create Profiles with the profile_info - profiles = res_guests_class.ResGuest.Profiles( - profile_info=profile_info - ) - + profiles = res_guests_class.ResGuest.Profiles(profile_info=profile_info) + # Create ResGuest with the profiles - res_guest = res_guests_class.ResGuest( - profiles=profiles - ) - + res_guest = res_guests_class.ResGuest(profiles=profiles) + # Create ResGuests with the res_guest - return res_guests_class( - res_guest=res_guest - ) - + return res_guests_class(res_guest=res_guest) + @staticmethod - def extract_primary_customer(res_guests: Union[NotifResGuests, RetrieveResGuests]) -> CustomerData: + def extract_primary_customer( + res_guests: Union[NotifResGuests, RetrieveResGuests], + ) -> CustomerData: """Extract the primary customer data from a ResGuests structure.""" - + # Navigate down the nested structure to get the customer customer = res_guests.res_guest.profiles.profile_info.profile.customer - + # Use the existing CustomerFactory conversion method if isinstance(res_guests, NotifResGuests): return CustomerFactory.from_notif_customer(customer) @@ -272,7 +355,7 @@ if __name__ == "__main__": name_prefix="Mr.", phone_numbers=[ ("+1234567890", PhoneTechType.MOBILE), # Phone number with type - ("+0987654321", None) # Phone number without type + ("+0987654321", None), # Phone number without type ], email_address="john.doe@example.com", email_newsletter=True, @@ -283,39 +366,96 @@ if __name__ == "__main__": address_catalog=False, gender="Male", birth_date="1980-01-01", - language="en" + language="en", ) - + # Create customer for OtaHotelResNotifRq notif_customer = CustomerFactory.create_notif_customer(customer_data) - print("Created NotifCustomer:", notif_customer.person_name.given_name, notif_customer.person_name.surname) - + print( + "Created NotifCustomer:", + notif_customer.person_name.given_name, + notif_customer.person_name.surname, + ) + # Create customer for OtaResRetrieveRs retrieve_customer = CustomerFactory.create_retrieve_customer(customer_data) - print("Created RetrieveCustomer:", retrieve_customer.person_name.given_name, retrieve_customer.person_name.surname) - + print( + "Created RetrieveCustomer:", + retrieve_customer.person_name.given_name, + retrieve_customer.person_name.surname, + ) + # Convert back to data class converted_data = CustomerFactory.from_notif_customer(notif_customer) print("Converted back to data:", converted_data.given_name, converted_data.surname) - + # Verify they contain the same information print("Original and converted data match:", customer_data == converted_data) - + + print("\n--- HotelReservationIdFactory Examples ---") + + # Create hotel reservation ID data + reservation_id_data = HotelReservationIdData( + res_id_type="123", + res_id_value="RESERVATION-456", + res_id_source="HOTEL_SYSTEM", + res_id_source_context="BOOKING_ENGINE", + ) + + # Create HotelReservationId for both types + notif_res_id = HotelReservationIdFactory.create_notif_hotel_reservation_id( + reservation_id_data + ) + retrieve_res_id = HotelReservationIdFactory.create_retrieve_hotel_reservation_id( + reservation_id_data + ) + + print( + "Created NotifHotelReservationId:", + notif_res_id.res_id_type, + notif_res_id.res_id_value, + ) + print( + "Created RetrieveHotelReservationId:", + retrieve_res_id.res_id_type, + retrieve_res_id.res_id_value, + ) + + # Convert back to data class + converted_res_id_data = HotelReservationIdFactory.from_notif_hotel_reservation_id( + notif_res_id + ) + print( + "Converted back to reservation ID data:", + converted_res_id_data.res_id_type, + converted_res_id_data.res_id_value, + ) + + # Verify they contain the same information + print( + "Original and converted reservation ID data match:", + reservation_id_data == converted_res_id_data, + ) + print("\n--- ResGuestFactory Examples ---") - + # Create complete ResGuests structure for OtaHotelResNotifRq - much simpler! notif_res_guests = ResGuestFactory.create_notif_res_guests(customer_data) - print("Created NotifResGuests with customer:", - notif_res_guests.res_guest.profiles.profile_info.profile.customer.person_name.given_name) - + print( + "Created NotifResGuests with customer:", + notif_res_guests.res_guest.profiles.profile_info.profile.customer.person_name.given_name, + ) + # Create complete ResGuests structure for OtaResRetrieveRs - much simpler! retrieve_res_guests = ResGuestFactory.create_retrieve_res_guests(customer_data) - print("Created RetrieveResGuests with customer:", - retrieve_res_guests.res_guest.profiles.profile_info.profile.customer.person_name.given_name) - + print( + "Created RetrieveResGuests with customer:", + retrieve_res_guests.res_guest.profiles.profile_info.profile.customer.person_name.given_name, + ) + # Extract primary customer data back from ResGuests structure extracted_data = ResGuestFactory.extract_primary_customer(retrieve_res_guests) print("Extracted customer data:", extracted_data.given_name, extracted_data.surname) - + # Verify roundtrip conversion - print("Roundtrip conversion successful:", customer_data == extracted_data) \ No newline at end of file + print("Roundtrip conversion successful:", customer_data == extracted_data) diff --git a/test/test_simplified_access.py b/test/test_simplified_access.py index bda40e0..fa5853f 100644 --- a/test/test_simplified_access.py +++ b/test/test_simplified_access.py @@ -10,11 +10,15 @@ from simplified_access import ( CustomerData, CustomerFactory, ResGuestFactory, + HotelReservationIdData, + HotelReservationIdFactory, PhoneTechType, NotifCustomer, RetrieveCustomer, NotifResGuests, - RetrieveResGuests + RetrieveResGuests, + NotifHotelReservationId, + RetrieveHotelReservationId ) @@ -53,6 +57,25 @@ def minimal_customer_data(): ) +@pytest.fixture +def sample_hotel_reservation_id_data(): + """Fixture providing sample hotel reservation ID data for testing.""" + return HotelReservationIdData( + res_id_type="123", + res_id_value="RESERVATION-456", + res_id_source="HOTEL_SYSTEM", + res_id_source_context="BOOKING_ENGINE" + ) + + +@pytest.fixture +def minimal_hotel_reservation_id_data(): + """Fixture providing minimal hotel reservation ID data (only required fields).""" + return HotelReservationIdData( + res_id_type="999" + ) + + class TestCustomerData: """Test the CustomerData dataclass.""" @@ -213,6 +236,73 @@ class TestCustomerFactory: assert customer.telephone[2].phone_tech_type == "5" # MOBILE +class TestHotelReservationIdData: + """Test the HotelReservationIdData dataclass.""" + + def test_hotel_reservation_id_data_creation_full(self, sample_hotel_reservation_id_data): + """Test creating HotelReservationIdData with all fields.""" + assert sample_hotel_reservation_id_data.res_id_type == "123" + assert sample_hotel_reservation_id_data.res_id_value == "RESERVATION-456" + assert sample_hotel_reservation_id_data.res_id_source == "HOTEL_SYSTEM" + assert sample_hotel_reservation_id_data.res_id_source_context == "BOOKING_ENGINE" + + def test_hotel_reservation_id_data_creation_minimal(self, minimal_hotel_reservation_id_data): + """Test creating HotelReservationIdData with only required fields.""" + assert minimal_hotel_reservation_id_data.res_id_type == "999" + assert minimal_hotel_reservation_id_data.res_id_value is None + assert minimal_hotel_reservation_id_data.res_id_source is None + assert minimal_hotel_reservation_id_data.res_id_source_context is None + + +class TestHotelReservationIdFactory: + """Test the HotelReservationIdFactory class.""" + + def test_create_notif_hotel_reservation_id_full(self, sample_hotel_reservation_id_data): + """Test creating a NotifHotelReservationId with full data.""" + reservation_id = HotelReservationIdFactory.create_notif_hotel_reservation_id(sample_hotel_reservation_id_data) + + assert isinstance(reservation_id, NotifHotelReservationId) + assert reservation_id.res_id_type == "123" + assert reservation_id.res_id_value == "RESERVATION-456" + assert reservation_id.res_id_source == "HOTEL_SYSTEM" + assert reservation_id.res_id_source_context == "BOOKING_ENGINE" + + def test_create_retrieve_hotel_reservation_id_full(self, sample_hotel_reservation_id_data): + """Test creating a RetrieveHotelReservationId with full data.""" + reservation_id = HotelReservationIdFactory.create_retrieve_hotel_reservation_id(sample_hotel_reservation_id_data) + + assert isinstance(reservation_id, RetrieveHotelReservationId) + assert reservation_id.res_id_type == "123" + assert reservation_id.res_id_value == "RESERVATION-456" + assert reservation_id.res_id_source == "HOTEL_SYSTEM" + assert reservation_id.res_id_source_context == "BOOKING_ENGINE" + + def test_create_hotel_reservation_id_minimal(self, minimal_hotel_reservation_id_data): + """Test creating hotel reservation IDs with minimal data.""" + notif_reservation_id = HotelReservationIdFactory.create_notif_hotel_reservation_id(minimal_hotel_reservation_id_data) + retrieve_reservation_id = HotelReservationIdFactory.create_retrieve_hotel_reservation_id(minimal_hotel_reservation_id_data) + + for reservation_id in [notif_reservation_id, retrieve_reservation_id]: + assert reservation_id.res_id_type == "999" + assert reservation_id.res_id_value is None + assert reservation_id.res_id_source is None + assert reservation_id.res_id_source_context is None + + def test_from_notif_hotel_reservation_id_roundtrip(self, sample_hotel_reservation_id_data): + """Test converting NotifHotelReservationId back to HotelReservationIdData.""" + reservation_id = HotelReservationIdFactory.create_notif_hotel_reservation_id(sample_hotel_reservation_id_data) + converted_data = HotelReservationIdFactory.from_notif_hotel_reservation_id(reservation_id) + + assert converted_data == sample_hotel_reservation_id_data + + def test_from_retrieve_hotel_reservation_id_roundtrip(self, sample_hotel_reservation_id_data): + """Test converting RetrieveHotelReservationId back to HotelReservationIdData.""" + reservation_id = HotelReservationIdFactory.create_retrieve_hotel_reservation_id(sample_hotel_reservation_id_data) + converted_data = HotelReservationIdFactory.from_retrieve_hotel_reservation_id(reservation_id) + + assert converted_data == sample_hotel_reservation_id_data + + class TestResGuestFactory: """Test the ResGuestFactory class.""" @@ -313,6 +403,17 @@ class TestIntegration: assert retrieve_customer.person_name.given_name == retrieve_from_res_guests.person_name.given_name assert retrieve_customer.person_name.surname == retrieve_from_res_guests.person_name.surname + def test_hotel_reservation_id_factories_produce_same_data(self, sample_hotel_reservation_id_data): + """Test that both HotelReservationId factories produce equivalent results.""" + notif_reservation_id = HotelReservationIdFactory.create_notif_hotel_reservation_id(sample_hotel_reservation_id_data) + retrieve_reservation_id = HotelReservationIdFactory.create_retrieve_hotel_reservation_id(sample_hotel_reservation_id_data) + + # Both should have the same field values + assert notif_reservation_id.res_id_type == retrieve_reservation_id.res_id_type + assert notif_reservation_id.res_id_value == retrieve_reservation_id.res_id_value + assert notif_reservation_id.res_id_source == retrieve_reservation_id.res_id_source + assert notif_reservation_id.res_id_source_context == retrieve_reservation_id.res_id_source_context + def test_complex_customer_workflow(self): """Test a complex workflow with multiple operations.""" # Create original data @@ -342,6 +443,29 @@ class TestIntegration: notif_extracted = ResGuestFactory.extract_primary_customer(notif_res_guests) retrieve_extracted = ResGuestFactory.extract_primary_customer(retrieve_res_guests) + # All should be equal + assert original_data == notif_extracted + assert original_data == retrieve_extracted + assert notif_extracted == retrieve_extracted + + def test_complex_hotel_reservation_id_workflow(self): + """Test a complex workflow with HotelReservationId operations.""" + # Create original reservation ID data + original_data = HotelReservationIdData( + res_id_type="456", + res_id_value="COMPLEX-RESERVATION-789", + res_id_source="INTEGRATION_SYSTEM", + res_id_source_context="API_CALL" + ) + + # Create HotelReservationId for both types + notif_reservation_id = HotelReservationIdFactory.create_notif_hotel_reservation_id(original_data) + retrieve_reservation_id = HotelReservationIdFactory.create_retrieve_hotel_reservation_id(original_data) + + # Extract data back from both + notif_extracted = HotelReservationIdFactory.from_notif_hotel_reservation_id(notif_reservation_id) + retrieve_extracted = HotelReservationIdFactory.from_retrieve_hotel_reservation_id(retrieve_reservation_id) + # All should be equal assert original_data == notif_extracted assert original_data == retrieve_extracted