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,83 @@
|
|
|
1
|
+
module Spree::Api::SwitchCm
|
|
2
|
+
module Ota
|
|
3
|
+
# Booking.com's two OTA reservation streams share one shape; subclasses name the stream.
|
|
4
|
+
class ReservationStreamsController < BaseController
|
|
5
|
+
# GET /api/switch_cm/hotels/ota/OTA_HotelResNotif (ResNotifsController): new reservations
|
|
6
|
+
# GET /api/switch_cm/hotels/ota/OTA_HotelResModifyNotif (ResModifyNotifsController): cancellations
|
|
7
|
+
# ?hotel_ids=&id=&last_change=&limit= returns what hasn't been acknowledged; `id` or
|
|
8
|
+
# `last_change` re-reads regardless.
|
|
9
|
+
def index
|
|
10
|
+
integrations, unknown_hotel_ids = requested_integrations(params[:hotel_ids])
|
|
11
|
+
return render_fault(:forbidden, 'Not authorized for these hotels') if integrations.empty?
|
|
12
|
+
|
|
13
|
+
reservations = SpreeCmCommissioner::Integrations::SwitchCm::ReservationFeed.new(integrations).public_send(
|
|
14
|
+
feed_method,
|
|
15
|
+
id: params[:id],
|
|
16
|
+
last_change: SpreeCmCommissioner::Integrations::SwitchCm::ReservationFeed.parse_last_change(params[:last_change]),
|
|
17
|
+
limit: params[:limit]
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
document = SpreeCmCommissioner::Integrations::SwitchCm::Ota::ResponseBuilder.notification(
|
|
21
|
+
notification_root, ruid: ruid, warnings: hotel_warnings(unknown_hotel_ids)
|
|
22
|
+
) do |xml|
|
|
23
|
+
xml.send(container) do
|
|
24
|
+
reservations.each do |reservation|
|
|
25
|
+
present(SpreeCmCommissioner::Integrations::SwitchCm::Ota::ReservationPresenter.new(reservation), xml)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
render xml: document
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# POST /api/switch_cm/hotels/ota/OTA_HotelResNotif (ResNotifsController)
|
|
33
|
+
# POST /api/switch_cm/hotels/ota/OTA_HotelResModifyNotif (ResModifyNotifsController)
|
|
34
|
+
# Acknowledges by reservation id: <...RS><Success/><...><HotelReservationID ResID_Value="..."/></...></...RS>
|
|
35
|
+
def acknowledge
|
|
36
|
+
# Booking.com's contract: <Success/> takes the reservations off the queue, while <Errors>
|
|
37
|
+
# (code 193) means the channel manager couldn't process them and they stay queued.
|
|
38
|
+
return render_success if processing_failed?
|
|
39
|
+
|
|
40
|
+
result = SpreeCmCommissioner::Integrations::SwitchCm::AcknowledgeReservations.call(
|
|
41
|
+
integrations: switch_cm_integrations.includes(:vendor).to_a,
|
|
42
|
+
reservation_ids: request_document.xpath('//HotelReservationID/@ResID_Value').map(&:value),
|
|
43
|
+
status: acknowledged_status
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
warnings = result.value[:unknown].map do |reservation_id|
|
|
47
|
+
{ type: 3, text: "Reservation #{reservation_id} not found for acknowledgement", record_id: reservation_id }
|
|
48
|
+
end
|
|
49
|
+
render_success(warnings: warnings)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def feed_method
|
|
55
|
+
raise NotImplementedError, "#{self.class.name} must implement feed_method"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def acknowledged_status
|
|
59
|
+
raise NotImplementedError, "#{self.class.name} must implement acknowledged_status"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def notification_root
|
|
63
|
+
raise NotImplementedError, "#{self.class.name} must implement notification_root"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def container
|
|
67
|
+
raise NotImplementedError, "#{self.class.name} must implement container"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def present(_presenter, _xml)
|
|
71
|
+
raise NotImplementedError, "#{self.class.name} must implement present"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def processing_failed?
|
|
75
|
+
request_document.at_xpath('/*/Errors').present? && request_document.at_xpath('/*/Success').nil?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def hotel_warnings(unknown_hotel_ids)
|
|
79
|
+
unknown_hotel_ids.map { |hotel_id| { type: 6, text: "Not authorized for hotel #{hotel_id}", record_id: hotel_id } }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Spree::Api::SwitchCm
|
|
2
|
+
class TokensController < BaseController
|
|
3
|
+
# Booking.com's tokens also last an hour; connectors refresh on that schedule.
|
|
4
|
+
TOKEN_LIFETIME = 1.hour
|
|
5
|
+
|
|
6
|
+
skip_before_action :authenticate_switch_cm!
|
|
7
|
+
|
|
8
|
+
# POST /api/switch_cm/token-based-authentication/exchange
|
|
9
|
+
# Client id and secret in (JSON or XML), { jwt, ruid } out, then `Authorization: Bearer` on every
|
|
10
|
+
# other call. The value is a Doorkeeper access token rather than a signed JWT, so a connector
|
|
11
|
+
# that only forwards it works but one that decodes it won't.
|
|
12
|
+
def create
|
|
13
|
+
client_id, client_secret = credentials
|
|
14
|
+
return render_fault(:bad_request, 'client_id and client_secret are required') if client_id.blank? || client_secret.blank?
|
|
15
|
+
|
|
16
|
+
@oauth_application = Spree::OauthApplication.find_by(uid: client_id)
|
|
17
|
+
unless @oauth_application&.secret_matches?(client_secret) && switch_cm_integrations.exists?
|
|
18
|
+
return render_fault(:unauthorized, 'Invalid client credentials')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
render_token(issue_token.plaintext_token)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def issue_token
|
|
27
|
+
Spree::OauthAccessToken.create_for(
|
|
28
|
+
application: @oauth_application,
|
|
29
|
+
resource_owner: nil,
|
|
30
|
+
scopes: '',
|
|
31
|
+
expires_in: TOKEN_LIFETIME.to_i,
|
|
32
|
+
use_refresh_token: false
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def credentials
|
|
37
|
+
return [params[:client_id], params[:client_secret]] unless xml_request?
|
|
38
|
+
|
|
39
|
+
%w[client_id client_secret].map { |name| request_document.at_xpath("/request/#{name}")&.text&.strip }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def xml_request?
|
|
43
|
+
request.content_mime_type&.symbol == :xml
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def render_token(token)
|
|
47
|
+
return render json: { jwt: token, ruid: ruid } unless xml_request?
|
|
48
|
+
|
|
49
|
+
document = SpreeCmCommissioner::Integrations::SwitchCm::Xml::ResponseBuilder.build('response', ruid: ruid) do |xml|
|
|
50
|
+
xml.jwt token
|
|
51
|
+
xml.ruid ruid
|
|
52
|
+
end
|
|
53
|
+
render xml: document
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# override
|
|
57
|
+
def render_fault(status, text, code: nil)
|
|
58
|
+
code ||= Rack::Utils.status_code(status)
|
|
59
|
+
|
|
60
|
+
if xml_request?
|
|
61
|
+
render xml: SpreeCmCommissioner::Integrations::SwitchCm::Xml::ResponseBuilder.fault('response', code: code, text: text, ruid: ruid),
|
|
62
|
+
status: status
|
|
63
|
+
else
|
|
64
|
+
render json: { errors: [{ code: code, message: text }], ruid: ruid }, status: status
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Spree::Api::SwitchCm
|
|
2
|
+
module Xml
|
|
3
|
+
class AvailabilitiesController < BaseController
|
|
4
|
+
before_action :require_active_integration!
|
|
5
|
+
|
|
6
|
+
# POST /api/switch_cm/hotels/xml/availability
|
|
7
|
+
# Rooms to sell, prices and closed in one message, validated and applied in the request
|
|
8
|
+
# (AcceptPush); the answer is the real outcome.
|
|
9
|
+
def create
|
|
10
|
+
result = SpreeCmCommissioner::Integrations::SwitchCm::AcceptPush.call(
|
|
11
|
+
integration: current_integration,
|
|
12
|
+
message: 'availability',
|
|
13
|
+
updates: parser.updates,
|
|
14
|
+
request_id: ruid
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
push_response = SpreeCmCommissioner::Integrations::SwitchCm::Xml::PushResponse.new(result: result.value, ruid: ruid)
|
|
18
|
+
render xml: push_response.to_xml, status: push_response.http_status
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# override
|
|
24
|
+
def response_root
|
|
25
|
+
'availability'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def parser
|
|
29
|
+
@parser ||= SpreeCmCommissioner::Integrations::SwitchCm::Xml::AvailabilityParser.new(request_document)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# B.XML pushes carry no hotel id; the rooms name it.
|
|
33
|
+
# override
|
|
34
|
+
def accommodation_id_from_request
|
|
35
|
+
vendor_id_of_room(parser.first_room_id)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Spree::Api::SwitchCm
|
|
2
|
+
module Xml
|
|
3
|
+
# Booking.com's B.XML family (/hotels/xml/...): a request that fails as a whole answers with
|
|
4
|
+
# a <fault code string/> under the call's root element. Requests carry their parameters
|
|
5
|
+
# in a <request> body.
|
|
6
|
+
class BaseController < Spree::Api::SwitchCm::BaseController
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def response_root
|
|
10
|
+
raise NotImplementedError, "#{self.class.name} must implement response_root"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# override
|
|
14
|
+
def render_fault(status, text, code: nil)
|
|
15
|
+
code ||= Rack::Utils.status_code(status)
|
|
16
|
+
render xml: SpreeCmCommissioner::Integrations::SwitchCm::Xml::ResponseBuilder.fault(response_root, code: code, text: text, ruid: ruid),
|
|
17
|
+
status: status
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def render_document(&block)
|
|
21
|
+
render xml: SpreeCmCommissioner::Integrations::SwitchCm::Xml::ResponseBuilder.build(response_root, ruid: ruid, &block)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# override
|
|
25
|
+
def accommodation_id_from_request
|
|
26
|
+
request_value('hotel_id')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# A parameter from the <request> body, falling back to the query string.
|
|
30
|
+
def request_value(name)
|
|
31
|
+
return params[name] if request.raw_post.blank?
|
|
32
|
+
|
|
33
|
+
request_document.at_xpath("/request/#{name}")&.text&.strip.presence || params[name]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Spree::Api::SwitchCm
|
|
2
|
+
module Xml
|
|
3
|
+
class ReservationSummariesController < BaseController
|
|
4
|
+
before_action :require_integration!
|
|
5
|
+
|
|
6
|
+
# POST /api/switch_cm/hotels/xml/reservationssummary with <request><hotel_id/></request>
|
|
7
|
+
# The hotel's confirmed stays checking out from tomorrow on, however long ago they were
|
|
8
|
+
# booked. The channel manager imports these while setting the hotel up, so they count against
|
|
9
|
+
# its availability before its first push. Read-only: nothing is marked seen.
|
|
10
|
+
def create
|
|
11
|
+
reservations = SpreeCmCommissioner::Integrations::SwitchCm::ReservationFeed.new([current_integration]).summary
|
|
12
|
+
|
|
13
|
+
render_document do |xml|
|
|
14
|
+
reservations.each do |reservation|
|
|
15
|
+
SpreeCmCommissioner::Integrations::SwitchCm::Xml::ReservationPresenter.new(reservation, summary: true).build(xml)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# override
|
|
23
|
+
def response_root
|
|
24
|
+
'reservations'
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Spree::Api::SwitchCm
|
|
2
|
+
module Xml
|
|
3
|
+
class ReservationsController < BaseController
|
|
4
|
+
# POST /api/switch_cm/hotels/xml/reservations with <request><hotel_id/><last_change/><limit/><id/></request>
|
|
5
|
+
# New and cancelled reservations in one stream. B.XML has no acknowledgement, so returning a
|
|
6
|
+
# reservation is what marks it seen; `last_change` re-reads recent ones regardless.
|
|
7
|
+
def create
|
|
8
|
+
integrations, = requested_integrations(request_value('hotel_id') || request_value('hotel_ids'))
|
|
9
|
+
return render_fault(:forbidden, 'Not authorized for these hotels') if integrations.empty?
|
|
10
|
+
|
|
11
|
+
reservations = SpreeCmCommissioner::Integrations::SwitchCm::ReservationFeed.new(integrations).changed_reservations(
|
|
12
|
+
id: request_value('id'),
|
|
13
|
+
last_change: SpreeCmCommissioner::Integrations::SwitchCm::ReservationFeed.parse_last_change(request_value('last_change')),
|
|
14
|
+
limit: request_value('limit')
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
document = SpreeCmCommissioner::Integrations::SwitchCm::Xml::ResponseBuilder.build(response_root, ruid: ruid) do |xml|
|
|
18
|
+
reservations.each { |reservation| SpreeCmCommissioner::Integrations::SwitchCm::Xml::ReservationPresenter.new(reservation).build(xml) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Marked only once the document is built. One that fails to mark is simply returned
|
|
22
|
+
# again next time, which is harmless: its status is the same.
|
|
23
|
+
failed = mark_seen(reservations)
|
|
24
|
+
log_mark_seen_failures(failed) if failed.any?
|
|
25
|
+
|
|
26
|
+
render xml: document
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# override
|
|
32
|
+
def response_root
|
|
33
|
+
'reservations'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def mark_seen(reservations)
|
|
37
|
+
reservations.each_with_object([]) do |reservation, failed|
|
|
38
|
+
SpreeCmCommissioner::Integrations::SwitchCm::MarkSeen.call(
|
|
39
|
+
integration: reservation.integration, order: reservation.order, status: reservation.status
|
|
40
|
+
)
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
failed << {
|
|
43
|
+
order_id: reservation.id,
|
|
44
|
+
integration_id: reservation.integration.id,
|
|
45
|
+
error_class: e.class.name,
|
|
46
|
+
error_message: e.message
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def log_mark_seen_failures(failed)
|
|
52
|
+
CmAppLogger.error(label: "#{self.class.name}#mark_seen failed", data: { ruid: ruid, failed: failed })
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Spree::Api::SwitchCm
|
|
2
|
+
module Xml
|
|
3
|
+
class RoomRateAvailabilitiesController < BaseController
|
|
4
|
+
DAYS_RANGE = (1..31)
|
|
5
|
+
|
|
6
|
+
before_action :require_integration!
|
|
7
|
+
|
|
8
|
+
# POST /api/switch_cm/hotels/xml/roomrateavailability with <request><hotel_id/><start_date/><number_of_days/><room_id/></request>
|
|
9
|
+
# What we hold per room and night, so the channel manager can check its pushes landed.
|
|
10
|
+
# number_of_days is 1-31, 31 by default, as at Booking.com.
|
|
11
|
+
def create
|
|
12
|
+
start_date = parse_date(request_value('start_date')) || Time.zone.today
|
|
13
|
+
days = (request_value('number_of_days').presence || DAYS_RANGE.max).to_i
|
|
14
|
+
return render_fault(:bad_request, "number_of_days must be between #{DAYS_RANGE.min} and #{DAYS_RANGE.max}") unless DAYS_RANGE.cover?(days)
|
|
15
|
+
|
|
16
|
+
rows = SpreeCmCommissioner::Integrations::SwitchCm::AvailabilityReadback.new(
|
|
17
|
+
integration: current_integration,
|
|
18
|
+
dates: (start_date...(start_date + days)).to_a,
|
|
19
|
+
room_id: request_value('room_id')
|
|
20
|
+
).rows
|
|
21
|
+
|
|
22
|
+
render_document { |xml| rows.each { |row| build_row(xml, row) } }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# override
|
|
28
|
+
def response_root
|
|
29
|
+
'result'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def build_row(xml, row)
|
|
33
|
+
xml.roomrate(
|
|
34
|
+
{
|
|
35
|
+
date: row.date.iso8601,
|
|
36
|
+
room_id: row.room_id,
|
|
37
|
+
rate_id: row.rate_id,
|
|
38
|
+
rooms_to_sell: row.rooms_to_sell,
|
|
39
|
+
booked: row.booked,
|
|
40
|
+
cancelled: row.cancelled,
|
|
41
|
+
closed: row.closed ? 1 : 0,
|
|
42
|
+
price: row.price && format('%.2f', row.price),
|
|
43
|
+
currency: row.currency,
|
|
44
|
+
pushed_at: row.pushed_at&.utc&.iso8601
|
|
45
|
+
}.compact
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def parse_date(value)
|
|
50
|
+
Date.iso8601(value) if value.present?
|
|
51
|
+
rescue Date::Error
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Spree::Api::SwitchCm
|
|
2
|
+
module Xml
|
|
3
|
+
class RoomRatesController < BaseController
|
|
4
|
+
before_action :require_integration!
|
|
5
|
+
|
|
6
|
+
# POST /api/switch_cm/hotels/xml/roomrates with <request><hotel_id/></request>
|
|
7
|
+
# The hotel's rooms, each with its rates, which the channel manager maps to its own
|
|
8
|
+
# ("Refresh Room" in switch.cm).
|
|
9
|
+
def create
|
|
10
|
+
vendor = current_integration.vendor
|
|
11
|
+
rooms = SpreeCmCommissioner::Integrations::SwitchCm::RoomCatalog.new(vendor).rooms
|
|
12
|
+
|
|
13
|
+
render_document do |xml|
|
|
14
|
+
rooms.each do |room|
|
|
15
|
+
xml.room(id: room.id, hotel_id: vendor.id, hotel_name: vendor.name, room_name: room.name, max_children: room.max_children) do
|
|
16
|
+
xml.rates do
|
|
17
|
+
xml.rate(id: room.rate_id, rate_name: room.rate_name, max_persons: room.max_persons, is_child_rate: 0, readonly: 0)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
# override
|
|
27
|
+
def response_root
|
|
28
|
+
'rooms'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -3,6 +3,8 @@ module Spree
|
|
|
3
3
|
module V2
|
|
4
4
|
module Operator
|
|
5
5
|
class CheckInsController < ::Spree::Api::V2::ResourceController
|
|
6
|
+
include SpreeCmCommissioner::Operator::EventAuthorization
|
|
7
|
+
|
|
6
8
|
before_action :require_spree_current_user, only: %i[index create]
|
|
7
9
|
|
|
8
10
|
# Check-in history data requires fresh/recent data for operator dashboards
|
|
@@ -45,15 +47,14 @@ module Spree
|
|
|
45
47
|
|
|
46
48
|
private
|
|
47
49
|
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
50
|
+
# The organizer who owns the event's vendor always sees check-in history.
|
|
51
|
+
# Crew/operators assigned via user.events only see it while the event is
|
|
52
|
+
# ongoing — once it ends, it becomes organizer-owned history. A missing/
|
|
53
|
+
# nonexistent taxon_id is restricted the same way.
|
|
52
54
|
def restricted?
|
|
53
|
-
return false if spree_current_user.organizer?
|
|
54
|
-
|
|
55
55
|
taxon = Spree::Taxon.find_by(id: params[:taxon_id])
|
|
56
56
|
return true if taxon.nil?
|
|
57
|
+
return false if organizer_for_event?(taxon)
|
|
57
58
|
return true unless spree_current_user.events.exists?(id: taxon.id)
|
|
58
59
|
|
|
59
60
|
taxon.ended?
|
|
@@ -3,6 +3,10 @@ module Spree
|
|
|
3
3
|
module V2
|
|
4
4
|
module Operator
|
|
5
5
|
class EventChartsController < ::Spree::Api::V2::ResourceController
|
|
6
|
+
include SpreeCmCommissioner::Operator::EventAuthorization
|
|
7
|
+
|
|
8
|
+
before_action :require_spree_current_user
|
|
9
|
+
|
|
6
10
|
ACCEPTED_KYC_FIELDS = %i[guest_gender guest_occupation guest_nationality].freeze
|
|
7
11
|
ADDITIONAL_FIELDS = %i[participation entry_type].freeze
|
|
8
12
|
|
|
@@ -40,18 +44,12 @@ module Spree
|
|
|
40
44
|
|
|
41
45
|
private
|
|
42
46
|
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
# need access). A missing/nonexistent taxon_id is restricted the same way.
|
|
47
|
+
# Only the organizer who owns the event's vendor may see chart data —
|
|
48
|
+
# crew/operators assigned via user.events never see it, regardless of
|
|
49
|
+
# whether the event is ongoing or ended. See organizer_for_event? (EventAuthorization).
|
|
47
50
|
def restricted?
|
|
48
|
-
return false if spree_current_user&.organizer?
|
|
49
|
-
|
|
50
51
|
taxon = Spree::Taxon.find_by(id: params[:taxon_id])
|
|
51
|
-
|
|
52
|
-
return true unless spree_current_user&.events&.exists?(id: taxon.id)
|
|
53
|
-
|
|
54
|
-
taxon.ended?
|
|
52
|
+
!organizer_for_event?(taxon)
|
|
55
53
|
end
|
|
56
54
|
|
|
57
55
|
def event_chart_aggregator_queries
|
|
@@ -3,11 +3,21 @@ module Spree
|
|
|
3
3
|
module V2
|
|
4
4
|
module Operator
|
|
5
5
|
class EventTicketAggregatorsController < ::Spree::Api::V2::ResourceController
|
|
6
|
+
include SpreeCmCommissioner::Operator::EventAuthorization
|
|
7
|
+
|
|
8
|
+
before_action :require_spree_current_user
|
|
9
|
+
|
|
6
10
|
def resource
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
taxon = Spree::Taxon.find_by(id: params[:taxon_id])
|
|
12
|
+
|
|
13
|
+
@resource = if organizer_for_event?(taxon)
|
|
14
|
+
SpreeCmCommissioner::EventTicketAggregatorQuery.new(
|
|
15
|
+
taxon_id: params[:taxon_id],
|
|
16
|
+
refreshed: params[:refreshed] || false
|
|
17
|
+
).call
|
|
18
|
+
else
|
|
19
|
+
SpreeCmCommissioner::EventTicketAggregator.new(id: params[:taxon_id], value: [])
|
|
20
|
+
end
|
|
11
21
|
end
|
|
12
22
|
|
|
13
23
|
def resource_serializer
|
|
@@ -3,8 +3,22 @@ module Spree
|
|
|
3
3
|
module V2
|
|
4
4
|
module Operator
|
|
5
5
|
class PieChartEventAggregatorsController < ::Spree::Api::V2::ResourceController
|
|
6
|
+
include SpreeCmCommissioner::Operator::EventAuthorization
|
|
7
|
+
|
|
8
|
+
before_action :require_spree_current_user
|
|
9
|
+
|
|
6
10
|
def resource
|
|
7
|
-
|
|
11
|
+
taxon = Spree::Taxon.find_by(id: params[:taxon_id])
|
|
12
|
+
|
|
13
|
+
@resource = if organizer_for_event?(taxon)
|
|
14
|
+
pie_chart_event_aggregator_queries.call
|
|
15
|
+
else
|
|
16
|
+
SpreeCmCommissioner::EventChart.new(
|
|
17
|
+
id: params[:chart_type] || 'participation',
|
|
18
|
+
chart_type: params[:chart_type] || 'participation',
|
|
19
|
+
product_charts: []
|
|
20
|
+
)
|
|
21
|
+
end
|
|
8
22
|
end
|
|
9
23
|
|
|
10
24
|
def resource_serializer
|
|
@@ -14,6 +14,34 @@ module Spree
|
|
|
14
14
|
def resource_serializer
|
|
15
15
|
::SpreeCmCommissioner::Api::V2::Platform::HomepageSectionRelatableOptionsSerializer
|
|
16
16
|
end
|
|
17
|
+
|
|
18
|
+
# Opt-in only (params[:taxon_scope] == 'events'/params[:tenant_id]), so existing callers
|
|
19
|
+
# that search across all taxons/vendors (e.g. ticket transfer rules, homepage sections)
|
|
20
|
+
# are unaffected.
|
|
21
|
+
def scope
|
|
22
|
+
result = super
|
|
23
|
+
result = result.merge(Spree::Taxon.events) if model_class == Spree::Taxon && params[:taxon_scope] == 'events'
|
|
24
|
+
result = scoped_to_tenant(result) if params[:tenant_id].present?
|
|
25
|
+
|
|
26
|
+
result
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# Product has its own tenant_id (set from its vendor — see
|
|
32
|
+
# SpreeCmCommissioner::ProductDecorator#set_tenant). Taxon (Event) has no tenant_id
|
|
33
|
+
# column of its own, so it's derived through the products that reference it as their
|
|
34
|
+
# event.
|
|
35
|
+
def scoped_to_tenant(result)
|
|
36
|
+
case model_class.name
|
|
37
|
+
when 'Spree::Vendor', 'Spree::Product'
|
|
38
|
+
result.where(tenant_id: params[:tenant_id])
|
|
39
|
+
when 'Spree::Taxon'
|
|
40
|
+
result.where(id: Spree::Product.where(tenant_id: params[:tenant_id]).select(:event_id))
|
|
41
|
+
else
|
|
42
|
+
result
|
|
43
|
+
end
|
|
44
|
+
end
|
|
17
45
|
end
|
|
18
46
|
end
|
|
19
47
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V2
|
|
4
|
+
module Storefront
|
|
5
|
+
class CrossAppHandoffTokensController < ::Spree::Api::V2::ResourceController
|
|
6
|
+
# No AR model backs a handoff token (see CrossAppHandoffTokens::Encode) — this just gives
|
|
7
|
+
# the generated {token:, expires_at:} pair an #id so it can go through the same
|
|
8
|
+
# serializer/JSON:API pipeline as every other storefront resource.
|
|
9
|
+
Resource = Struct.new(:token, :expires_at) do
|
|
10
|
+
def id
|
|
11
|
+
token
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
return render_error_payload(I18n.t('authenticator.incorrect_login'), 401) if spree_current_user.blank?
|
|
17
|
+
|
|
18
|
+
result = SpreeCmCommissioner::CrossAppHandoffTokens::Encode.call(user: spree_current_user, purpose: purpose)
|
|
19
|
+
return render_error_payload(result.error, 422) unless result.success?
|
|
20
|
+
|
|
21
|
+
render_serialized_payload(201) { serialize_resource(Resource.new(result.value[:token], result.value[:expires_at])) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def serialize_resource(resource)
|
|
25
|
+
resource_serializer.new(resource).serializable_hash
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def resource_serializer
|
|
29
|
+
SpreeCmCommissioner::V2::Storefront::CrossAppHandoffTokenSerializer
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def purpose
|
|
35
|
+
params[:purpose].to_s
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -16,10 +16,12 @@ module Spree
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def collection
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
# for_feed applies the segment itself, and its fallback only counts rows that survive
|
|
20
|
+
# the filters above, so it goes last.
|
|
21
|
+
@collection ||= model_class.active
|
|
21
22
|
.where(tenant_id: nil)
|
|
22
23
|
.where(preview: false)
|
|
24
|
+
.for_feed(params[:homepage_id] || :general, params[:mini_app])
|
|
23
25
|
.order(position: :asc)
|
|
24
26
|
end
|
|
25
27
|
end
|