spree_cm_commissioner 2.0.3.pre.pre.pre7 → 2.1.0.pre.pre1
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/.github/workflows/test_and_build_gem.yml +16 -2
- data/.gitignore +2 -1
- data/Gemfile.lock +39 -4
- data/Rakefile +33 -4
- data/app/assets/stylesheets/spree_cm_commissioner/backend/calendar.scss +8 -11
- data/app/controllers/spree/admin/inventory_items_controller.rb +83 -0
- data/app/controllers/spree/admin/locations_controller.rb +62 -0
- data/app/controllers/spree/admin/stock_managements_controller.rb +63 -1
- data/app/controllers/spree/api/v2/platform/places_controller.rb +4 -1
- data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +42 -0
- data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +14 -31
- data/app/controllers/spree/api/v2/storefront/dynamic_fields_controller.rb +1 -1
- data/app/controllers/spree/api/v2/storefront/guests_controller.rb +26 -18
- data/app/controllers/spree/api/v2/storefront/inventory_items_controller.rb +57 -0
- data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +2 -2
- data/app/controllers/spree/api/v2/storefront/transit/draft_orders_controller.rb +46 -0
- data/app/controllers/spree/api/v2/storefront/trip_places_controller.rb +29 -0
- data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +62 -0
- data/app/controllers/spree/api/v2/storefront/trips_controller.rb +24 -0
- data/app/finders/spree_cm_commissioner/accommodations/find.rb +37 -0
- data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +32 -0
- data/app/interactors/spree_cm_commissioner/billing_address_creator.rb +33 -0
- data/app/interactors/spree_cm_commissioner/customer_notification_sender.rb +7 -2
- data/app/interactors/spree_cm_commissioner/ensure_correct_product_type.rb +40 -0
- data/app/interactors/spree_cm_commissioner/fetch_facebook_user_data.rb +45 -0
- data/app/interactors/spree_cm_commissioner/google_places_fetcher.rb +1 -0
- data/app/interactors/spree_cm_commissioner/intercity_taxi_order_creator.rb +106 -0
- data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +25 -0
- data/app/interactors/spree_cm_commissioner/stock/inventory_item_resetter.rb +44 -0
- data/app/interactors/spree_cm_commissioner/stock/inventory_items_adjuster.rb +13 -0
- data/app/interactors/spree_cm_commissioner/stock/inventory_items_generator.rb +15 -0
- data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +75 -0
- data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +32 -0
- data/app/interactors/spree_cm_commissioner/taxi_trip_creator.rb +66 -0
- data/app/interactors/spree_cm_commissioner/transit/draft_order_creator.rb +136 -0
- data/app/interactors/spree_cm_commissioner/trip_clone_creator.rb +155 -0
- data/app/interactors/spree_cm_commissioner/user_fb_token_authenticator.rb +37 -0
- data/app/interactors/spree_cm_commissioner/user_fb_token_checker.rb +20 -0
- data/app/interactors/spree_cm_commissioner/user_identity_checker.rb +8 -8
- data/app/interactors/spree_cm_commissioner/user_registration_with_fb_token.rb +62 -0
- data/app/interactors/spree_cm_commissioner/variant_block_updater.rb +62 -0
- data/app/interactors/spree_cm_commissioner/vehicle_updater.rb +41 -0
- data/app/jobs/spree_cm_commissioner/application_job.rb +20 -0
- data/app/jobs/spree_cm_commissioner/application_unique_job.rb +20 -0
- data/app/jobs/spree_cm_commissioner/ensure_correct_product_type_job.rb +7 -0
- data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +7 -0
- data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +11 -0
- data/app/jobs/spree_cm_commissioner/stock/inventory_items_generator_job.rb +11 -0
- data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +9 -0
- data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +18 -15
- data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +29 -15
- data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +144 -0
- data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +3 -12
- data/app/models/concerns/spree_cm_commissioner/order_seatable.rb +44 -0
- data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +39 -0
- data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +1 -3
- data/app/models/concerns/spree_cm_commissioner/product_type.rb +10 -0
- data/app/models/concerns/spree_cm_commissioner/route_type.rb +1 -1
- data/app/models/concerns/spree_cm_commissioner/user_identity.rb +12 -4
- data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +1 -0
- data/app/models/concerns/spree_cm_commissioner/vehicle_type.rb +11 -0
- data/app/models/spree_cm_commissioner/address_decorator.rb +36 -2
- data/app/models/spree_cm_commissioner/block.rb +43 -0
- data/app/models/spree_cm_commissioner/customer_notification.rb +6 -1
- data/app/models/spree_cm_commissioner/dynamic_field.rb +2 -0
- data/app/models/spree_cm_commissioner/guest.rb +39 -0
- data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +4 -0
- data/app/models/spree_cm_commissioner/inventory.rb +11 -0
- data/app/models/spree_cm_commissioner/inventory_item.rb +82 -0
- data/app/models/spree_cm_commissioner/line_item_decorator.rb +47 -78
- data/app/models/spree_cm_commissioner/notification_taxon.rb +1 -1
- data/app/models/spree_cm_commissioner/option_type_decorator.rb +1 -11
- data/app/models/spree_cm_commissioner/order/address_book_decorator.rb +30 -12
- data/app/models/spree_cm_commissioner/order_decorator.rb +38 -1
- data/app/models/spree_cm_commissioner/place.rb +3 -4
- data/app/models/spree_cm_commissioner/price_decorator.rb +9 -0
- data/app/models/spree_cm_commissioner/product_decorator.rb +13 -10
- data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +41 -0
- data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +126 -0
- data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +36 -0
- data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +25 -0
- data/app/models/spree_cm_commissioner/reserved_block.rb +31 -0
- data/app/models/spree_cm_commissioner/saved_guest.rb +21 -0
- data/app/models/spree_cm_commissioner/seat_layout.rb +20 -0
- data/app/models/spree_cm_commissioner/seat_section.rb +16 -0
- data/app/models/spree_cm_commissioner/seats/blocks_canceler.rb +30 -0
- data/app/models/spree_cm_commissioner/seats/blocks_holder.rb +53 -0
- data/app/models/spree_cm_commissioner/seats/blocks_reserver.rb +49 -0
- data/app/models/spree_cm_commissioner/seats/errors/blocks_are_on_hold_by_other_guest.rb +4 -0
- data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_other_guest.rb +4 -0
- data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_same_guest.rb +4 -0
- data/app/models/spree_cm_commissioner/seats/errors/unable_to_save_reserved_block_record.rb +4 -0
- data/app/models/spree_cm_commissioner/service_calendar.rb +0 -2
- data/app/models/spree_cm_commissioner/state_decorator.rb +0 -1
- data/app/models/spree_cm_commissioner/stock/availability_checker.rb +26 -25
- data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +2 -1
- data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
- data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +44 -0
- data/app/models/spree_cm_commissioner/stock_item_decorator.rb +17 -0
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +7 -1
- data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +0 -6
- data/app/models/spree_cm_commissioner/trip.rb +19 -10
- data/app/models/spree_cm_commissioner/trip_connection.rb +5 -5
- data/app/models/spree_cm_commissioner/trip_stop.rb +10 -21
- data/app/models/spree_cm_commissioner/variant_block.rb +17 -0
- data/app/models/spree_cm_commissioner/variant_decorator.rb +37 -47
- data/app/models/spree_cm_commissioner/variant_options.rb +4 -23
- data/app/models/spree_cm_commissioner/vehicle.rb +12 -15
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +14 -14
- data/app/models/spree_cm_commissioner/vendor_place.rb +13 -3
- data/app/overrides/spree/admin/shared/sub_menu/_configuration/locations_tab.html.erb.deface +5 -0
- data/app/queries/spree_cm_commissioner/trip_query.rb +110 -131
- data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +3 -0
- data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
- data/app/request_schemas/spree_cm_commissioner/inventory_item_schema.rb +8 -0
- data/app/request_schemas/spree_cm_commissioner/trip_search_request_schema.rb +20 -0
- data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +19 -0
- data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +2 -0
- data/app/serializers/spree/v2/storefront/cart_serializer_decorator.rb +1 -0
- data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +3 -1
- data/app/serializers/spree/v2/storefront/user_serializer_decorator.rb +1 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/amenity_serializer.rb +15 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/block_serializer.rb +11 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +5 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/inventory_item_serializer.rb +42 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/reserved_block_serializer.rb +9 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/saved_guest_serializer.rb +21 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/seat_layout_serializer.rb +12 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/seat_section_serializer.rb +11 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_place_serializer.rb +10 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_query_result_serializer.rb +14 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_result_serializer.rb +17 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_serializer.rb +20 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_stop_serializer.rb +11 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_variant_serializer.rb +12 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_vehicle_serializer.rb +16 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_vendor_serializer.rb +16 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/variant_block_serializer.rb +9 -0
- data/app/services/spree_cm_commissioner/transit/legs_builder_service.rb +46 -0
- data/app/services/spree_cm_commissioner/user_authenticator.rb +10 -1
- data/app/views/shared/_map.html.erb +5 -4
- data/app/views/spree/admin/customer_notifications/_form.html.erb +3 -3
- data/app/views/spree/admin/inventory_items/show.html.erb +72 -0
- data/app/views/spree/admin/locations/_form.html.erb +133 -0
- data/app/views/spree/admin/locations/edit.html.erb +11 -0
- data/app/views/spree/admin/locations/index.html.erb +67 -0
- data/app/views/spree/admin/locations/new.html.erb +11 -0
- data/app/views/spree/admin/stock_managements/_variant_stock_items.html.erb +7 -2
- data/app/views/spree/admin/stock_managements/calendar.html.erb +56 -0
- data/app/views/spree/admin/stock_managements/index.html.erb +55 -6
- data/config/initializers/paper_trail.rb +1 -0
- data/config/initializers/spree_permitted_attributes.rb +24 -4
- data/config/locales/en.yml +2 -0
- data/config/routes.rb +32 -2
- data/db/migrate/20240202080634_update_counter_cache_of_vehicle_type.rb +3 -1
- data/db/migrate/20250122000000_move_route_type_from_vehicles_to_trips.rb +7 -0
- data/db/migrate/20250304293518_create_cm_inventory_items.rb +21 -0
- data/db/migrate/20250428092706_add_active_to_cm_customer_notifications.rb +7 -0
- data/db/migrate/20250428103550_remove_tenant_id_and_vendor_id_from_cm_customer_notifications.rb +9 -0
- data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +5 -0
- data/db/migrate/20250502025848_add_index_to_spree_products.rb +5 -0
- data/db/migrate/20250502030001_add_product_type_to_spree_variants.rb +5 -0
- data/db/migrate/20250502030002_add_product_type_to_spree_line_items.rb +5 -0
- data/db/migrate/20250603035256_add_inventory_item_to_spree_prices.rb +7 -0
- data/db/migrate/20250619073724_drop_table_cm_line_item_seats.rb +5 -0
- data/db/migrate/20250619073812_drop_table_cm_vehicle_seats.rb +5 -0
- data/db/migrate/20250619073844_drop_table_cm_vehicle_types.rb +9 -0
- data/db/migrate/20250619073957_drop_table_cm_option_value_vehicle_types.rb +5 -0
- data/db/migrate/20250619082354_remove_unnecessary_fields_from_cm_places.rb +9 -0
- data/db/migrate/20250619082736_remove_route_type_from_spree_products.rb +5 -0
- data/db/migrate/20250619083055_remove_unnecessary_fields_from_spree_taxons.rb +5 -0
- data/db/migrate/20250620083055_remove_variant_id_from_cm_trips.rb +5 -0
- data/db/migrate/20250620090000_update_cm_trip_connections_to_use_cm_trips.rb +6 -0
- data/db/migrate/20250620090001_create_cm_seat_layouts.rb +17 -0
- data/db/migrate/20250620090002_create_cm_seat_sections.rb +18 -0
- data/db/migrate/20250620090003_create_cm_blocks.rb +18 -0
- data/db/migrate/20250624091005_create_cm_reserved_blocks.rb +29 -0
- data/db/migrate/20250626083642_create_cm_variant_blocks.rb +24 -0
- data/db/migrate/20250627023314_add_block_id_to_cm_guests.rb +13 -0
- data/db/migrate/20250716022821_add_location_reference_to_cm_vendor_places.rb +5 -0
- data/db/migrate/20250716031743_drop_table_cm_vendor_stops.rb +5 -0
- data/db/migrate/20250717023824_add_vendor_reference_to_cm_trips.rb +5 -0
- data/db/migrate/20250717041414_add_location_place_reference_to_cm_trip_stops.rb +5 -0
- data/db/migrate/20250717042539_rename_cm_trip_stops_stop_id_column_to_stop_place_id.rb +7 -0
- data/db/migrate/20250717042707_rename_cm_trips_origin_and_destination_to_origin_place_and_destination_place.rb +11 -0
- data/db/migrate/20250721080738_add_vehicle_type_to_cm_vehicles.rb +7 -0
- data/db/migrate/20250725092713_add_block_type_to_cm_blocks.rb +5 -0
- data/db/migrate/20250731062816_add_departure_time_and_arrival_time_to_trip_stop.rb +6 -0
- data/db/migrate/20250807033035_create_spree_cm_commissioner_saved_guests.rb +23 -0
- data/db/migrate/20250807040000_generate_pickup_time_integer_option_values.rb +71 -0
- data/db/migrate/20250808054835_add_saved_guest_reference_to_cm_blocks.rb +5 -0
- data/docker-compose.yml +1 -1
- data/lib/cm_app_logger.rb +17 -1
- data/lib/generators/spree_cm_commissioner/install/install_generator.rb +14 -11
- data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_cm_commissioner → spree_dashboard/spree_cm_commissioner}/utilities.js +4 -0
- data/lib/spree_cm_commissioner/cached_inventory_item.rb +23 -0
- data/lib/spree_cm_commissioner/calendar_event.rb +11 -1
- data/lib/spree_cm_commissioner/test_helper/factories/block_factory.rb +16 -0
- data/lib/spree_cm_commissioner/test_helper/factories/guest_factory.rb +10 -0
- data/lib/spree_cm_commissioner/test_helper/factories/homepage_section_relatable_factory.rb +1 -1
- data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +20 -0
- data/lib/spree_cm_commissioner/test_helper/factories/line_item_factory.rb +1 -1
- data/lib/spree_cm_commissioner/test_helper/factories/option_type_factory.rb +6 -30
- data/lib/spree_cm_commissioner/test_helper/factories/order_factory.rb +0 -36
- data/lib/spree_cm_commissioner/test_helper/factories/product_factory.rb +18 -34
- data/lib/spree_cm_commissioner/test_helper/factories/reserved_block_factory.rb +27 -0
- data/lib/spree_cm_commissioner/test_helper/factories/saved_guest_factory.rb +8 -0
- data/lib/spree_cm_commissioner/test_helper/factories/seat_layout_factory.rb +11 -0
- data/lib/spree_cm_commissioner/test_helper/factories/seat_section_factory.rb +16 -0
- data/lib/spree_cm_commissioner/test_helper/factories/stock_location_factory.rb +2 -2
- data/lib/spree_cm_commissioner/test_helper/factories/trip_connection_factory.rb +6 -0
- data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +11 -3
- data/lib/spree_cm_commissioner/test_helper/factories/trip_stop_factory.rb +13 -0
- data/lib/spree_cm_commissioner/test_helper/factories/variant_block_factory.rb +7 -0
- data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +41 -19
- data/lib/spree_cm_commissioner/test_helper/factories/vehicle_factory.rb +1 -1
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +6 -1
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +13 -1
- data/lib/spree_cm_commissioner/transit/leg.rb +37 -0
- data/lib/spree_cm_commissioner/transit/seat_selection.rb +27 -0
- data/lib/spree_cm_commissioner/trip_query_result.rb +50 -0
- data/lib/spree_cm_commissioner/trip_result.rb +19 -10
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +37 -1
- data/lib/tasks/create_default_non_permanent_inventory_items.rake +16 -0
- data/lib/tasks/ensure_correct_product_type.rake +7 -0
- data/lib/tasks/generate_inventory_items.rake +7 -0
- data/spree_cm_commissioner.gemspec +7 -0
- metadata +195 -26
- data/app/controllers/concerns/spree_cm_commissioner/transit/taxon_bitwise.rb +0 -44
- data/app/finders/spree_cm_commissioner/line_items/find_by_variant_decorator.rb +0 -20
- data/app/models/spree_cm_commissioner/branch.rb +0 -12
- data/app/models/spree_cm_commissioner/line_item_seat.rb +0 -10
- data/app/models/spree_cm_commissioner/option_value_vehicle_type.rb +0 -8
- data/app/models/spree_cm_commissioner/stop.rb +0 -23
- data/app/models/spree_cm_commissioner/vehicle_seat.rb +0 -11
- data/app/models/spree_cm_commissioner/vehicle_type.rb +0 -76
- data/app/models/spree_cm_commissioner/vendor_stop.rb +0 -10
- data/app/queries/spree_cm_commissioner/trip_search_query.rb +0 -76
- data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +0 -45
- data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +0 -55
- data/app/queries/spree_cm_commissioner/vendor_stop_place_query.rb +0 -54
- data/app/services/spree_cm_commissioner/vehicle_option_value_creator.rb +0 -11
- data/lib/spree_cm_commissioner/test_helper/factories/branch_factory.rb +0 -12
- data/lib/spree_cm_commissioner/test_helper/factories/departure_time_option_type_factory.rb +0 -8
- data/lib/spree_cm_commissioner/test_helper/factories/duration_option_type_factory.rb +0 -8
- data/lib/spree_cm_commissioner/test_helper/factories/line_item_seat_factory.rb +0 -7
- data/lib/spree_cm_commissioner/test_helper/factories/stop_factory.rb +0 -14
- data/lib/spree_cm_commissioner/test_helper/factories/transit_place_factory.rb +0 -8
- data/lib/spree_cm_commissioner/test_helper/factories/vehicle_option_type_factory.rb +0 -8
- data/lib/spree_cm_commissioner/test_helper/factories/vehicle_type_factory.rb +0 -96
- data/lib/spree_cm_commissioner/trip_seat_layout_result.rb +0 -11
@@ -5,6 +5,8 @@ module SpreeCmCommissioner
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
+
state_machine.before_transition to: :payment, do: :hold_blocks!
|
9
|
+
|
8
10
|
state_machine.before_transition to: :complete, do: :request, if: :need_confirmation?
|
9
11
|
state_machine.before_transition to: :complete, do: :generate_bib_number
|
10
12
|
|
@@ -14,10 +16,14 @@ module SpreeCmCommissioner
|
|
14
16
|
state_machine.after_transition to: :complete, do: :send_order_complete_telegram_alert_to_vendors, unless: :need_confirmation?
|
15
17
|
state_machine.after_transition to: :complete, do: :send_order_complete_telegram_alert_to_store, unless: :need_confirmation?
|
16
18
|
|
19
|
+
state_machine.around_transition to: :complete, do: :unstock_inventory!
|
20
|
+
|
17
21
|
state_machine.after_transition to: :complete, do: :send_transaction_email_to_user, if: :user_has_email?
|
18
22
|
state_machine.after_transition to: :resumed, do: :precalculate_conversion
|
23
|
+
state_machine.around_transition to: :resumed, do: :unstock_inventory!
|
19
24
|
|
20
25
|
state_machine.after_transition to: :canceled, do: :precalculate_conversion
|
26
|
+
state_machine.after_transition to: :canceled, do: :restock_inventory!
|
21
27
|
|
22
28
|
scope :accepted, -> { where(request_state: 'accepted') }
|
23
29
|
|
@@ -67,6 +73,39 @@ module SpreeCmCommissioner
|
|
67
73
|
end
|
68
74
|
end
|
69
75
|
|
76
|
+
def unstock_inventory!
|
77
|
+
ActiveRecord::Base.transaction do
|
78
|
+
yield # Equal to block.call
|
79
|
+
|
80
|
+
# After the transition is complete, the following code will execute first before proceeding to other `after_transition` callbacks.
|
81
|
+
# This ensures that if `reserve_blocks!` or `unstock_inventory_in_redis!` fails, the state will be rolled back,
|
82
|
+
# and neither the `finalize!` method nor any notifications will be triggered.
|
83
|
+
# The payment will be reversed in vPago gem, and `Spree::Checkout::Complete` will be called, which checks `order.reload.complete?`.
|
84
|
+
# This is critical because if the order state is complete, the payment will be marked as paid.
|
85
|
+
|
86
|
+
reserve_blocks!
|
87
|
+
unstock_inventory_in_redis!
|
88
|
+
|
89
|
+
# We rollback only order state, and we keep payment state as it is.
|
90
|
+
# We implement payment in vPago gem, and it will be reversed in the gem.
|
91
|
+
# Some bank has api for refund, but some don't have the api to refund yet. So we keep the payment state as it is and refund manually.
|
92
|
+
end
|
93
|
+
rescue StandardError => e
|
94
|
+
CmAppLogger.log(
|
95
|
+
label: 'SpreeCmCommissioner::OrderStateMachine#reserve_inventory failed',
|
96
|
+
data: { order_id: id, error: e.message, type: e.class.name, backtrace: e.backtrace&.first(5)&.join("\n") }
|
97
|
+
)
|
98
|
+
|
99
|
+
raise e
|
100
|
+
end
|
101
|
+
|
102
|
+
def restock_inventory!
|
103
|
+
ActiveRecord::Base.transaction do
|
104
|
+
cancel_blocks!
|
105
|
+
restock_inventory_in_redis!
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
70
109
|
def generate_bib_number
|
71
110
|
line_items.find_each(&:generate_remaining_guests)
|
72
111
|
|
@@ -3,12 +3,10 @@ module SpreeCmCommissioner
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
delegate :
|
7
|
-
:subscribable?,
|
6
|
+
delegate :subscribable?,
|
8
7
|
:allowed_upload_later?,
|
9
8
|
:need_confirmation?, :need_confirmation,
|
10
9
|
:allow_anonymous_booking,
|
11
|
-
:accommodation?, :service?, :ecommerce?,
|
12
10
|
:allow_self_check_in,
|
13
11
|
:allow_self_check_in?,
|
14
12
|
:required_self_check_in_location,
|
@@ -6,10 +6,20 @@ module SpreeCmCommissioner
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
PRODUCT_TYPES = %i[accommodation service ecommerce transit].freeze
|
9
|
+
PERMANENT_STOCK_PRODUCT_TYPES = %w[accommodation service transit].freeze
|
10
|
+
PRE_INVENTORY_DAYS = { 'transit' => 90, 'accommodation' => 365, 'service' => 30 }.freeze
|
9
11
|
|
10
12
|
included do
|
11
13
|
enum product_type: PRODUCT_TYPES if table_exists? && column_names.include?('product_type')
|
12
14
|
enum primary_product_type: PRODUCT_TYPES if table_exists? && column_names.include?('primary_product_type')
|
13
15
|
end
|
16
|
+
|
17
|
+
def permanent_stock?
|
18
|
+
PERMANENT_STOCK_PRODUCT_TYPES.include?(product_type)
|
19
|
+
end
|
20
|
+
|
21
|
+
def pre_inventory_days
|
22
|
+
PRE_INVENTORY_DAYS[product_type]
|
23
|
+
end
|
14
24
|
end
|
15
25
|
end
|
@@ -2,7 +2,7 @@ module SpreeCmCommissioner
|
|
2
2
|
module RouteType
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
ROUTE_TYPES = %i[
|
5
|
+
ROUTE_TYPES = %i[bus intercity_taxi airport_shuttle rails ferry].freeze
|
6
6
|
|
7
7
|
included do
|
8
8
|
enum route_type: ROUTE_TYPES if table_exists? && column_names.include?('route_type')
|
@@ -7,19 +7,27 @@ module SpreeCmCommissioner
|
|
7
7
|
|
8
8
|
has_many :user_identity_providers, dependent: :destroy, class_name: 'SpreeCmCommissioner::UserIdentityProvider'
|
9
9
|
|
10
|
-
|
10
|
+
# Attribute to flag social network registration to skip presence validation
|
11
|
+
# for email, login, phone_number, and user_identity_providers
|
12
|
+
attr_accessor :registering_via_social_network
|
11
13
|
|
12
|
-
validates :
|
14
|
+
validates :user_identity_providers, presence: true, if: lambda { |u|
|
15
|
+
u.require_login_identity_all_blank_for(:user_identity_providers) && !u.registering_via_social_network
|
16
|
+
}
|
17
|
+
|
18
|
+
validates :phone_number, presence: true, if: lambda { |u|
|
19
|
+
u.require_login_identity_all_blank_for(:phone_number) && !u.registering_via_social_network
|
20
|
+
}
|
13
21
|
validates :phone_number, uniqueness: { scope: :tenant_id, allow_blank: true }
|
14
22
|
validates :phone_number, format: { with: /^\d{8,12}$/, :multiline => true, allow_blank: true }
|
15
23
|
|
16
|
-
validates :login, presence: true, if: -> (u) { u.require_login_identity_all_blank_for(:login) }
|
24
|
+
validates :login, presence: true, if: -> (u) { u.require_login_identity_all_blank_for(:login) && !u.registering_via_social_network }
|
17
25
|
validates :login, uniqueness: { scope: :tenant_id, case_sensitive: false, allow_blank: true }
|
18
26
|
|
19
27
|
_validators.reject! { |key, _| key == :email }
|
20
28
|
_validate_callbacks.each { |c| c.filter.attributes.delete(:email) if c.filter.respond_to?(:attributes) }
|
21
29
|
|
22
|
-
validates :email, presence: true, if: -> (u) { u.require_login_identity_all_blank_for(:email) }
|
30
|
+
validates :email, presence: true, if: -> (u) { u.require_login_identity_all_blank_for(:email) && !u.registering_via_social_network }
|
23
31
|
validates :email, uniqueness: { scope: :tenant_id, case_sensitive: false, allow_blank: true }
|
24
32
|
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP, allow_blank: true }
|
25
33
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
module VehicleType
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
VEHICLE_TYPES = %i[suv sedan minivan van sleeping_bus luxury_van air_bus bus].freeze
|
6
|
+
|
7
|
+
included do
|
8
|
+
enum vehicle_type: VEHICLE_TYPES if table_exists? && column_names.include?('vehicle_type')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -1,10 +1,44 @@
|
|
1
1
|
module SpreeCmCommissioner
|
2
2
|
module AddressDecorator
|
3
3
|
def self.prepended(base)
|
4
|
-
# Field is not mandatory
|
5
4
|
base.enum gender: { :not_selected => 0, :male => 1, :female => 2, :other => 3 }
|
5
|
+
|
6
|
+
base.validates :address1, presence: true, if: :require_address1?
|
7
|
+
base.validates :city, presence: true, if: :require_city?
|
8
|
+
base.validates :country, presence: true, if: :require_country?
|
9
|
+
end
|
10
|
+
|
11
|
+
# override to return false instead of true
|
12
|
+
# in case no country
|
13
|
+
def require_zipcode?
|
14
|
+
country ? country.zipcode_required? : false
|
15
|
+
end
|
16
|
+
|
17
|
+
def require_address1?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def require_city?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def require_country?
|
26
|
+
false
|
6
27
|
end
|
7
28
|
end
|
8
29
|
end
|
9
30
|
|
10
|
-
|
31
|
+
if Spree::Address.included_modules.exclude?(SpreeCmCommissioner::AddressDecorator)
|
32
|
+
keys = %i[address1 city country]
|
33
|
+
|
34
|
+
Spree::Address._validators.reject! { |key, _| keys.include?(key) }
|
35
|
+
Spree::Address._validate_callbacks.each do |c|
|
36
|
+
next unless c.filter.respond_to?(:attributes)
|
37
|
+
|
38
|
+
c.filter.attributes.delete(:address1)
|
39
|
+
c.filter.attributes.delete(:city)
|
40
|
+
c.filter.attributes.delete(:country)
|
41
|
+
end
|
42
|
+
|
43
|
+
Spree::Address.prepend(SpreeCmCommissioner::AddressDecorator)
|
44
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class Block < Base
|
3
|
+
enum block_type: {
|
4
|
+
seat: 1,
|
5
|
+
sleeping_seat: 2,
|
6
|
+
driver: 3,
|
7
|
+
bathroom: 4,
|
8
|
+
other: 0
|
9
|
+
}
|
10
|
+
|
11
|
+
belongs_to :seat_section, class_name: 'SpreeCmCommissioner::SeatSection', optional: true
|
12
|
+
belongs_to :seat_layout, class_name: 'SpreeCmCommissioner::SeatLayout', optional: false
|
13
|
+
|
14
|
+
validates :label, presence: true, if: :label_required?
|
15
|
+
|
16
|
+
has_many :variant_blocks, class_name: 'SpreeCmCommissioner::VariantBlock', dependent: :destroy
|
17
|
+
has_many :variants, class_name: 'Spree::Variant', through: :variant_blocks
|
18
|
+
|
19
|
+
validates :width, presence: true, numericality: { greater_than: 0 }
|
20
|
+
validates :height, presence: true, numericality: { greater_than: 0 }
|
21
|
+
validates :x, presence: true, numericality: true
|
22
|
+
validates :y, presence: true, numericality: true
|
23
|
+
validates :rotation, presence: true, numericality: { greater_than_or_equal_to: -360, less_than_or_equal_to: 360 }
|
24
|
+
|
25
|
+
before_validation :assign_layout_from_section, if: -> { seat_layout.nil? && seat_section.present? }
|
26
|
+
|
27
|
+
def label_required?
|
28
|
+
seatable? || block_type.to_s == 'other'
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.seatable?(block_type)
|
32
|
+
block_type.to_s.in?(%w[sleeping_seat seat])
|
33
|
+
end
|
34
|
+
|
35
|
+
def seatable?
|
36
|
+
self.class.seatable?(block_type)
|
37
|
+
end
|
38
|
+
|
39
|
+
def assign_layout_from_section
|
40
|
+
self.seat_layout = seat_section.seat_layout
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -6,14 +6,19 @@ module SpreeCmCommissioner
|
|
6
6
|
has_one :feature_image, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::FeatureImage'
|
7
7
|
|
8
8
|
has_many :feature_images, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::FeatureImage'
|
9
|
-
has_many :notification_taxons, class_name: 'SpreeCmCommissioner::NotificationTaxon'
|
9
|
+
has_many :notification_taxons, dependent: :destroy, class_name: 'SpreeCmCommissioner::NotificationTaxon'
|
10
10
|
has_many :taxons, through: :notification_taxons, class_name: 'Spree::Taxon'
|
11
11
|
|
12
|
+
belongs_to :vendor, class_name: 'Spree::Vendor'
|
13
|
+
|
12
14
|
validates :title, presence: true
|
13
15
|
validates :url, presence: true
|
14
16
|
|
15
17
|
validates :notification_type, presence: true
|
16
18
|
|
19
|
+
self.whitelisted_ransackable_attributes = %w[title excerpt notification_type]
|
20
|
+
self.whitelisted_ransackable_associations = %w[notification_taxons taxons]
|
21
|
+
|
17
22
|
enum notification_type: { :promotion => 0, :announcement => 1 }
|
18
23
|
|
19
24
|
def push_notification_image_url
|
@@ -18,6 +18,8 @@ module SpreeCmCommissioner
|
|
18
18
|
validates :configurations, presence: true, allow_blank: false
|
19
19
|
validate :validate_data_fill_stage_phase
|
20
20
|
|
21
|
+
scope :with_dynamic_field_options, -> { includes(dynamic_field_options: :dynamic_field) }
|
22
|
+
|
21
23
|
def requires_dynamic_field_options?
|
22
24
|
checkbox? || radio? || selection?
|
23
25
|
end
|
@@ -24,10 +24,17 @@ module SpreeCmCommissioner
|
|
24
24
|
scope :none_bib, -> { where(bib_prefix: [nil, '']) }
|
25
25
|
|
26
26
|
belongs_to :line_item, class_name: 'Spree::LineItem'
|
27
|
+
|
27
28
|
has_one :variant, class_name: 'Spree::Variant', through: :line_item
|
29
|
+
|
28
30
|
belongs_to :user, class_name: 'Spree::User'
|
29
31
|
belongs_to :occupation, class_name: 'Spree::Taxon'
|
30
32
|
belongs_to :nationality, class_name: 'Spree::Taxon'
|
33
|
+
belongs_to :block, class_name: 'SpreeCmCommissioner::Block', optional: true
|
34
|
+
belongs_to :saved_guest, class_name: 'SpreeCmCommissioner::SavedGuest', optional: true
|
35
|
+
|
36
|
+
has_one :reserved_block, class_name: 'SpreeCmCommissioner::ReservedBlock'
|
37
|
+
|
31
38
|
scope :checked_ins, -> { joins(:check_in) }
|
32
39
|
scope :no_show, -> { left_outer_joins(:check_in).where(cm_check_ins: { id: nil }) }
|
33
40
|
|
@@ -48,12 +55,22 @@ module SpreeCmCommissioner
|
|
48
55
|
|
49
56
|
before_create :generate_bib, if: -> { line_item.reload && variant.bib_pre_generation_on_create? }
|
50
57
|
|
58
|
+
after_create :preload_order_block_ids, if: -> { block_id.present? }
|
59
|
+
after_update :preload_order_block_ids, if: :saved_change_to_block_id?
|
60
|
+
after_destroy :preload_order_block_ids
|
61
|
+
|
51
62
|
validates :seat_number, uniqueness: { scope: :event_id }, allow_nil: true, if: -> { event_id.present? }
|
52
63
|
validates :bib_index, uniqueness: true, allow_nil: true
|
53
64
|
|
65
|
+
validate :validate_block, if: :should_validate_block?
|
66
|
+
|
54
67
|
self.whitelisted_ransackable_associations = %w[id_card event line_item]
|
55
68
|
self.whitelisted_ransackable_attributes = %w[first_name last_name phone_number gender contact occupation_id card_type created_at check_in_status]
|
56
69
|
|
70
|
+
scope :with_dynamic_fields_and_options, lambda {
|
71
|
+
includes(guest_dynamic_fields: { dynamic_field: :dynamic_field_options })
|
72
|
+
}
|
73
|
+
|
57
74
|
def self.csv_importable_columns
|
58
75
|
%i[
|
59
76
|
first_name last_name phone_number age dob gender address other_occupation
|
@@ -228,6 +245,28 @@ module SpreeCmCommissioner
|
|
228
245
|
end
|
229
246
|
end
|
230
247
|
|
248
|
+
# validate only if block_id is present AND (new record OR block_id is changing)
|
249
|
+
# goal: don't bother re-validating when block_id stays the same
|
250
|
+
def should_validate_block?
|
251
|
+
block_id.present? && (new_record? || will_save_change_to_block_id?)
|
252
|
+
end
|
253
|
+
|
254
|
+
def validate_block
|
255
|
+
return if block_id.blank?
|
256
|
+
return if line_item.blank? || line_item.variant.blank?
|
257
|
+
return if line_item.variant.variant_blocks.exists?(block_id: block_id)
|
258
|
+
|
259
|
+
errors.add(:block, "does not exist in variant #{line_item.variant_id}")
|
260
|
+
end
|
261
|
+
|
262
|
+
def preload_order_block_ids
|
263
|
+
return if line_item.blank?
|
264
|
+
return if line_item.order.blank?
|
265
|
+
|
266
|
+
block_ids = line_item.order.blocks.pluck(:id)
|
267
|
+
line_item.order.update(preload_block_ids: block_ids)
|
268
|
+
end
|
269
|
+
|
231
270
|
def all_required_dynamic_fields_completed?(stage)
|
232
271
|
missing_dynamic_fields_for_stage(stage).blank?
|
233
272
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class Inventory
|
3
|
+
include ActiveModel::Model
|
4
|
+
|
5
|
+
attr_accessor :variant_id, :inventory_date, :quantity_available, :max_capacity, :product_type
|
6
|
+
|
7
|
+
validates :variant_id, presence: true
|
8
|
+
validates :quantity_available, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, allow_nil: true
|
9
|
+
validates :max_capacity, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, allow_nil: true
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class InventoryItem < Base
|
3
|
+
include SpreeCmCommissioner::ProductType
|
4
|
+
|
5
|
+
MAX_DISPLAY_STOCK = 20
|
6
|
+
|
7
|
+
# Association
|
8
|
+
belongs_to :variant, class_name: 'Spree::Variant', optional: false
|
9
|
+
|
10
|
+
has_many :prices, class_name: 'Spree::Price', inverse_of: :inventory_item, dependent: :destroy
|
11
|
+
|
12
|
+
has_many :reserved_blocks, -> { reserved_or_on_hold }, class_name: 'SpreeCmCommissioner::ReservedBlock', inverse_of: :inventory_item
|
13
|
+
|
14
|
+
# Validation
|
15
|
+
validates :quantity_available, numericality: { greater_than_or_equal_to: 0 }
|
16
|
+
validates :max_capacity, numericality: { greater_than_or_equal_to: 0 } # Originally inventory of each variant.
|
17
|
+
validates :inventory_date, presence: true, if: :permanent_stock?
|
18
|
+
validates :variant_id, uniqueness: { scope: :inventory_date, message: -> (object, _data) { "The variant is taken on #{object.inventory_date}" } }
|
19
|
+
|
20
|
+
# Scope
|
21
|
+
scope :active, -> { where(inventory_date: nil).or(where('inventory_date >= ?', Time.zone.today)) }
|
22
|
+
|
23
|
+
before_save -> { self.product_type = variant.product_type }, if: -> { product_type.nil? }
|
24
|
+
|
25
|
+
def public_quantity_available
|
26
|
+
[quantity_available, MAX_DISPLAY_STOCK].min
|
27
|
+
end
|
28
|
+
|
29
|
+
def price_in(currency)
|
30
|
+
prices.detect { |price| price.currency == currency } || prices.build(currency: currency)
|
31
|
+
end
|
32
|
+
|
33
|
+
# This method is only used when admin update stock
|
34
|
+
def adjust_quantity!(quantity)
|
35
|
+
with_lock do
|
36
|
+
self.max_capacity = [max_capacity + quantity, 0].max
|
37
|
+
self.quantity_available = [quantity_available + quantity, 0].max
|
38
|
+
save!
|
39
|
+
|
40
|
+
# When user has been searched or booked a product, it has cached the quantity in redis,
|
41
|
+
# So we need to update redis cache if inventory key has been created in redis
|
42
|
+
adjust_quantity_in_redis(quantity)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def redis_key
|
47
|
+
"inventory:#{id}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def adjust_quantity_in_redis(quantity)
|
51
|
+
SpreeCmCommissioner.redis_pool.with do |redis|
|
52
|
+
cached_quantity_available = redis.get(redis_key)
|
53
|
+
# ignore if redis doesn't exist
|
54
|
+
return if cached_quantity_available.nil? # rubocop:disable Lint/NonLocalExitFromIterator
|
55
|
+
|
56
|
+
script = <<~LUA
|
57
|
+
local key = KEYS[1]
|
58
|
+
local increment = tonumber(ARGV[1])
|
59
|
+
local current = tonumber(redis.call('GET', key) or 0)
|
60
|
+
local new_value = current + increment
|
61
|
+
if new_value < 0 then
|
62
|
+
new_value = 0
|
63
|
+
end
|
64
|
+
redis.call('SET', key, new_value)
|
65
|
+
return new_value
|
66
|
+
LUA
|
67
|
+
|
68
|
+
redis.eval(script, keys: [redis_key], argv: [quantity])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def active?
|
73
|
+
inventory_date.nil? || inventory_date >= Time.zone.today
|
74
|
+
end
|
75
|
+
|
76
|
+
def redis_expired_in
|
77
|
+
expired_in = 31_536_000 # 1 year for normal stock
|
78
|
+
expired_in = Time.parse(inventory_date.to_s).end_of_day.to_i - Time.zone.now.to_i if inventory_date.present?
|
79
|
+
[expired_in, 0].max
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SpreeCmCommissioner
|
2
2
|
module LineItemDecorator
|
3
|
-
def self.prepended(base) # rubocop:disable Metrics/MethodLength
|
3
|
+
def self.prepended(base) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
4
4
|
include_modules(base)
|
5
5
|
|
6
6
|
base.belongs_to :accepter, class_name: 'Spree::User', optional: true
|
@@ -10,31 +10,32 @@ module SpreeCmCommissioner
|
|
10
10
|
base.has_one :google_wallet, class_name: 'SpreeCmCommissioner::GoogleWallet', through: :product
|
11
11
|
|
12
12
|
base.has_many :option_types, through: :product
|
13
|
+
|
14
|
+
base.has_many :inventory_items, lambda { |line_item|
|
15
|
+
where(inventory_date: nil).or(where(inventory_date: line_item.date_range))
|
16
|
+
}, through: :variant
|
17
|
+
|
13
18
|
base.has_many :taxons, class_name: 'Spree::Taxon', through: :product
|
14
19
|
base.has_many :guests, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
|
20
|
+
base.has_many :guests_with_blocks, -> { where.not(block_id: nil) }, class_name: 'SpreeCmCommissioner::Guest'
|
21
|
+
base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
|
15
22
|
base.has_many :pending_guests, pending_guests_query, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
|
16
23
|
base.has_many :product_completion_steps, class_name: 'SpreeCmCommissioner::ProductCompletionStep', through: :product
|
17
|
-
base.has_many :line_item_seats, class_name: 'SpreeCmCommissioner::LineItemSeat', dependent: :destroy
|
18
24
|
|
19
25
|
base.before_save :update_vendor_id
|
20
|
-
base.before_save :update_quantity, if: :transit?
|
21
|
-
|
22
|
-
base.validate :validate_seats_reservation, if: :transit?
|
23
26
|
|
24
27
|
base.before_create :add_due_date, if: :subscription?
|
28
|
+
base.before_save -> { self.product_type = variant.product_type }, if: -> { product_type.nil? }
|
25
29
|
|
26
30
|
base.validate :ensure_not_exceed_max_quantity_per_order, if: -> { variant&.max_quantity_per_order.present? }
|
27
31
|
|
28
32
|
base.whitelisted_ransackable_associations |= %w[guests order]
|
29
33
|
base.whitelisted_ransackable_attributes |= %w[number to_date from_date vendor_id]
|
30
34
|
|
31
|
-
base.delegate :delivery_required?, :
|
35
|
+
base.delegate :delivery_required?, :high_demand,
|
32
36
|
to: :variant
|
33
|
-
base.delegate :discontinue_on, :product_type, :accommodation?, :service?, :ecommerce?, :need_confirmation,
|
34
|
-
to: :product
|
35
37
|
|
36
38
|
base.accepts_nested_attributes_for :guests, allow_destroy: true
|
37
|
-
base.accepts_nested_attributes_for :line_item_seats, allow_destroy: true
|
38
39
|
|
39
40
|
def base.json_api_columns
|
40
41
|
json_api_columns = column_names.reject { |c| c.match(/_id$|id|preferences|(.*)password|(.*)token|(.*)api_key/) }
|
@@ -42,6 +43,10 @@ module SpreeCmCommissioner
|
|
42
43
|
json_api_columns << :vendor_id
|
43
44
|
end
|
44
45
|
|
46
|
+
def discontinue_on
|
47
|
+
variant.discontinue_on || product.discontinue_on
|
48
|
+
end
|
49
|
+
|
45
50
|
def base.search_by_qr_data!(data)
|
46
51
|
matches = data.match(/(R\d+)-([A-Za-z0-9_\-]+)-(L\d+)/)&.captures
|
47
52
|
|
@@ -60,6 +65,8 @@ module SpreeCmCommissioner
|
|
60
65
|
base.include SpreeCmCommissioner::LineItemDurationable
|
61
66
|
base.include SpreeCmCommissioner::LineItemsFilterScope
|
62
67
|
base.include SpreeCmCommissioner::LineItemGuestsConcern
|
68
|
+
base.include SpreeCmCommissioner::LineItemTransitable
|
69
|
+
base.include SpreeCmCommissioner::ProductType
|
63
70
|
base.include SpreeCmCommissioner::ProductDelegation
|
64
71
|
base.include SpreeCmCommissioner::KycBitwise
|
65
72
|
end
|
@@ -75,24 +82,39 @@ module SpreeCmCommissioner
|
|
75
82
|
}
|
76
83
|
end
|
77
84
|
|
78
|
-
|
79
|
-
|
80
|
-
|
85
|
+
# override to calculate price per date for permanent stock
|
86
|
+
def update_price_from_modifier(currency, opts)
|
87
|
+
self.currency = currency
|
81
88
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
# override
|
88
|
-
def amount
|
89
|
-
base_price = price * quantity
|
89
|
+
# these fields can be null during this process below.
|
90
|
+
# it is needed for permanent_stock?, date_range to work.
|
91
|
+
self.product_type = variant.product_type
|
92
|
+
self.from_date = opts.delete(:from_date)&.to_datetime
|
93
|
+
self.to_date = opts.delete(:to_date)&.to_datetime
|
90
94
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
95
|
+
base_price = variant.price_in(currency)
|
96
|
+
|
97
|
+
self.price = if permanent_stock?
|
98
|
+
date_range.map do |date|
|
99
|
+
selected_price = variant.price_for_date(date: date, currency: currency) || base_price
|
100
|
+
(selected_price.amount || 0) + variant.price_modifier_amount_in(currency, opts.merge(date: date))
|
101
|
+
end.sum
|
102
|
+
else
|
103
|
+
(base_price.amount || 0) + variant.price_modifier_amount_in(currency, opts)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# override to calculate price per date for permanent stock
|
108
|
+
def update_price
|
109
|
+
base_price = variant.price_in(order.currency)
|
110
|
+
self.price = if permanent_stock?
|
111
|
+
date_range.map do |date|
|
112
|
+
selected_price = variant.price_for_date(date: date, currency: order.currency) || base_price
|
113
|
+
selected_price.amount || 0
|
114
|
+
end.sum
|
115
|
+
else
|
116
|
+
base_price.amount || 0
|
117
|
+
end
|
96
118
|
end
|
97
119
|
|
98
120
|
def allowed_self_check_in?
|
@@ -179,8 +201,6 @@ module SpreeCmCommissioner
|
|
179
201
|
|
180
202
|
# override
|
181
203
|
def sufficient_stock?
|
182
|
-
return transit_sufficient_stock? if variant.product.product_type == 'transit'
|
183
|
-
|
184
204
|
SpreeCmCommissioner::Stock::LineItemAvailabilityChecker.new(self).can_supply?(quantity)
|
185
205
|
end
|
186
206
|
|
@@ -199,18 +219,6 @@ module SpreeCmCommissioner
|
|
199
219
|
errors.add(:quantity, 'exceeded_max_quantity_per_order') if quantity > variant.max_quantity_per_order
|
200
220
|
end
|
201
221
|
|
202
|
-
def transit_sufficient_stock?
|
203
|
-
return selected_seats_available? if reservation_trip.allow_seat_selection
|
204
|
-
|
205
|
-
seat_quantity_available?(reservation_trip)
|
206
|
-
end
|
207
|
-
|
208
|
-
def update_quantity
|
209
|
-
return if line_item_seats.blank?
|
210
|
-
|
211
|
-
self.quantity = line_item_seats.size
|
212
|
-
end
|
213
|
-
|
214
222
|
def update_vendor_id
|
215
223
|
self.vendor_id = variant.vendor_id
|
216
224
|
end
|
@@ -233,45 +241,6 @@ module SpreeCmCommissioner
|
|
233
241
|
|
234
242
|
from_date + variant.month.month + day.days
|
235
243
|
end
|
236
|
-
|
237
|
-
def validate_seats_reservation
|
238
|
-
if reservation_trip.allow_seat_selection && !selected_seats_available?
|
239
|
-
errors.add(:base, :some_seats_are_booked, message: 'Some seats are already booked')
|
240
|
-
elsif !reservation_trip.allow_seat_selection && !seat_quantity_available?(reservation_trip)
|
241
|
-
errors.add(:quantity, :exceeded_available_quantity, message: 'exceeded available quantity')
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
def selected_seats_available?
|
246
|
-
selected_seat_ids = line_item_seats.map(&:seat_id)
|
247
|
-
!selected_seat_ids_occupied?(selected_seat_ids)
|
248
|
-
end
|
249
|
-
|
250
|
-
def seat_quantity_available?(trip)
|
251
|
-
booked_quantity = Spree::LineItem.joins(:order)
|
252
|
-
.where(variant_id: variant_id, date: date, spree_orders: { state: 'complete' })
|
253
|
-
.where.not(spree_line_items: { id: id })
|
254
|
-
.sum(:quantity)
|
255
|
-
remaining_quantity = trip.vehicle.number_of_seats - booked_quantity
|
256
|
-
remaining_quantity >= quantity
|
257
|
-
end
|
258
|
-
|
259
|
-
def reservation_trip
|
260
|
-
return @trip if defined? @trip
|
261
|
-
|
262
|
-
route = Spree::Variant.find_by(id: variant_id).product
|
263
|
-
@trip = route.trip
|
264
|
-
end
|
265
|
-
|
266
|
-
def selected_seat_ids_occupied?(selected_seat_ids)
|
267
|
-
# check to see if there are any selected_ids exist in the line_item_seats and belongs to completed order
|
268
|
-
SpreeCmCommissioner::LineItemSeat.joins(line_item: :order)
|
269
|
-
.where(seat_id: selected_seat_ids, date: date, variant_id: variant_id, spree_orders: { state: 'complete',
|
270
|
-
canceled_at: nil
|
271
|
-
}
|
272
|
-
)
|
273
|
-
.present?
|
274
|
-
end
|
275
244
|
end
|
276
245
|
end
|
277
246
|
|