Works but form_id is not unique. Need to find something else
This commit is contained in:
170
logs/wix_test_data_20250929_160843.json
Normal file
170
logs/wix_test_data_20250929_160843.json
Normal file
@@ -0,0 +1,170 @@
|
||||
{
|
||||
"timestamp": "2025-09-29T16:08:43.177480",
|
||||
"client_ip": "127.0.0.1",
|
||||
"headers": {
|
||||
"host": "localhost:8080",
|
||||
"content-type": "application/json",
|
||||
"user-agent": "insomnia/2023.5.8",
|
||||
"accept": "*/*",
|
||||
"content-length": "4518"
|
||||
},
|
||||
"data": {
|
||||
"data": {
|
||||
"formName": "Contact us",
|
||||
"submissions": [
|
||||
{
|
||||
"label": "Anreisedatum",
|
||||
"value": "2026-01-17"
|
||||
},
|
||||
{
|
||||
"label": "Abreisedatum",
|
||||
"value": "2026-01-24"
|
||||
},
|
||||
{
|
||||
"label": "Anzahl Erwachsene",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"label": "Anzahl Kinder",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"label": "Anrede",
|
||||
"value": "Herr"
|
||||
},
|
||||
{
|
||||
"label": "Vorname",
|
||||
"value": "Weislinger "
|
||||
},
|
||||
{
|
||||
"label": "Nachname",
|
||||
"value": "Alain "
|
||||
},
|
||||
{
|
||||
"label": "Email",
|
||||
"value": "alain-et-evelyne@hotmail.fr"
|
||||
},
|
||||
{
|
||||
"label": "Phone",
|
||||
"value": "+33 6 41 77 99 09"
|
||||
},
|
||||
{
|
||||
"label": "Einwilligung Marketing",
|
||||
"value": "Cochée"
|
||||
}
|
||||
],
|
||||
"field:date_picker_7e65": "2026-01-24",
|
||||
"field:number_7cf5": "2",
|
||||
"submissionTime": "2025-09-27T19:36:39.137Z",
|
||||
"field:form_field_5a7b": "Cochée",
|
||||
"context": {
|
||||
"metaSiteId": "7b28c2ce-1e20-4d07-9e86-73d822007e18",
|
||||
"activationId": "d59c463c-96e0-4742-b4f7-70b8f0431168"
|
||||
},
|
||||
"field:email_5139": "alain-et-evelyne@hotmail.fr",
|
||||
"field:phone_4c77": "+33 6 41 77 99 09",
|
||||
"_context": {
|
||||
"activation": {
|
||||
"id": "d59c463c-96e0-4742-b4f7-70b8f0431168"
|
||||
},
|
||||
"configuration": {
|
||||
"id": "483806f6-24ba-413f-9431-6b1ad9379f5c"
|
||||
},
|
||||
"app": {
|
||||
"id": "225dd912-7dea-4738-8688-4b8c6955ffc2"
|
||||
},
|
||||
"action": {
|
||||
"id": "a85d9873-f8ed-426a-90b0-fb64a8e50406"
|
||||
},
|
||||
"trigger": {
|
||||
"key": "wix_form_app-form_submitted"
|
||||
}
|
||||
},
|
||||
"formFieldMask": [
|
||||
"field:angebot_auswaehlen",
|
||||
"field:date_picker_a7c8",
|
||||
"field:date_picker_7e65",
|
||||
"field:number_7cf5",
|
||||
"field:anzahl_kinder",
|
||||
"field:alter_kind_3",
|
||||
"field:alter_kind_25",
|
||||
"field:alter_kind_4",
|
||||
"field:alter_kind_5",
|
||||
"field:alter_kind_6",
|
||||
"field:alter_kind_7",
|
||||
"field:alter_kind_8",
|
||||
"field:alter_kind_9",
|
||||
"field:alter_kind_10",
|
||||
"field:alter_kind_11",
|
||||
"field:anrede",
|
||||
"field:first_name_abae",
|
||||
"field:last_name_d97c",
|
||||
"field:email_5139",
|
||||
"field:phone_4c77",
|
||||
"field:long_answer_3524",
|
||||
"field:form_field_5a7b",
|
||||
"field:utm_source",
|
||||
"field:utm_medium",
|
||||
"field:utm_campaign",
|
||||
"field:utm_term",
|
||||
"field:utm_content",
|
||||
"field:utm_term_id",
|
||||
"field:utm_content_id",
|
||||
"field:gad_source",
|
||||
"field:gad_campaignid",
|
||||
"field:gbraid",
|
||||
"field:gclid",
|
||||
"field:fbclid",
|
||||
"metaSiteId"
|
||||
],
|
||||
"contact": {
|
||||
"name": {
|
||||
"first": "Weislinger",
|
||||
"last": "Alain"
|
||||
},
|
||||
"email": "alain-et-evelyne@hotmail.fr",
|
||||
"locale": "de-de",
|
||||
"phones": [
|
||||
{
|
||||
"tag": "UNTAGGED",
|
||||
"formattedPhone": "+33 6 41 77 99 09",
|
||||
"id": "90ffc824-1fd7-4167-b29f-24a4b62a0773",
|
||||
"countryCode": "FR",
|
||||
"e164Phone": "+33641779909",
|
||||
"primary": true,
|
||||
"phone": "6 41 77 99 09"
|
||||
}
|
||||
],
|
||||
"contactId": "250e24db-d41e-4f6e-835d-75acdf2ef2b7",
|
||||
"emails": [
|
||||
{
|
||||
"id": "2c071108-2410-4db8-99fa-b50b75a02493",
|
||||
"tag": "UNTAGGED",
|
||||
"email": "alain-et-evelyne@hotmail.fr",
|
||||
"primary": true
|
||||
}
|
||||
],
|
||||
"updatedDate": "2025-09-27T19:36:41.908Z",
|
||||
"phone": "+33641779909",
|
||||
"createdDate": "2025-09-27T19:36:41.054Z"
|
||||
},
|
||||
"submissionId": "6cfee967-69a8-454a-a10e-0aa03868ba6d",
|
||||
"field:anzahl_kinder": "0",
|
||||
"field:first_name_abae": "Weislinger ",
|
||||
"contactId": "250e24db-d41e-4f6e-835d-75acdf2ef2b7",
|
||||
"field:date_picker_a7c8": "2026-01-17",
|
||||
"field:last_name_d97c": "Alain ",
|
||||
"submissionsLink": "https://manage.wix.app/forms/submissions/7b28c2ce-1e20-4d07-9e86-73d822007e18/e084006b-ae83-4e4d-b2f5-074118cdb3b1?d=https%3A%2F%2Fmanage.wix.com%2Fdashboard%2F7b28c2ce-1e20-4d07-9e86-73d822007e18%2Fwix-forms%2Fform%2Fe084006b-ae83-4e4d-b2f5-074118cdb3b1%2Fsubmissions&s=true",
|
||||
"field:anrede": "Herr",
|
||||
"formId": "e084006b-ae83-4e4d-b2f5-074118cdb3b1"
|
||||
}
|
||||
},
|
||||
"origin_header": null,
|
||||
"all_headers": {
|
||||
"host": "localhost:8080",
|
||||
"content-type": "application/json",
|
||||
"user-agent": "insomnia/2023.5.8",
|
||||
"accept": "*/*",
|
||||
"content-length": "4518"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,19 @@
|
||||
from datetime import datetime, timezone
|
||||
from typing import Union, Optional, Any, TypeVar
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
|
||||
from typing import Tuple
|
||||
|
||||
from alpine_bits_python.db import Customer, Reservation
|
||||
|
||||
# Import the generated classes
|
||||
from .generated.alpinebits import OtaHotelResNotifRq, OtaResRetrieveRs, CommentName2
|
||||
from .generated.alpinebits import HotelReservationResStatus, OtaHotelResNotifRq, OtaResRetrieveRs, CommentName2, UniqueIdType2
|
||||
import logging
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_LOGGER.setLevel(logging.INFO)
|
||||
|
||||
# Define type aliases for the two Customer types
|
||||
NotifCustomer = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGuests.ResGuest.Profiles.ProfileInfo.Profile.Customer
|
||||
@@ -650,7 +659,146 @@ class AlpineBitsFactory:
|
||||
raise ValueError(f"Unsupported object type: {type(obj)}")
|
||||
|
||||
|
||||
def create_xml_from_db(list: list[Tuple[Reservation, Customer]]):
|
||||
""" Create RetrievedReservation XML from database entries.
|
||||
|
||||
list of pairs (Reservation, Customer)
|
||||
"""
|
||||
|
||||
reservations_list = []
|
||||
|
||||
for reservation, customer in list:
|
||||
_LOGGER.info(f"Creating XML for reservation {reservation.form_id} and customer {customer.given_name}")
|
||||
|
||||
phone_numbers = [(customer.phone, PhoneTechType.MOBILE)] if customer.phone is not None else []
|
||||
customer_data = CustomerData(
|
||||
given_name=customer.given_name,
|
||||
surname=customer.surname,
|
||||
name_prefix=customer.name_prefix,
|
||||
name_title=customer.name_title,
|
||||
phone_numbers=phone_numbers,
|
||||
email_address=customer.email_address,
|
||||
email_newsletter=customer.email_newsletter,
|
||||
address_line=customer.address_line,
|
||||
city_name=customer.city_name,
|
||||
postal_code=customer.postal_code,
|
||||
country_code=customer.country_code,
|
||||
address_catalog=customer.address_catalog,
|
||||
gender=customer.gender,
|
||||
birth_date=customer.birth_date,
|
||||
language=customer.language,
|
||||
)
|
||||
alpine_bits_factory = AlpineBitsFactory()
|
||||
res_guests = alpine_bits_factory.create_res_guests(
|
||||
customer_data, OtaMessageType.RETRIEVE
|
||||
)
|
||||
|
||||
# Guest counts
|
||||
children_ages = [int(a) for a in reservation.children_ages.split(",") if a]
|
||||
guest_counts = GuestCountsFactory.create_retrieve_guest_counts(
|
||||
reservation.num_adults, children_ages
|
||||
)
|
||||
|
||||
# UniqueID
|
||||
unique_id = OtaResRetrieveRs.ReservationsList.HotelReservation.UniqueId(
|
||||
type_value=UniqueIdType2.VALUE_14, id=reservation.form_id
|
||||
)
|
||||
|
||||
# TimeSpan
|
||||
time_span = OtaResRetrieveRs.ReservationsList.HotelReservation.RoomStays.RoomStay.TimeSpan(
|
||||
start=reservation.start_date.isoformat() if reservation.start_date else None,
|
||||
end=reservation.end_date.isoformat() if reservation.end_date else None,
|
||||
)
|
||||
room_stay = (
|
||||
OtaResRetrieveRs.ReservationsList.HotelReservation.RoomStays.RoomStay(
|
||||
time_span=time_span,
|
||||
guest_counts=guest_counts,
|
||||
)
|
||||
)
|
||||
room_stays = OtaResRetrieveRs.ReservationsList.HotelReservation.RoomStays(
|
||||
room_stay=[room_stay],
|
||||
)
|
||||
hotel_res_id_data = HotelReservationIdData(
|
||||
res_id_type="13",
|
||||
res_id_value=reservation.fbclid or reservation.gclid,
|
||||
res_id_source=None,
|
||||
res_id_source_context="99tales",
|
||||
)
|
||||
|
||||
hotel_res_id = alpine_bits_factory.create(
|
||||
hotel_res_id_data, OtaMessageType.RETRIEVE
|
||||
)
|
||||
hotel_res_ids = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.HotelReservationIds(
|
||||
hotel_reservation_id=[hotel_res_id]
|
||||
)
|
||||
basic_property_info = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.BasicPropertyInfo(
|
||||
hotel_code=reservation.hotel_code,
|
||||
hotel_name=reservation.hotel_name,
|
||||
)
|
||||
# Comments
|
||||
offer_comment = CommentData(
|
||||
name=CommentName2.ADDITIONAL_INFO,
|
||||
text="Angebot/Offerta",
|
||||
list_items=[
|
||||
CommentListItemData(
|
||||
value=reservation.offer,
|
||||
language=customer.language,
|
||||
list_item="1",
|
||||
)
|
||||
],
|
||||
)
|
||||
comment = None
|
||||
if reservation.user_comment:
|
||||
comment = CommentData(
|
||||
name=CommentName2.CUSTOMER_COMMENT,
|
||||
text=reservation.user_comment,
|
||||
list_items=[
|
||||
CommentListItemData(
|
||||
value="Landing page comment",
|
||||
language=customer.language,
|
||||
list_item="1",
|
||||
)
|
||||
],
|
||||
)
|
||||
comments = [offer_comment, comment] if comment else [offer_comment]
|
||||
comments_data = CommentsData(comments=comments)
|
||||
comments_xml = alpine_bits_factory.create(comments_data, OtaMessageType.RETRIEVE)
|
||||
|
||||
res_global_info = (
|
||||
OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo(
|
||||
hotel_reservation_ids=hotel_res_ids,
|
||||
basic_property_info=basic_property_info,
|
||||
comments=comments_xml,
|
||||
)
|
||||
)
|
||||
|
||||
hotel_reservation = OtaResRetrieveRs.ReservationsList.HotelReservation(
|
||||
create_date_time=datetime.now(timezone.utc).isoformat(),
|
||||
res_status=HotelReservationResStatus.REQUESTED,
|
||||
room_stay_reservation="true",
|
||||
unique_id=unique_id,
|
||||
room_stays=room_stays,
|
||||
res_guests=res_guests,
|
||||
res_global_info=res_global_info,
|
||||
)
|
||||
|
||||
reservations_list.append(hotel_reservation)
|
||||
|
||||
retrieved_reservations = OtaResRetrieveRs.ReservationsList(
|
||||
hotel_reservation=reservations_list
|
||||
)
|
||||
|
||||
ota_res_retrieve_rs = OtaResRetrieveRs(
|
||||
version="7.000", success=None, reservations_list=retrieved_reservations
|
||||
)
|
||||
|
||||
try:
|
||||
ota_res_retrieve_rs.model_validate(ota_res_retrieve_rs.model_dump())
|
||||
except Exception as e:
|
||||
_LOGGER.error(f"Validation error: {e}")
|
||||
raise
|
||||
|
||||
return ota_res_retrieve_rs
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ from xml.etree import ElementTree as ET
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, IntEnum
|
||||
|
||||
from alpine_bits_python.alpine_bits_helpers import PhoneTechType, create_xml_from_db
|
||||
|
||||
|
||||
|
||||
from .generated.alpinebits import OtaPingRq, OtaPingRs, WarningStatus, OtaReadRq
|
||||
from xsdata_pydantic.bindings import XmlSerializer
|
||||
from xsdata.formats.dataclass.serializers.config import SerializerConfig
|
||||
@@ -407,6 +411,8 @@ def validate_hotel_authentication(username: str, password: str, hotelid: str, co
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ReadAction(AlpineBitsAction):
|
||||
"""Implementation for OTA_Read action."""
|
||||
|
||||
@@ -478,7 +484,19 @@ class ReadAction(AlpineBitsAction):
|
||||
for reservation, customer in reservation_customer_pairs:
|
||||
_LOGGER.info(f"Reservation: {reservation.id}, Customer: {customer.given_name}")
|
||||
|
||||
res_retrive_rs = create_xml_from_db(reservation_customer_pairs)
|
||||
|
||||
config = SerializerConfig(
|
||||
pretty_print=True, xml_declaration=True, encoding="UTF-8"
|
||||
)
|
||||
serializer = XmlSerializer(config=config)
|
||||
response_xml = serializer.render(
|
||||
res_retrive_rs, ns_map={None: "http://www.opentravel.org/OTA/2003/05"}
|
||||
)
|
||||
|
||||
return AlpineBitsResponse(response_xml, HttpStatusCode.OK)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user