notif_report #3

Merged
jonas merged 18 commits from notif_report into main 2025-10-06 12:50:41 +00:00
2 changed files with 68 additions and 18 deletions
Showing only changes of commit b8e4f4fd01 - Show all commits

View File

@@ -1,4 +1,5 @@
from datetime import datetime, timezone from datetime import datetime, timezone
import traceback
from typing import Union, Optional, Any, TypeVar from typing import Union, Optional, Any, TypeVar
from pydantic import BaseModel, ConfigDict, Field from pydantic import BaseModel, ConfigDict, Field
from dataclasses import dataclass from dataclasses import dataclass
@@ -14,6 +15,7 @@ from .generated.alpinebits import (
OtaHotelResNotifRq, OtaHotelResNotifRq,
OtaResRetrieveRs, OtaResRetrieveRs,
CommentName2, CommentName2,
ProfileProfileType,
UniqueIdType2, UniqueIdType2,
) )
import logging import logging
@@ -735,10 +737,12 @@ def _process_single_reservation(reservation: Reservation, customer: Customer, me
UniqueId = NotifUniqueId UniqueId = NotifUniqueId
RoomStays = NotifRoomStays RoomStays = NotifRoomStays
HotelReservation = NotifHotelReservation HotelReservation = NotifHotelReservation
Profile = OtaHotelResNotifRq.HotelReservations.HotelReservation.ResGlobalInfo.Profiles.ProfileInfo.Profile
elif message_type == OtaMessageType.RETRIEVE: elif message_type == OtaMessageType.RETRIEVE:
UniqueId = RetrieveUniqueId UniqueId = RetrieveUniqueId
RoomStays = RetrieveRoomStays RoomStays = RetrieveRoomStays
HotelReservation = RetrieveHotelReservation HotelReservation = RetrieveHotelReservation
Profile = OtaResRetrieveRs.ReservationsList.HotelReservation.ResGlobalInfo.Profiles.ProfileInfo.Profile
else: else:
raise ValueError(f"Unsupported message type: {message_type}") raise ValueError(f"Unsupported message type: {message_type}")
@@ -795,10 +799,24 @@ def _process_single_reservation(reservation: Reservation, customer: Customer, me
else: # extract string from Column object else: # extract string from Column object
klick_id = str(klick_id) klick_id = str(klick_id)
utm_medium = (
str(reservation.utm_medium)
if reservation.utm_medium is not None and str(reservation.utm_medium) != ""
else "website"
)
#shorten klick_id if longer than 64 characters
if klick_id is not None and len(klick_id) > 64:
klick_id = klick_id[:64]
hotel_res_id_data = HotelReservationIdData( hotel_res_id_data = HotelReservationIdData(
res_id_type="13", res_id_type="13",
res_id_value=klick_id, res_id_value=klick_id,
res_id_source=None, res_id_source=utm_medium,
res_id_source_context="99tales", res_id_source_context="99tales",
) )
@@ -866,12 +884,26 @@ def _process_single_reservation(reservation: Reservation, customer: Customer, me
comments_xml = alpine_bits_factory.create( comments_xml = alpine_bits_factory.create(
comments_data, message_type comments_data, message_type
) )
company_name = Profile.CompanyInfo.CompanyName(value="99tales GmbH", code="who knows?", code_context="who knows?")
company_info = Profile.CompanyInfo(company_name=company_name)
profile = Profile(company_info=company_info, profile_type=ProfileProfileType.VALUE_4)
profile_info = HotelReservation.ResGlobalInfo.Profiles.ProfileInfo(profile=profile)
_LOGGER.info(f"Type of profile_info: {type(profile_info)}")
profiles = HotelReservation.ResGlobalInfo.Profiles(profile_info=profile_info)
res_global_info = ( res_global_info = (
HotelReservation.ResGlobalInfo( HotelReservation.ResGlobalInfo(
hotel_reservation_ids=hotel_res_ids, hotel_reservation_ids=hotel_res_ids,
basic_property_info=basic_property_info, basic_property_info=basic_property_info,
comments=comments_xml, comments=comments_xml,
profiles=profiles,
) )
) )
@@ -917,6 +949,7 @@ def _create_xml_from_db(entries: list[Tuple[Reservation, Customer]] | Tuple[Rese
_LOGGER.error( _LOGGER.error(
f"Error creating XML for reservation {reservation.unique_id} and customer {customer.given_name}: {e}" f"Error creating XML for reservation {reservation.unique_id} and customer {customer.given_name}: {e}"
) )
_LOGGER.debug(traceback.format_exc())
if type == OtaMessageType.NOTIF: if type == OtaMessageType.NOTIF:
retrieved_reservations = OtaHotelResNotifRq.HotelReservations( retrieved_reservations = OtaHotelResNotifRq.HotelReservations(

View File

@@ -31,6 +31,7 @@ from datetime import datetime
from typing import Dict, Any, Optional, List from typing import Dict, Any, Optional, List
import json import json
import os import os
import asyncio
import gzip import gzip
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from .alpinebits_server import AlpineBitsClientInfo, AlpineBitsServer, Version, AlpineBitsActionName from .alpinebits_server import AlpineBitsClientInfo, AlpineBitsServer, Version, AlpineBitsActionName
@@ -113,13 +114,25 @@ async def push_listener(customer: DBCustomer, reservation: DBReservation, hotel)
if request.status_code != 200: if request.status_code != 200:
_LOGGER.error(f"Failed to generate push request for hotel {hotel_id}, reservation {reservation.unique_id}: {request.xml_content}") _LOGGER.error(f"Failed to generate push request for hotel {hotel_id}, reservation {reservation.unique_id}: {request.xml_content}")
return return
print(request.xml_content)
# TODO: Generate AlpineBits OTA_HotelResNotifRQ request
# action = "OTA_HotelResNotifRQ"
# request = server.handle_request(action, ...)
print(f"--- Push Payload --- received. Sending to endpoint., hotelid {hotel_id}, reservation {reservation.unique_id}")
# save push request to file
logs_dir = "logs/push_requests"
if not os.path.exists(logs_dir):
os.makedirs(logs_dir, mode=0o755, exist_ok=True)
stat_info = os.stat(logs_dir)
_LOGGER.info(
f"Created directory owner: uid:{stat_info.st_uid}, gid:{stat_info.st_gid}"
)
_LOGGER.info(f"Directory mode: {oct(stat_info.st_mode)[-3:]}")
log_filename = (
f"{logs_dir}/alpinebits_push_{hotel_id}_{reservation.unique_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xml"
)
with open(log_filename, "w", encoding="utf-8") as f:
f.write(request.xml_content)
return return
headers = {"Authorization": f"Bearer {push_endpoint.get('token','')}"} if push_endpoint.get('token') else {} headers = {"Authorization": f"Bearer {push_endpoint.get('token','')}"} if push_endpoint.get('token') else {}
@@ -337,7 +350,7 @@ async def process_wix_form_submission(request: Request, data: Dict[str, Any], db
name_prefix = data.get("field:anrede") name_prefix = data.get("field:anrede")
email_newsletter_string = data.get("field:form_field_5a7b", "") email_newsletter_string = data.get("field:form_field_5a7b", "")
yes_values = {"Selezionato", "Angekreuzt"} yes_values = {"Selezionato", "Angekreuzt", "Checked"}
email_newsletter = (email_newsletter_string in yes_values) email_newsletter = (email_newsletter_string in yes_values)
address_line = None address_line = None
city_name = None city_name = None
@@ -460,17 +473,21 @@ async def process_wix_form_submission(request: Request, data: Dict[str, Any], db
await db.commit() await db.commit()
await db.refresh(db_reservation) await db.refresh(db_reservation)
async def push_event():
# Fire event for listeners (push, etc.) - hotel-specific dispatch
dispatcher = getattr(request.app.state, "event_dispatcher", None)
if dispatcher:
# Get hotel_code from reservation to target the right listeners
hotel_code = getattr(db_reservation, 'hotel_code', None)
if hotel_code and hotel_code.strip():
await dispatcher.dispatch_for_hotel("form_processed", hotel_code, db_customer, db_reservation)
_LOGGER.info(f"Dispatched form_processed event for hotel {hotel_code}")
else:
_LOGGER.warning("No hotel_code in reservation, skipping push notifications")
# Fire event for listeners (push, etc.) - hotel-specific dispatch asyncio.create_task(push_event())
dispatcher = getattr(request.app.state, "event_dispatcher", None)
if dispatcher:
# Get hotel_code from reservation to target the right listeners
hotel_code = getattr(db_reservation, 'hotel_code', None)
if hotel_code and hotel_code.strip():
await dispatcher.dispatch_for_hotel("form_processed", hotel_code, db_customer, db_reservation)
_LOGGER.info(f"Dispatched form_processed event for hotel {hotel_code}")
else:
_LOGGER.warning("No hotel_code in reservation, skipping push notifications")
return { return {
"status": "success", "status": "success",