diff --git a/logs/push_requests/alpinebits_push_12345_c52702c9-55b9-44e1-b158-ec9544c73cc7_20251007_162404.xml b/logs/push_requests/alpinebits_push_12345_c52702c9-55b9-44e1-b158-ec9544c73cc7_20251007_162404.xml new file mode 100644 index 0000000..c8df446 --- /dev/null +++ b/logs/push_requests/alpinebits_push_12345_c52702c9-55b9-44e1-b158-ec9544c73cc7_20251007_162404.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + Frau + Genesia + Supino + + + supinogenesia@gmail.com + + + + + + + + + + + + + + + 99tales GmbH + + + + + + + + + diff --git a/src/alpine_bits_python/alpine_bits_helpers.py b/src/alpine_bits_python/alpine_bits_helpers.py index b5ab013..3804ea0 100644 --- a/src/alpine_bits_python/alpine_bits_helpers.py +++ b/src/alpine_bits_python/alpine_bits_helpers.py @@ -6,7 +6,14 @@ from enum import Enum from typing import Any from alpine_bits_python.db import Customer, Reservation -from alpine_bits_python.schemas import HotelReservationIdData +from alpine_bits_python.schemas import ( + CommentData, + CommentListItemData, + CommentsData, + CustomerData, + HotelReservationIdData, + PhoneTechType, +) # Import the generated classes from .generated.alpinebits import ( @@ -68,13 +75,6 @@ NotifHotelReservation = OtaHotelResNotifRq.HotelReservations.HotelReservation RetrieveHotelReservation = OtaResRetrieveRs.ReservationsList.HotelReservation -# phonetechtype enum 1,3,5 voice, fax, mobile -class PhoneTechType(Enum): - VOICE = "1" - FAX = "3" - MOBILE = "5" - - # Enum to specify which OTA message type to use class OtaMessageType(Enum): NOTIF = "notification" # For OtaHotelResNotifRq @@ -88,37 +88,6 @@ class KidsAgeData: ages: list[int] -@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) - ) - email_address: None | str = None - 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 - ) - gender: None | str = None # "Unknown", "Male", "Female" - birth_date: None | str = None - language: None | str = None # Two-letter language code - - def __post_init__(self): - if self.phone_numbers is None: - self.phone_numbers = [] - - class GuestCountsFactory: """Factory class to create GuestCounts instances for both OtaHotelResNotifRq and OtaResRetrieveRs.""" @@ -129,6 +98,7 @@ class GuestCountsFactory: message_type: OtaMessageType = OtaMessageType.RETRIEVE, ) -> NotifGuestCounts: """Create a GuestCounts object for OtaHotelResNotifRq or OtaResRetrieveRs. + :param adults: Number of adults :param kids: List of ages for each kid (optional) :return: GuestCounts instance @@ -147,7 +117,8 @@ class GuestCountsFactory: def _create_guest_counts( adults: int, kids: list[int] | None, guest_counts_class: type ) -> Any: - """Internal method to create a GuestCounts object of the specified type. + """Create a GuestCounts object of the specified type. + :param adults: Number of adults :param kids: List of ages for each kid (optional) :param guest_counts_class: The GuestCounts class to instantiate @@ -173,7 +144,7 @@ class GuestCountsFactory: class CustomerFactory: - """Factory class to create Customer instances for both OtaHotelResNotifRq and OtaResRetrieveRs.""" + """Factory class to create Customer instances for both Retrieve and Notif.""" @staticmethod def create_notif_customer(data: CustomerData) -> NotifCustomer: @@ -186,8 +157,10 @@ class CustomerFactory: 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.""" + def _create_customer( + customer_class: type[RetrieveCustomer | NotifCustomer], data: CustomerData + ) -> Any: + """Create a customer of the specified type.""" # Create PersonName person_name = customer_class.PersonName( given_name=data.given_name, @@ -260,19 +233,21 @@ class CustomerFactory: @staticmethod def _customer_to_data(customer: Any) -> CustomerData: - """Internal method to convert any customer type to CustomerData.""" + """Convert any customer type to CustomerData.""" # Extract phone numbers phone_numbers = [] if customer.telephone: - for tel in customer.telephone: - phone_numbers.append( + phone_numbers.extend( + [ ( tel.phone_number, PhoneTechType(tel.phone_tech_type) if tel.phone_tech_type else None, ) - ) + for tel in customer.telephone + ] + ) # Extract email info email_address = None @@ -389,39 +364,6 @@ 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: str | None = 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.""" @@ -494,11 +436,7 @@ class CommentFactory: ) ) - # Extract comment data - comment_data = CommentData( - name=comment.name, text=comment.text, list_items=list_items_data - ) - comments_data_list.append(comment_data) + comments_data_list.append(comment) return CommentsData(comments=comments_data_list) @@ -527,7 +465,9 @@ class ResGuestFactory: @staticmethod def _create_res_guests( - res_guests_class: type, customer_class: type, customer_data: CustomerData + res_guests_class: type[RetrieveResGuests] | type[NotifResGuests], + customer_class: type[NotifCustomer | RetrieveCustomer], + customer_data: CustomerData, ) -> Any: """Create the complete ResGuests structure.""" # Create the customer using the existing CustomerFactory diff --git a/src/alpine_bits_python/schemas.py b/src/alpine_bits_python/schemas.py index 84ceb0a..4cbb24f 100644 --- a/src/alpine_bits_python/schemas.py +++ b/src/alpine_bits_python/schemas.py @@ -10,10 +10,18 @@ from XML generation (xsdata) follows clean architecture principles. """ from datetime import date +from enum import Enum from pydantic import BaseModel, EmailStr, Field, field_validator, model_validator +# phonetechtype enum 1,3,5 voice, fax, mobile +class PhoneTechType(Enum): + VOICE = "1" + FAX = "3" + MOBILE = "5" + + class PhoneNumber(BaseModel): """Phone number with optional type.""" @@ -34,7 +42,7 @@ class CustomerData(BaseModel): surname: str = Field(..., min_length=1, max_length=100) name_prefix: str | None = Field(None, max_length=20) name_title: str | None = Field(None, max_length=20) - phone_numbers: list[PhoneNumber] = Field(default_factory=list) + phone_numbers: list[tuple[str, None | PhoneTechType]] = Field(default_factory=list) email_address: EmailStr | None = None email_newsletter: bool | None = None address_line: str | None = Field(None, max_length=255)