2025-08-02 22:37:17 +02:00
import requests
2026-01-22 16:17:05 +01:00
from requests . exceptions import JSONDecodeError
2025-08-02 22:37:17 +02:00
from config . constants import RESOURCE_URL , BOOKING_API_BASE , CHECKOUT_FORM_API , ANNY_BASE_URL , SERVICE_ID
class BookingClient :
def __init__ ( self , cookies ) :
self . session = requests . Session ( )
self . session . cookies = cookies
self . token = cookies . get ( ' anny_shop_jwt ' )
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 '
} )
def find_available_resource ( self , start , end ) :
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 ,
2025-08-03 00:11:18 +02:00
' filter[exclude_hidden] ' : 0 ,
' filter[exclude_child_resources] ' : 0 ,
' filter[availability_service_id] ' : int ( SERVICE_ID ) ,
2025-08-02 22:37:17 +02:00
' filter[include_unavailable] ' : 0 ,
2025-08-03 00:11:18 +02:00
' filter[pre_order_ids] ' : ' ' ,
2025-08-02 22:37:17 +02:00
' 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 :
resources = response . json ( ) . get ( ' data ' , [ ] )
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-01-23 09:03:20 +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 = {
' 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 '
} ,
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-05 01:32:36 +01:00
# "booking_quota_grant_id":"24735199",
" booking_quota_grant_id " : " 24735202 " ,
2025-08-02 22:37:17 +02:00
" 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-02 13:21:04 +01:00
# print(f"❌ Invalid JSON response from booking request: {booking.text[:200]}")
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
2025-08-02 22:37:17 +02: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 " ) ,
" email " : customer . get ( " email " )
} ,
" 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 } " ,
" meta " : { " timezone " : " Europe/Berlin " }
}
)
if final . ok :
print ( " ✅ Reservation successful! " )
return True
print ( " ❌ Reservation failed. " )
return False