spree_cm_commissioner 2.13.4 → 2.13.7
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 +5 -0
- data/Gemfile.lock +1 -1
- data/app/controllers/spree/admin/base_controller_decorator.rb +14 -0
- data/app/controllers/spree/admin/customer_notifications_controller.rb +16 -1
- data/app/controllers/spree/admin/inventory_items_controller.rb +11 -0
- data/app/controllers/spree/admin/payment_fee_rules_controller.rb +76 -0
- data/app/controllers/spree/admin/prepaid_transactions_controller.rb +69 -0
- data/app/controllers/spree/admin/private_sales_controller.rb +6 -0
- data/app/controllers/spree/admin/product_commissions_controller.rb +2 -1
- data/app/controllers/spree/admin/reschedule_policies_controller.rb +148 -0
- data/app/controllers/spree/admin/reschedule_requests_controller.rb +82 -0
- data/app/controllers/spree/admin/service_fee_rules_controller.rb +1 -0
- data/app/controllers/spree/admin/store_credit_admin_controller.rb +122 -0
- data/app/controllers/spree/admin/ticket_transfer_rules_controller.rb +7 -0
- data/app/controllers/spree/api/v2/platform/store_credits_controller_decorator.rb +35 -0
- data/app/controllers/spree/api/v2/storefront/account/prepaid_balances_controller.rb +52 -0
- data/app/controllers/spree/api/v2/storefront/account/prepaid_transactions_controller.rb +56 -0
- data/app/controllers/spree/api/v2/storefront/cart_payment_fees_controller.rb +48 -0
- data/app/controllers/spree/api/v2/storefront/draft_orders_controller.rb +37 -0
- data/app/controllers/spree/api/v2/storefront/prepaid_config_controller.rb +22 -0
- data/app/controllers/spree/api/v2/storefront/reschedule_requests_controller.rb +156 -0
- data/app/controllers/spree/api/v2/storefront/seat_layouts_controller.rb +3 -1
- data/app/controllers/spree/api/v2/storefront/transit/item_availabilities_controller.rb +66 -0
- data/app/controllers/spree/api/v2/tenant/account/prepaid_balances_controller.rb +51 -0
- data/app/controllers/spree/api/v2/tenant/account/prepaid_transactions_controller.rb +53 -0
- data/app/controllers/spree/api/v2/tenant/base_controller.rb +20 -0
- data/app/controllers/spree/api/v2/tenant/cart_payment_fees_controller.rb +43 -0
- data/app/controllers/spree/api/v2/tenant/draft_orders_controller.rb +42 -0
- data/app/controllers/spree/api/v2/tenant/prepaid_config_controller.rb +29 -0
- data/app/controllers/spree_cm_commissioner/admin/store_credits_controller_decorator.rb +217 -0
- data/app/errors/spree_cm_commissioner/reschedule_policies/invalid_policyable_error.rb +8 -0
- data/app/errors/spree_cm_commissioner/reschedule_policies/not_reschedulable_error.rb +11 -0
- data/app/errors/spree_cm_commissioner/reschedule_requests/cancel_not_allowed_error.rb +6 -0
- data/app/errors/spree_cm_commissioner/reschedule_requests/complete_cash_payment_error.rb +6 -0
- data/app/errors/spree_cm_commissioner/reschedule_requests/eligibility_denied_error.rb +7 -0
- data/app/factory/spree_cm_commissioner/order_telegram_message_factory.rb +6 -2
- data/app/factory/spree_cm_commissioner/reschedule_telegram_message_factory.rb +141 -0
- data/app/finders/spree_cm_commissioner/inventory_items/recently_changed_finder.rb +1 -1
- data/app/helpers/spree/admin/base_helper_decorator.rb +12 -0
- data/app/helpers/spree/admin/reschedule_policies_helper.rb +35 -0
- data/app/helpers/spree/admin/reschedule_requests_helper.rb +79 -0
- data/app/helpers/spree_cm_commissioner/admin/fee_rules_helper.rb +23 -0
- data/app/interactors/spree_cm_commissioner/create_ticket.rb +1 -0
- data/app/jobs/spree_cm_commissioner/audit_event_job.rb +29 -0
- data/app/jobs/spree_cm_commissioner/prepaid_reconciliation_cron_job.rb +9 -0
- data/app/jobs/spree_cm_commissioner/prepaid_reverse_top_up_job.rb +16 -0
- data/app/jobs/spree_cm_commissioner/prepaid_setup_types_job.rb +24 -0
- data/app/jobs/spree_cm_commissioner/prepaid_top_up_credit_job.rb +31 -0
- data/app/jobs/spree_cm_commissioner/reschedule_requests/approval_reminder_job.rb +17 -0
- data/app/jobs/spree_cm_commissioner/reschedule_requests/execute_job.rb +20 -0
- data/app/jobs/spree_cm_commissioner/reschedule_requests/expire_overdue_requests_job.rb +12 -0
- data/app/jobs/spree_cm_commissioner/reschedule_requests/expire_request_job.rb +15 -0
- data/app/jobs/spree_cm_commissioner/reschedule_requests/payment_reminder_job.rb +17 -0
- data/app/models/concerns/spree_cm_commissioner/audit_wrapper.rb +139 -0
- data/app/models/concerns/spree_cm_commissioner/integrations/inventory_sync_cachable.rb +9 -0
- data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +2 -1
- data/app/models/concerns/spree_cm_commissioner/order_prepaid_payment.rb +15 -0
- data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +58 -8
- data/app/models/concerns/spree_cm_commissioner/percent_fee_calculable.rb +36 -0
- data/app/models/concerns/spree_cm_commissioner/product_type.rb +6 -2
- data/app/models/concerns/spree_cm_commissioner/reschedule_request_state_machine.rb +332 -0
- data/app/models/concerns/spree_cm_commissioner/scoped_fee_rule.rb +129 -0
- data/app/models/concerns/spree_cm_commissioner/service_type.rb +1 -1
- data/app/models/concerns/spree_cm_commissioner/store_preference.rb +1 -0
- data/app/models/concerns/spree_cm_commissioner/tenant_preference.rb +6 -0
- 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/core/controller_helpers/currency_decorator.rb +70 -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/payment_fee_flat_amount.rb +21 -0
- data/app/models/spree_cm_commissioner/calculators/payment_fee_percent.rb +17 -0
- data/app/models/spree_cm_commissioner/calculators/service_fee_flat_amount.rb +4 -0
- data/app/models/spree_cm_commissioner/calculators/service_fee_percent.rb +5 -2
- data/app/models/spree_cm_commissioner/configuration.rb +17 -9
- data/app/models/spree_cm_commissioner/currency_rate.rb +15 -0
- data/app/models/spree_cm_commissioner/current.rb +8 -0
- data/app/models/spree_cm_commissioner/customer_notification.rb +4 -1
- data/app/models/spree_cm_commissioner/exports/import_order_guests_csv.rb +153 -0
- data/app/models/spree_cm_commissioner/guest.rb +21 -0
- data/app/models/spree_cm_commissioner/integration.rb +31 -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/vireak_buntham.rb +82 -0
- data/app/models/spree_cm_commissioner/inventory_item.rb +22 -5
- data/app/models/spree_cm_commissioner/line_item_decorator.rb +6 -2
- data/app/models/spree_cm_commissioner/notification.rb +8 -0
- data/app/models/spree_cm_commissioner/order_decorator.rb +31 -3
- data/app/models/spree_cm_commissioner/order_updater_decorator.rb +6 -1
- data/app/models/spree_cm_commissioner/payment_decorator.rb +31 -0
- data/app/models/spree_cm_commissioner/payment_fee_rule.rb +97 -0
- data/app/models/spree_cm_commissioner/payment_method_decorator.rb +5 -0
- data/app/models/spree_cm_commissioner/payment_method_store_credit_decorator.rb +81 -0
- data/app/models/spree_cm_commissioner/place.rb +2 -0
- data/app/models/spree_cm_commissioner/prepaid_config.rb +59 -0
- data/app/models/spree_cm_commissioner/prepaid_transaction.rb +102 -0
- data/app/models/spree_cm_commissioner/product_decorator.rb +6 -0
- data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +4 -2
- data/app/models/spree_cm_commissioner/reschedule_policy.rb +94 -0
- data/app/models/spree_cm_commissioner/reschedule_policy_assignment.rb +19 -0
- data/app/models/spree_cm_commissioner/reschedule_request.rb +227 -0
- data/app/models/spree_cm_commissioner/reschedule_requests/guest_selection.rb +80 -0
- data/app/models/spree_cm_commissioner/reschedule_snapshot.rb +65 -0
- data/app/models/spree_cm_commissioner/route.rb +1 -0
- data/app/models/spree_cm_commissioner/seat_layout.rb +8 -0
- data/app/models/spree_cm_commissioner/service_calendar.rb +4 -0
- data/app/models/spree_cm_commissioner/service_fee_rule.rb +17 -114
- 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/store_credit_category_decorator.rb +23 -0
- data/app/models/spree_cm_commissioner/store_credit_decorator.rb +142 -0
- data/app/models/spree_cm_commissioner/store_credit_event_decorator.rb +94 -0
- data/app/models/spree_cm_commissioner/store_credit_type_decorator.rb +43 -0
- data/app/models/spree_cm_commissioner/store_decorator.rb +8 -0
- data/app/models/spree_cm_commissioner/tenant.rb +37 -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 +79 -0
- data/app/models/spree_cm_commissioner/variant_decorator.rb +9 -1
- 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 +53 -0
- data/app/models/spree_cm_commissioner/vendor_place.rb +2 -0
- data/app/notifications/spree_cm_commissioner/reschedule_approved_notification.rb +7 -0
- data/app/notifications/spree_cm_commissioner/reschedule_cancelled_notification.rb +7 -0
- data/app/notifications/spree_cm_commissioner/reschedule_completed_notification.rb +7 -0
- data/app/notifications/spree_cm_commissioner/reschedule_expired_notification.rb +7 -0
- data/app/notifications/spree_cm_commissioner/reschedule_failed_notification.rb +7 -0
- data/app/notifications/spree_cm_commissioner/reschedule_notification_base.rb +41 -0
- data/app/notifications/spree_cm_commissioner/reschedule_payment_reminder_notification.rb +15 -0
- data/app/notifications/spree_cm_commissioner/reschedule_rejected_notification.rb +7 -0
- data/app/notifications/spree_cm_commissioner/reschedule_requested_notification.rb +7 -0
- data/app/overrides/spree/admin/products/_form/offline.html.erb.deface +9 -0
- data/app/overrides/spree/admin/shared/_main_menu/sidebar_reschedule.html.erb.deface +9 -0
- data/app/overrides/spree/admin/shared/_main_menu/sidebar_store_credit.html.erb.deface +8 -0
- data/app/overrides/spree/admin/shared/_order_tabs/reschedule_requests.html.erb.deface +10 -0
- data/app/overrides/spree/admin/shared/_product_tabs/stock_managements.html.erb.deface +1 -1
- data/app/overrides/spree/admin/shared/sub_menu/_configuration/menu_items.html.erb.deface +5 -0
- data/app/presenters/spree_cm_commissioner/prepaid_balance_presenter.rb +16 -0
- data/app/queries/spree_cm_commissioner/store_credit_overview_query.rb +75 -0
- data/app/queries/spree_cm_commissioner/user_store_credit_summary_query.rb +53 -0
- data/app/serializables/spree_cm_commissioner/item_availability_sync.rb +10 -0
- data/app/serializers/spree/v2/storefront/prepaid_balance_serializer.rb +15 -0
- data/app/serializers/spree/v2/storefront/prepaid_config_serializer.rb +11 -0
- data/app/serializers/spree/v2/storefront/prepaid_transaction_serializer.rb +17 -0
- data/app/serializers/spree/v2/storefront/user_serializer_decorator.rb +6 -0
- data/app/serializers/spree/v2/tenant/cart_serializer.rb +2 -1
- data/app/serializers/spree/v2/tenant/payment_method_serializer.rb +3 -0
- data/app/serializers/spree/v2/tenant/prepaid_balance_serializer.rb +15 -0
- data/app/serializers/spree/v2/tenant/prepaid_config_serializer.rb +16 -0
- data/app/serializers/spree/v2/tenant/prepaid_transaction_serializer.rb +16 -0
- data/app/serializers/spree_cm_commissioner/api/v2/platform/homepage_section_relatable_options_serializer.rb +5 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/cart_serializer_decorator.rb +3 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/inventory_item_serializer.rb +1 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/item_availability_sync_serializer.rb +10 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/payment_fee_preview_serializer.rb +19 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/payment_method_serializer_decorator.rb +16 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/reschedule_request_serializer.rb +49 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/reschedule_snapshot_serializer.rb +24 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/seat_layout_serializer.rb +8 -0
- data/app/services/spree_cm_commissioner/audit_logger.rb +59 -0
- data/app/services/spree_cm_commissioner/checkout/add_store_credit_decorator.rb +17 -0
- data/app/services/spree_cm_commissioner/checkout/add_store_credit_payments.rb +96 -0
- data/app/services/spree_cm_commissioner/checkout/remove_store_credit_decorator.rb +17 -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/customer_notifications/clone.rb +39 -0
- data/app/services/spree_cm_commissioner/google_maps_geocoder.rb +41 -0
- data/app/services/spree_cm_commissioner/imports/orders/create.rb +24 -11
- 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/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_holds/release.rb +13 -0
- data/app/services/spree_cm_commissioner/inventory_items/generate_permanent_item.rb +48 -0
- data/app/services/spree_cm_commissioner/order_holds/hold.rb +17 -0
- data/app/services/spree_cm_commissioner/order_holds/release.rb +31 -0
- data/app/services/spree_cm_commissioner/payment_fees/apply.rb +30 -0
- data/app/services/spree_cm_commissioner/payment_fees/clear.rb +15 -0
- data/app/services/spree_cm_commissioner/payment_fees/preview.rb +70 -0
- data/app/services/spree_cm_commissioner/payments/find_or_create_decorator.rb +18 -0
- data/app/services/spree_cm_commissioner/place_resolver.rb +95 -0
- data/app/services/spree_cm_commissioner/prepaid/admin_credit.rb +44 -0
- data/app/services/spree_cm_commissioner/prepaid/check_top_up_limits.rb +47 -0
- data/app/services/spree_cm_commissioner/prepaid/freeze.rb +58 -0
- data/app/services/spree_cm_commissioner/prepaid/mutation.rb +78 -0
- data/app/services/spree_cm_commissioner/prepaid/reverse_order_top_up.rb +23 -0
- data/app/services/spree_cm_commissioner/prepaid/reverse_top_up.rb +53 -0
- data/app/services/spree_cm_commissioner/prepaid/top_up.rb +68 -0
- data/app/services/spree_cm_commissioner/prepaid/unfreeze.rb +47 -0
- data/app/services/spree_cm_commissioner/prepaid_metrics.rb +37 -0
- data/app/services/spree_cm_commissioner/prepaid_reconciliation_service.rb +71 -0
- data/app/services/spree_cm_commissioner/reschedule_policies/assign.rb +52 -0
- data/app/services/spree_cm_commissioner/reschedule_policies/create.rb +71 -0
- data/app/services/spree_cm_commissioner/reschedule_policies/exclude.rb +40 -0
- data/app/services/spree_cm_commissioner/reschedule_policies/resolve.rb +109 -0
- data/app/services/spree_cm_commissioner/reschedule_policies/unassign.rb +23 -0
- data/app/services/spree_cm_commissioner/reschedule_policies/update.rb +73 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/authorize_initiator.rb +79 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/build_request.rb +317 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/calculate_fee.rb +71 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/cancel.rb +55 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/check_eligibility.rb +243 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/collect_payment.rb +204 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/execute.rb +252 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/expire_overdue_requests.rb +28 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/expire_request.rb +24 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/guests/update_seats.rb +210 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/initiate.rb +255 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/issue_compensation.rb +67 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/issue_coupon.rb +90 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/issue_store_credit.rb +16 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/notifications/send_approval_reminder.rb +43 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/notifications/send_payment_reminder.rb +46 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/notifications/send_status_update.rb +42 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/seats/hold.rb +137 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/split_line_item.rb +86 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/telegram/notify_operations.rb +37 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/telegram/notify_vendor.rb +51 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/vendors/approve.rb +61 -0
- data/app/services/spree_cm_commissioner/reschedule_requests/vendors/reject.rb +58 -0
- data/app/services/spree_cm_commissioner/topup_draft_orders/create.rb +234 -0
- data/app/services/spree_cm_commissioner/trips/service_calendars/create_or_update.rb +25 -14
- data/app/services/spree_cm_commissioner/trips/update_single_leg.rb +43 -6
- data/app/views/spree/admin/classifications/edit.html.erb +17 -2
- data/app/views/spree/admin/classifications/new.html.erb +18 -2
- data/app/views/spree/admin/customer_notifications/index.html.erb +45 -3
- data/app/views/spree/admin/integrations/_book_me_bus_v1_fields.html.erb +47 -0
- data/app/views/spree/admin/integrations/_form.html.erb +12 -0
- data/app/views/spree/admin/integrations/_larryta_fields.html.erb +58 -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/payment_fee_rules/_form.html.erb +135 -0
- data/app/views/spree/admin/payment_fee_rules/edit.html.erb +11 -0
- data/app/views/spree/admin/payment_fee_rules/index.html.erb +100 -0
- data/app/views/spree/admin/payment_fee_rules/new.html.erb +11 -0
- data/app/views/spree/admin/prepaid_transactions/index.html.erb +102 -0
- data/app/views/spree/admin/prepaid_transactions/show.html.erb +146 -0
- data/app/views/spree/admin/private_sales/_form.html.erb +24 -1
- data/app/views/spree/admin/private_sales/_stock.html.erb +6 -1
- data/app/views/spree/admin/product_commissions/index.html.erb +7 -2
- data/app/views/spree/admin/reschedule_policies/_form.html.erb +65 -0
- data/app/views/spree/admin/reschedule_policies/edit.html.erb +11 -0
- data/app/views/spree/admin/reschedule_policies/index.html.erb +84 -0
- data/app/views/spree/admin/reschedule_policies/new.html.erb +11 -0
- data/app/views/spree/admin/reschedule_requests/_cancel_modal.html.erb +34 -0
- data/app/views/spree/admin/reschedule_requests/_search_form.html.erb +57 -0
- data/app/views/spree/admin/reschedule_requests/_tabs.html.erb +14 -0
- data/app/views/spree/admin/reschedule_requests/index.html.erb +64 -0
- data/app/views/spree/admin/reschedule_requests/show.html.erb +212 -0
- data/app/views/spree/admin/reschedule_requests/state_changes.html.erb +42 -0
- data/app/views/spree/admin/service_fee_rules/_form.html.erb +15 -9
- data/app/views/spree/admin/service_fee_rules/index.html.erb +1 -1
- data/app/views/spree/admin/shared/_products.html.erb +3 -0
- data/app/views/spree/admin/shared/_reschedule_policies_tabs.html.erb +22 -0
- data/app/views/spree/admin/shared/_ticket_transfer_details.html.erb +3 -0
- data/app/views/spree/admin/shared/sub_menu/_reschedule.html.erb +4 -0
- data/app/views/spree/admin/stock_managements/_header.html.erb +26 -0
- data/app/views/spree/admin/stock_managements/_variant_stock_items.html.erb +1 -1
- data/app/views/spree/admin/stock_managements/calendar.html.erb +285 -171
- data/app/views/spree/admin/stock_managements/index.html.erb +1 -18
- data/app/views/spree/admin/store_credit_admin/_tabs.html.erb +31 -0
- data/app/views/spree/admin/store_credit_admin/_tenant_selector.html.erb +17 -0
- data/app/views/spree/admin/store_credit_admin/show.html.erb +200 -0
- data/app/views/spree/admin/store_credits/index.html.erb +224 -0
- data/app/views/spree/admin/tenants/_form.html.erb +33 -0
- data/app/views/spree/admin/ticket_transfer_rules/_form.html.erb +28 -5
- data/config/initializers/spree_dependencies.rb +3 -0
- data/config/initializers/spree_permitted_attributes.rb +1 -0
- data/config/locales/en.yml +363 -1
- data/config/locales/km.yml +282 -1
- data/config/routes.rb +67 -2
- 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/20260506120000_create_cm_reschedule_policies.rb +38 -0
- data/db/migrate/20260506120001_create_cm_reschedule_requests.rb +67 -0
- data/db/migrate/20260506120002_add_reschedule_count_to_cm_guests.rb +5 -0
- data/db/migrate/20260521140000_create_cm_reschedule_snapshots.rb +38 -0
- data/db/migrate/20260522160000_create_cm_reschedule_policy_assignments.rb +17 -0
- data/db/migrate/20260722000001_create_cm_prepaid_transactions.rb +31 -0
- data/db/migrate/20260722000002_add_constraints_to_store_credits.rb +46 -0
- data/db/migrate/20260722000003_add_expires_at_to_store_credits.rb +6 -0
- data/db/migrate/20260722000004_add_issuer_tenant_id_to_spree_store_credits.rb +7 -0
- data/db/migrate/20260722000005_add_immutability_trigger_to_cm_prepaid_transactions.rb +36 -0
- data/db/migrate/20260918045558_add_prepaid_currency_columns_to_cm_tenants.rb +6 -0
- data/db/migrate/20260923090000_add_public_private_metadata_to_cm_prepaid_transactions.rb +36 -0
- data/db/migrate/20260928000001_add_closed_to_cm_inventory_items.rb +5 -0
- data/db/migrate/20261001100000_create_cm_payment_fee_rules.rb +17 -0
- data/db/migrate/20261001100001_add_payment_fee_total_to_spree_orders.rb +5 -0
- data/db/migrate/20261006073317_add_offline_to_spree_products.rb +6 -0
- data/lib/spree_cm_commissioner/cached_inventory_item.rb +7 -1
- data/lib/spree_cm_commissioner/payment_fees/payment_fee_preview.rb +24 -0
- data/lib/spree_cm_commissioner/reschedule_policy_rules.rb +75 -0
- data/lib/spree_cm_commissioner/serializable_transaction.rb +38 -0
- data/lib/spree_cm_commissioner/store_credit_currency_summary.rb +11 -0
- data/lib/spree_cm_commissioner/store_credit_summary.rb +11 -0
- data/lib/spree_cm_commissioner/test_helper/factories/integration_factory.rb +11 -0
- data/lib/spree_cm_commissioner/test_helper/factories/prepaid_transaction_factory.rb +12 -0
- data/lib/spree_cm_commissioner/test_helper/factories/reschedule_policy_assignment_factory.rb +7 -0
- data/lib/spree_cm_commissioner/test_helper/factories/reschedule_policy_factory.rb +59 -0
- data/lib/spree_cm_commissioner/test_helper/factories/reschedule_request_factory.rb +51 -0
- data/lib/spree_cm_commissioner/test_helper/factories/reschedule_snapshot_factory.rb +27 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +5 -0
- data/lib/tasks/prepaid_reconciliation_cron_scheduler.rake +7 -0
- data/lib/tasks/prepaid_setup_types.rake +7 -0
- metadata +295 -2
|
@@ -20,6 +20,14 @@ module SpreeCmCommissioner
|
|
|
20
20
|
ticket_transfer_completed_notification
|
|
21
21
|
ticket_transfer_rejected_notification
|
|
22
22
|
ticket_transfer_expired_notification
|
|
23
|
+
reschedule_requested_notification
|
|
24
|
+
reschedule_approved_notification
|
|
25
|
+
reschedule_completed_notification
|
|
26
|
+
reschedule_rejected_notification
|
|
27
|
+
reschedule_cancelled_notification
|
|
28
|
+
reschedule_expired_notification
|
|
29
|
+
reschedule_failed_notification
|
|
30
|
+
reschedule_payment_reminder_notification
|
|
23
31
|
]
|
|
24
32
|
)
|
|
25
33
|
}
|
|
@@ -11,6 +11,7 @@ module SpreeCmCommissioner
|
|
|
11
11
|
base.include SpreeCmCommissioner::OrderScopes
|
|
12
12
|
base.include SpreeCmCommissioner::TicketTransferable
|
|
13
13
|
base.include SpreeCmCommissioner::OrderQrCodeable
|
|
14
|
+
base.include SpreeCmCommissioner::OrderPrepaidPayment
|
|
14
15
|
|
|
15
16
|
base.before_create :link_by_phone_number
|
|
16
17
|
base.before_create :associate_customer
|
|
@@ -21,7 +22,7 @@ module SpreeCmCommissioner
|
|
|
21
22
|
base.store_private_metadata :preload_main_trip_ids, :array, default: []
|
|
22
23
|
base.store_public_metadata :order_options, :array, default: []
|
|
23
24
|
|
|
24
|
-
base.money_methods :service_fee_total
|
|
25
|
+
base.money_methods :service_fee_total, :payment_fee_total
|
|
25
26
|
|
|
26
27
|
base.validates :promo_total, base::MONEY_VALIDATION
|
|
27
28
|
base.validates :phone_number, presence: true, if: :require_phone_number
|
|
@@ -40,6 +41,9 @@ module SpreeCmCommissioner
|
|
|
40
41
|
base.has_many :vendors, through: :products, class_name: 'Spree::Vendor'
|
|
41
42
|
base.has_many :taxons, through: :products, class_name: 'Spree::Taxon'
|
|
42
43
|
base.has_many :guests, through: :line_items, class_name: 'SpreeCmCommissioner::Guest'
|
|
44
|
+
base.has_many :reschedule_requests,
|
|
45
|
+
class_name: 'SpreeCmCommissioner::RescheduleRequest',
|
|
46
|
+
foreign_key: :order_id
|
|
43
47
|
|
|
44
48
|
base.has_many :saved_guests,
|
|
45
49
|
-> { reorder(nil).distinct },
|
|
@@ -51,6 +55,7 @@ module SpreeCmCommissioner
|
|
|
51
55
|
base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
|
|
52
56
|
base.has_many :guest_card_classes, class_name: 'SpreeCmCommissioner::GuestCardClass', through: :variants
|
|
53
57
|
base.has_many :product_completion_steps, class_name: 'SpreeCmCommissioner::ProductCompletionStep', through: :line_items
|
|
58
|
+
base.has_many :audit_events, class_name: 'SpreeCmCommissioner::AuditEvent', as: :auditable
|
|
54
59
|
|
|
55
60
|
base.delegate :customer, to: :user, allow_nil: true
|
|
56
61
|
|
|
@@ -166,6 +171,17 @@ module SpreeCmCommissioner
|
|
|
166
171
|
SpreeCmCommissioner::ServiceFeeRule.adjust(self, line_items)
|
|
167
172
|
end
|
|
168
173
|
|
|
174
|
+
# A payment fee is only correct for the total it was computed on, so one left over from an
|
|
175
|
+
# earlier payment attempt is dropped whenever checkout steps re-run. Skipped once a gateway
|
|
176
|
+
# payment exists: its amount already includes the fee, and clearing it would make the order
|
|
177
|
+
# total smaller than what that payment charges.
|
|
178
|
+
def clear_stale_payment_fee!
|
|
179
|
+
return unless adjustments.payment_fee.exists?
|
|
180
|
+
return if payments.valid.any? { |payment| !payment.store_credit? }
|
|
181
|
+
|
|
182
|
+
SpreeCmCommissioner::PaymentFees::Clear.call(order: self)
|
|
183
|
+
end
|
|
184
|
+
|
|
169
185
|
# overrided
|
|
170
186
|
def payment_required?
|
|
171
187
|
return false if need_confirmation?
|
|
@@ -221,12 +237,18 @@ module SpreeCmCommissioner
|
|
|
221
237
|
def create_default_payment_if_eligble
|
|
222
238
|
return unless subscription?
|
|
223
239
|
|
|
224
|
-
|
|
240
|
+
# `covered_by_store_credit` checks the total across the user's store-default-currency
|
|
241
|
+
# credit, so re-scope to this order's own store/currency here -- a user with credit in
|
|
242
|
+
# more than one currency (e.g. USD and KHR) must have the source credit match the order's
|
|
243
|
+
# currency, or Spree::StoreCredit#authorize rejects it as a currency_mismatch.
|
|
244
|
+
store_credit = covered_by_store_credit && user.store_credits.for_store(store).where(currency: currency).order_by_priority.first
|
|
245
|
+
|
|
246
|
+
if store_credit
|
|
225
247
|
payment_method = Spree::PaymentMethod::StoreCredit.available_on_back_end.first_or_create! do |method|
|
|
226
248
|
method.name ||= 'StoreCredit'
|
|
227
249
|
method.stores = [Spree::Store.default] if method.stores.empty?
|
|
228
250
|
end
|
|
229
|
-
source_id =
|
|
251
|
+
source_id = store_credit.id
|
|
230
252
|
source_type = 'Spree::StoreCredit'
|
|
231
253
|
else
|
|
232
254
|
payment_method = Spree::PaymentMethod::Check.available_on_back_end.first_or_create! do |method|
|
|
@@ -247,6 +269,12 @@ module SpreeCmCommissioner
|
|
|
247
269
|
subscription.present?
|
|
248
270
|
end
|
|
249
271
|
|
|
272
|
+
# A top-up order carries only the virtual `prepaid_top_up` product -- never mixed with
|
|
273
|
+
# real products. See docs/concepts/store-credit-wallet-system.md Section 4.1.
|
|
274
|
+
def prepaid_top_up_order?
|
|
275
|
+
line_items.present? && products.all?(&:prepaid_top_up?)
|
|
276
|
+
end
|
|
277
|
+
|
|
250
278
|
# Returns true when the order was created under a tenant context.
|
|
251
279
|
def purchased_from_tenant?
|
|
252
280
|
!tenant_id.nil?
|
|
@@ -12,10 +12,14 @@ module SpreeCmCommissioner
|
|
|
12
12
|
def update_adjustment_total
|
|
13
13
|
super
|
|
14
14
|
order.service_fee_total = line_items.sum(:service_fee_total)
|
|
15
|
+
|
|
16
|
+
# Order-level adjustments (see PaymentFees::Apply) are already in adjustment_total via
|
|
17
|
+
# core's `adjustments.eligible.sum(:amount)`; this is the display-only breakdown.
|
|
18
|
+
order.payment_fee_total = adjustments.payment_fee.eligible.sum(:amount)
|
|
15
19
|
end
|
|
16
20
|
|
|
17
21
|
# Duplicates Spree::OrderUpdater#persist_totals' update_columns call (spree_core 4.5.3)
|
|
18
|
-
# rather than calling super + a second update_columns for
|
|
22
|
+
# rather than calling super + a second update_columns for the fee totals, to keep this
|
|
19
23
|
# to a single UPDATE per order -- with read replicas/connection pooling in front of this,
|
|
20
24
|
# a second round-trip per persist_totals call isn't free. Must be kept in sync if core ever
|
|
21
25
|
# changes that column list.
|
|
@@ -33,6 +37,7 @@ module SpreeCmCommissioner
|
|
|
33
37
|
promo_total: order.promo_total,
|
|
34
38
|
total: order.total,
|
|
35
39
|
service_fee_total: order.service_fee_total,
|
|
40
|
+
payment_fee_total: order.payment_fee_total,
|
|
36
41
|
updated_at: Time.current
|
|
37
42
|
)
|
|
38
43
|
end
|
|
@@ -33,6 +33,22 @@ module SpreeCmCommissioner
|
|
|
33
33
|
payment_method.is_a?(Spree::PaymentMethod::Check)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
# Reschedule linkage. CollectPayment stamps the owning request's id into
|
|
37
|
+
# private_metadata so the completed-payment hook, the expiry guard, and the
|
|
38
|
+
# stale-payment sweep can all find "the payment for this reschedule" without
|
|
39
|
+
# re-deriving the metadata key in each place.
|
|
40
|
+
def reschedule_request_id
|
|
41
|
+
private_metadata.to_h['reschedule_request_id']
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def reschedule_request_id=(value)
|
|
45
|
+
self.private_metadata = private_metadata.to_h.merge('reschedule_request_id' => value)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def for_reschedule_request?(request)
|
|
49
|
+
reschedule_request_id.to_s == request.id.to_s
|
|
50
|
+
end
|
|
51
|
+
|
|
36
52
|
# @override Spree::Payment#after_completed
|
|
37
53
|
# Runs inside the transition to :completed, so completing the transfer stays
|
|
38
54
|
# atomic with the payment. Payment completion is the single trigger for
|
|
@@ -40,6 +56,7 @@ module SpreeCmCommissioner
|
|
|
40
56
|
def after_completed
|
|
41
57
|
super
|
|
42
58
|
order.complete_ticket_transfer_if_ready
|
|
59
|
+
execute_reschedule_if_completable
|
|
43
60
|
order.run_order_complete_alerts
|
|
44
61
|
end
|
|
45
62
|
|
|
@@ -56,6 +73,8 @@ module SpreeCmCommissioner
|
|
|
56
73
|
private
|
|
57
74
|
|
|
58
75
|
def lock_holds_for_payment
|
|
76
|
+
return if reschedule_request_id.present?
|
|
77
|
+
|
|
59
78
|
order.lock_order_holds_for_payment
|
|
60
79
|
end
|
|
61
80
|
|
|
@@ -67,6 +86,18 @@ module SpreeCmCommissioner
|
|
|
67
86
|
.set(wait: delay)
|
|
68
87
|
.perform_later(order_id: order.id)
|
|
69
88
|
end
|
|
89
|
+
|
|
90
|
+
def execute_reschedule_if_completable
|
|
91
|
+
return unless completed?
|
|
92
|
+
|
|
93
|
+
request_id = reschedule_request_id
|
|
94
|
+
return if request_id.blank?
|
|
95
|
+
|
|
96
|
+
request = SpreeCmCommissioner::RescheduleRequest.find_by(id: request_id, state: 'pending_payment')
|
|
97
|
+
return if request.nil?
|
|
98
|
+
|
|
99
|
+
SpreeCmCommissioner::RescheduleRequests::ExecuteJob.perform_later(reschedule_request_id: request.id)
|
|
100
|
+
end
|
|
70
101
|
end
|
|
71
102
|
end
|
|
72
103
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class PaymentFeeRule < SpreeCmCommissioner::Base
|
|
3
|
+
include SpreeCmCommissioner::ScopedFeeRule
|
|
4
|
+
include Spree::AdjustmentSource
|
|
5
|
+
include Spree::CalculatedAdjustments
|
|
6
|
+
|
|
7
|
+
# Same reason as ServiceFeeRule: without class_name Rails looks for
|
|
8
|
+
# SpreeCmCommissioner::Adjustment.
|
|
9
|
+
has_many :adjustments, as: :source, class_name: 'Spree::Adjustment'
|
|
10
|
+
|
|
11
|
+
# optional: false spelled out because Spree turns off belongs_to_required_by_default; without
|
|
12
|
+
# it a blank admin form reaches the NOT NULL column and raises instead of showing a form error.
|
|
13
|
+
belongs_to :payment_method, class_name: 'Spree::PaymentMethod', optional: false
|
|
14
|
+
|
|
15
|
+
# One rule per (payment method, scope, currency), active or not: `active` is an on/off switch,
|
|
16
|
+
# not a way to keep old versions around. A duplicate is pointed at the existing rule instead
|
|
17
|
+
# (see #duplicate_rule and the admin form).
|
|
18
|
+
validates :currency,
|
|
19
|
+
uniqueness: {
|
|
20
|
+
scope: %i[payment_method_id ruleable_type ruleable_id tenant_id],
|
|
21
|
+
case_sensitive: false,
|
|
22
|
+
message: lambda { |object, _data|
|
|
23
|
+
I18n.t('payment_fee.rules.rule_already_exists_for_scope',
|
|
24
|
+
payment_method: object.payment_method&.name,
|
|
25
|
+
scope_type: object.ruleable_type_label,
|
|
26
|
+
currency: object.currency
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
scope :for_payment_method, -> (payment_method) { where(payment_method_id: payment_method) }
|
|
32
|
+
|
|
33
|
+
def duplicate_rule
|
|
34
|
+
self.class.where.not(id: id).find_by(
|
|
35
|
+
payment_method_id: payment_method_id, ruleable_type: ruleable_type, ruleable_id: ruleable_id,
|
|
36
|
+
tenant_id: tenant_id, currency: currency
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Caches on the payment method whether any active rule exists for it, at any scope, so the
|
|
41
|
+
# catalog can serialize fee_configured without a query. Coarser than "could reach this vendor"
|
|
42
|
+
# (a shared store method is flagged for every vendor once one vendor has a fee), but `false`
|
|
43
|
+
# still guarantees no fee, which is all the client relies on.
|
|
44
|
+
after_commit :sync_payment_method_fee_configured!
|
|
45
|
+
|
|
46
|
+
def self.resolve_for(line_item:, payment_method:, currency:)
|
|
47
|
+
resolve_scoped(line_item: line_item, currency: currency, relation: for_payment_method(payment_method))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.available_calculator_types
|
|
51
|
+
[SpreeCmCommissioner::Calculators::PaymentFeePercent, SpreeCmCommissioner::Calculators::PaymentFeeFlatAmount]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Required by Spree::AdjustmentSource, but PaymentFees::Apply never goes through it: it stores
|
|
55
|
+
# the amounts PaymentFees::Preview computed, as closed adjustments, so this is only reached if
|
|
56
|
+
# something reopens one. Recomputing here would need the whole order's gateway split, so keep
|
|
57
|
+
# whatever was stored.
|
|
58
|
+
def compute_amount(adjustable)
|
|
59
|
+
adjustments.find_by(adjustable: adjustable)&.amount || 0
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def fee_description
|
|
63
|
+
return Spree.t(:service_fee_rule_not_configured) if calculator.nil?
|
|
64
|
+
return Spree.t(:payment_fee_mode_none) if no_fee?
|
|
65
|
+
|
|
66
|
+
calculator.fee_description(currency: currency)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# An explicit zero rule: how a narrower scope opts out of a broader rule's fee.
|
|
70
|
+
def no_fee?
|
|
71
|
+
case calculator
|
|
72
|
+
when Calculators::PaymentFeePercent
|
|
73
|
+
calculator.preferred_percent.to_d.zero? && calculator.preferred_flat_amount.to_d.zero?
|
|
74
|
+
when Calculators::PaymentFeeFlatAmount
|
|
75
|
+
calculator.preferred_flat_amount.to_d.zero?
|
|
76
|
+
else
|
|
77
|
+
true
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def label
|
|
82
|
+
Spree.t(:payment_fee)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
# Also re-syncs the previous method when a rule moves to another one.
|
|
88
|
+
def sync_payment_method_fee_configured!
|
|
89
|
+
ids = [payment_method_id, payment_method_id_previously_was].compact.uniq
|
|
90
|
+
|
|
91
|
+
Spree::PaymentMethod.where(id: ids).find_each do |payment_method|
|
|
92
|
+
payment_method.preload_fee_configured = self.class.active_rules.exists?(payment_method_id: payment_method.id)
|
|
93
|
+
payment_method.save! if payment_method.changed?
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -7,6 +7,11 @@ module SpreeCmCommissioner
|
|
|
7
7
|
|
|
8
8
|
base.whitelisted_ransackable_attributes = %w[name]
|
|
9
9
|
|
|
10
|
+
base.include SpreeCmCommissioner::StoreMetadata
|
|
11
|
+
# Kept in sync by PaymentFeeRule#sync_payment_method_fee_configured!, so the cached payment
|
|
12
|
+
# methods catalog can say whether to ask for fee previews without a rules query per request.
|
|
13
|
+
base.store_private_metadata :preload_fee_configured, :boolean, default: false
|
|
14
|
+
|
|
10
15
|
# Expose a dedicated class helper so services can call Spree::PaymentMethod.ticket_transfer
|
|
11
16
|
# instead of duplicating lookup/creation logic.
|
|
12
17
|
base.define_singleton_method(:ticket_transfer) do
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module PaymentMethodStoreCreditDecorator
|
|
3
|
+
# Forced false, not left as a per-store admin toggle: OrderStateMachine#
|
|
4
|
+
# capture_authorized_store_credit_payments! is the only thing that ever captures a store-credit
|
|
5
|
+
# payment, deferring it until stock is confirmed cut inside the same DB transaction as order
|
|
6
|
+
# completion (see docs/concepts/store-credit-wallet-system.md Section 5). If a store's own
|
|
7
|
+
# PaymentMethod::StoreCredit#auto_capture column were left/set true, process_payments! would
|
|
8
|
+
# capture (spend) the wallet balance immediately, before stock is cut -- reintroducing the
|
|
9
|
+
# "captured, then stock fails, needs a manual refund" case this design exists to avoid.
|
|
10
|
+
def auto_capture?
|
|
11
|
+
false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Reuses the payment's own pre-generated response_code as this authorize event's
|
|
15
|
+
# authorization_code, instead of letting Spree::StoreCredit#authorize mint a fresh one.
|
|
16
|
+
# Spree::StoreCreditEvent#order (core) resolves by matching authorization_code back to
|
|
17
|
+
# Payment#response_code -- if authorize generates its own code, that match fails until
|
|
18
|
+
# Payment::Processing#handle_response updates response_code afterward, which happens too
|
|
19
|
+
# late for StoreCreditEventDecorator's after_create ledger mirror (PrepaidTransaction#order
|
|
20
|
+
# comes back nil). Reusing the code the payment already carries closes that gap
|
|
21
|
+
# unconditionally, including for an authorization that's later voided or never captured --
|
|
22
|
+
# exactly the case where a customer would most want their wallet history to still point back
|
|
23
|
+
# at the order.
|
|
24
|
+
#
|
|
25
|
+
# started_processing! (Payment::Processing#process_authorization) already stamps state:
|
|
26
|
+
# 'processing' before this method is ever reached, and store_credit.with_lock (inside
|
|
27
|
+
# handle_action_call, below) serializes concurrent authorize attempts on the same
|
|
28
|
+
# store_credit -- so at most one payment can genuinely be 'processing' against this source
|
|
29
|
+
# at a time.
|
|
30
|
+
#
|
|
31
|
+
# Duplicates core's Spree::PaymentMethod::StoreCredit#authorize body (rather than calling
|
|
32
|
+
# super) because the only way to change what's passed to Spree::StoreCredit#authorize is to
|
|
33
|
+
# rebuild the lambda that calls it -- core exposes no hook to inject an extra keyword arg.
|
|
34
|
+
def authorize(amount_in_cents, store_credit, gateway_options = {})
|
|
35
|
+
return super if store_credit.nil?
|
|
36
|
+
|
|
37
|
+
payment = Spree::Payment.find_by(source: store_credit, payment_method: self, state: 'processing')
|
|
38
|
+
|
|
39
|
+
action = lambda do |sc|
|
|
40
|
+
sc.authorize(
|
|
41
|
+
amount_in_cents / 100.0.to_d,
|
|
42
|
+
gateway_options[:currency],
|
|
43
|
+
action_originator: gateway_options[:originator],
|
|
44
|
+
action_authorization_code: payment&.response_code
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
handle_action_call(store_credit, action, :authorize)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Core's own #cancel (called by Spree::Order#after_cancel -> Payment#cancel! for every
|
|
51
|
+
# *completed* payment on a canceled order -- this is the path that reverses a captured
|
|
52
|
+
# store-credit payment when the order itself gets canceled, not the top-up wallet reversal in
|
|
53
|
+
# Prepaid::ReverseOrderTopUp, which is a separate ledger entirely) calls `store_credit.credit`
|
|
54
|
+
# with zero options -- no gateway_options, no originator -- so the mirrored PrepaidTransaction
|
|
55
|
+
# this produces (StoreCreditEventDecorator#mirror_to_prepaid_ledger) always came out with a
|
|
56
|
+
# blank Note, with no way to tell it apart from a manual admin credit after the fact.
|
|
57
|
+
#
|
|
58
|
+
# Passing the payment itself as originator gives mirrored_reason something concrete to point
|
|
59
|
+
# at (the order), even though this is a genuine Spree::Payment, not a Spree::Refund -- core
|
|
60
|
+
# only ever reads `originator` back through polymorphic association, it never assumes a type.
|
|
61
|
+
#
|
|
62
|
+
# Duplicates core's #cancel body (rather than calling super) for the same reason #authorize
|
|
63
|
+
# above does: the only way to add an option to the store_credit.credit call is to rebuild the
|
|
64
|
+
# lambda that makes it.
|
|
65
|
+
def cancel(auth_code, payment = nil)
|
|
66
|
+
store_credit_event = Spree::StoreCreditEvent.find_by(authorization_code: auth_code, action: Spree::StoreCredit::CAPTURE_ACTION)
|
|
67
|
+
store_credit = store_credit_event.try(:store_credit)
|
|
68
|
+
|
|
69
|
+
return super if !store_credit_event || !store_credit
|
|
70
|
+
|
|
71
|
+
action = lambda do |sc|
|
|
72
|
+
sc.credit(store_credit_event.amount, auth_code, sc.currency, action_originator: payment)
|
|
73
|
+
end
|
|
74
|
+
handle_action(action, :cancel, auth_code)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
unless Spree::PaymentMethod::StoreCredit.included_modules.include?(SpreeCmCommissioner::PaymentMethodStoreCreditDecorator)
|
|
80
|
+
Spree::PaymentMethod::StoreCredit.prepend SpreeCmCommissioner::PaymentMethodStoreCreditDecorator
|
|
81
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
# Presenter-shaped value object for GET prepaid/config -- reads the same platform-wide
|
|
3
|
+
# Spree::Store.default currency settings that Prepaid::TopUp already enforces
|
|
4
|
+
# (docs/concepts/store-credit-wallet-system.md Section 8), plus the fraud/velocity limits from
|
|
5
|
+
# SpreeCmCommissioner::Configuration. `id` is a fixed string since this isn't a database-backed
|
|
6
|
+
# resource; jsonapi-serializer requires one.
|
|
7
|
+
#
|
|
8
|
+
# supported_currencies/preferred_currency/currency_limits ARE tenant-aware, though: pass
|
|
9
|
+
# `tenant:` (from Spree::Api::V2::Tenant::BaseController#require_tenant) to resolve
|
|
10
|
+
# Tenant#supported_currencies_list/#preferred_currency_or_default instead of the platform
|
|
11
|
+
# ceiling -- these are the exact same values POST draft_orders/topup and GET account/prepaid
|
|
12
|
+
# already validate/default `?currency=` against (Tenant::BaseController#
|
|
13
|
+
# resolve_requested_currency), just finally made discoverable by the client instead of only
|
|
14
|
+
# enforced after the fact on submit.
|
|
15
|
+
PrepaidConfig = Struct.new(
|
|
16
|
+
:id, :daily_topup_count, :supported_currencies, :preferred_currency, :currency_limits,
|
|
17
|
+
keyword_init: true
|
|
18
|
+
) do
|
|
19
|
+
def self.resolve(tenant: nil)
|
|
20
|
+
config = SpreeCmCommissioner::Configuration.new
|
|
21
|
+
store = Spree::Store.default
|
|
22
|
+
preferred_currency = tenant ? tenant.preferred_currency_or_default : store.default_currency
|
|
23
|
+
supported_currencies = order_preferred_first(
|
|
24
|
+
tenant ? tenant.supported_currencies_list : store.supported_currency_codes, preferred_currency
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
new(
|
|
28
|
+
id: 'prepaid_config',
|
|
29
|
+
daily_topup_count: config.prepaid_max_topup_count_daily,
|
|
30
|
+
supported_currencies: supported_currencies,
|
|
31
|
+
preferred_currency: preferred_currency,
|
|
32
|
+
currency_limits: build_currency_limits(config, supported_currencies)
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Preferred currency first, so the client's currency picker (and the currency_limits hash
|
|
37
|
+
# key order below, which Ruby/JSON preserves) both default to it without the client having
|
|
38
|
+
# to know which entry is preferred and reorder it themselves.
|
|
39
|
+
def self.order_preferred_first(currencies, preferred_currency)
|
|
40
|
+
currencies.sort_by { |currency| currency == preferred_currency ? 0 : 1 }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Scales the base limits into each supported currency via Configuration#prepaid_currency_rates.
|
|
44
|
+
# A currency missing a configured rate is omitted rather than shown unconverted.
|
|
45
|
+
def self.build_currency_limits(config, supported_currencies)
|
|
46
|
+
supported_currencies.each_with_object({}) do |currency, limits|
|
|
47
|
+
rate = config.prepaid_currency_rates[currency]
|
|
48
|
+
next unless rate
|
|
49
|
+
|
|
50
|
+
limits[currency] = {
|
|
51
|
+
min_topup_amount: (config.prepaid_topup_min_amount * rate).round(2),
|
|
52
|
+
max_topup_amount: (config.prepaid_topup_max_amount * rate).round(2),
|
|
53
|
+
daily_topup_amount: (config.prepaid_daily_topup_limit * rate).round(2),
|
|
54
|
+
max_balance: (config.prepaid_max_balance * rate).round(2)
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class PrepaidTransaction < Base
|
|
3
|
+
include SpreeCmCommissioner::StoreMetadata
|
|
4
|
+
|
|
5
|
+
TRANSACTION_TYPES = %w[
|
|
6
|
+
top_up admin_credit authorize capture void credit reverse_top_up freeze unfreeze
|
|
7
|
+
].freeze
|
|
8
|
+
|
|
9
|
+
STATUSES = %w[pending completed failed reversed].freeze
|
|
10
|
+
|
|
11
|
+
# English fallback label for every TRANSACTION_TYPES value -- covers capture/reverse_top_up
|
|
12
|
+
# too, even though neither is customer-facing (see CUSTOMER_FACING_TYPES below), because the
|
|
13
|
+
# admin dashboard/per-user transactions tabs show every type with no allowlist filter; without
|
|
14
|
+
# an entry here those rows would display the raw, un-friendly type string instead of a label.
|
|
15
|
+
DISPLAY_TYPES = {
|
|
16
|
+
'top_up' => 'Top Up',
|
|
17
|
+
'admin_credit' => 'Admin Credit',
|
|
18
|
+
'authorize' => 'Purchase',
|
|
19
|
+
'capture' => 'Capture',
|
|
20
|
+
'void' => 'Canceled',
|
|
21
|
+
'credit' => 'Refund',
|
|
22
|
+
'reverse_top_up' => 'Reversal',
|
|
23
|
+
'freeze' => 'Freeze',
|
|
24
|
+
'unfreeze' => 'Unfreeze'
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
# Which types ever reach the customer-facing storefront/tenant API (see
|
|
28
|
+
# PrepaidTransactionsController::DISPLAYED_TRANSACTION_TYPES). Excludes `capture` (always
|
|
29
|
+
# amount: 0, a bookkeeping-only row that never changes the balance) and `freeze`/`unfreeze`
|
|
30
|
+
# (also amount: 0 -- a status change, not a transaction; nothing useful to show in a money
|
|
31
|
+
# list, and no client currently renders them).
|
|
32
|
+
#
|
|
33
|
+
# reverse_top_up IS included, even though it's admin-initiated: Prepaid::ReverseTopUp
|
|
34
|
+
# actually reduces the credit's real amount, so hiding it would leave an admin_credit/top_up
|
|
35
|
+
# row permanently visible with no visible transaction explaining why that money is gone --
|
|
36
|
+
# exactly the "I see a transaction but the balance doesn't match" confusion this list exists
|
|
37
|
+
# to prevent. Kept as its own list rather than derived from DISPLAY_TYPES.keys, so expanding
|
|
38
|
+
# DISPLAY_TYPES for the admin UI's sake can't silently widen what customers are shown.
|
|
39
|
+
CUSTOMER_FACING_TYPES = %w[top_up admin_credit authorize void credit reverse_top_up].freeze
|
|
40
|
+
|
|
41
|
+
belongs_to :user, class_name: 'Spree::User'
|
|
42
|
+
belongs_to :store_credit, class_name: 'Spree::StoreCredit'
|
|
43
|
+
belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant', optional: true
|
|
44
|
+
belongs_to :order, class_name: 'Spree::Order', optional: true
|
|
45
|
+
# The admin who performed an admin-initiated action (admin_credit, reverse_top_up, freeze,
|
|
46
|
+
# unfreeze) -- a real column, not a metadata key, since "who did this" is audit-critical,
|
|
47
|
+
# queryable identity data (see the migration adding this column for the full reasoning).
|
|
48
|
+
# nil for non-admin-initiated types (top_up, authorize, capture, void, credit).
|
|
49
|
+
belongs_to :admin, class_name: 'Spree::User', optional: true
|
|
50
|
+
|
|
51
|
+
# Internal/audit detail that's never exposed to a customer via an API serializer -- freeze
|
|
52
|
+
# metadata isn't identity data (unlike admin_id above) and doesn't need to be queried on, so
|
|
53
|
+
# it doesn't need its own column. requested_amount/reversed_amount (reverse_top_up) are
|
|
54
|
+
# written directly into private_metadata without a typed accessor below -- StoreMetadata has
|
|
55
|
+
# no :decimal type, and these are money amounts where losing precision through a lossy type
|
|
56
|
+
# cast isn't acceptable.
|
|
57
|
+
store_private_metadata :reason, :text
|
|
58
|
+
store_private_metadata :level, :string
|
|
59
|
+
store_private_metadata :until_at, :datetime
|
|
60
|
+
store_private_metadata :prior_frozen_by_id, :integer
|
|
61
|
+
store_private_metadata :prior_freeze_reason, :text
|
|
62
|
+
store_private_metadata :prior_freeze_level, :string
|
|
63
|
+
|
|
64
|
+
# Spree::Money-formatted display_amount/display_balance_after, same display_* convention as
|
|
65
|
+
# products/orders/store credits (Spree::DisplayMoney). Negative on authorize rows (a hold) --
|
|
66
|
+
# Spree::Money formats the sign as-is, no special-casing needed here.
|
|
67
|
+
extend Spree::DisplayMoney
|
|
68
|
+
money_methods :amount, :balance_after
|
|
69
|
+
|
|
70
|
+
validates :transaction_type, presence: true
|
|
71
|
+
validates :amount, :balance_after, numericality: true
|
|
72
|
+
validates :currency, presence: true
|
|
73
|
+
validates :idempotency_key, presence: true
|
|
74
|
+
validates :status, inclusion: { in: STATUSES }
|
|
75
|
+
|
|
76
|
+
scope :for_tenant, -> (tenant_id) { where(tenant_id: tenant_id) }
|
|
77
|
+
scope :completed, -> { where(status: 'completed') }
|
|
78
|
+
|
|
79
|
+
def self.ransackable_attributes(_auth_object = nil)
|
|
80
|
+
%w[transaction_type status currency tenant_id user_id store_credit_id admin_id created_at]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# user/order let the admin wallet transactions search filter by user_email_cont/
|
|
84
|
+
# order_number_cont without exposing every association on the model.
|
|
85
|
+
self.whitelisted_ransackable_associations = %w[user order]
|
|
86
|
+
|
|
87
|
+
def readonly?
|
|
88
|
+
persisted? && status_was == 'completed'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Client-facing label for `transaction_type` ("Top Up" / "Purchase"), localized to the
|
|
92
|
+
# current request's locale -- DISPLAY_TYPES only supplies the English fallback; the actual
|
|
93
|
+
# string comes from locale files, so a Khmer-speaking client doesn't get English baked into
|
|
94
|
+
# the API response. See CUSTOMER_FACING_TYPES for which types customers are ever shown.
|
|
95
|
+
def display_type
|
|
96
|
+
I18n.t(
|
|
97
|
+
"spree_cm_commissioner.prepaid_transaction.display_type.#{transaction_type}",
|
|
98
|
+
default: DISPLAY_TYPES.fetch(transaction_type, transaction_type)
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -37,6 +37,12 @@ module SpreeCmCommissioner
|
|
|
37
37
|
base.has_one :default_state, through: :vendor
|
|
38
38
|
base.has_one :google_wallet, class_name: 'SpreeCmCommissioner::GoogleWallet', dependent: :destroy
|
|
39
39
|
|
|
40
|
+
base.has_one :reschedule_policy_assignment, as: :policyable,
|
|
41
|
+
class_name: 'SpreeCmCommissioner::ReschedulePolicyAssignment',
|
|
42
|
+
dependent: :destroy
|
|
43
|
+
base.has_one :reschedule_policy, through: :reschedule_policy_assignment,
|
|
44
|
+
class_name: 'SpreeCmCommissioner::ReschedulePolicy'
|
|
45
|
+
|
|
40
46
|
base.has_many :complete_line_items, through: :classifications, source: :line_items
|
|
41
47
|
base.has_many :inventory_items, through: :variants
|
|
42
48
|
base.has_many :guests, through: :line_items
|
|
@@ -49,13 +49,15 @@ module SpreeCmCommissioner
|
|
|
49
49
|
quantity_locked_on_hold: cache_inventory(locked_hold_keys[index], item, item.quantity_locked_on_hold, locked_hold[index]),
|
|
50
50
|
max_capacity: item.max_capacity,
|
|
51
51
|
inventory_item_id: item.id,
|
|
52
|
-
variant_id: item.variant_id
|
|
52
|
+
variant_id: item.variant_id,
|
|
53
|
+
closed: item.closed
|
|
53
54
|
)
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
def cache_inventory(key, inventory_item, db_value, count_in_redis)
|
|
58
|
+
# Past dates are warmed too: InventoryItem#adjust_quantity! relies on this to seed the key before
|
|
59
|
+
# applying its delta, and an admin can still edit a past date's stock.
|
|
57
60
|
return count_in_redis.to_i if count_in_redis.present?
|
|
58
|
-
return db_value unless inventory_item.active?
|
|
59
61
|
|
|
60
62
|
# Use atomic SET NX to prevent race condition where multiple concurrent reads
|
|
61
63
|
# initialize cache with stale values. Only the first thread wins.
|