notif_report #3

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

View File

@@ -681,7 +681,7 @@ def create_xml_from_db(list: list[Tuple[Reservation, Customer]]):
for reservation, customer in list:
_LOGGER.info(
f"Creating XML for reservation {reservation.form_id} and customer {customer.given_name}"
f"Creating XML for reservation {reservation.unique_id} and customer {customer.given_name}"
)
try:
@@ -718,10 +718,7 @@ def create_xml_from_db(list: list[Tuple[Reservation, Customer]]):
reservation.num_adults, children_ages
)
unique_id_string = reservation.form_id
if len(unique_id_string) > 32:
unique_id_string = unique_id_string[:32] # Truncate to 32 characters
unique_id_string = reservation.unique_id
# UniqueID
unique_id = OtaResRetrieveRs.ReservationsList.HotelReservation.UniqueId(
@@ -828,7 +825,7 @@ def create_xml_from_db(list: list[Tuple[Reservation, Customer]]):
except Exception as e:
_LOGGER.error(
f"Error creating XML for reservation {reservation.form_id} and customer {customer.given_name}: {e}"
f"Error creating XML for reservation {reservation.unique_id} and customer {customer.given_name}: {e}"
)
retrieved_reservations = OtaResRetrieveRs.ReservationsList(

View File

@@ -26,7 +26,7 @@ from xsdata.formats.dataclass.serializers.config import SerializerConfig
from abc import ABC, abstractmethod
from xsdata_pydantic.bindings import XmlParser
import logging
from .db import Reservation, Customer
from .db import AckedRequest, Reservation, Customer
from sqlalchemy import select
from sqlalchemy.orm import joinedload
@@ -493,6 +493,8 @@ class ReadAction(AlpineBitsAction):
# query all reservations for this hotel from the database, where start_date is greater than or equal to the given start_date
stmt = (
select(Reservation, Customer)
.join(Customer, Reservation.customer_id == Customer.id)
@@ -500,6 +502,20 @@ class ReadAction(AlpineBitsAction):
)
if start_date:
stmt = stmt.filter(Reservation.start_date >= start_date)
else:
# remove reservations that have been acknowledged via client_id
if client_info.client_id:
subquery = (
select(Reservation.id)
.join(
AckedRequest,
AckedRequest.unique_id == Reservation.unique_id,
)
.filter(AckedRequest.client_id == client_info.client_id)
)
stmt = stmt.filter(~Reservation.id.in_(subquery))
result = await dbsession.execute(stmt)
reservation_customer_pairs: list[tuple[Reservation, Customer]] = (

View File

@@ -16,7 +16,7 @@ from .config_loader import load_config
from fastapi.responses import HTMLResponse, PlainTextResponse, Response
from .models import WixFormSubmission
from datetime import datetime, date, timezone
from .auth import validate_api_key, validate_wix_signature, generate_api_key
from .auth import generate_unique_id, validate_api_key, validate_wix_signature, generate_api_key
from .rate_limit import (
limiter,
webhook_limiter,
@@ -280,12 +280,16 @@ async def process_wix_form_submission(request: Request, data: Dict[str, Any], db
("utm_Term", "utm_term"),
("utm_Content", "utm_content"),
]
utm_comment_text = []
for label, field in utm_fields:
val = data.get(f"field:{field}") or data.get(label)
if val:
utm_comment_text.append(f"{label}: {val}")
utm_comment = ",".join(utm_comment_text) if utm_comment_text else None
# get submissionId and ensure max length 35. Generate one if not present
unique_id = data.get("submissionId", generate_unique_id())
if len(unique_id) > 35:
# strip to first 35 chars
unique_id = unique_id[:35]
# use database session
@@ -309,19 +313,19 @@ async def process_wix_form_submission(request: Request, data: Dict[str, Any], db
name_title=None,
)
db.add(db_customer)
await db.commit()
await db.refresh(db_customer)
await db.flush() # This assigns db_customer.id without committing
#await db.refresh(db_customer)
db_reservation = DBReservation(
customer_id=db_customer.id,
form_id=data.get("submissionId"),
unique_id=unique_id,
start_date=date.fromisoformat(start_date) if start_date else None,
end_date=date.fromisoformat(end_date) if end_date else None,
num_adults=num_adults,
num_children=num_children,
children_ages=",".join(str(a) for a in children_ages),
offer=offer,
utm_comment=utm_comment,
created_at=datetime.now(timezone.utc),
utm_source=data.get("field:utm_source"),
utm_medium=data.get("field:utm_medium"),

View File

@@ -30,6 +30,10 @@ if os.getenv("WIX_API_KEY"):
if os.getenv("ADMIN_API_KEY"):
API_KEYS["admin-key"] = os.getenv("ADMIN_API_KEY")
def generate_unique_id() -> str:
"""Generate a unique ID with max length 35 characters"""
return secrets.token_urlsafe(26)[:35] # 26 bytes -> 35 chars in base64url
def generate_api_key() -> str:
"""Generate a secure API key"""

View File

@@ -44,14 +44,13 @@ class Reservation(Base):
__tablename__ = "reservations"
id = Column(Integer, primary_key=True)
customer_id = Column(Integer, ForeignKey("customers.id"))
form_id = Column(String, unique=True)
unique_id = Column(String(35), unique=True) # max length 35
start_date = Column(Date)
end_date = Column(Date)
num_adults = Column(Integer)
num_children = Column(Integer)
children_ages = Column(String) # comma-separated
offer = Column(String)
utm_comment = Column(String)
created_at = Column(DateTime)
# Add all UTM fields and user comment for XML
utm_source = Column(String)
@@ -68,11 +67,11 @@ class Reservation(Base):
customer = relationship("Customer", back_populates="reservations")
class HashedCustomer(Base):
__tablename__ = "hashed_customers"
# Table for tracking acknowledged requests by client
class AckedRequest(Base):
__tablename__ = 'acked_requests'
id = Column(Integer, primary_key=True)
customer_id = Column(Integer)
hashed_email = Column(String)
hashed_phone = Column(String)
hashed_name = Column(String)
redacted_at = Column(DateTime)
client_id = Column(String, index=True)
unique_id = Column(String, index=True) # Should match Reservation.form_id or another unique field
timestamp = Column(DateTime)

View File

@@ -256,7 +256,7 @@ def create_xml_from_db(customer: DBCustomer, reservation: DBReservation):
# UniqueID
unique_id = ab.OtaResRetrieveRs.ReservationsList.HotelReservation.UniqueId(
type_value=ab.UniqueIdType2.VALUE_14, id=reservation.form_id
type_value=ab.UniqueIdType2.VALUE_14, id=reservation.unique_id
)
# TimeSpan