2025-08-02 22:37:17 +02:00
import requests
2026-01-22 16:17:05 +01:00
from requests . exceptions import JSONDecodeError
2026-02-06 17:42:40 +01:00
from config . constants import (
RESOURCE_URL ,
BOOKING_API_BASE ,
CHECKOUT_FORM_API ,
ANNY_BASE_URL ,
SERVICE_ID ,
)
2025-08-02 22:37:17 +02:00
class BookingClient :
def __init__ ( self , cookies ) :
self . session = requests . Session ( )
self . session . cookies = cookies
2026-02-06 17:42:40 +01:00
self . token = cookies . get ( " anny_shop_jwt " )
2025-08-02 22:37:17 +02:00
2026-02-06 17:42:40 +01:00
self . session . headers . update (
{
" authorization " : f " Bearer { self . token } " ,
" content-type " : " application/vnd.api+json " ,
" origin " : ANNY_BASE_URL ,
" referer " : ANNY_BASE_URL + " / " ,
" user-agent " : " Mozilla/5.0 " ,
}
)
2025-08-02 22:37:17 +02:00
def find_available_resource ( self , start , end ) :
2026-02-06 17:42:40 +01:00
response = self . session . get (
RESOURCE_URL ,
params = {
" page[number] " : 1 ,
" page[size] " : 250 ,
" filter[available_from] " : start ,
" filter[available_to] " : end ,
" filter[availability_exact_match] " : 1 ,
" filter[exclude_hidden] " : 0 ,
" filter[exclude_child_resources] " : 0 ,
" filter[availability_service_id] " : int ( SERVICE_ID ) ,
" filter[include_unavailable] " : 0 ,
" filter[pre_order_ids] " : " " ,
" sort " : " name " ,
} ,
)
2026-01-22 16:17:05 +01:00
if not response . ok :
print ( f " ❌ Failed to fetch resources: HTTP { response . status_code } " )
return None
try :
2026-02-06 17:42:40 +01:00
resources = response . json ( ) . get ( " data " , [ ] )
2026-01-22 16:17:05 +01:00
except ( ValueError , JSONDecodeError ) :
2026-02-02 13:21:04 +01:00
print ( f " ❌ Invalid JSON response when fetching resources: { response . text } " )
# print(f"❌ Invalid JSON response when fetching resources: {response.text[:200]}")
2026-01-22 16:17:05 +01:00
return None
2026-02-06 17:42:40 +01:00
return resources [ - 1 ] [ " id " ] if resources else None
2025-08-02 22:37:17 +02:00
def reserve ( self , resource_id , start , end ) :
2026-02-05 01:32:36 +01:00
print ( start )
print ( end )
2025-08-02 22:37:17 +02:00
booking = self . session . post (
2026-01-23 09:03:20 +01:00
f " { BOOKING_API_BASE } /order/bookings " ,
params = {
2026-02-06 17:42:40 +01:00
" stateless " : " 1 " ,
" include " : " customer,voucher,bookings.booking_add_ons.add_on.cover_image,bookings.sub_bookings.resource,bookings.sub_bookings.service,bookings.customer,bookings.service.custom_forms.custom_fields,bookings.service.add_ons.cover_image,bookings.service.add_ons.group,bookings.cancellation_policy,bookings.resource.cover_image,bookings.resource.parent,bookings.resource.location,bookings.resource.category,bookings.reminders,bookings.booking_series,bookings.sequenced_bookings.resource,bookings.sequenced_bookings.service,bookings.sequenced_bookings.service.add_ons.cover_image,bookings.sequenced_bookings.service.add_ons.group,bookings.booking_participants,sub_orders.bookings,sub_orders.organization.legal_documents " ,
2026-01-23 09:03:20 +01:00
} ,
2025-08-02 22:37:17 +02:00
json = {
" resource_id " : [ resource_id ] ,
" service_id " : { SERVICE_ID : 1 } ,
" start_date " : start ,
" end_date " : end ,
" description " : " " ,
" customer_note " : " " ,
" add_ons_by_service " : { SERVICE_ID : [ [ ] ] } ,
" sub_bookings_by_service " : { } ,
2026-02-07 13:50:59 +01:00
# INFO: changes every week: e.g. booking for a monday needs new id
2026-02-05 01:32:36 +01:00
# "booking_quota_grant_id":"24735199",
2026-02-06 17:42:40 +01:00
" booking_quota_grant_id " : " 24735202 " ,
" strategy " : " multi-resource " ,
} ,
2026-02-02 13:21:04 +01:00
# data = '{"resource_id":["15994"],"service_id":{"601":1},"start_date":"2026-02-03T22:30:00+01:00","end_date":"2026-02-03T23:30:00+01:00","description":"","customer_note":"","add_ons_by_service":{"601":[[]]},"sub_bookings_by_service":{},"booking_quota_grant_id":"24735199","strategy":"multi-resource"}'
2025-08-02 22:37:17 +02:00
)
2026-02-02 13:21:04 +01:00
print ( " resource id: %s " % resource_id )
2025-08-02 22:37:17 +02:00
if not booking . ok :
2026-01-22 16:17:05 +01:00
print ( f " ❌ Booking failed: HTTP { booking . status_code } " )
return False
try :
data = booking . json ( ) . get ( " data " , { } )
except ( ValueError , JSONDecodeError ) :
2026-02-07 13:50:59 +01:00
if " Bad Request " in booking . text and " 400 " in booking . text :
print ( " ❌ Bad Request 400 on Booking request. " )
else :
print ( f " ❌ Invalid JSON response from booking request: { booking . text } " )
2025-08-02 22:37:17 +02:00
return False
oid = data . get ( " id " )
oat = data . get ( " attributes " , { } ) . get ( " access_token " )
2026-01-22 16:17:05 +01:00
if not oid or not oat :
print ( " ❌ Missing booking ID or access token in response " )
return False
2026-02-06 17:42:40 +01:00
checkout = self . session . get (
f " { CHECKOUT_FORM_API } ?oid= { oid } &oat= { oat } &stateless=1 "
)
2026-01-22 16:17:05 +01:00
if not checkout . ok :
print ( f " ❌ Checkout form failed: HTTP { checkout . status_code } " )
return False
try :
customer = checkout . json ( ) . get ( " default " , { } ) . get ( " customer " , { } )
except ( ValueError , JSONDecodeError ) :
2026-02-02 13:21:04 +01:00
print ( f " ❌ Invalid JSON response from checkout form: { checkout . text } " )
# print(f"❌ Invalid JSON response from checkout form: {checkout.text[:200]}")
2026-01-22 16:17:05 +01:00
return False
2025-08-02 22:37:17 +02:00
final = self . session . post (
f " { BOOKING_API_BASE } /order?oid= { oid } &oat= { oat } &stateless=1 " ,
json = {
" customer " : {
" given_name " : customer . get ( " given_name " ) ,
" family_name " : customer . get ( " family_name " ) ,
2026-02-06 17:42:40 +01:00
" email " : customer . get ( " email " ) ,
2025-08-02 22:37:17 +02:00
} ,
" accept_terms " : True ,
" payment_method " : " " ,
" success_url " : f " { ANNY_BASE_URL } /checkout/success?oids= { oid } &oats= { oat } " ,
" cancel_url " : f " { ANNY_BASE_URL } /checkout?step=checkout&childResource= { resource_id } " ,
2026-02-06 17:42:40 +01:00
" meta " : { " timezone " : " Europe/Berlin " } ,
} ,
2025-08-02 22:37:17 +02:00
)
if final . ok :
print ( " ✅ Reservation successful! " )
return True
print ( " ❌ Reservation failed. " )
return False