diff --git a/echo_data_response.json b/echo_data_response.json new file mode 100644 index 0000000..fd92356 --- /dev/null +++ b/echo_data_response.json @@ -0,0 +1,135 @@ +{ + "versions": [ + { + "version": "2024-10", + "actions": [ + { + "action": "action_OTA_Read" + }, + { + "action": "action_OTA_HotelResNotif_GuestRequests" + }, + { + "action": "action_OTA_HotelResNotif_GuestRequests_StatusUpdate" + }, + { + "action": "action_OTA_HotelInvCountNotif", + "supports": [ + "OTA_HotelInvCountNotif_accept_rooms", + "OTA_HotelInvCountNotif_accept_categories", + "OTA_HotelInvCountNotif_accept_deltas", + "OTA_HotelInvCountNotif_accept_out_of_market", + "OTA_HotelInvCountNotif_accept_out_of_order", + "OTA_HotelInvCountNotif_accept_complete_set", + "OTA_HotelInvCountNotif_accept_closing_seasons" + ] + }, + { + "action": "action_OTA_HotelDescriptiveContentNotif_Inventory", + "supports": [ + "OTA_HotelDescriptiveContentNotif_Inventory_use_rooms", + "OTA_HotelDescriptiveContentNotif_Inventory_occupancy_children" + ] + }, + { + "action": "action_OTA_HotelDescriptiveContentNotif_Info" + }, + { + "action": "action_OTA_HotelDescriptiveInfo_Inventory" + }, + { + "action": "action_OTA_HotelDescriptiveInfo_Info" + }, + { + "action": "action_OTA_HotelRatePlanNotif_RatePlans", + "supports": [ + "OTA_HotelRatePlanNotif_accept_ArrivalDOW", + "OTA_HotelRatePlanNotif_accept_DepartureDOW", + "OTA_HotelRatePlanNotif_accept_RatePlan_BookingRule", + "OTA_HotelRatePlanNotif_accept_RatePlan_RoomType_BookingRule", + "OTA_HotelRatePlanNotif_accept_RatePlan_mixed_BookingRule", + "OTA_HotelRatePlanNotif_accept_Supplements", + "OTA_HotelRatePlanNotif_accept_FreeNightsOffers", + "OTA_HotelRatePlanNotif_accept_FamilyOffers", + "OTA_HotelRatePlanNotif_accept_full", + "OTA_HotelRatePlanNotif_accept_overlay", + "OTA_HotelRatePlanNotif_accept_RatePlanJoin", + "OTA_HotelRatePlanNotif_accept_OfferRule_BookingOffset", + "OTA_HotelRatePlanNotif_accept_OfferRule_DOWLOS" + ] + }, + { + "action": "action_OTA_HotelRatePlan_BaseRates", + "supports": [ + "OTA_HotelRatePlan_BaseRates_deltas" + ] + }, + { + "action": "action_OTA_HotelPostEventNotif_EventReports" + } + ] + }, + { + "version": "2022-10", + "actions": [ + { + "action": "action_OTA_Ping" + }, + { + "action": "action_OTA_Read" + }, + { + "action": "action_OTA_HotelResNotif_GuestRequests" + }, + { + "action": "action_OTA_HotelResNotif_GuestRequests_StatusUpdate" + }, + { + "action": "action_OTA_HotelInvCountNotif", + "supports": [ + "OTA_HotelInvCountNotif_accept_rooms", + "OTA_HotelInvCountNotif_accept_categories", + "OTA_HotelInvCountNotif_accept_deltas", + "OTA_HotelInvCountNotif_accept_out_of_market", + "OTA_HotelInvCountNotif_accept_out_of_order", + "OTA_HotelInvCountNotif_accept_complete_set", + "OTA_HotelInvCountNotif_accept_closing_seasons" + ] + }, + { + "action": "action_OTA_HotelDescriptiveContentNotif_Inventory", + "supports": [ + "OTA_HotelDescriptiveContentNotif_Inventory_use_rooms", + "OTA_HotelDescriptiveContentNotif_Inventory_occupancy_children" + ] + }, + { + "action": "action_OTA_HotelDescriptiveContentNotif_Info" + }, + { + "action": "action_OTA_HotelDescriptiveInfo_Inventory" + }, + { + "action": "action_OTA_HotelDescriptiveInfo_Info" + }, + { + "action": "action_OTA_HotelRatePlanNotif_RatePlans", + "supports": [ + "OTA_HotelRatePlanNotif_accept_ArrivalDOW", + "OTA_HotelRatePlanNotif_accept_DepartureDOW", + "OTA_HotelRatePlanNotif_accept_RatePlan_BookingRule", + "OTA_HotelRatePlanNotif_accept_RatePlan_RoomType_BookingRule", + "OTA_HotelRatePlanNotif_accept_RatePlan_mixed_BookingRule", + "OTA_HotelRatePlanNotif_accept_Supplements", + "OTA_HotelRatePlanNotif_accept_FreeNightsOffers", + "OTA_HotelRatePlanNotif_accept_FamilyOffers", + "OTA_HotelRatePlanNotif_accept_overlay", + "OTA_HotelRatePlanNotif_accept_RatePlanJoin", + "OTA_HotelRatePlanNotif_accept_OfferRule_BookingOffset", + "OTA_HotelRatePlanNotif_accept_OfferRule_DOWLOS" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/alpine_bits_python/alpinebits_server.py b/src/alpine_bits_python/alpinebits_server.py index 0bcc388..f98100b 100644 --- a/src/alpine_bits_python/alpinebits_server.py +++ b/src/alpine_bits_python/alpinebits_server.py @@ -299,16 +299,24 @@ class PingAction(AlpineBitsAction): # Create successful ping response with matched capabilities capabilities_json = json.dumps(matching_capabilities, indent=2) - - response_xml = f''' - - - - {capabilities_json} - - {capabilities_json} -''' + warning = OtaPingRs.Warnings.Warning(type_value=WarningStatus.ALPINEBITS_HANDSHAKE.value, code="11", content=[capabilities_json]) + + warning_response = OtaPingRs.Warnings(warning=[warning]) + + response_ota_ping = OtaPingRs(version= "7.000", warnings=warning_response, echo_data=capabilities_json) + + + + + + config = SerializerConfig( + pretty_print=True, xml_declaration=True, encoding="UTF-8" + ) + + serializer = XmlSerializer(config=config) + + response_xml = serializer.render(response_ota_ping, ns_map={None: "http://www.opentravel.org/OTA/2003/05"}) @@ -338,7 +346,7 @@ class HotelAvailNotifAction(AlpineBitsAction): def __init__(self): self.name = AlpineBitsActionName.OTA_HOTEL_AVAIL_NOTIF - self.version = Version.V2024_10 + self.version = Version.V2022_10 self.supports = [ "OTA_HotelAvailNotif_accept_rooms", "OTA_HotelAvailNotif_accept_categories", @@ -450,6 +458,10 @@ class AlpineBitsServer: else: return await action_instance.handle(request_action_name, request_xml, version_enum) except Exception as e: + print(f"Error handling request {request_action_name}: {str(e)}") + # print stack trace for debugging + import traceback + traceback.print_exc() return AlpineBitsResponse( f"Error: Internal server error while processing {request_action_name}: {str(e)}", HttpStatusCode.INTERNAL_SERVER_ERROR diff --git a/src/alpine_bits_python/util/handshake_util.py b/src/alpine_bits_python/util/handshake_util.py index 0ecb1af..f82cbae 100644 --- a/src/alpine_bits_python/util/handshake_util.py +++ b/src/alpine_bits_python/util/handshake_util.py @@ -7,7 +7,7 @@ from xsdata_pydantic.bindings import XmlParser def main(): # test parsing a ping request sample - path = "AlpineBits-HotelData-2024-10/files/samples/Handshake/Handshake-OTA_PingRQ.xml" + path = "AlpineBits-HotelData-2024-10/files/samples/Handshake/Handshake-OTA_PingRS.xml" with open( path, "r", encoding="utf-8") as f: @@ -22,12 +22,23 @@ def main(): - parsed_result = parser.from_string(xml, OtaPingRq) + parsed_result = parser.from_string(xml, OtaPingRs) print(parsed_result.echo_data) + warning = parsed_result.warnings.warning[0] + + print(warning.type_value) + + print(type(warning.content)) + + print(warning.content[0]) + + + + # save json in echo_data to file with indents - output_path = "parsed_echo_data.json" + output_path = "echo_data_response.json" with open(output_path, "w", encoding="utf-8") as out_f: import json json.dump(json.loads(parsed_result.echo_data), out_f, indent=4)