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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c83a53b69842100120ae6f6edea538c4a7335fc9859e52765f4be45ad2506b0c
|
|
4
|
+
data.tar.gz: 61cd2bea3a4a011a385ad636c6f3330bc44e04085eb39ea22c64c96f86c59978
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 18012dec394174123a5fefcb459c369aab56bf075cabb068e695ab42eac92c1f487468047d6201bee6dc2f1f8730147260ec7d4b4dbfa1b4c0f5c98c31720508
|
|
7
|
+
data.tar.gz: 5dae3a462226fe008f4c17d43231d315d45e24a415fd07fe8c564f61694821ba70e037b311f8f653766df763a009e00b2ccf0d8f7bbbaf712e858a50b0cbdf43
|
data/.env.example
CHANGED
|
@@ -86,3 +86,8 @@ PAYMENT_INCOMPLETE_NOTIFICATION_DELAY_IN_MINUTES=5 # Delay before notifying a c
|
|
|
86
86
|
|
|
87
87
|
# See: app/jobs/spree_cm_commissioner/telegram_alerts/order_integrity_check_job.rb
|
|
88
88
|
ORDER_INTEGRITY_TELEGRAM_ALERT_ENABLED="no" # Set to yes to enable the order integrity Telegram alert job (off by default to avoid flooding Telegram rate limits during traffic spikes)
|
|
89
|
+
|
|
90
|
+
# See: app/models/concerns/spree_cm_commissioner/product_type.rb
|
|
91
|
+
PRE_INVENTORY_DAYS_TRANSIT=180 # How many days ahead inventory items are pre-generated for transit variants
|
|
92
|
+
PRE_INVENTORY_DAYS_ACCOMMODATION=365 # How many days ahead inventory items are pre-generated for accommodation variants
|
|
93
|
+
PRE_INVENTORY_DAYS_SERVICE=180 # How many days ahead inventory items are pre-generated for service variants
|
data/Gemfile.lock
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
module Admin
|
|
3
3
|
module BaseControllerDecorator
|
|
4
|
+
def self.prepended(base)
|
|
5
|
+
base.before_action :set_prepaid_current_actor
|
|
6
|
+
end
|
|
7
|
+
|
|
4
8
|
# even db in read only mode, authorizor still need to run Warden callbacks which will write to db
|
|
5
9
|
# this include update tracked fields such as sign_in_count, last_sign_in_at, etc.
|
|
6
10
|
def authorize!(*args)
|
|
@@ -40,6 +44,16 @@ module Spree
|
|
|
40
44
|
|
|
41
45
|
redirect_back fallback_location: admin_root_path
|
|
42
46
|
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# See SpreeCmCommissioner::Current#actor -- lets StoreCreditEventDecorator's after_create
|
|
51
|
+
# mirror attribute an admin-triggered authorize/capture/void/credit event (refunds, voids)
|
|
52
|
+
# to whoever is signed in, without threading current_user through Spree core's own
|
|
53
|
+
# Payment/Refund/StoreCredit call chain.
|
|
54
|
+
def set_prepaid_current_actor
|
|
55
|
+
SpreeCmCommissioner::Current.actor = try_spree_current_user
|
|
56
|
+
end
|
|
43
57
|
end
|
|
44
58
|
end
|
|
45
59
|
end
|
|
@@ -2,7 +2,22 @@ module Spree
|
|
|
2
2
|
module Admin
|
|
3
3
|
class CustomerNotificationsController < Spree::Admin::ResourceController
|
|
4
4
|
def index
|
|
5
|
-
@
|
|
5
|
+
@search = model_class.ransack(params[:q])
|
|
6
|
+
@search.sorts = 'created_at desc' if @search.sorts.empty?
|
|
7
|
+
@notifications = @search.result.page(params[:page]).per(params[:per_page] || 25)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# POST /admin/customer_notifications/:id/clone
|
|
11
|
+
def clone
|
|
12
|
+
result = SpreeCmCommissioner::CustomerNotifications::Clone.call(customer_notification: @object)
|
|
13
|
+
|
|
14
|
+
if result.success?
|
|
15
|
+
flash[:success] = Spree.t(:customer_notification_cloned)
|
|
16
|
+
redirect_to edit_admin_customer_notification_url(result.value)
|
|
17
|
+
else
|
|
18
|
+
flash[:error] = Spree.t(:customer_notification_not_cloned, error: result.error.to_s)
|
|
19
|
+
redirect_to admin_customer_notifications_url
|
|
20
|
+
end
|
|
6
21
|
end
|
|
7
22
|
|
|
8
23
|
def model_class
|
|
@@ -59,6 +59,17 @@ module Spree
|
|
|
59
59
|
redirect_back fallback_location: admin_product_stock_managements_path(@product)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
# PATCH /products/:slug/inventory_items/bulk_update_closed
|
|
63
|
+
#
|
|
64
|
+
# Ids travel in the form body, not the query string: a range across a year can be hundreds of ids.
|
|
65
|
+
def bulk_update_closed
|
|
66
|
+
closed = ActiveModel::Type::Boolean.new.cast(params[:closed])
|
|
67
|
+
count = @product.inventory_items.where(id: params[:inventory_item_ids]).update_all(closed: closed, updated_at: Time.current) # rubocop:disable Rails/SkipsModelValidations
|
|
68
|
+
|
|
69
|
+
flash[:success] = "#{closed ? 'Closed' : 'Reopened'} #{count} inventory items for sale"
|
|
70
|
+
redirect_back fallback_location: admin_product_stock_managements_path(@product)
|
|
71
|
+
end
|
|
72
|
+
|
|
62
73
|
# PATCH /products/:slug/inventory_items/bulk_reset?inventory_item_ids=1,2,3
|
|
63
74
|
def bulk_reset
|
|
64
75
|
inventory_item_ids = params[:inventory_item_ids]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
# Same CRUD as ServiceFeeRulesController (scope picker, tenant dropdown, calculator partial),
|
|
4
|
+
# plus the payment method a rule applies to.
|
|
5
|
+
class PaymentFeeRulesController < Spree::Admin::ResourceController
|
|
6
|
+
helper SpreeCmCommissioner::Admin::FeeRulesHelper
|
|
7
|
+
helper_method :selected_tenant
|
|
8
|
+
|
|
9
|
+
before_action :load_data
|
|
10
|
+
|
|
11
|
+
def index
|
|
12
|
+
@search = model_class.ransack(params[:q])
|
|
13
|
+
@status = %w[active inactive].include?(params[:status]) ? params[:status] : 'all'
|
|
14
|
+
|
|
15
|
+
scope = @search.result.includes(:payment_method, :ruleable, :calculator, :tenant)
|
|
16
|
+
scope = scope.where(active: true) if @status == 'active'
|
|
17
|
+
scope = scope.where(active: false) if @status == 'inactive'
|
|
18
|
+
# Same tenant semantics as ServiceFeeRulesController#index.
|
|
19
|
+
scope = scope.where(tenant_id: selected_tenant&.id)
|
|
20
|
+
|
|
21
|
+
@payment_fee_rules = scope.order(ruleable_type: :asc, ruleable_id: :asc, payment_method_id: :asc, currency: :asc)
|
|
22
|
+
.page(params[:page])
|
|
23
|
+
.per(25)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# See ServiceFeeRulesController#build_resource: tenant_id comes from the URL only.
|
|
27
|
+
def build_resource
|
|
28
|
+
model_class.new(tenant_id: params[:tenant_id].presence)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def load_data
|
|
34
|
+
@calculators = model_class.available_calculator_types.sort_by(&:name)
|
|
35
|
+
@tenants ||= SpreeCmCommissioner::Tenant.order(:name)
|
|
36
|
+
@payment_methods = Spree::PaymentMethod.includes(:vendor).order(:name)
|
|
37
|
+
@currencies = (current_store.supported_currencies_list.map(&:iso_code) | [@object&.currency]).compact.sort
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def selected_tenant
|
|
41
|
+
return @selected_tenant if defined?(@selected_tenant)
|
|
42
|
+
|
|
43
|
+
@selected_tenant = params[:tenant_id].presence && SpreeCmCommissioner::Tenant.find_by(id: params[:tenant_id])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def model_class
|
|
47
|
+
SpreeCmCommissioner::PaymentFeeRule
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def object_name
|
|
51
|
+
'spree_cm_commissioner_payment_fee_rule'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def collection_url
|
|
55
|
+
admin_payment_fee_rules_url
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def location_after_save
|
|
59
|
+
edit_admin_payment_fee_rule_path(@object)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# tenant_id is deliberately excluded -- see build_resource.
|
|
63
|
+
def permitted_resource_params
|
|
64
|
+
params.require(:spree_cm_commissioner_payment_fee_rule).permit(
|
|
65
|
+
:payment_method_id,
|
|
66
|
+
:ruleable_type,
|
|
67
|
+
:ruleable_id,
|
|
68
|
+
:active,
|
|
69
|
+
:currency,
|
|
70
|
+
:calculator_type,
|
|
71
|
+
calculator_attributes: %i[id preferred_percent preferred_flat_amount]
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
# Two read-only views over the prepaid ledger:
|
|
4
|
+
# - #index: platform-wide filterable browse (GET /admin/store_credit/transactions).
|
|
5
|
+
# - #show: a single ledger row's full detail (GET /admin/store_credit/transactions/:id),
|
|
6
|
+
# reached from both #index's row links and the per-user store_credits Transactions tab.
|
|
7
|
+
# Not nested under a user/store_credit -- PrepaidTransaction has a global id, and one
|
|
8
|
+
# detail page reached from two different listings is simpler than two near-identical ones.
|
|
9
|
+
# Currency, balance, admin, and reason/freeze metadata live here rather than cluttering
|
|
10
|
+
# either listing table.
|
|
11
|
+
class PrepaidTransactionsController < Spree::Admin::BaseController
|
|
12
|
+
TRANSACTIONS_PER_PAGE = 25
|
|
13
|
+
|
|
14
|
+
before_action :load_transaction, only: :show
|
|
15
|
+
|
|
16
|
+
# GET /admin/store_credit/transactions -- the admin/store_credit dashboard's own
|
|
17
|
+
# platform-wide ledger browse (see Spree::Admin::StoreCreditAdminController's other tabs and
|
|
18
|
+
# store_credit_admin/_tabs.html.erb), but its own route/controller rather than a #show?
|
|
19
|
+
# tab=transactions query param, so filters/pagination live in a real URL.
|
|
20
|
+
def index
|
|
21
|
+
@current_tab = 'transactions'
|
|
22
|
+
@tenants = SpreeCmCommissioner::Tenant.order(:name)
|
|
23
|
+
@current_tenant_id = params[:tenant_id].presence&.to_i
|
|
24
|
+
@store = Spree::Store.default
|
|
25
|
+
build_transactions_search
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def show; end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def load_transaction
|
|
33
|
+
@transaction = SpreeCmCommissioner::PrepaidTransaction.find(params[:id])
|
|
34
|
+
@user = @transaction.user
|
|
35
|
+
@store_credit = @transaction.store_credit
|
|
36
|
+
@reversed = SpreeCmCommissioner::PrepaidTransaction
|
|
37
|
+
.exists?(user: @user, transaction_type: 'reverse_top_up', idempotency_key: "admin_reverse:#{@transaction.id}")
|
|
38
|
+
@return_to = safe_return_to
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# So the back link on the detail page returns to the exact filtered/paginated Transactions
|
|
42
|
+
# tab state the admin came from, not a bare reset to page 1 -- only same-admin-namespace
|
|
43
|
+
# paths are honored, since this is attacker-controllable input (an admin could be tricked
|
|
44
|
+
# into following a crafted link) and open-redirecting out of /admin would be a phishing vector.
|
|
45
|
+
def safe_return_to
|
|
46
|
+
candidate = params[:return_to]
|
|
47
|
+
candidate if candidate.present? && candidate.start_with?('/admin/')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Individual ledger row search/browse -- scoped to whichever tenant the dashboard's own
|
|
51
|
+
# tenant selector has picked (tenant_id: nil => platform-issued, same convention as
|
|
52
|
+
# StoreCreditOverviewQuery), further filtered via Ransack (q[user_email_cont],
|
|
53
|
+
# q[currency_eq], q[transaction_type_eq], q[created_at_gteq]/[created_at_lteq], ...).
|
|
54
|
+
def build_transactions_search
|
|
55
|
+
params[:q] = {} if params[:q].blank?
|
|
56
|
+
@transactions_search = SpreeCmCommissioner::PrepaidTransaction.where(tenant_id: @current_tenant_id).ransack(params[:q])
|
|
57
|
+
@transactions = @transactions_search.result
|
|
58
|
+
.includes(:user, :order, :tenant, :admin, :store_credit)
|
|
59
|
+
.order(created_at: :desc)
|
|
60
|
+
.page(params[:page])
|
|
61
|
+
.per(TRANSACTIONS_PER_PAGE)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def model_class
|
|
65
|
+
SpreeCmCommissioner::PrepaidTransaction
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -14,6 +14,7 @@ module Spree
|
|
|
14
14
|
# partial reads these ivars — without this a rejected save is a 500 instead of a form.
|
|
15
15
|
before_action :load_stock_rows, only: %i[edit update]
|
|
16
16
|
before_action :load_assignable_roles, only: %i[new create edit update]
|
|
17
|
+
before_action :load_offline_product_ids, only: %i[new create edit update]
|
|
17
18
|
|
|
18
19
|
# GET /admin/private_sales
|
|
19
20
|
def index
|
|
@@ -45,6 +46,11 @@ module Spree
|
|
|
45
46
|
@assignable_roles = Spree::Role.non_vendor.order(:name)
|
|
46
47
|
end
|
|
47
48
|
|
|
49
|
+
# The product search only returns `name`, so the form labels offline products from this list.
|
|
50
|
+
def load_offline_product_ids
|
|
51
|
+
@offline_product_ids = Spree::Product.where(offline: true).pluck(:id)
|
|
52
|
+
end
|
|
53
|
+
|
|
48
54
|
def location_after_save
|
|
49
55
|
edit_admin_private_sale_path(@private_sale)
|
|
50
56
|
end
|
|
@@ -42,7 +42,8 @@ module Spree
|
|
|
42
42
|
|
|
43
43
|
def commission_for(product)
|
|
44
44
|
commission_rate = product.commission_rate || product.vendor&.commission_rate || 0
|
|
45
|
-
product
|
|
45
|
+
# A product can have no price in the store currency yet (e.g. a freshly created ticket).
|
|
46
|
+
(product.price || 0) * commission_rate / 100
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
# override
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
# Platform-admin management of reschedule policies, built like the Payment
|
|
4
|
+
# Methods page: a scoped tab bar (Store / Vendors / Tenants) over the shared
|
|
5
|
+
# ReschedulePolicy table.
|
|
6
|
+
#
|
|
7
|
+
# - Store tab (default): platform policies (vendor_id nil). Full CRUD.
|
|
8
|
+
# - Vendors tab: every vendor policy, read-only.
|
|
9
|
+
# - Tenants tab: vendor policies whose vendor belongs to a tenant, read-only.
|
|
10
|
+
#
|
|
11
|
+
# Create/Update delegate to the existing ReschedulePolicies services (with
|
|
12
|
+
# vendor: nil), which own calculator building, typed rules, and the
|
|
13
|
+
# one-default-per-scope rule.
|
|
14
|
+
class ReschedulePoliciesController < BaseController
|
|
15
|
+
# Only these tabs switch the page into read-only vendor/tenant mode; any
|
|
16
|
+
# other value falls back to the store tab, in the controller and the view
|
|
17
|
+
# alike (see `current_tab`).
|
|
18
|
+
TABS = %w[vendors tenants].freeze
|
|
19
|
+
|
|
20
|
+
before_action :load_policy, only: %i[edit update destroy set_default]
|
|
21
|
+
|
|
22
|
+
helper_method :current_tab
|
|
23
|
+
|
|
24
|
+
def index
|
|
25
|
+
authorize! :manage, SpreeCmCommissioner::ReschedulePolicy
|
|
26
|
+
|
|
27
|
+
@search = collection.ransack(params[:q])
|
|
28
|
+
@reschedule_policies = @search.result
|
|
29
|
+
.order(default: :desc, name: :asc)
|
|
30
|
+
.page(params[:page])
|
|
31
|
+
.per(params[:per_page] || 20)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def new
|
|
35
|
+
authorize! :manage, SpreeCmCommissioner::ReschedulePolicy
|
|
36
|
+
@reschedule_policy = SpreeCmCommissioner::ReschedulePolicy.new(status: :active)
|
|
37
|
+
# Seed a calculator so the fee fields render; the form/services can swap it.
|
|
38
|
+
@reschedule_policy.calculator_type = 'Spree::Calculator::FlatRate'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def create
|
|
42
|
+
authorize! :manage, SpreeCmCommissioner::ReschedulePolicy
|
|
43
|
+
|
|
44
|
+
result = SpreeCmCommissioner::ReschedulePolicies::Create.call(vendor: nil, options: policy_params)
|
|
45
|
+
if result.success?
|
|
46
|
+
flash[:success] = Spree.t(:successfully_created, resource: reschedule_policy_name)
|
|
47
|
+
redirect_to admin_reschedule_policies_path
|
|
48
|
+
else
|
|
49
|
+
@reschedule_policy = result.value || SpreeCmCommissioner::ReschedulePolicy.new
|
|
50
|
+
flash.now[:error] = result.error&.value
|
|
51
|
+
render :new, status: :unprocessable_entity
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def update
|
|
56
|
+
result = SpreeCmCommissioner::ReschedulePolicies::Update.call(policy: @reschedule_policy, options: policy_params)
|
|
57
|
+
if result.success?
|
|
58
|
+
flash[:success] = Spree.t(:successfully_updated, resource: reschedule_policy_name)
|
|
59
|
+
redirect_to admin_reschedule_policies_path
|
|
60
|
+
else
|
|
61
|
+
flash.now[:error] = result.error&.value
|
|
62
|
+
render :edit, status: :unprocessable_entity
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def destroy
|
|
67
|
+
if @reschedule_policy.active?
|
|
68
|
+
# The reschedule flow resolves the store policy from the *active*
|
|
69
|
+
# store policies, so deleting this one would reject every reschedule.
|
|
70
|
+
flash[:error] = Spree.t('admin.reschedule_policies.cannot_delete_active')
|
|
71
|
+
elsif @reschedule_policy.destroy
|
|
72
|
+
flash[:success] = Spree.t(:successfully_removed, resource: reschedule_policy_name)
|
|
73
|
+
else
|
|
74
|
+
flash[:error] = @reschedule_policy.errors.full_messages.to_sentence
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
redirect_to admin_reschedule_policies_path
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Promote this store policy to the active default; the Update service
|
|
81
|
+
# demotes the current default in the same scope first.
|
|
82
|
+
def set_default
|
|
83
|
+
result = SpreeCmCommissioner::ReschedulePolicies::Update.call(
|
|
84
|
+
policy: @reschedule_policy, options: { default: true, status: :active }
|
|
85
|
+
)
|
|
86
|
+
flash[:success] = Spree.t(:successfully_updated, resource: reschedule_policy_name) if result.success?
|
|
87
|
+
flash[:error] = result.error&.value if result.failure?
|
|
88
|
+
redirect_to admin_reschedule_policies_path
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
# nil for the store tab (including unknown/blank `tab` values), otherwise
|
|
94
|
+
# the recognised tab name.
|
|
95
|
+
def current_tab
|
|
96
|
+
params[:tab] if TABS.include?(params[:tab])
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# All statuses are shown (draft/inactive included) so the admin can manage
|
|
100
|
+
# them, so the raw vendor_id/tenant_id filters are used, not the
|
|
101
|
+
# active-only `store_policies` / `vendor_policies` scopes.
|
|
102
|
+
def collection
|
|
103
|
+
base = SpreeCmCommissioner::ReschedulePolicy
|
|
104
|
+
case current_tab
|
|
105
|
+
when 'vendors'
|
|
106
|
+
base.where.not(vendor_id: nil).includes(:vendor)
|
|
107
|
+
when 'tenants'
|
|
108
|
+
base.where.not(vendor_id: nil).where.not(tenant_id: nil).includes(vendor: :tenant)
|
|
109
|
+
else
|
|
110
|
+
base.where(vendor_id: nil)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def load_policy
|
|
115
|
+
authorize! :manage, SpreeCmCommissioner::ReschedulePolicy
|
|
116
|
+
# Edits apply to store policies only; vendor/tenant policies are read-only here.
|
|
117
|
+
@reschedule_policy = SpreeCmCommissioner::ReschedulePolicy.where(vendor_id: nil).find(params[:id])
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Store policies only carry a fee calculator; the typed reschedule rules
|
|
121
|
+
# (cutoff, max-per-booking, vendor approval, ...) belong to vendor policies
|
|
122
|
+
# and are managed elsewhere, so they are not collected here.
|
|
123
|
+
def policy_params
|
|
124
|
+
params.require(:spree_cm_commissioner_reschedule_policy).permit(
|
|
125
|
+
:name,
|
|
126
|
+
:description,
|
|
127
|
+
:status,
|
|
128
|
+
:default,
|
|
129
|
+
:calculator_type,
|
|
130
|
+
calculator_attributes: calculator_attribute_keys
|
|
131
|
+
)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Only the preferences of the selected (whitelisted) calculator subclass
|
|
135
|
+
# are permitted, so preferences never land on the wrong calculator type.
|
|
136
|
+
def calculator_attribute_keys
|
|
137
|
+
type = params.dig(:spree_cm_commissioner_reschedule_policy, :calculator_type)
|
|
138
|
+
return [] unless %w[Spree::Calculator::FlatRate Spree::Calculator::PercentOnLineItem].include?(type)
|
|
139
|
+
|
|
140
|
+
type.constantize.new.defined_preferences.map { |preference| "preferred_#{preference}" }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def reschedule_policy_name
|
|
144
|
+
SpreeCmCommissioner::ReschedulePolicy.model_name.human
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
class RescheduleRequestsController < Spree::Admin::ResourceController
|
|
4
|
+
helper Spree::Admin::RescheduleRequestsHelper
|
|
5
|
+
|
|
6
|
+
def index
|
|
7
|
+
@search = model_class.includes(:order, :user, :vendor, :vendor_policy).ransack(params[:q])
|
|
8
|
+
@reschedule_requests = @search.result
|
|
9
|
+
.order(created_at: :desc)
|
|
10
|
+
.page(params[:page])
|
|
11
|
+
.per(params[:per_page] || Spree::Backend::Config[:admin_orders_per_page])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def show
|
|
15
|
+
@reschedule_request = load_request
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def state_changes
|
|
19
|
+
@reschedule_request = model_class.find(params[:id])
|
|
20
|
+
@state_changes = @reschedule_request.state_changes.includes(:user).order(created_at: :desc)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def approve
|
|
24
|
+
run_service(
|
|
25
|
+
SpreeCmCommissioner::RescheduleRequests::Vendors::Approve,
|
|
26
|
+
approved_by: try_spree_current_user,
|
|
27
|
+
success_key: 'approved'
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def reject
|
|
32
|
+
run_service(
|
|
33
|
+
SpreeCmCommissioner::RescheduleRequests::Vendors::Reject,
|
|
34
|
+
rejected_by: try_spree_current_user,
|
|
35
|
+
success_key: 'rejected'
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def cancel
|
|
40
|
+
run_service(
|
|
41
|
+
SpreeCmCommissioner::RescheduleRequests::Cancel,
|
|
42
|
+
cancelled_by: try_spree_current_user,
|
|
43
|
+
reason: params[:cancellation_reason].presence,
|
|
44
|
+
success_key: 'cancelled'
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# Each service takes the acting admin so audit rows record who acted
|
|
51
|
+
# rather than the request's customer.
|
|
52
|
+
def run_service(service, success_key:, **)
|
|
53
|
+
@reschedule_request = model_class.find(params[:id])
|
|
54
|
+
|
|
55
|
+
result = service.call(reschedule_request: @reschedule_request, **)
|
|
56
|
+
if result.success?
|
|
57
|
+
flash[:success] = t("spree.admin.reschedule_requests.#{success_key}")
|
|
58
|
+
else
|
|
59
|
+
flash[:error] = result.error&.value
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
redirect_to admin_reschedule_request_path(@reschedule_request)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def load_request
|
|
66
|
+
model_class.includes(
|
|
67
|
+
:order, :user, :vendor, :tenant, :vendor_policy, :store_policy,
|
|
68
|
+
previous_request_snapshots: %i[variant line_item],
|
|
69
|
+
new_request_snapshots: %i[variant line_item]
|
|
70
|
+
).find(params[:id])
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def model_class
|
|
74
|
+
SpreeCmCommissioner::RescheduleRequest
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def object_name
|
|
78
|
+
'spree_cm_commissioner_reschedule_request'
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
class StoreCreditAdminController < Spree::Admin::BaseController
|
|
4
|
+
TABS = %w[overview frozen_store_credits settings].freeze
|
|
5
|
+
|
|
6
|
+
def show
|
|
7
|
+
@current_tab = TABS.include?(params[:tab]) ? params[:tab] : 'overview'
|
|
8
|
+
@tenants = SpreeCmCommissioner::Tenant.order(:name)
|
|
9
|
+
@current_tenant_id = params[:tenant_id].presence&.to_i
|
|
10
|
+
store_credit_overview = SpreeCmCommissioner::StoreCreditOverviewQuery.new(issuer_tenant_id: @current_tenant_id)
|
|
11
|
+
@summary = store_credit_overview.call
|
|
12
|
+
@frozen_store_credits = store_credit_overview.frozen_store_credits
|
|
13
|
+
@config = SpreeCmCommissioner::Configuration.new
|
|
14
|
+
@store = Spree::Store.default
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Covers every prepaid_* Configuration preference editable from the Settings tab -- the
|
|
18
|
+
# currency rate table (keyed by Spree::Store.default#supported_currency_codes -- edit the
|
|
19
|
+
# currency list itself on the store's own admin settings page, not here) and the
|
|
20
|
+
# fraud/velocity limits (Configuration's comment on prepaid_max_topups_per_hour and
|
|
21
|
+
# friends). One form/action since nothing here is ever meaningfully saved independently.
|
|
22
|
+
SETTINGS_KEYS = %i[
|
|
23
|
+
prepaid_currency_rates prepaid_topup_min_amount prepaid_topup_max_amount
|
|
24
|
+
prepaid_max_topups_per_hour prepaid_max_topup_count_daily prepaid_daily_topup_limit
|
|
25
|
+
prepaid_max_balance
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
def update_settings
|
|
29
|
+
config = SpreeCmCommissioner::Configuration.new
|
|
30
|
+
new_values = {
|
|
31
|
+
prepaid_currency_rates: permitted_currency_rates(config),
|
|
32
|
+
prepaid_topup_min_amount: params[:prepaid_topup_min_amount].to_d,
|
|
33
|
+
prepaid_topup_max_amount: params[:prepaid_topup_max_amount].to_d,
|
|
34
|
+
prepaid_max_topups_per_hour: params[:prepaid_max_topups_per_hour].to_i,
|
|
35
|
+
prepaid_max_topup_count_daily: params[:prepaid_max_topup_count_daily].to_i,
|
|
36
|
+
prepaid_daily_topup_limit: params[:prepaid_daily_topup_limit].to_d,
|
|
37
|
+
prepaid_max_balance: params[:prepaid_max_balance].to_d
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
error = invalid_settings_reason(new_values)
|
|
41
|
+
if error
|
|
42
|
+
flash[:error] = error
|
|
43
|
+
return redirect_to admin_store_credit_path(tab: 'settings')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
old_values = SETTINGS_KEYS.index_with { |key| config[key] }
|
|
47
|
+
SETTINGS_KEYS.each { |key| config[key] = new_values[key] }
|
|
48
|
+
|
|
49
|
+
log_settings_change(old_values, new_values)
|
|
50
|
+
|
|
51
|
+
flash[:success] = I18n.t('spree_cm_commissioner.store_credit_admin.settings_updated')
|
|
52
|
+
redirect_to admin_store_credit_path(tab: 'settings')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def run_reconciliation
|
|
56
|
+
report = SpreeCmCommissioner::PrepaidReconciliationService.run_daily
|
|
57
|
+
|
|
58
|
+
if report.drift_count.zero?
|
|
59
|
+
flash[:success] = I18n.t('spree_cm_commissioner.store_credit_admin.reconciliation_success', checked_count: report.checked_count)
|
|
60
|
+
else
|
|
61
|
+
flash[:error] = I18n.t(
|
|
62
|
+
'spree_cm_commissioner.store_credit_admin.reconciliation_drift',
|
|
63
|
+
checked_count: report.checked_count, drift_count: report.drift_count
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
redirect_back fallback_location: admin_store_credit_path
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# Keyed by the store's current supported-currencies list, so a dropped currency's rate
|
|
73
|
+
# doesn't linger and a new one gets an explicit (fallback 1.0) entry.
|
|
74
|
+
def permitted_currency_rates(config)
|
|
75
|
+
currency_codes = Spree::Store.default.supported_currency_codes
|
|
76
|
+
submitted = params[:prepaid_currency_rates]
|
|
77
|
+
submitted = submitted.is_a?(ActionController::Parameters) ? submitted.permit(*currency_codes) : {}
|
|
78
|
+
|
|
79
|
+
currency_codes.index_with do |currency|
|
|
80
|
+
submitted[currency].presence&.to_f || config.prepaid_currency_rates[currency] || 1.0
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# These preferences are the only fraud/velocity ceiling enforced on store credit money-in
|
|
85
|
+
# (Prepaid::CheckTopUpLimits, Prepaid::TopUp) -- a negative value would be silently treated
|
|
86
|
+
# as "no limit" by comparisons like `amount > limit`, and a non-positive currency rate would
|
|
87
|
+
# corrupt every cross-currency conversion built on it.
|
|
88
|
+
def invalid_settings_reason(values)
|
|
89
|
+
%i[
|
|
90
|
+
prepaid_topup_min_amount prepaid_topup_max_amount prepaid_max_topups_per_hour
|
|
91
|
+
prepaid_max_topup_count_daily prepaid_daily_topup_limit prepaid_max_balance
|
|
92
|
+
].each do |key|
|
|
93
|
+
return "#{key} can't be negative" if values[key].negative?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
if values[:prepaid_topup_min_amount] > values[:prepaid_topup_max_amount] && values[:prepaid_topup_max_amount].positive?
|
|
97
|
+
return 'prepaid_topup_min_amount cannot exceed prepaid_topup_max_amount'
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
values[:prepaid_currency_rates].each do |currency, rate|
|
|
101
|
+
return "currency rate for #{currency} must be positive" unless rate.positive?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# No dedicated audit-log model for Configuration preferences (they're key/value, not an
|
|
108
|
+
# ActiveRecord row PaperTrail can version) -- structured log line is the same pattern
|
|
109
|
+
# #run_reconciliation already uses ("-- see logs") for admin-triggered store credit actions.
|
|
110
|
+
def log_settings_change(old_values, new_values)
|
|
111
|
+
changed = SETTINGS_KEYS.each_with_object({}) do |key, diff|
|
|
112
|
+
diff[key] = { from: old_values[key], to: new_values[key] } if old_values[key] != new_values[key]
|
|
113
|
+
end
|
|
114
|
+
return if changed.empty?
|
|
115
|
+
|
|
116
|
+
Rails.logger.info(
|
|
117
|
+
"[store_credit_settings_change] admin_id=#{try_spree_current_user&.id} changes=#{changed}"
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
module Admin
|
|
3
3
|
class TicketTransferRulesController < Spree::Admin::ResourceController
|
|
4
|
+
before_action :load_offline_product_ids, only: %i[new edit create update]
|
|
5
|
+
|
|
4
6
|
def index
|
|
5
7
|
@search = model_class.ransack(params[:q])
|
|
6
8
|
@ticket_transfer_rules = @search.result
|
|
@@ -11,6 +13,11 @@ module Spree
|
|
|
11
13
|
|
|
12
14
|
private
|
|
13
15
|
|
|
16
|
+
# The scope-target search only returns `name`, so the form labels offline products from this list.
|
|
17
|
+
def load_offline_product_ids
|
|
18
|
+
@offline_product_ids = Spree::Product.where(offline: true).pluck(:id)
|
|
19
|
+
end
|
|
20
|
+
|
|
14
21
|
def model_class
|
|
15
22
|
SpreeCmCommissioner::TicketTransferRule
|
|
16
23
|
end
|