diff --git a/src/main.py b/src/main.py index dc2a61b..e817df3 100644 --- a/src/main.py +++ b/src/main.py @@ -7,7 +7,11 @@ import re from xsdata_pydantic.bindings import XmlSerializer from simplified_access import ( + CommentData, + CommentsData, + CommentListItemData, CustomerData, + HotelReservationIdData, PhoneTechType, AlpineBitsFactory, @@ -87,10 +91,35 @@ def main(): hotel_code="123", hotel_name="Frangart Inn" ) + comment = CommentData( + name= ab.CommentName2.CUSTOMER_COMMENT, + text="This is a sample comment.", + list_items=[CommentListItemData( + value="Landing page comment", + language="en", + list_item="1", + )], + + + ) + + comment2 = CommentData( + name= ab.CommentName2.ADDITIONAL_INFO, + text="This is a special request comment.", + + ) + + comments_data = CommentsData(comments=[comment, comment2]) + + + comments = alpine_bits_factory.create(comments_data, OtaMessageType.RETRIEVE) + + + # ResGlobalInfo res_global_info = ( ab.OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo( - hotel_reservation_ids=hotel_res_ids, basic_property_info=basic_property_info + hotel_reservation_ids=hotel_res_ids, basic_property_info=basic_property_info, comments=comments ) ) diff --git a/src/output.xml b/src/output.xml index 7652092..3ff5871 100644 --- a/src/output.xml +++ b/src/output.xml @@ -1,7 +1,7 @@ - + @@ -37,6 +37,15 @@ + + + Landing page comment + This is a sample comment. + + + This is a special request comment. + + diff --git a/src/simplified_access.py b/src/simplified_access.py index 6f8f0bd..eac901c 100644 --- a/src/simplified_access.py +++ b/src/simplified_access.py @@ -4,7 +4,7 @@ from dataclasses import dataclass from enum import Enum # Import the generated classes -from generated.alpinebits import OtaHotelResNotifRq, OtaResRetrieveRs +from generated.alpinebits import OtaHotelResNotifRq, OtaResRetrieveRs, CommentName2 # Define type aliases for the two Customer types NotifCustomer = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGuests.ResGuest.Profiles.ProfileInfo.Profile.Customer @@ -14,6 +14,12 @@ RetrieveCustomer = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGuests. NotifHotelReservationId = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGlobalInfo.HotelReservationIds.HotelReservationId RetrieveHotelReservationId = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.HotelReservationIds.HotelReservationId +# Define type aliases for Comments types +NotifComments = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGlobalInfo.Comments +RetrieveComments = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.Comments +NotifComment = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGlobalInfo.Comments.Comment +RetrieveComment = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.Comments.Comment + # phonetechtype enum 1,3,5 voice, fax, mobile class PhoneTechType(Enum): @@ -288,6 +294,113 @@ class HotelReservationIdFactory: ) +@dataclass +class CommentListItemData: + """Simple data class to hold comment list item information.""" + value: str # The text content of the list item + list_item: str # Numeric identifier (pattern: [0-9]+) + language: str # Two-letter language code (pattern: [a-z][a-z]) + + +@dataclass +class CommentData: + """Simple data class to hold comment information without nested type constraints.""" + name: CommentName2 # Required: "included services", "customer comment", "additional info" + text: Optional[str] = None # Optional text content + list_items: list[CommentListItemData] = None # Optional list items + + def __post_init__(self): + if self.list_items is None: + self.list_items = [] + + +@dataclass +class CommentsData: + """Simple data class to hold multiple comments (1-3 max).""" + comments: list[CommentData] = None # 1-3 comments maximum + + def __post_init__(self): + if self.comments is None: + self.comments = [] + + +class CommentFactory: + """Factory class to create Comment instances for both OtaHotelResNotifRq and OtaResRetrieveRs.""" + + @staticmethod + def create_notif_comments(data: CommentsData) -> NotifComments: + """Create Comments for OtaHotelResNotifRq.""" + return CommentFactory._create_comments(NotifComments, NotifComment, data) + + @staticmethod + def create_retrieve_comments(data: CommentsData) -> RetrieveComments: + """Create Comments for OtaResRetrieveRs.""" + return CommentFactory._create_comments(RetrieveComments, RetrieveComment, data) + + @staticmethod + def _create_comments(comments_class: type, comment_class: type, data: CommentsData) -> Any: + """Internal method to create comments of the specified type.""" + + comments_list = [] + for comment_data in data.comments: + # Create list items + list_items = [] + for item_data in comment_data.list_items: + list_item = comment_class.ListItem( + value=item_data.value, + list_item=item_data.list_item, + language=item_data.language + ) + list_items.append(list_item) + + # Create comment + comment = comment_class( + name=comment_data.name, + text=comment_data.text, + list_item=list_items + ) + comments_list.append(comment) + + # Create comments container + return comments_class(comment=comments_list) + + @staticmethod + def from_notif_comments(comments: NotifComments) -> CommentsData: + """Convert NotifComments back to CommentsData.""" + return CommentFactory._comments_to_data(comments) + + @staticmethod + def from_retrieve_comments(comments: RetrieveComments) -> CommentsData: + """Convert RetrieveComments back to CommentsData.""" + return CommentFactory._comments_to_data(comments) + + @staticmethod + def _comments_to_data(comments: Any) -> CommentsData: + """Internal method to convert any comments type to CommentsData.""" + + comments_data_list = [] + for comment in comments.comment: + # Extract list items + list_items_data = [] + if comment.list_item: + for list_item in comment.list_item: + list_items_data.append(CommentListItemData( + value=list_item.value, + list_item=list_item.list_item, + language=list_item.language + )) + + # Extract comment data + comment_data = CommentData( + name=comment.name, + text=comment.text, + list_items=list_items_data + ) + comments_data_list.append(comment_data) + + return CommentsData(comments=comments_data_list) + + # Define type aliases for ResGuests types NotifResGuests = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGuests RetrieveResGuests = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGuests @@ -356,12 +469,12 @@ class AlpineBitsFactory: """Unified factory class for creating AlpineBits objects with a simple interface.""" @staticmethod - def create(data: Union[CustomerData, HotelReservationIdData], message_type: OtaMessageType) -> Any: + def create(data: Union[CustomerData, HotelReservationIdData, CommentsData], message_type: OtaMessageType) -> Any: """ Create an AlpineBits object based on the data type and message type. Args: - data: The data object (CustomerData, HotelReservationIdData, etc.) + data: The data object (CustomerData, HotelReservationIdData, CommentsData, etc.) message_type: Whether to create for NOTIF or RETRIEVE message types Returns: @@ -378,6 +491,12 @@ class AlpineBitsFactory: return HotelReservationIdFactory.create_notif_hotel_reservation_id(data) else: return HotelReservationIdFactory.create_retrieve_hotel_reservation_id(data) + + elif isinstance(data, CommentsData): + if message_type == OtaMessageType.NOTIF: + return CommentFactory.create_notif_comments(data) + else: + return CommentFactory.create_retrieve_comments(data) else: raise ValueError(f"Unsupported data type: {type(data)}") @@ -400,7 +519,7 @@ class AlpineBitsFactory: return ResGuestFactory.create_retrieve_res_guests(customer_data) @staticmethod - def extract_data(obj: Any) -> Union[CustomerData, HotelReservationIdData]: + def extract_data(obj: Any) -> Union[CustomerData, HotelReservationIdData, CommentsData]: """ Extract data from an AlpineBits object back to a simple data class. @@ -424,6 +543,13 @@ class AlpineBitsFactory: elif isinstance(obj, RetrieveHotelReservationId): return HotelReservationIdFactory.from_retrieve_hotel_reservation_id(obj) + # Check if it's a Comments object + elif hasattr(obj, 'comment'): + if isinstance(obj, NotifComments): + return CommentFactory.from_notif_comments(obj) + elif isinstance(obj, RetrieveComments): + return CommentFactory.from_retrieve_comments(obj) + # Check if it's a ResGuests object elif hasattr(obj, 'res_guest'): return ResGuestFactory.extract_primary_customer(obj) @@ -564,6 +690,33 @@ if __name__ == "__main__": retrieve_res_id = AlpineBitsFactory.create(reservation_id_data, OtaMessageType.RETRIEVE) print("Created reservation IDs using unified factory") + print("=== Comments Creation ===") + comments_data = CommentsData(comments=[ + CommentData( + name=CommentName2.CUSTOMER_COMMENT, + text="This is a customer comment about the reservation", + list_items=[ + CommentListItemData( + value="Special dietary requirements: vegetarian", + list_item="1", + language="en" + ), + CommentListItemData( + value="Late arrival expected", + list_item="2", + language="en" + ) + ] + ), + CommentData( + name=CommentName2.ADDITIONAL_INFO, + text="Additional information about the stay" + ) + ]) + notif_comments = AlpineBitsFactory.create(comments_data, OtaMessageType.NOTIF) + retrieve_comments = AlpineBitsFactory.create(comments_data, OtaMessageType.RETRIEVE) + print("Created comments using unified factory") + print("=== ResGuests Creation ===") notif_res_guests = AlpineBitsFactory.create_res_guests(customer_data, OtaMessageType.NOTIF) retrieve_res_guests = AlpineBitsFactory.create_res_guests(customer_data, OtaMessageType.RETRIEVE) @@ -573,11 +726,13 @@ if __name__ == "__main__": # Extract data back using unified interface extracted_customer_data = AlpineBitsFactory.extract_data(notif_customer) extracted_res_id_data = AlpineBitsFactory.extract_data(notif_res_id) + extracted_comments_data = AlpineBitsFactory.extract_data(retrieve_comments) extracted_from_res_guests = AlpineBitsFactory.extract_data(retrieve_res_guests) print("Data extraction successful:") print("- Customer roundtrip:", customer_data == extracted_customer_data) print("- ReservationId roundtrip:", reservation_id_data == extracted_res_id_data) + print("- Comments roundtrip:", comments_data == extracted_comments_data) print("- ResGuests roundtrip:", customer_data == extracted_from_res_guests) print("\n--- Comparison with old approach ---")