spree_cm_commissioner 2.13.2 → 2.13.3.pre.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.env.example +1 -0
- data/Gemfile.lock +1 -1
- data/app/controllers/concerns/spree_cm_commissioner/operator/event_authorization.rb +19 -0
- data/app/controllers/spree/admin/homepage_section_controller.rb +32 -8
- data/app/controllers/spree/admin/integrations_controller.rb +5 -7
- data/app/controllers/spree/admin/inventory_items_controller.rb +12 -0
- data/app/controllers/spree/admin/notification_users_controller.rb +39 -7
- data/app/controllers/spree/admin/service_fee_rules_controller.rb +83 -0
- data/app/controllers/spree/admin/stock_managements_controller.rb +5 -5
- data/app/controllers/spree/api/switch_cm/base_controller.rb +98 -0
- data/app/controllers/spree/api/switch_cm/ota/avail_notifs_controller.rb +17 -0
- data/app/controllers/spree/api/switch_cm/ota/base_controller.rb +27 -0
- data/app/controllers/spree/api/switch_cm/ota/product_notifs_controller.rb +44 -0
- data/app/controllers/spree/api/switch_cm/ota/pushes_controller.rb +46 -0
- data/app/controllers/spree/api/switch_cm/ota/rate_amount_notifs_controller.rb +17 -0
- data/app/controllers/spree/api/switch_cm/ota/res_modify_notifs_controller.rb +31 -0
- data/app/controllers/spree/api/switch_cm/ota/res_notifs_controller.rb +29 -0
- data/app/controllers/spree/api/switch_cm/ota/reservation_streams_controller.rb +83 -0
- data/app/controllers/spree/api/switch_cm/tokens_controller.rb +68 -0
- data/app/controllers/spree/api/switch_cm/xml/availabilities_controller.rb +39 -0
- data/app/controllers/spree/api/switch_cm/xml/base_controller.rb +37 -0
- data/app/controllers/spree/api/switch_cm/xml/reservation_summaries_controller.rb +28 -0
- data/app/controllers/spree/api/switch_cm/xml/reservations_controller.rb +56 -0
- data/app/controllers/spree/api/switch_cm/xml/room_rate_availabilities_controller.rb +56 -0
- data/app/controllers/spree/api/switch_cm/xml/room_rates_controller.rb +32 -0
- data/app/controllers/spree/api/v2/operator/check_ins_controller.rb +7 -6
- data/app/controllers/spree/api/v2/operator/event_charts_controller.rb +8 -10
- data/app/controllers/spree/api/v2/operator/event_ticket_aggregators_controller.rb +14 -4
- data/app/controllers/spree/api/v2/operator/pie_chart_event_aggregators_controller.rb +15 -1
- data/app/controllers/spree/api/v2/platform/homepage_section_relatable_options_controller.rb +28 -0
- data/app/controllers/spree/api/v2/storefront/cross_app_handoff_tokens_controller.rb +41 -0
- data/app/controllers/spree/api/v2/storefront/homepage_sections_controller.rb +4 -2
- data/app/controllers/spree/api/v2/storefront/transit/item_availabilities_controller.rb +66 -0
- data/app/controllers/spree/api/v2/tenant/checkout_controller.rb +11 -0
- data/app/controllers/spree/api/v2/tenant/vendor_photos_controller.rb +25 -0
- data/app/controllers/spree_cm_commissioner/admin/orders_controller_decorator.rb +9 -1
- data/app/controllers/spree_cm_commissioner/api/v2/storefront/checkout_controller_decorator.rb +15 -0
- data/app/factory/spree_cm_commissioner/order_telegram_message_factory.rb +6 -2
- data/app/helpers/spree/admin/customer_notifications_helper.rb +57 -0
- data/app/helpers/spree_cm_commissioner/admin/homepage_segment_helper.rb +45 -23
- data/app/interactors/spree_cm_commissioner/customer_notification_sender.rb +18 -9
- data/app/interactors/spree_cm_commissioner/user_cross_app_handoff_authenticator.rb +17 -0
- data/app/jobs/spree_cm_commissioner/audit_event_job.rb +29 -0
- data/app/models/concerns/spree_cm_commissioner/audit_wrapper.rb +139 -0
- data/app/models/concerns/spree_cm_commissioner/homepage_section_bitwise.rb +37 -1
- data/app/models/concerns/spree_cm_commissioner/integrations/inventory_sync_cachable.rb +9 -0
- data/app/models/concerns/spree_cm_commissioner/line_item_open_dated_trippable.rb +2 -2
- data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +10 -0
- data/app/models/concerns/spree_cm_commissioner/phone_number_sanitizer.rb +5 -1
- data/app/models/concerns/spree_cm_commissioner/user_notification.rb +3 -1
- data/app/models/concerns/spree_cm_commissioner/variant_metadata.rb +24 -0
- data/app/models/concerns/spree_cm_commissioner/vehicle_kind.rb +1 -1
- data/app/models/spree_cm_commissioner/adjustable/adjuster/service_fee.rb +31 -0
- data/app/models/spree_cm_commissioner/adjustment_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/audit_event.rb +11 -0
- data/app/models/spree_cm_commissioner/calculators/service_fee_flat_amount.rb +17 -0
- data/app/models/spree_cm_commissioner/calculators/service_fee_percent.rb +20 -0
- data/app/models/spree_cm_commissioner/currency_rate.rb +15 -0
- data/app/models/spree_cm_commissioner/customer_notification.rb +15 -1
- data/app/models/spree_cm_commissioner/homepage_section.rb +25 -0
- data/app/models/spree_cm_commissioner/integration.rb +46 -0
- data/app/models/spree_cm_commissioner/integrations/book_me_bus_v1.rb +64 -0
- data/app/models/spree_cm_commissioner/integrations/larryta.rb +81 -0
- data/app/models/spree_cm_commissioner/integrations/stadium_x_v1.rb +4 -10
- data/app/models/spree_cm_commissioner/integrations/switch_cm.rb +86 -0
- data/app/models/spree_cm_commissioner/integrations/vireak_buntham.rb +82 -0
- data/app/models/spree_cm_commissioner/inventory_item.rb +18 -0
- data/app/models/spree_cm_commissioner/line_item_decorator.rb +2 -0
- data/app/models/spree_cm_commissioner/order_decorator.rb +13 -1
- data/app/models/spree_cm_commissioner/order_updater_decorator.rb +31 -0
- data/app/models/spree_cm_commissioner/place.rb +2 -0
- data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +2 -1
- data/app/models/spree_cm_commissioner/route.rb +1 -0
- data/app/models/spree_cm_commissioner/seat_layout.rb +1 -0
- data/app/models/spree_cm_commissioner/service_fee_rule.rb +183 -0
- data/app/models/spree_cm_commissioner/stock/availability_checker.rb +1 -1
- data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +1 -1
- data/app/models/spree_cm_commissioner/stock_item_decorator.rb +4 -0
- data/app/models/spree_cm_commissioner/trip.rb +2 -1
- data/app/models/spree_cm_commissioner/trip_stop.rb +2 -0
- data/app/models/spree_cm_commissioner/user_decorator.rb +4 -0
- data/app/models/spree_cm_commissioner/variant_decorator.rb +5 -0
- data/app/models/spree_cm_commissioner/vehicle.rb +3 -0
- data/app/models/spree_cm_commissioner/vehicle_type.rb +1 -0
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +17 -0
- data/app/models/spree_cm_commissioner/vendor_place.rb +2 -0
- data/app/overrides/spree/admin/orders/index/line_items_row.html.erb.deface +14 -0
- data/app/overrides/spree/admin/orders/index/row_actions.html.erb.deface +17 -0
- data/app/overrides/spree/admin/shared/sub_menu/_configuration/menu_items.html.erb.deface +5 -0
- data/app/queries/spree_cm_commissioner/users_by_event_fetcher_query.rb +6 -7
- data/app/serializables/spree_cm_commissioner/item_availability_sync.rb +10 -0
- data/app/serializers/spree/api/v2/platform/service_fee_rule_serializer.rb +17 -0
- data/app/serializers/spree/v2/storefront/homepage_section_serializer.rb +1 -1
- data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +8 -2
- data/app/serializers/spree/v2/tenant/cart_serializer.rb +2 -1
- data/app/serializers/spree/v2/tenant/line_item_serializer.rb +7 -1
- data/app/serializers/spree_cm_commissioner/v2/operator/guest_serializer.rb +2 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/cart_serializer_decorator.rb +2 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/cross_app_handoff_token_serializer.rb +9 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/item_availability_sync_serializer.rb +10 -0
- data/app/services/spree_cm_commissioner/api_caches/invalidate.rb +1 -1
- data/app/services/spree_cm_commissioner/audit_logger.rb +59 -0
- data/app/services/spree_cm_commissioner/checkout/advance_to_payment.rb +27 -0
- data/app/services/spree_cm_commissioner/cross_app_handoff_tokens/decode.rb +42 -0
- data/app/services/spree_cm_commissioner/cross_app_handoff_tokens/encode.rb +47 -0
- data/app/services/spree_cm_commissioner/currency_converter/create.rb +27 -0
- data/app/services/spree_cm_commissioner/currency_rates/manage.rb +99 -0
- data/app/services/spree_cm_commissioner/draft_orders/create.rb +1 -0
- data/app/services/spree_cm_commissioner/google_maps_geocoder.rb +41 -0
- data/app/services/spree_cm_commissioner/integrations/base/sync_manager.rb +1 -2
- data/app/services/spree_cm_commissioner/integrations/base/sync_result.rb +11 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/external_client/client.rb +230 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/external_client/connection.rb +147 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/inventory/external_inventory_item_status.rb +52 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/inventory/external_inventory_items.rb +91 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/inventory/unstock_inventory.rb +188 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_inventory.rb +79 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_item_availability.rb +354 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_locations.rb +103 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_nationality_pricing.rb +93 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_product.rb +70 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_route_stops.rb +121 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_routes.rb +128 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_seat_layout.rb +412 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_service_calendars.rb +59 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_trip_stop.rb +224 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_trips.rb +769 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_variant.rb +69 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_vehicle_types.rb +92 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/time_parser.rb +19 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/base.rb +40 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/inventory_item_status.rb +148 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/location.rb +55 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/reservation_cart.rb +85 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat.rb +128 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb +386 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/stop.rb +84 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/trip.rb +237 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/wallet_payment.rb +48 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/sync_manager.rb +22 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/sync_strategies/full_sync_strategy.rb +116 -0
- data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/sync_strategies/incremental_sync_strategy.rb +63 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/external_client/client.rb +314 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/external_client/connection.rb +74 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/inventory/external_inventory_item_status.rb +53 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/inventory/external_inventory_items.rb +106 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/inventory/hold_seats.rb +143 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/inventory/release_seats.rb +90 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/inventory/unstock_inventory.rb +143 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_item_availability.rb +325 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_product.rb +72 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_routes.rb +142 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_seat_layout.rb +255 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_stock_item.rb +55 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_trip_stop.rb +171 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_trips.rb +397 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_variant.rb +63 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_vehicle_type.rb +79 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/base.rb +39 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/booking.rb +113 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/booking_session.rb +43 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/booking_transaction.rb +236 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/direction.rb +71 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/passenger.rb +48 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/schedule.rb +150 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/seat.rb +31 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/seat_availability.rb +49 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/resources/seat_layout.rb +211 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/sync_manager.rb +17 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/sync_strategies/full_sync_strategy.rb +79 -0
- data/app/services/spree_cm_commissioner/integrations/larryta/sync_strategies/incremental_sync_strategy.rb +58 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/external_client/client.rb +14 -15
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_matches.rb +7 -4
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_zones.rb +6 -3
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_manager.rb +0 -3
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/full_sync_strategy.rb +1 -3
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/incremental_sync_strategy.rb +1 -3
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/webhook_sync_strategy.rb +1 -2
- data/app/services/spree_cm_commissioner/integrations/switch_cm/accept_push.rb +101 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/accommodation_lock.rb +41 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/acknowledge_reservations.rb +43 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/apply_ari.rb +119 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/ari_update.rb +24 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/availability_readback.rb +86 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/mark_seen.rb +53 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/ota/avail_notif_parser.rb +60 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/ota/base_parser.rb +60 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/ota/push_response.rb +38 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/ota/rate_amount_notif_parser.rb +46 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/ota/reservation_presenter.rb +99 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/ota/response_builder.rb +52 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/pushed_nights.rb +79 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/reservation.rb +118 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/reservation_feed.rb +143 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/room_catalog.rb +56 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/sync_manager.rb +16 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/sync_strategies/full_sync_strategy.rb +39 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/sync_strategies/incremental_sync_strategy.rb +51 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/unseen_room_nights.rb +39 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/validate_ari_updates.rb +136 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/xml/availability_parser.rb +103 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/xml/push_response.rb +45 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/xml/reservation_presenter.rb +74 -0
- data/app/services/spree_cm_commissioner/integrations/switch_cm/xml/response_builder.rb +19 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/external_client/client.rb +170 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/external_client/connection.rb +59 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/inventory/external_inventory_item_status.rb +48 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/inventory/external_inventory_items.rb +92 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/inventory/unstock_inventory.rb +230 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_item_availability.rb +270 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_locations.rb +96 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_nationality_pricing.rb +76 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_product.rb +69 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_routes.rb +110 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_seat_layout.rb +207 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_stock_item.rb +43 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_trip_stop.rb +192 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_trips.rb +377 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_variant.rb +56 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_vehicle_type.rb +51 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/base.rb +32 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/booking.rb +48 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/booking_transaction.rb +46 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/cell.rb +53 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/confirm_booking_request.rb +43 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/location.rb +37 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/schedule.rb +138 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/seat.rb +48 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/seat_layout.rb +79 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/sync_manager.rb +17 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/sync_strategies/full_sync_strategy.rb +87 -0
- data/app/services/spree_cm_commissioner/integrations/vireak_buntham/sync_strategies/incremental_sync_strategy.rb +53 -0
- data/app/services/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_by_variant.rb +4 -0
- data/app/services/spree_cm_commissioner/inventory_items/generate_permanent_item.rb +48 -0
- data/app/services/spree_cm_commissioner/inventory_items/reset.rb +4 -0
- data/app/services/spree_cm_commissioner/order_holds/hold.rb +17 -0
- data/app/services/spree_cm_commissioner/order_holds/release.rb +17 -0
- data/app/services/spree_cm_commissioner/place_resolver.rb +95 -0
- data/app/services/spree_cm_commissioner/transit_order/create.rb +1 -0
- data/app/services/spree_cm_commissioner/user_authenticator.rb +20 -12
- data/app/views/spree/admin/customer_notifications/_form.html.erb +9 -9
- data/app/views/spree/admin/customer_notifications/index.html.erb +36 -19
- data/app/views/spree/admin/homepage_section/_form.html.erb +19 -2
- data/app/views/spree/admin/homepage_section/_tabs.html.erb +7 -7
- data/app/views/spree/admin/homepage_section/index.html.erb +73 -6
- data/app/views/spree/admin/integrations/_book_me_bus_v1_fields.html.erb +47 -0
- data/app/views/spree/admin/integrations/_form.html.erb +16 -0
- data/app/views/spree/admin/integrations/_larryta_fields.html.erb +58 -0
- data/app/views/spree/admin/integrations/_switch_cm_fields.html.erb +53 -0
- data/app/views/spree/admin/integrations/_vireak_buntham_fields.html.erb +75 -0
- data/app/views/spree/admin/integrations/index.html.erb +1 -1
- data/app/views/spree/admin/notifications/index.html.erb +2 -1
- data/app/views/spree/admin/orders/line_items.html.erb +53 -0
- data/app/views/spree/admin/service_fee_rules/_form.html.erb +119 -0
- data/app/views/spree/admin/service_fee_rules/edit.html.erb +11 -0
- data/app/views/spree/admin/service_fee_rules/index.html.erb +91 -0
- data/app/views/spree/admin/service_fee_rules/new.html.erb +11 -0
- data/app/views/spree/admin/shared/_send_all_form.html.erb +1 -0
- data/app/views/spree/admin/shared/_send_test_form.html.erb +3 -3
- data/app/views/spree/admin/stock_managements/index.html.erb +14 -0
- data/config/locales/en.yml +36 -0
- data/config/locales/km.yml +32 -0
- data/config/routes.rb +34 -0
- data/db/migrate/20260327143200_create_cm_audit_events.rb +21 -0
- data/db/migrate/20260410045815_create_cm_currency_rates.rb +23 -0
- data/db/migrate/20260411102139_add_metadata_to_cm_inventory_items.rb +6 -0
- data/db/migrate/20260914000000_add_mini_app_to_homepage_sections.rb +5 -0
- data/db/migrate/20260917085551_create_cm_service_fee_rules.rb +16 -0
- data/db/migrate/20260917085552_add_service_fee_total_to_spree_line_items_and_orders.rb +6 -0
- data/db/migrate/20260928000000_add_oauth_application_id_to_cm_integrations.rb +5 -0
- data/db/migrate/20260928000001_add_closed_to_cm_inventory_items.rb +5 -0
- data/lib/spree_cm_commissioner/cached_inventory_item.rb +7 -1
- data/lib/spree_cm_commissioner/engine.rb +3 -0
- data/lib/spree_cm_commissioner/test_helper/factories/homepage_section_factory.rb +7 -0
- data/lib/spree_cm_commissioner/test_helper/factories/integration_factory.rb +17 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- metadata +187 -4
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
module SpreeCmCommissioner::Integrations::BookMeBusV1::ExternalClient
|
|
2
|
+
class Client
|
|
3
|
+
include Connection
|
|
4
|
+
include SpreeCmCommissioner::AuditWrapper
|
|
5
|
+
|
|
6
|
+
BASE_PATH = '/api/v2'.freeze
|
|
7
|
+
RATE_LIMIT = 100
|
|
8
|
+
|
|
9
|
+
attr_reader :integration
|
|
10
|
+
|
|
11
|
+
def initialize(integration:)
|
|
12
|
+
@integration = integration
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Location Operations
|
|
16
|
+
|
|
17
|
+
# Get all available locations
|
|
18
|
+
# @return [Array<SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::Location>] Array of location objects
|
|
19
|
+
def get_locations! # rubocop:disable Naming/AccessorMethodName
|
|
20
|
+
endpoint = "#{BASE_PATH}/locations"
|
|
21
|
+
|
|
22
|
+
response = get(endpoint)
|
|
23
|
+
handle_response(response, SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::Location, collection: true)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Trip Operations
|
|
27
|
+
|
|
28
|
+
# Search available trips for a given route and date
|
|
29
|
+
# @param origin_id [String] The origin location ID
|
|
30
|
+
# @param destination_id [String] The destination location ID
|
|
31
|
+
# @param on_date [String] The travel date (YYYY-MM-DD format)
|
|
32
|
+
# @return [Array<SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::Trip>] Array of available trip objects
|
|
33
|
+
def search_trips!(origin_id:, destination_id:, on_date:)
|
|
34
|
+
params = {
|
|
35
|
+
origin_id: origin_id,
|
|
36
|
+
destination_id: destination_id,
|
|
37
|
+
on_date: on_date,
|
|
38
|
+
# Scopes results to this integration's operator when multiple Integrations share one
|
|
39
|
+
# BookMeBus application (Application#use_multiple_operators?). Compacted out (rather than
|
|
40
|
+
# sent as an empty value) when unset, so a single-operator setup behaves exactly as before.
|
|
41
|
+
operator_id: integration.operator_id
|
|
42
|
+
}.compact
|
|
43
|
+
endpoint = "#{BASE_PATH}/trip_availabilities"
|
|
44
|
+
|
|
45
|
+
response = get(endpoint, params)
|
|
46
|
+
handle_response(response, SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::Trip, collection: true)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Seat Layout Operations
|
|
50
|
+
|
|
51
|
+
# Get seat layout for a specific trip segment
|
|
52
|
+
# @param trip_id [String] The trip ID
|
|
53
|
+
# @param from_stop_id [String] The departure stop ID
|
|
54
|
+
# @param to_stop_id [String] The arrival stop ID
|
|
55
|
+
# @param on_date [String] The travel date (YYYY-MM-DD format)
|
|
56
|
+
# @param show_all_stops [Boolean] Whether to show all stops (default: false)
|
|
57
|
+
# @return [SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::SeatLayout] Seat layout object
|
|
58
|
+
def get_seat_layout!(trip_id:, from_stop_id:, to_stop_id:, on_date:, show_all_stops: false)
|
|
59
|
+
params = {
|
|
60
|
+
trip_id: trip_id,
|
|
61
|
+
from_stop_id: from_stop_id,
|
|
62
|
+
to_stop_id: to_stop_id,
|
|
63
|
+
on_date: on_date,
|
|
64
|
+
show_all_stops: show_all_stops
|
|
65
|
+
}
|
|
66
|
+
endpoint = "#{BASE_PATH}/seat_layouts"
|
|
67
|
+
|
|
68
|
+
response = get(endpoint, params)
|
|
69
|
+
handle_response(response, SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::SeatLayout)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Reservation Operations
|
|
73
|
+
|
|
74
|
+
# Create a reservation cart in BookMeBus
|
|
75
|
+
# @param params [Hash] Reservation parameters
|
|
76
|
+
# @option params [Integer] :trip_id The BookMeBus trip ID
|
|
77
|
+
# @option params [Integer] :from_stop_id The boarding stop ID
|
|
78
|
+
# @option params [Integer] :to_stop_id The drop-off stop ID
|
|
79
|
+
# @option params [Integer] :from_stop_time_id The boarding stop time ID
|
|
80
|
+
# @option params [Integer] :to_stop_time_id The drop-off stop time ID
|
|
81
|
+
# @option params [String] :departure_date The travel date (YYYY-MM-DD format)
|
|
82
|
+
# @option params [Hash] :reserved_seats Reserved seats hash keyed by stop_id with seat detail objects
|
|
83
|
+
# @option params [String] :contact_name Passenger contact name
|
|
84
|
+
# @option params [String] :contact_email Passenger contact email
|
|
85
|
+
# @option params [String] :contact_phone Passenger contact phone
|
|
86
|
+
# @option params [Object] :internal_order Internal order for audit
|
|
87
|
+
# @return [SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::ReservationCart] The created reservation cart
|
|
88
|
+
def create_reservation!(params)
|
|
89
|
+
number_of_seats = params[:reserved_seats].values.flatten.count
|
|
90
|
+
|
|
91
|
+
body = {
|
|
92
|
+
reservations: [
|
|
93
|
+
{
|
|
94
|
+
trip_id: params[:trip_id],
|
|
95
|
+
from_stop_id: params[:from_stop_id],
|
|
96
|
+
to_stop_id: params[:to_stop_id],
|
|
97
|
+
from_stop_time_id: params[:from_stop_time_id],
|
|
98
|
+
to_stop_time_id: params[:to_stop_time_id],
|
|
99
|
+
departure_date: params[:departure_date],
|
|
100
|
+
number_of_seats: number_of_seats,
|
|
101
|
+
reserved_seats: params[:reserved_seats],
|
|
102
|
+
contact_name: params[:contact_name],
|
|
103
|
+
contact_email: params[:contact_email],
|
|
104
|
+
contact_phone: params[:contact_phone],
|
|
105
|
+
is_request_pickup: false
|
|
106
|
+
}.compact
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
endpoint = "#{BASE_PATH}/trip_reservations"
|
|
111
|
+
|
|
112
|
+
with_audit(
|
|
113
|
+
event_base: 'bookmebus.reservations.post',
|
|
114
|
+
request: { method: 'POST', endpoint: endpoint, body: body },
|
|
115
|
+
auditable: params[:internal_order]
|
|
116
|
+
) do
|
|
117
|
+
response = post(endpoint, body)
|
|
118
|
+
handle_response(response, SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::ReservationCart)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Wallet Payment Operations
|
|
123
|
+
# Create a wallet payment for a reservation cart
|
|
124
|
+
# @param cart_id [String] The reservation cart ID
|
|
125
|
+
# @return [SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::WalletPayment] The created wallet payment
|
|
126
|
+
def create_wallet_payment!(cart_id:, internal_order:)
|
|
127
|
+
endpoint = "#{BASE_PATH}/wallet_payments?reservation_cart_id=#{cart_id}"
|
|
128
|
+
|
|
129
|
+
with_audit(
|
|
130
|
+
event_base: 'bookmebus.wallet_payments.post',
|
|
131
|
+
request: { method: 'POST', endpoint: endpoint, body: {} },
|
|
132
|
+
auditable: internal_order
|
|
133
|
+
) do
|
|
134
|
+
response = post(endpoint, {})
|
|
135
|
+
handle_response(response, SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::WalletPayment)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Confirm a wallet payment (deduct from user's BookMeBus wallet)
|
|
140
|
+
# @param payment_id [String] The wallet payment ID
|
|
141
|
+
# @return [SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::WalletPayment] The confirmed wallet payment
|
|
142
|
+
def confirm_wallet_payment!(payment_id:, internal_order:)
|
|
143
|
+
endpoint = "#{BASE_PATH}/bmb_wallets?payment_id=#{payment_id}"
|
|
144
|
+
|
|
145
|
+
with_audit(
|
|
146
|
+
event_base: 'bookmebus.wallet_payments.post',
|
|
147
|
+
request: { method: 'POST', endpoint: endpoint, body: {} },
|
|
148
|
+
auditable: internal_order
|
|
149
|
+
) do
|
|
150
|
+
response = post(endpoint, {})
|
|
151
|
+
handle_response(response, SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::WalletPayment)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Get passenger seat info for a specific seat
|
|
156
|
+
# @param stop_id [String] The stop ID
|
|
157
|
+
# @param trip_id [String] The trip ID
|
|
158
|
+
# @param seat [String] The seat number/label
|
|
159
|
+
# @param departure_date [String] The departure date (YYYY-MM-DD format)
|
|
160
|
+
# @return [SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::InventoryItemStatus] Seat/passenger info
|
|
161
|
+
def inventory_item_status!(stop_id:, trip_id:, label:, layer:, departure_date:)
|
|
162
|
+
params = {
|
|
163
|
+
stop_id: stop_id,
|
|
164
|
+
trip_id: trip_id,
|
|
165
|
+
seat: {
|
|
166
|
+
label: label,
|
|
167
|
+
layer: layer
|
|
168
|
+
},
|
|
169
|
+
departure_date: departure_date
|
|
170
|
+
}
|
|
171
|
+
endpoint = "#{BASE_PATH}/passenger_seat_infos"
|
|
172
|
+
|
|
173
|
+
with_audit(
|
|
174
|
+
event_base: 'bookmebus.passenger_seat_infos.get',
|
|
175
|
+
request: { method: 'GET', endpoint: endpoint, params: params },
|
|
176
|
+
auditable: integration
|
|
177
|
+
) do
|
|
178
|
+
response = get(endpoint, params)
|
|
179
|
+
handle_response(response, SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::InventoryItemStatus)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
private
|
|
184
|
+
|
|
185
|
+
def handle_response(response, model_class, collection: false) # rubocop:disable Metrics/PerceivedComplexity
|
|
186
|
+
raise_api_error(response) unless response.success?
|
|
187
|
+
|
|
188
|
+
data = response.body
|
|
189
|
+
|
|
190
|
+
# Handle both JSON:API format and direct object format
|
|
191
|
+
if data.is_a?(Hash) && data['data'].present?
|
|
192
|
+
# JSON:API format
|
|
193
|
+
collection ? model_class.from_json_api(data) : model_class.from_json_api_single(data)
|
|
194
|
+
|
|
195
|
+
elsif collection && data.is_a?(Array)
|
|
196
|
+
# Direct array format
|
|
197
|
+
data.map { |item| model_class.new(item) }
|
|
198
|
+
elsif !collection && data.is_a?(Hash)
|
|
199
|
+
# Direct object format
|
|
200
|
+
model_class.new(data)
|
|
201
|
+
else
|
|
202
|
+
Rails.logger.warn "handle_response - returning nil, data: #{data.inspect}"
|
|
203
|
+
nil
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def raise_api_error(response)
|
|
208
|
+
status = response.status
|
|
209
|
+
body = response.body
|
|
210
|
+
|
|
211
|
+
message = if body.is_a?(Hash)
|
|
212
|
+
error = body['errors']&.first || body['error'] || body['message']
|
|
213
|
+
case error
|
|
214
|
+
when Hash
|
|
215
|
+
error['detail'] || error['title'] || error.to_json
|
|
216
|
+
when String
|
|
217
|
+
error
|
|
218
|
+
else
|
|
219
|
+
"API request failed with status #{status}"
|
|
220
|
+
end
|
|
221
|
+
else
|
|
222
|
+
"API request failed with status #{status}"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
message = "#{message} (body: #{body.to_json})" if status >= 500
|
|
226
|
+
|
|
227
|
+
raise SpreeCmCommissioner::Integrations::ExternalClientError.new(message, status)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/external_client/connection.rb
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module SpreeCmCommissioner::Integrations::BookMeBusV1::ExternalClient
|
|
2
|
+
module Connection
|
|
3
|
+
OAUTH_TOKEN_PATH = '/oauth/token'.freeze
|
|
4
|
+
REQUEST_TIMEOUT = 30
|
|
5
|
+
OPEN_TIMEOUT = 10
|
|
6
|
+
|
|
7
|
+
def get(url, params = nil, headers = nil)
|
|
8
|
+
execute_request { connection.get(url, params, build_headers(headers)) }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def post(url, body = nil, headers = nil)
|
|
12
|
+
execute_request { connection.post(url, body, build_headers(headers)) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def put(url, body = nil, headers = nil)
|
|
16
|
+
execute_request { connection.put(url, body, build_headers(headers)) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def patch(url, body = nil, headers = nil)
|
|
20
|
+
execute_request { connection.patch(url, body, build_headers(headers)) }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def delete(url, params = nil, headers = nil)
|
|
24
|
+
execute_request { connection.delete(url, params, build_headers(headers)) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def connection
|
|
28
|
+
@connection ||= Faraday.new(url: @integration.base_url) do |faraday|
|
|
29
|
+
faraday.request :json
|
|
30
|
+
faraday.response :json, content_type: /\bjson$/
|
|
31
|
+
faraday.options.timeout = REQUEST_TIMEOUT
|
|
32
|
+
faraday.options.open_timeout = OPEN_TIMEOUT
|
|
33
|
+
faraday.adapter Faraday.default_adapter
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Thread-safe token access with automatic refresh on expiration
|
|
38
|
+
def access_token
|
|
39
|
+
token_mutex.synchronize do
|
|
40
|
+
@access_token ||= @integration.access_token
|
|
41
|
+
@token_expires_at ||= @integration.token_expires_at
|
|
42
|
+
|
|
43
|
+
fetch_and_persist_access_token! if token_expired?
|
|
44
|
+
|
|
45
|
+
@access_token
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def token_mutex
|
|
52
|
+
@token_mutex ||= Mutex.new
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def token_expired?
|
|
56
|
+
@access_token.blank? || @token_expires_at.blank? || Time.current >= @token_expires_at
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def fetch_and_persist_access_token!
|
|
60
|
+
response = oauth_connection.post(OAUTH_TOKEN_PATH) do |req|
|
|
61
|
+
req.body = {
|
|
62
|
+
grant_type: 'client_credentials',
|
|
63
|
+
client_id: @integration.client_id,
|
|
64
|
+
client_secret: @integration.client_secret
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
unless response.success?
|
|
69
|
+
raise SpreeCmCommissioner::Integrations::ExternalClientError.new(
|
|
70
|
+
'Failed to fetch access token',
|
|
71
|
+
response.status
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
token_data = response.body
|
|
76
|
+
@access_token = token_data['access_token']
|
|
77
|
+
expires_in = token_data['expires_in'] || 3600
|
|
78
|
+
@token_expires_at = Time.current + expires_in.seconds - 60.seconds
|
|
79
|
+
|
|
80
|
+
update_integration_token!
|
|
81
|
+
reset_connection
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Execute HTTP request with automatic token refresh on 401
|
|
85
|
+
def execute_request(retry_count: 0, &block)
|
|
86
|
+
response = block.call
|
|
87
|
+
|
|
88
|
+
if response.status == 401 && retry_count.zero?
|
|
89
|
+
invalidate_token
|
|
90
|
+
access_token
|
|
91
|
+
reset_connection
|
|
92
|
+
return execute_request(retry_count: 1, &block)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
response
|
|
96
|
+
rescue Faraday::TimeoutError => e
|
|
97
|
+
raise SpreeCmCommissioner::Integrations::ExternalClientError.new(
|
|
98
|
+
"Request timeout: #{e.message}",
|
|
99
|
+
408
|
|
100
|
+
)
|
|
101
|
+
rescue Faraday::Error => e
|
|
102
|
+
raise SpreeCmCommissioner::Integrations::ExternalClientError.new(
|
|
103
|
+
"Request failed: #{e.message}",
|
|
104
|
+
nil
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def build_headers(extra_headers)
|
|
109
|
+
default_headers = {
|
|
110
|
+
'Content-Type' => 'application/json',
|
|
111
|
+
'Accept' => 'application/json',
|
|
112
|
+
'Authorization' => "Bearer #{access_token}"
|
|
113
|
+
}
|
|
114
|
+
return default_headers if extra_headers.blank?
|
|
115
|
+
|
|
116
|
+
default_headers.merge(extra_headers)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def invalidate_token
|
|
120
|
+
token_mutex.synchronize do
|
|
121
|
+
@access_token = nil
|
|
122
|
+
@token_expires_at = nil
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def oauth_connection
|
|
127
|
+
@oauth_connection ||= Faraday.new(url: @integration.base_url) do |faraday|
|
|
128
|
+
faraday.request :url_encoded
|
|
129
|
+
faraday.response :json, content_type: /\bjson$/
|
|
130
|
+
faraday.options.timeout = REQUEST_TIMEOUT
|
|
131
|
+
faraday.options.open_timeout = OPEN_TIMEOUT
|
|
132
|
+
faraday.adapter Faraday.default_adapter
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def reset_connection
|
|
137
|
+
@connection = nil
|
|
138
|
+
connection
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def update_integration_token!
|
|
142
|
+
@integration.access_token = @access_token
|
|
143
|
+
@integration.token_expires_at = @token_expires_at
|
|
144
|
+
@integration.save! if @integration.changed?
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SpreeCmCommissioner
|
|
4
|
+
module Integrations
|
|
5
|
+
class BookMeBusV1
|
|
6
|
+
module Inventory
|
|
7
|
+
# Fetches detailed status for a specific inventory item (seat) from BookMeBus
|
|
8
|
+
# Uses the inventory_item_status! API (passenger_seat_infos endpoint)
|
|
9
|
+
class ExternalInventoryItemStatus
|
|
10
|
+
prepend ::Spree::ServiceModule::Base
|
|
11
|
+
|
|
12
|
+
def call(integration:, order:, options:)
|
|
13
|
+
@integration = integration
|
|
14
|
+
@order = order
|
|
15
|
+
@options = options
|
|
16
|
+
|
|
17
|
+
validate_params!
|
|
18
|
+
item_status = fetch_item_status
|
|
19
|
+
|
|
20
|
+
success(item_status: item_status)
|
|
21
|
+
rescue SpreeCmCommissioner::Integrations::ExternalClientError => e
|
|
22
|
+
failure(nil, e.message)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
attr_reader :integration, :order, :options
|
|
28
|
+
|
|
29
|
+
def validate_params!
|
|
30
|
+
raise_error('stop_id is required') if options[:stop_id].blank?
|
|
31
|
+
raise_error('seat is required') if options[:label].blank?
|
|
32
|
+
raise_error('departure_date is required') if options[:departure_date].blank?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def fetch_item_status
|
|
36
|
+
integration.client.inventory_item_status!(
|
|
37
|
+
stop_id: options[:stop_id],
|
|
38
|
+
trip_id: options[:trip_id],
|
|
39
|
+
label: options[:label],
|
|
40
|
+
layer: options[:layer],
|
|
41
|
+
departure_date: options[:departure_date]
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def raise_error(msg)
|
|
46
|
+
raise SpreeCmCommissioner::Integrations::SyncError, msg
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SpreeCmCommissioner
|
|
4
|
+
module Integrations
|
|
5
|
+
class BookMeBusV1
|
|
6
|
+
module Inventory
|
|
7
|
+
# Fetches all inventory items (seats) for an order from BookMeBus
|
|
8
|
+
# Uses the get_seat_layout! API to retrieve seat availability
|
|
9
|
+
class ExternalInventoryItems
|
|
10
|
+
prepend ::Spree::ServiceModule::Base
|
|
11
|
+
|
|
12
|
+
def call(integration:, order:)
|
|
13
|
+
@integration = integration
|
|
14
|
+
@order = order
|
|
15
|
+
|
|
16
|
+
items = []
|
|
17
|
+
order.line_items.each do |line_item|
|
|
18
|
+
items.concat(fetch_items_for_line_item(line_item))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
success(items: items)
|
|
22
|
+
rescue SpreeCmCommissioner::Integrations::ExternalClientError => e
|
|
23
|
+
failure(nil, e.message)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :integration, :order
|
|
29
|
+
|
|
30
|
+
def fetch_items_for_line_item(line_item)
|
|
31
|
+
trip_mapping = find_trip_mapping(line_item)
|
|
32
|
+
return [] if trip_mapping.nil?
|
|
33
|
+
|
|
34
|
+
seat_layout = fetch_seat_layout(line_item, trip_mapping)
|
|
35
|
+
build_inventory_items(seat_layout, line_item, trip_mapping)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def find_trip_mapping(line_item)
|
|
39
|
+
return nil if line_item.trip_id.blank?
|
|
40
|
+
|
|
41
|
+
SpreeCmCommissioner::IntegrationMapping.find_by(
|
|
42
|
+
integration_id: integration.id,
|
|
43
|
+
internal_type: 'SpreeCmCommissioner::Trip',
|
|
44
|
+
internal_id: line_item.trip_id,
|
|
45
|
+
status: :active
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def fetch_seat_layout(line_item, trip_mapping)
|
|
50
|
+
integration.client.get_seat_layout!(
|
|
51
|
+
trip_id: trip_mapping.external_id.to_i,
|
|
52
|
+
from_stop_id: fetch_stop_id(trip_mapping, line_item.boarding_trip_stop_id, 'from_stop_id'),
|
|
53
|
+
to_stop_id: fetch_stop_id(trip_mapping, line_item.drop_off_trip_stop_id, 'to_stop_id'),
|
|
54
|
+
on_date: line_item.from_date.to_date.strftime('%Y-%m-%d')
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def fetch_stop_id(trip_mapping, trip_stop_id, fallback_key)
|
|
59
|
+
return trip_mapping.external_payload[fallback_key] if trip_stop_id.blank?
|
|
60
|
+
|
|
61
|
+
stop_mapping = SpreeCmCommissioner::IntegrationMapping.find_by(
|
|
62
|
+
internal_type: 'SpreeCmCommissioner::TripStop',
|
|
63
|
+
internal_id: trip_stop_id,
|
|
64
|
+
status: :active
|
|
65
|
+
)
|
|
66
|
+
stop_mapping&.external_payload&.dig('stop', 'id') || trip_mapping.external_payload[fallback_key]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def build_inventory_items(seat_layout, line_item, trip_mapping)
|
|
70
|
+
items = []
|
|
71
|
+
items += seat_layout.seats.map do |seat|
|
|
72
|
+
{
|
|
73
|
+
id: "#{trip_mapping.external_id}-#{seat.label}",
|
|
74
|
+
seat_label: seat.label,
|
|
75
|
+
seat_type: seat.seat_type_name,
|
|
76
|
+
layer: seat.layer,
|
|
77
|
+
status: seat.available? ? 'available' : 'booked',
|
|
78
|
+
gender: seat.gender,
|
|
79
|
+
position: seat.position,
|
|
80
|
+
from_stop_id: seat_layout.from_stop_id,
|
|
81
|
+
departure_date: line_item.from_date.to_date.strftime('%Y-%m-%d'),
|
|
82
|
+
trip_id: trip_mapping.external_id.to_i
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
items
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|