spree_cm_commissioner 2.0.0 → 2.0.1.pre.pre
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 +32 -1
- 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/stock_managements_controller.rb +63 -1
- data/app/controllers/spree/api/v2/organizer/invite_guests_controller.rb +1 -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/guests_controller.rb +13 -13
- data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +2 -2
- data/app/factory/spree_cm_commissioner/invite_guest_claimed_telegram_message_factory.rb +81 -23
- 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/create_ticket.rb +5 -6
- data/app/interactors/spree_cm_commissioner/ensure_correct_product_type.rb +40 -0
- data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +25 -0
- data/app/interactors/spree_cm_commissioner/pin_code_sender.rb +1 -0
- data/app/interactors/spree_cm_commissioner/sms.rb +1 -1
- 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/user_id_token_authenticator.rb +3 -7
- data/app/interactors/spree_cm_commissioner/user_id_token_checker.rb +3 -11
- data/app/interactors/spree_cm_commissioner/user_identity_checker.rb +6 -12
- data/app/interactors/spree_cm_commissioner/user_registration_with_id_token.rb +1 -7
- 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/sms_pin_code_job.rb +1 -1
- 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/mailers/spree/order_mailer_decorator.rb +3 -18
- data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +9 -15
- data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +1 -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/taxon_kind.rb +1 -1
- data/app/models/concerns/spree_cm_commissioner/tenant_preference.rb +0 -1
- data/app/models/spree_cm_commissioner/block.rb +23 -0
- data/app/models/spree_cm_commissioner/dynamic_field.rb +0 -20
- data/app/models/spree_cm_commissioner/guest.rb +18 -56
- data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +1 -41
- data/app/models/spree_cm_commissioner/inventory.rb +11 -0
- data/app/models/spree_cm_commissioner/inventory_item.rb +69 -0
- data/app/models/spree_cm_commissioner/line_item_decorator.rb +46 -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_decorator.rb +30 -1
- data/app/models/spree_cm_commissioner/place.rb +1 -4
- data/app/models/spree_cm_commissioner/price_decorator.rb +9 -0
- data/app/models/spree_cm_commissioner/product_decorator.rb +10 -28
- 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 +30 -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 +0 -1
- data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +0 -6
- data/app/models/spree_cm_commissioner/trip.rb +8 -10
- data/app/models/spree_cm_commissioner/trip_connection.rb +5 -5
- data/app/models/spree_cm_commissioner/trip_stop.rb +6 -25
- data/app/models/spree_cm_commissioner/user_identity_provider.rb +4 -26
- data/app/models/spree_cm_commissioner/variant_block.rb +9 -0
- data/app/models/spree_cm_commissioner/variant_decorator.rb +37 -47
- data/app/models/spree_cm_commissioner/variant_options.rb +0 -23
- data/app/models/spree_cm_commissioner/vehicle.rb +9 -14
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +11 -17
- data/app/models/spree_cm_commissioner/vendor_place.rb +9 -3
- data/app/queries/spree_cm_commissioner/trip_query.rb +70 -44
- 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/variant_request_schema.rb +19 -0
- data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +2 -0
- data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +1 -0
- data/app/serializers/spree/v2/tenant/user_serializer.rb +0 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_serializer.rb +1 -1
- data/app/services/spree_cm_commissioner/user_authenticator.rb +1 -1
- data/app/views/spree/admin/inventory_items/show.html.erb +72 -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/app/views/spree/admin/tenant_vendors/index.html.erb +2 -9
- data/app/views/spree/admin/tenants/_form.html.erb +0 -9
- data/app/views/spree/admin/tenants/edit.html.erb +1 -2
- data/app/views/spree/admin/tenants/index.html.erb +1 -7
- data/app/views/spree/admin/vendors/_form.html.erb +0 -14
- data/app/views/spree/order_mailer/confirm_email.html.erb +16 -27
- data/app/views/spree_cm_commissioner/layouts/order_mailer.html.erb +1 -5
- data/app/views/spree_cm_commissioner/order_mailer/_mailer_stylesheets.html.erb +4 -41
- data/config/initializers/paper_trail.rb +1 -0
- data/config/initializers/spree_permitted_attributes.rb +5 -0
- data/config/locales/en.yml +1 -5
- data/config/routes.rb +21 -2
- data/db/migrate/20240202080634_update_counter_cache_of_vehicle_type.rb +3 -1
- data/db/migrate/20250304293518_create_cm_inventory_items.rb +21 -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/docker-compose.yml +1 -1
- data/lib/cm_app_logger.rb +11 -4
- 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 +15 -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 +9 -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/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 +10 -0
- data/lib/spree_cm_commissioner/test_helper/factories/user_identity_provider_factory.rb +1 -1
- 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/trip_query_result.rb +8 -0
- data/lib/spree_cm_commissioner/trip_result.rb +5 -3
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +35 -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 +141 -38
- data/app/assets/images/mailer/mail.png +0 -0
- data/app/assets/images/mailer/tenant_phone.png +0 -0
- data/app/assets/images/mailer/tenant_user.png +0 -0
- 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/app/views/spree_cm_commissioner/order_mailer/tenant/_customer_info.html.erb +0 -42
- data/app/views/spree_cm_commissioner/order_mailer/tenant/_footer.html.erb +0 -25
- data/app/views/spree_cm_commissioner/order_mailer/tenant/_greeting.html.erb +0 -19
- data/app/views/spree_cm_commissioner/order_mailer/tenant/_support_contact.html.erb +0 -33
- data/db/migrate/20250709073455_add_email_fields_to_spree_vendors.rb +0 -6
- data/db/migrate/20250715103333_remove_indexes_from_cm_user_identity_providers.rb +0 -13
- data/db/migrate/20250718071620_add_data_fill_stage_to_dynamic_fields.rb +0 -5
- 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
@@ -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,7 @@ module SpreeCmCommissioner
|
|
60
65
|
base.include SpreeCmCommissioner::LineItemDurationable
|
61
66
|
base.include SpreeCmCommissioner::LineItemsFilterScope
|
62
67
|
base.include SpreeCmCommissioner::LineItemGuestsConcern
|
68
|
+
base.include SpreeCmCommissioner::ProductType
|
63
69
|
base.include SpreeCmCommissioner::ProductDelegation
|
64
70
|
base.include SpreeCmCommissioner::KycBitwise
|
65
71
|
end
|
@@ -75,24 +81,39 @@ module SpreeCmCommissioner
|
|
75
81
|
}
|
76
82
|
end
|
77
83
|
|
78
|
-
|
79
|
-
|
80
|
-
|
84
|
+
# override to calculate price per date for permanent stock
|
85
|
+
def update_price_from_modifier(currency, opts)
|
86
|
+
self.currency = currency
|
81
87
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
# override
|
88
|
-
def amount
|
89
|
-
base_price = price * quantity
|
88
|
+
# these fields can be null during this process below.
|
89
|
+
# it is needed for permanent_stock?, date_range to work.
|
90
|
+
self.product_type = variant.product_type
|
91
|
+
self.from_date = opts.delete(:from_date)&.to_date
|
92
|
+
self.to_date = opts.delete(:to_date)&.to_date
|
90
93
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
base_price = variant.price_in(currency)
|
95
|
+
|
96
|
+
self.price = if permanent_stock?
|
97
|
+
date_range.map do |date|
|
98
|
+
selected_price = variant.price_for_date(date: date, currency: currency) || base_price
|
99
|
+
(selected_price.amount || 0) + variant.price_modifier_amount_in(currency, opts.merge(date: date))
|
100
|
+
end.sum
|
101
|
+
else
|
102
|
+
(base_price.amount || 0) + variant.price_modifier_amount_in(currency, opts)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# override to calculate price per date for permanent stock
|
107
|
+
def update_price
|
108
|
+
base_price = variant.price_in(order.currency)
|
109
|
+
self.price = if permanent_stock?
|
110
|
+
date_range.map do |date|
|
111
|
+
selected_price = variant.price_for_date(date: date, currency: order.currency) || base_price
|
112
|
+
selected_price.amount || 0
|
113
|
+
end.sum
|
114
|
+
else
|
115
|
+
base_price.amount || 0
|
116
|
+
end
|
96
117
|
end
|
97
118
|
|
98
119
|
def allowed_self_check_in?
|
@@ -179,8 +200,6 @@ module SpreeCmCommissioner
|
|
179
200
|
|
180
201
|
# override
|
181
202
|
def sufficient_stock?
|
182
|
-
return transit_sufficient_stock? if variant.product.product_type == 'transit'
|
183
|
-
|
184
203
|
SpreeCmCommissioner::Stock::LineItemAvailabilityChecker.new(self).can_supply?(quantity)
|
185
204
|
end
|
186
205
|
|
@@ -199,18 +218,6 @@ module SpreeCmCommissioner
|
|
199
218
|
errors.add(:quantity, 'exceeded_max_quantity_per_order') if quantity > variant.max_quantity_per_order
|
200
219
|
end
|
201
220
|
|
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
221
|
def update_vendor_id
|
215
222
|
self.vendor_id = variant.vendor_id
|
216
223
|
end
|
@@ -233,45 +240,6 @@ module SpreeCmCommissioner
|
|
233
240
|
|
234
241
|
from_date + variant.month.month + day.days
|
235
242
|
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
243
|
end
|
276
244
|
end
|
277
245
|
|
@@ -6,7 +6,7 @@ module SpreeCmCommissioner
|
|
6
6
|
base.include SpreeCmCommissioner::ParameterizeName
|
7
7
|
base.include SpreeCmCommissioner::OptionTypeAttrType
|
8
8
|
|
9
|
-
base.enum kind: %i[variant product vendor
|
9
|
+
base.enum kind: %i[variant product vendor vehicle]
|
10
10
|
|
11
11
|
base.validates :name, presence: true
|
12
12
|
|
@@ -19,16 +19,6 @@ module SpreeCmCommissioner
|
|
19
19
|
base.scope :promoted, -> { where(promoted: true) }
|
20
20
|
base.whitelisted_ransackable_attributes = %w[kind]
|
21
21
|
|
22
|
-
def base.amenities
|
23
|
-
Spree::OptionType.where(kind: 'vehicle_type', name: 'amenities', presentation: 'Amenities', attr_type: 'amenity').first_or_create
|
24
|
-
end
|
25
|
-
|
26
|
-
def base.vehicle
|
27
|
-
Spree::OptionType.where(presentation: 'vehicle', attr_type: 'vehicle_id', kind: 'variant',
|
28
|
-
name: 'vehicle'
|
29
|
-
).first_or_create
|
30
|
-
end
|
31
|
-
|
32
22
|
def base.rules_option_type
|
33
23
|
Spree::OptionType.find_by(name: RULES_OPTION_TYPE_NAME)
|
34
24
|
end
|
@@ -2,6 +2,7 @@ module SpreeCmCommissioner
|
|
2
2
|
module OrderDecorator
|
3
3
|
def self.prepended(base) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
4
4
|
base.include SpreeCmCommissioner::PhoneNumberSanitizer
|
5
|
+
base.include SpreeCmCommissioner::OrderSeatable
|
5
6
|
base.include SpreeCmCommissioner::OrderStateMachine
|
6
7
|
|
7
8
|
base.scope :subscription, -> { where.not(subscription_id: nil) }
|
@@ -42,6 +43,8 @@ module SpreeCmCommissioner
|
|
42
43
|
base.has_many :vendors, through: :products, class_name: 'Spree::Vendor'
|
43
44
|
base.has_many :taxons, through: :products, class_name: 'Spree::Taxon'
|
44
45
|
base.has_many :guests, through: :line_items, class_name: 'SpreeCmCommissioner::Guest'
|
46
|
+
base.has_many :blocks, through: :guests, class_name: 'SpreeCmCommissioner::Block', source: :block
|
47
|
+
base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
|
45
48
|
base.has_many :guest_card_classes, class_name: 'SpreeCmCommissioner::GuestCardClass', through: :variants
|
46
49
|
|
47
50
|
base.delegate :customer, to: :user, allow_nil: true
|
@@ -58,6 +61,13 @@ module SpreeCmCommissioner
|
|
58
61
|
end
|
59
62
|
end
|
60
63
|
|
64
|
+
# override
|
65
|
+
# spree use this method to check stock availability & consider whether :order can continue to next state.
|
66
|
+
def insufficient_stock_lines
|
67
|
+
checker = SpreeCmCommissioner::Stock::OrderAvailabilityChecker.new(self)
|
68
|
+
checker.insufficient_stock_lines
|
69
|
+
end
|
70
|
+
|
61
71
|
def ticket_seller_user?
|
62
72
|
return false if user.nil?
|
63
73
|
|
@@ -106,7 +116,14 @@ module SpreeCmCommissioner
|
|
106
116
|
end
|
107
117
|
|
108
118
|
def mark_as_archive
|
109
|
-
|
119
|
+
blocks_canceled = begin
|
120
|
+
cancel_blocks!
|
121
|
+
true
|
122
|
+
rescue StandardError
|
123
|
+
false
|
124
|
+
end
|
125
|
+
|
126
|
+
update(archived_at: Time.current) if blocks_canceled
|
110
127
|
end
|
111
128
|
|
112
129
|
# overrided
|
@@ -199,6 +216,18 @@ module SpreeCmCommissioner
|
|
199
216
|
|
200
217
|
private
|
201
218
|
|
219
|
+
def unstock_inventory_in_redis!
|
220
|
+
CmAppLogger.log(label: "#{self.class.name}#unstock_inventory_in_redis!", data: { order_id: id }) do
|
221
|
+
SpreeCmCommissioner::RedisStock::InventoryUpdater.new(line_item_ids).unstock!
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def restock_inventory_in_redis!
|
226
|
+
CmAppLogger.log(label: "#{self.class.name}#restock_inventory_in_redis!", data: { order_id: id }) do
|
227
|
+
SpreeCmCommissioner::RedisStock::InventoryUpdater.new(line_item_ids).restock!
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
202
231
|
# override :spree_api
|
203
232
|
def webhook_payload_body
|
204
233
|
resource_serializer.new(
|
@@ -1,7 +1,5 @@
|
|
1
|
-
require_dependency 'spree_cm_commissioner'
|
2
|
-
|
3
1
|
module SpreeCmCommissioner
|
4
|
-
class Place <
|
2
|
+
class Place < Base
|
5
3
|
acts_as_nested_set
|
6
4
|
|
7
5
|
validates :reference, presence: true, if: :validate_reference?
|
@@ -17,7 +15,6 @@ module SpreeCmCommissioner
|
|
17
15
|
has_many :products, through: :product_places
|
18
16
|
|
19
17
|
has_many :children, -> { order(:lft) }, class_name: 'SpreeCmCommissioner::Place', foreign_key: :parent_id, dependent: :destroy
|
20
|
-
has_many :vendor_stops, class_name: 'SpreeCmCommissioner::VendorStop', dependent: :destroy, foreign_key: :stop_id
|
21
18
|
|
22
19
|
has_many :taxon_places, class_name: 'SpreeCmCommissioner::TaxonPlace', dependent: :destroy
|
23
20
|
has_many :taxons, through: :taxon_places
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
module PriceDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.belongs_to :inventory_item, class_name: 'SpreeCmCommissioner::InventoryItem', inverse_of: :prices, optional: true
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Spree::Price.prepend(SpreeCmCommissioner::PriceDecorator) unless Spree::Price.included_modules.include?(SpreeCmCommissioner::PriceDecorator)
|
@@ -6,7 +6,6 @@ module SpreeCmCommissioner
|
|
6
6
|
base.include SpreeCmCommissioner::KycBitwise
|
7
7
|
base.include SpreeCmCommissioner::Metafield
|
8
8
|
base.include SpreeCmCommissioner::TenantUpdatable
|
9
|
-
base.include SpreeCmCommissioner::RouteType
|
10
9
|
|
11
10
|
base.has_many :variant_kind_option_types, -> { where(kind: :variant).order(:position) },
|
12
11
|
through: :product_option_types, source: :option_type
|
@@ -33,6 +32,7 @@ module SpreeCmCommissioner
|
|
33
32
|
base.has_one :google_wallet, class_name: 'SpreeCmCommissioner::GoogleWallet', dependent: :destroy
|
34
33
|
|
35
34
|
base.has_many :complete_line_items, through: :classifications, source: :line_items
|
35
|
+
base.has_many :inventory_items, through: :variants
|
36
36
|
base.has_many :guests, through: :line_items
|
37
37
|
|
38
38
|
base.has_many :product_places, class_name: 'SpreeCmCommissioner::ProductPlace', dependent: :destroy
|
@@ -64,20 +64,17 @@ module SpreeCmCommissioner
|
|
64
64
|
base.before_validation :set_event_id
|
65
65
|
|
66
66
|
base.validate :validate_event_taxons, if: -> { taxons.event.present? }
|
67
|
-
|
68
67
|
base.validate :validate_product_date, if: -> { available_on.present? && discontinue_on.present? }
|
69
|
-
|
68
|
+
base.validate :product_type_unchanged, on: :update
|
70
69
|
base.validates :commission_rate, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }, allow_nil: true
|
71
70
|
|
72
|
-
base.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status vendor_id short_name
|
71
|
+
base.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status vendor_id short_name]
|
73
72
|
|
74
73
|
base.after_update :update_variants_vendor_id, if: :saved_change_to_vendor_id?
|
75
74
|
base.after_update :sync_event_id_to_children, if: :saved_change_to_event_id?
|
76
75
|
|
77
76
|
base.enum purchasable_on: { both: 0, web: 1, app: 2 }
|
78
77
|
|
79
|
-
base.accepts_nested_attributes_for :trip, allow_destroy: true
|
80
|
-
|
81
78
|
base.multi_tenant :tenant, class_name: 'SpreeCmCommissioner::Tenant'
|
82
79
|
base.before_save :set_tenant
|
83
80
|
end
|
@@ -86,28 +83,6 @@ module SpreeCmCommissioner
|
|
86
83
|
"#{Spree::Store.default.formatted_url}/tickets/#{slug}"
|
87
84
|
end
|
88
85
|
|
89
|
-
def dynamic_fields_by_collection_phase
|
90
|
-
{
|
91
|
-
pre_registration: dynamic_fields.pre_registration.order(:position),
|
92
|
-
post_registration: dynamic_fields.post_registration.order(:position),
|
93
|
-
during_check_in: dynamic_fields.during_check_in.order(:position)
|
94
|
-
}
|
95
|
-
end
|
96
|
-
|
97
|
-
def required_dynamic_fields_completed?(guest, phase)
|
98
|
-
required_fields = dynamic_fields.where(data_fill_stage: phase)
|
99
|
-
return true if required_fields.empty?
|
100
|
-
|
101
|
-
filled_ids = guest.guest_dynamic_fields.where(dynamic_field_id: required_fields.select(:id)).pluck(:dynamic_field_id)
|
102
|
-
(required_fields.pluck(:id) - filled_ids).empty?
|
103
|
-
end
|
104
|
-
|
105
|
-
def required_fields_for_guest(guest)
|
106
|
-
dynamic_fields_by_collection_phase.transform_values do |fields|
|
107
|
-
fields.select { |field| guest.guest_dynamic_fields.where(dynamic_field: field).empty? }
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
86
|
private
|
112
87
|
|
113
88
|
def set_tenant
|
@@ -136,6 +111,13 @@ module SpreeCmCommissioner
|
|
136
111
|
|
137
112
|
errors.add(:discontinue_on, 'must be after the available on date')
|
138
113
|
end
|
114
|
+
|
115
|
+
def product_type_unchanged
|
116
|
+
return if product_type_was.nil?
|
117
|
+
return unless product_type_changed?
|
118
|
+
|
119
|
+
errors.add(:product_type, 'cannot be changed once set')
|
120
|
+
end
|
139
121
|
end
|
140
122
|
end
|
141
123
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
module RedisStock
|
3
|
+
class CachedInventoryItemsBuilder
|
4
|
+
attr_reader :inventory_items
|
5
|
+
|
6
|
+
def initialize(inventory_items)
|
7
|
+
@inventory_items = inventory_items
|
8
|
+
end
|
9
|
+
|
10
|
+
# output: [ CachedInventoryItem(...), CachedInventoryItem(...) ]
|
11
|
+
def call
|
12
|
+
keys = inventory_items.map { |item| "inventory:#{item.id}" }
|
13
|
+
return [] unless keys.any?
|
14
|
+
|
15
|
+
counts = SpreeCmCommissioner.redis_pool.with { |redis| redis.mget(*keys) }
|
16
|
+
inventory_items.map.with_index do |inventory_item, i|
|
17
|
+
::SpreeCmCommissioner::CachedInventoryItem.new(
|
18
|
+
inventory_key: keys[i],
|
19
|
+
active: inventory_item.active?,
|
20
|
+
quantity_available: cache_inventory(keys[i], inventory_item, counts[i]),
|
21
|
+
inventory_item_id: inventory_item.id,
|
22
|
+
variant_id: inventory_item.variant_id
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def cache_inventory(key, inventory_item, count_in_redis)
|
30
|
+
return count_in_redis.to_i if count_in_redis.present?
|
31
|
+
return inventory_item.quantity_available unless inventory_item.active?
|
32
|
+
|
33
|
+
SpreeCmCommissioner.redis_pool.with do |redis|
|
34
|
+
redis.set(key, inventory_item.quantity_available, ex: inventory_item.redis_expired_in)
|
35
|
+
end
|
36
|
+
|
37
|
+
inventory_item.quantity_available
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
module RedisStock
|
3
|
+
class InventoryUpdater
|
4
|
+
class UnableToRestock < StandardError; end
|
5
|
+
class UnableToUnstock < StandardError; end
|
6
|
+
|
7
|
+
def initialize(line_item_ids)
|
8
|
+
@line_item_ids = line_item_ids
|
9
|
+
end
|
10
|
+
|
11
|
+
def unstock!
|
12
|
+
keys, quantities, inventory_ids = extract_inventory_data
|
13
|
+
|
14
|
+
raise UnableToUnstock, Spree.t(:insufficient_stock_lines_present) unless unstock(keys, quantities)
|
15
|
+
|
16
|
+
inventory_id_and_quantities = inventory_ids.map.with_index do |inventory_id, i|
|
17
|
+
{ inventory_id: inventory_id, quantity: -quantities[i] }
|
18
|
+
end
|
19
|
+
|
20
|
+
schedule_sync_inventory(inventory_id_and_quantities)
|
21
|
+
end
|
22
|
+
|
23
|
+
def restock!
|
24
|
+
keys, quantities, inventory_ids = extract_inventory_data
|
25
|
+
|
26
|
+
raise UnableToRestock unless restock(keys, quantities)
|
27
|
+
|
28
|
+
inventory_id_and_quantities = inventory_ids.map.with_index do |inventory_id, i|
|
29
|
+
{ inventory_id: inventory_id, quantity: quantities[i] }
|
30
|
+
end
|
31
|
+
|
32
|
+
schedule_sync_inventory(inventory_id_and_quantities)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# only unstock or restock when variants is available, track inventory, not backorderable & not need_confirmation.
|
38
|
+
# otherwise, we can ignore them.
|
39
|
+
def line_items
|
40
|
+
return @line_items if defined?(@line_items)
|
41
|
+
|
42
|
+
@line_items = Spree::LineItem.where(id: @line_item_ids).includes(variant: :stock_items)
|
43
|
+
@line_items = @line_items.map do |line_item|
|
44
|
+
next unless line_item.variant.available?
|
45
|
+
next unless line_item.variant.should_track_inventory?
|
46
|
+
next if line_item.variant.backorderable?
|
47
|
+
next if line_item.variant.need_confirmation?
|
48
|
+
|
49
|
+
line_item
|
50
|
+
end.compact
|
51
|
+
end
|
52
|
+
|
53
|
+
def unstock(keys, quantities)
|
54
|
+
SpreeCmCommissioner.redis_pool.with do |redis|
|
55
|
+
redis.eval(unstock_redis_script, keys: keys, argv: quantities)
|
56
|
+
end.positive?
|
57
|
+
end
|
58
|
+
|
59
|
+
def restock(keys, quantities)
|
60
|
+
SpreeCmCommissioner.redis_pool.with do |redis|
|
61
|
+
redis.eval(restock_redis_script, keys: keys, argv: quantities)
|
62
|
+
end.positive?
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return: [CachedInventoryItem(...), CachedInventoryItem(...)]
|
66
|
+
def cached_inventory_items
|
67
|
+
@cached_inventory_items ||= SpreeCmCommissioner::RedisStock::LineItemsCachedInventoryItemsBuilder.new(line_item_ids: line_items.pluck(:id))
|
68
|
+
.call.values.flatten
|
69
|
+
end
|
70
|
+
|
71
|
+
def extract_inventory_data
|
72
|
+
keys = []
|
73
|
+
quantities = []
|
74
|
+
inventory_ids = []
|
75
|
+
|
76
|
+
cached_inventory_items.each do |cached_inventory_item|
|
77
|
+
keys << cached_inventory_item.inventory_key
|
78
|
+
quantities << line_items.find { |item| item.variant_id == cached_inventory_item.variant_id }.quantity
|
79
|
+
inventory_ids << cached_inventory_item.inventory_item_id
|
80
|
+
end
|
81
|
+
|
82
|
+
[keys, quantities, inventory_ids]
|
83
|
+
end
|
84
|
+
|
85
|
+
def unstock_redis_script
|
86
|
+
<<~LUA
|
87
|
+
local keys = KEYS
|
88
|
+
local quantities = ARGV
|
89
|
+
|
90
|
+
-- Check availability first
|
91
|
+
for i, key in ipairs(keys) do
|
92
|
+
local current = tonumber(redis.call('GET', key) or 0)
|
93
|
+
if current - tonumber(quantities[i]) < 0 then
|
94
|
+
return 0
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
-- Apply updates
|
99
|
+
for i, key in ipairs(keys) do
|
100
|
+
redis.call('DECRBY', key, tonumber(quantities[i]))
|
101
|
+
end
|
102
|
+
|
103
|
+
return 1
|
104
|
+
LUA
|
105
|
+
end
|
106
|
+
|
107
|
+
def restock_redis_script
|
108
|
+
<<~LUA
|
109
|
+
local keys = KEYS
|
110
|
+
local quantities = ARGV
|
111
|
+
|
112
|
+
-- Apply restock updates
|
113
|
+
for i, key in ipairs(keys) do
|
114
|
+
redis.call('INCRBY', key, tonumber(quantities[i]))
|
115
|
+
end
|
116
|
+
|
117
|
+
return 1
|
118
|
+
LUA
|
119
|
+
end
|
120
|
+
|
121
|
+
def schedule_sync_inventory(inventory_id_and_quantities)
|
122
|
+
SpreeCmCommissioner::InventoryItemSyncerJob.perform_later(inventory_id_and_quantities:)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
module RedisStock
|
3
|
+
class LineItemsCachedInventoryItemsBuilder
|
4
|
+
attr_reader :line_item_ids
|
5
|
+
|
6
|
+
def initialize(line_item_ids:)
|
7
|
+
@line_item_ids = line_item_ids
|
8
|
+
end
|
9
|
+
|
10
|
+
# return list of inventory items group by :line_item_id:
|
11
|
+
# {
|
12
|
+
# 1: [ CachedInventoryItem(...), CachedInventoryItem(...) ],
|
13
|
+
# 2: [ CachedInventoryItem(...), CachedInventoryItem(...) ],
|
14
|
+
# }
|
15
|
+
def call
|
16
|
+
cached_inventory_items.group_by do |cached_inventory_item|
|
17
|
+
line_item = line_items.find { |item| item.variant_id == cached_inventory_item.variant_id }
|
18
|
+
line_item.id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def cached_inventory_items
|
23
|
+
@cached_inventory_items ||= SpreeCmCommissioner::RedisStock::CachedInventoryItemsBuilder.new(inventory_items)
|
24
|
+
.call
|
25
|
+
end
|
26
|
+
|
27
|
+
def inventory_items
|
28
|
+
@inventory_items ||= line_items.flat_map(&:inventory_items)
|
29
|
+
end
|
30
|
+
|
31
|
+
def line_items
|
32
|
+
@line_items ||= Spree::LineItem.where(id: line_item_ids).includes(:inventory_items)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
module RedisStock
|
3
|
+
class VariantCachedInventoryItemsBuilder
|
4
|
+
attr_reader :variant_id, :dates
|
5
|
+
|
6
|
+
def initialize(variant_id:, dates: [])
|
7
|
+
@variant_id = variant_id
|
8
|
+
@dates = dates
|
9
|
+
end
|
10
|
+
|
11
|
+
# output: [ CachedInventoryItem(...), CachedInventoryItem(...) ]
|
12
|
+
def call
|
13
|
+
::SpreeCmCommissioner::RedisStock::CachedInventoryItemsBuilder.new(inventory_items).call
|
14
|
+
end
|
15
|
+
|
16
|
+
def inventory_items
|
17
|
+
variant = Spree::Variant.find(variant_id)
|
18
|
+
|
19
|
+
inventory_items = variant.inventory_items
|
20
|
+
inventory_items = inventory_items.where(inventory_date: dates) if variant.permanent_stock?
|
21
|
+
inventory_items
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class ReservedBlock < Base
|
3
|
+
has_paper_trail
|
4
|
+
|
5
|
+
belongs_to :updated_by, optional: true, class_name: 'Spree::User'
|
6
|
+
belongs_to :guest, optional: true, class_name: 'SpreeCmCommissioner::Guest'
|
7
|
+
belongs_to :inventory_item, class_name: 'SpreeCmCommissioner::InventoryItem'
|
8
|
+
belongs_to :block, class_name: 'SpreeCmCommissioner::Block'
|
9
|
+
|
10
|
+
enum status: {
|
11
|
+
reserved: 0, # confirmed reservation
|
12
|
+
on_hold: 1, # temporary hold
|
13
|
+
canceled: 2
|
14
|
+
}
|
15
|
+
|
16
|
+
validates :status, presence: true
|
17
|
+
validates :expired_at, presence: true, if: -> { on_hold? }
|
18
|
+
|
19
|
+
scope :active_on_hold, -> { on_hold.where('expired_at IS NULL OR expired_at > ?', Time.current) }
|
20
|
+
scope :active, -> { where('expired_at IS NULL OR expired_at > ?', Time.current) }
|
21
|
+
|
22
|
+
def expired?
|
23
|
+
expired_at.present? && expired_at <= Time.current
|
24
|
+
end
|
25
|
+
|
26
|
+
def active_on_hold?
|
27
|
+
on_hold? && !expired?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|