spree_cm_commissioner 2.5.0.pre.pre8 → 2.5.0.pre.pre10
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/.bundle/config +3 -2
- data/.github/workflows/test_and_build_gem.yml +123 -57
- data/.tool-versions +1 -1
- data/Gemfile.lock +1 -1
- data/Rakefile +55 -29
- data/app/controllers/spree/admin/base_controller_decorator.rb +3 -3
- data/app/controllers/spree/admin/base_import_orders_controller.rb +6 -1
- data/app/controllers/spree/admin/classifications_controller.rb +1 -1
- data/app/controllers/spree/admin/integration_mappings_controller.rb +21 -0
- data/app/controllers/spree/admin/integration_sessions_controller.rb +21 -0
- data/app/controllers/spree/admin/integrations_controller.rb +83 -0
- data/app/controllers/spree/admin/notification_sender_controller.rb +1 -1
- data/app/controllers/spree/api/v2/storefront/event_matches_controller.rb +15 -0
- data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +6 -6
- data/app/controllers/spree/api/v2/storefront/trips_controller.rb +11 -0
- data/app/errors/spree_cm_commissioner/integrations/external_client_error.rb +10 -0
- data/app/errors/spree_cm_commissioner/integrations/sync_error.rb +4 -0
- data/app/finders/spree_cm_commissioner/events/find_matches.rb +15 -0
- data/app/helpers/spree_cm_commissioner/external_integrations_helper.rb +58 -0
- data/app/interactors/spree_cm_commissioner/create_event.rb +1 -1
- data/app/interactors/spree_cm_commissioner/customer_notification_cron_executor.rb +1 -1
- data/app/interactors/spree_cm_commissioner/stock/inventory_item_resetter.rb +1 -1
- data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +3 -2
- data/app/jobs/spree_cm_commissioner/conversion_pre_calculator_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/customer_notification_sender_job.rb +3 -3
- data/app/jobs/spree_cm_commissioner/enqueue_cart/add_item_job.rb +7 -7
- data/app/jobs/spree_cm_commissioner/ensure_event_for_product_line_item_guests_job.rb +1 -1
- data/app/jobs/spree_cm_commissioner/event_line_items_date_syncer_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/export_csv_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/import_order_job.rb +5 -5
- data/app/jobs/spree_cm_commissioner/integrations/base_job.rb +39 -0
- data/app/jobs/spree_cm_commissioner/integrations/polling_job.rb +53 -0
- data/app/jobs/spree_cm_commissioner/integrations/polling_scheduler_job.rb +30 -0
- data/app/jobs/spree_cm_commissioner/invalidate_cache_request_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +8 -2
- data/app/jobs/spree_cm_commissioner/option_type_variants_public_metadata_updater_job.rb +7 -3
- data/app/jobs/spree_cm_commissioner/option_value_variants_public_metadata_updater_job.rb +6 -2
- data/app/jobs/spree_cm_commissioner/order_complete_telegram_sender_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/product_event_id_to_children_syncer_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/reports_assigner_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/sms_pin_code_job.rb +1 -1
- data/app/jobs/spree_cm_commissioner/state_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +6 -3
- data/app/jobs/spree_cm_commissioner/stock/inventory_items_generator_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/telegram_alerts/integration_sync_failure_job.rb +17 -0
- data/app/jobs/spree_cm_commissioner/transit/route_fulfilled_order_count_incrementer_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/transit/route_order_count_incrementer_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/transit/route_previous_trip_count_decrementer_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/transit/route_trip_count_decrementer_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/transit/route_trip_count_incrementer_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/vendor_creation_telegram_alert_sender_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/vendor_job.rb +2 -2
- data/app/jobs/spree_cm_commissioner/waiting_room_session_firebase_logger_job.rb +1 -1
- data/app/models/concerns/spree_cm_commissioner/integrations/integration_mappable.rb +61 -0
- data/app/models/concerns/spree_cm_commissioner/line_item_integration.rb +36 -0
- data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +16 -4
- data/app/models/concerns/spree_cm_commissioner/option_value_attr_type.rb +1 -1
- data/app/models/concerns/spree_cm_commissioner/order_integration.rb +33 -0
- data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +4 -2
- data/app/models/concerns/spree_cm_commissioner/store_metadata.rb +14 -2
- data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +1 -7
- data/app/models/spree_cm_commissioner/export.rb +1 -1
- data/app/models/spree_cm_commissioner/guest.rb +13 -0
- data/app/models/spree_cm_commissioner/integration.rb +29 -0
- data/app/models/spree_cm_commissioner/integration_mapping.rb +41 -0
- data/app/models/spree_cm_commissioner/integration_sync_session.rb +15 -0
- data/app/models/spree_cm_commissioner/integrations/stadium_x_v1.rb +37 -0
- data/app/models/spree_cm_commissioner/inventory_item.rb +5 -1
- data/app/models/spree_cm_commissioner/line_item_decorator.rb +13 -1
- data/app/models/spree_cm_commissioner/option_type_decorator.rb +8 -0
- data/app/models/spree_cm_commissioner/option_value_decorator.rb +34 -0
- data/app/models/spree_cm_commissioner/order_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/product_decorator.rb +4 -3
- data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +2 -2
- data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +6 -3
- data/app/models/spree_cm_commissioner/stock_item_decorator.rb +4 -4
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +2 -1
- data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +13 -1
- data/app/models/spree_cm_commissioner/variant_decorator.rb +7 -4
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +6 -2
- data/app/overrides/spree/admin/shared/sub_menu/_integrations/external_integrations.html.erb.deface +6 -0
- data/app/presenters/spree/variants/{visable_options_presenter.rb → visible_options_presenter.rb} +2 -4
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_serializer.rb +1 -1
- data/app/services/spree_cm_commissioner/integrations/base/sync_manager.rb +69 -0
- data/app/services/spree_cm_commissioner/integrations/base/sync_result.rb +183 -0
- data/app/services/spree_cm_commissioner/integrations/polling.rb +70 -0
- data/app/services/spree_cm_commissioner/integrations/polling_scheduler.rb +79 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/external_client/client.rb +152 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/inventory/unstock_inventory.rb +83 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_matches.rb +113 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_zones.rb +215 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/base.rb +20 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/league.rb +19 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/match.rb +95 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/ticket.rb +81 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/ticket_image.rb +19 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/zone.rb +90 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_manager.rb +35 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/full_sync_strategy.rb +38 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/incremental_sync_strategy.rb +44 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/webhook_sync_strategy.rb +16 -0
- data/app/services/spree_cm_commissioner/telegram_alerts/integration_sync_failure.rb +49 -0
- data/app/views/spree/admin/integration_mappings/_integration_mappings.html.erb +107 -0
- data/app/views/spree/admin/integration_mappings/index.html.erb +33 -0
- data/app/views/spree/admin/integration_sessions/_integration_sync_sessions.html.erb +116 -0
- data/app/views/spree/admin/integration_sessions/index.html.erb +42 -0
- data/app/views/spree/admin/integrations/_form.html.erb +104 -0
- data/app/views/spree/admin/integrations/_stadium_x_v1_fields.html.erb +29 -0
- data/app/views/spree/admin/integrations/edit.html.erb +45 -0
- data/app/views/spree/admin/integrations/index.html.erb +75 -0
- data/app/views/spree/admin/integrations/new.html.erb +25 -0
- data/bin/run_spec_group +101 -0
- data/config/locales/en.yml +8 -0
- data/config/locales/km.yml +8 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20251017094845_create_cm_integrations.rb +22 -0
- data/db/migrate/20251017101555_create_cm_integration_sync_sessions.rb +68 -0
- data/db/migrate/20251017101605_create_cm_integration_mappings.rb +52 -0
- data/lib/cm_app_logger.rb +36 -4
- data/lib/spree_cm_commissioner/test_helper/factories/integration_factory.rb +25 -0
- data/lib/spree_cm_commissioner/test_helper/factories/integration_mapping_factory.rb +14 -0
- data/lib/spree_cm_commissioner/test_helper/factories/integration_sync_session_factory.rb +7 -0
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -0
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +3 -2
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +8 -7
- metadata +58 -3
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Caches the integration status of a line item's variant in private_metadata.
|
|
2
|
+
#
|
|
3
|
+
# Why cache?
|
|
4
|
+
# Most products don't have integrations, so checking `variant.vendor.integration.present?`
|
|
5
|
+
# on every read would cause N+1 queries. Caching avoids this performance hit.
|
|
6
|
+
#
|
|
7
|
+
# Behavior:
|
|
8
|
+
# The flag is set once at line item creation and remains immutable. This preserves
|
|
9
|
+
# the historical integration state of the order, even if the vendor's integration
|
|
10
|
+
# status changes later. We don't have use cases requiring dynamic updates of this yet,
|
|
11
|
+
# so we keep it constant for simplicity and consistency.
|
|
12
|
+
module SpreeCmCommissioner
|
|
13
|
+
module LineItemIntegration
|
|
14
|
+
extend ActiveSupport::Concern
|
|
15
|
+
|
|
16
|
+
included do
|
|
17
|
+
before_create :set_integration_flag
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def integration?
|
|
21
|
+
return false if private_metadata['integration'].nil?
|
|
22
|
+
|
|
23
|
+
ActiveModel::Type::Boolean.new.cast(private_metadata['integration'])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def set_integration_flag
|
|
29
|
+
return if private_metadata.key?('integration')
|
|
30
|
+
return if variant.nil? || variant.vendor.nil?
|
|
31
|
+
|
|
32
|
+
# We use variant.vendor instead of .vendor directly as on create, the association may not be set to line item yet.
|
|
33
|
+
private_metadata['integration'] ||= variant.vendor.integration.present?
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -45,7 +45,8 @@ module SpreeCmCommissioner
|
|
|
45
45
|
'color' => 'color',
|
|
46
46
|
'ticket-type' => 'string',
|
|
47
47
|
'seat-type' => 'string',
|
|
48
|
-
'intercity-taxi' => 'string'
|
|
48
|
+
'intercity-taxi' => 'string',
|
|
49
|
+
'rules' => 'string'
|
|
49
50
|
}.freeze
|
|
50
51
|
|
|
51
52
|
included do
|
|
@@ -56,7 +57,7 @@ module SpreeCmCommissioner
|
|
|
56
57
|
|
|
57
58
|
validate :ensure_name_is_not_changed, on: :update
|
|
58
59
|
|
|
59
|
-
before_validation :
|
|
60
|
+
before_validation :set_reserved_options_attributes, if: :reserved_option?
|
|
60
61
|
|
|
61
62
|
after_save :sort_date_time_option_values, if: -> { attr_type == 'date' || attr_type == 'time' }
|
|
62
63
|
after_save :update_variants_metadata, if: :saved_change_to_name?
|
|
@@ -68,6 +69,17 @@ module SpreeCmCommissioner
|
|
|
68
69
|
end
|
|
69
70
|
end
|
|
70
71
|
|
|
72
|
+
class_methods do
|
|
73
|
+
def rules_option_type = find_by(name: 'rules')
|
|
74
|
+
|
|
75
|
+
def ticket_type
|
|
76
|
+
Spree::OptionType.find_or_create_by!(name: 'ticket-type') do |ot|
|
|
77
|
+
ot.presentation = 'Ticket Type'
|
|
78
|
+
ot.kind = :variant
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
71
83
|
def reserved_option?
|
|
72
84
|
return name_was.in?(RESERVED_OPTIONS.keys) if name_changed?
|
|
73
85
|
|
|
@@ -78,7 +90,7 @@ module SpreeCmCommissioner
|
|
|
78
90
|
name == 'ticket-type'
|
|
79
91
|
end
|
|
80
92
|
|
|
81
|
-
def
|
|
93
|
+
def set_reserved_options_attributes
|
|
82
94
|
self.attr_type = RESERVED_OPTIONS[name]
|
|
83
95
|
self.kind = :variant
|
|
84
96
|
end
|
|
@@ -92,7 +104,7 @@ module SpreeCmCommissioner
|
|
|
92
104
|
end
|
|
93
105
|
|
|
94
106
|
def update_variants_metadata
|
|
95
|
-
SpreeCmCommissioner::OptionTypeVariantsPublicMetadataUpdaterJob.perform_later(id)
|
|
107
|
+
SpreeCmCommissioner::OptionTypeVariantsPublicMetadataUpdaterJob.perform_later(option_type_id: id)
|
|
96
108
|
end
|
|
97
109
|
|
|
98
110
|
private
|
|
@@ -76,7 +76,7 @@ module SpreeCmCommissioner
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def update_variants_metadata
|
|
79
|
-
SpreeCmCommissioner::OptionValueVariantsPublicMetadataUpdaterJob.perform_later(id)
|
|
79
|
+
SpreeCmCommissioner::OptionValueVariantsPublicMetadataUpdaterJob.perform_later(option_value_id: id)
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
private
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module OrderIntegration
|
|
3
|
+
# Checks if any line item in this order has an integration (i.e., is from a vendor with an integration).
|
|
4
|
+
# This is used to determine if inventory management operations should be delegated to an external system.
|
|
5
|
+
def integration?
|
|
6
|
+
line_items.any?(&:integration?)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Attempts to unstock inventory for all integration line items in this order.
|
|
10
|
+
# Groups line items by vendor and delegates to the vendor's integration service.
|
|
11
|
+
def unstock_inventory_from_external_system!
|
|
12
|
+
integration_line_items = line_items.select(&:integration?)
|
|
13
|
+
return if integration_line_items.empty?
|
|
14
|
+
|
|
15
|
+
integration_line_items.group_by(&:vendor_id).each do |_, line_items|
|
|
16
|
+
integration = line_items.first&.vendor&.integration
|
|
17
|
+
integration.unstock_external_inventory!(self, line_items) if integration.present?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Attempts to restock inventory for all integration line items in this order.
|
|
22
|
+
# Groups line items by vendor and delegates to the vendor's integration service.
|
|
23
|
+
def restock_inventory_from_external_system!
|
|
24
|
+
integration_line_items = line_items.select(&:integration?)
|
|
25
|
+
return if integration_line_items.empty?
|
|
26
|
+
|
|
27
|
+
integration_line_items.group_by(&:vendor_id).each do |_, line_items|
|
|
28
|
+
integration = line_items.first&.vendor&.integration
|
|
29
|
+
integration.restock_external_inventory!(self, line_items) if integration.present?
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -83,7 +83,7 @@ module SpreeCmCommissioner
|
|
|
83
83
|
|
|
84
84
|
def precalculate_conversion
|
|
85
85
|
line_items.each do |item|
|
|
86
|
-
SpreeCmCommissioner::ConversionPreCalculatorJob.perform_later(item.product_id)
|
|
86
|
+
SpreeCmCommissioner::ConversionPreCalculatorJob.perform_later(product_id: item.product_id)
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
|
|
@@ -143,6 +143,7 @@ module SpreeCmCommissioner
|
|
|
143
143
|
# The payment will be reversed in vPago gem, and `Spree::Checkout::Complete` will be called, which checks `order.reload.complete?`.
|
|
144
144
|
# This is critical because if the order state is complete, the payment will be marked as paid.
|
|
145
145
|
|
|
146
|
+
unstock_inventory_from_external_system!
|
|
146
147
|
reserve_blocks!
|
|
147
148
|
unstock_inventory_in_redis!
|
|
148
149
|
|
|
@@ -161,6 +162,7 @@ module SpreeCmCommissioner
|
|
|
161
162
|
|
|
162
163
|
def restock_inventory!
|
|
163
164
|
ActiveRecord::Base.transaction do
|
|
165
|
+
restock_inventory_from_external_system!
|
|
164
166
|
cancel_blocks!
|
|
165
167
|
restock_inventory_in_redis!
|
|
166
168
|
end
|
|
@@ -244,7 +246,7 @@ module SpreeCmCommissioner
|
|
|
244
246
|
end
|
|
245
247
|
|
|
246
248
|
def notify_order_complete_telegram_notification_to_user
|
|
247
|
-
SpreeCmCommissioner::OrderCompleteTelegramSenderJob.perform_later(id) if user_id.present?
|
|
249
|
+
SpreeCmCommissioner::OrderCompleteTelegramSenderJob.perform_later(order_id: id) if user_id.present?
|
|
248
250
|
end
|
|
249
251
|
|
|
250
252
|
def send_order_requested_app_notification_to_user
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# - integer
|
|
14
14
|
# - array
|
|
15
15
|
# - datetime
|
|
16
|
+
# - hash
|
|
16
17
|
#
|
|
17
18
|
# Example usage:
|
|
18
19
|
# ```
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
# store_public_metadata :completed, :boolean, default: true
|
|
23
24
|
# store_public_metadata :count, :integer, default: 5
|
|
24
25
|
# store_public_metadata :tags, :array, default: []
|
|
26
|
+
# store_public_metadata :tags, :hash
|
|
25
27
|
# store_private_metadata :app_token, :string, default: "XYZ"
|
|
26
28
|
# store_public_metadata :scheduled_at, :datetime, default: Time.now
|
|
27
29
|
# end
|
|
@@ -92,7 +94,7 @@ module SpreeCmCommissioner
|
|
|
92
94
|
# - Return default if nil
|
|
93
95
|
# - Cast to correct type
|
|
94
96
|
# - Add `?` predicate for booleans
|
|
95
|
-
def define_metadata_reader(column_name, key, type, default)
|
|
97
|
+
def define_metadata_reader(column_name, key, type, default) # rubocop:disable Metrics/CyclomaticComplexity
|
|
96
98
|
define_method(key) do
|
|
97
99
|
metadata = send(column_name) || {}
|
|
98
100
|
raw_value = metadata[key.to_s]
|
|
@@ -109,6 +111,8 @@ module SpreeCmCommissioner
|
|
|
109
111
|
Array(raw_value)
|
|
110
112
|
when :datetime
|
|
111
113
|
Time.zone.parse(raw_value.to_s)
|
|
114
|
+
when :hash
|
|
115
|
+
raw_value.is_a?(Hash) ? raw_value : {}
|
|
112
116
|
else
|
|
113
117
|
raw_value
|
|
114
118
|
end
|
|
@@ -118,7 +122,7 @@ module SpreeCmCommissioner
|
|
|
118
122
|
end
|
|
119
123
|
|
|
120
124
|
# Validates only new assignments (raw JSON values) for type safety
|
|
121
|
-
def define_metadata_validation(column_name, key, type) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
125
|
+
def define_metadata_validation(column_name, key, type) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity,Metrics/AbcSize
|
|
122
126
|
case type
|
|
123
127
|
when :boolean
|
|
124
128
|
validates key, inclusion: { in: [true, false] }, allow_nil: true
|
|
@@ -160,6 +164,14 @@ module SpreeCmCommissioner
|
|
|
160
164
|
errors.add(key, 'is not a valid datetime')
|
|
161
165
|
end
|
|
162
166
|
end
|
|
167
|
+
when :hash
|
|
168
|
+
validate do
|
|
169
|
+
metadata = send(column_name) || {}
|
|
170
|
+
raw_value = metadata[key.to_s]
|
|
171
|
+
next if raw_value.nil?
|
|
172
|
+
|
|
173
|
+
errors.add(key, 'must be a hash') unless raw_value.is_a?(Hash)
|
|
174
|
+
end
|
|
163
175
|
end
|
|
164
176
|
end
|
|
165
177
|
end
|
|
@@ -35,12 +35,6 @@ module SpreeCmCommissioner
|
|
|
35
35
|
to: :options
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
# Override variant.rb to return cached formatted options text, avoiding repeated database queries.
|
|
39
|
-
# Falls back to database queries & computing the format if preload data is unavailable.
|
|
40
|
-
def options_text
|
|
41
|
-
@options_text ||= public_metadata[:preload_options_text].presence || Spree::Variants::VisableOptionsPresenter.new(self).to_sentence
|
|
42
|
-
end
|
|
43
|
-
|
|
44
38
|
def options
|
|
45
39
|
@options ||= VariantOptions.new(self)
|
|
46
40
|
end
|
|
@@ -111,7 +105,7 @@ module SpreeCmCommissioner
|
|
|
111
105
|
# Precomputes the human-readable format (e.g., "Red, 256GB") to avoid
|
|
112
106
|
# repeated formatting and association queries.
|
|
113
107
|
# Example: {"color" => "red", "storage" => "256GB"} - option_type_name => option_value_name pairs
|
|
114
|
-
self.public_metadata[:preload_options_text] = Spree::Variants::
|
|
108
|
+
self.public_metadata[:preload_options_text] = Spree::Variants::VisibleOptionsPresenter.new(self).to_sentence
|
|
115
109
|
end
|
|
116
110
|
|
|
117
111
|
def set_options_to_public_metadata!
|
|
@@ -3,6 +3,8 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class Guest < SpreeCmCommissioner::Base # rubocop:disable Metrics/ClassLength
|
|
4
4
|
include SpreeCmCommissioner::KycBitwise
|
|
5
5
|
include SpreeCmCommissioner::PhoneNumberSanitizer
|
|
6
|
+
include SpreeCmCommissioner::StoreMetadata
|
|
7
|
+
include SpreeCmCommissioner::Integrations::IntegrationMappable
|
|
6
8
|
|
|
7
9
|
delegate :kyc, to: :line_item, allow_nil: true
|
|
8
10
|
delegate :allowed_upload_later?, to: :line_item, allow_nil: true
|
|
@@ -212,9 +214,20 @@ module SpreeCmCommissioner
|
|
|
212
214
|
end
|
|
213
215
|
|
|
214
216
|
def qr_data
|
|
217
|
+
return external_qr_data if external_qr_data.present?
|
|
218
|
+
|
|
215
219
|
token
|
|
216
220
|
end
|
|
217
221
|
|
|
222
|
+
# QR data for check-in. If external_wins? is true, use their QR data (they have their own check-in system).
|
|
223
|
+
# Otherwise, use our system's QR data. Only applicable to models with QR support (e.g., line_item, guest).
|
|
224
|
+
def external_qr_data
|
|
225
|
+
return nil if line_item.nil? || !line_item.integration?
|
|
226
|
+
|
|
227
|
+
mapping = external_wins_integration_mappings.first
|
|
228
|
+
mapping.external_qr_data if mapping.present?
|
|
229
|
+
end
|
|
230
|
+
|
|
218
231
|
def current_age
|
|
219
232
|
return nil if dob.nil?
|
|
220
233
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class Integration < Base
|
|
3
|
+
include StoreMetadata
|
|
4
|
+
|
|
5
|
+
enum status: { inactive: 0, active: 1, paused: 2 }
|
|
6
|
+
enum conflict_strategy: { newest_wins: 0, internal_wins: 1, external_wins: 2, manual_resolution: 3 }
|
|
7
|
+
|
|
8
|
+
belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant', optional: true
|
|
9
|
+
belongs_to :vendor, class_name: 'Spree::Vendor', optional: false, inverse_of: :integration
|
|
10
|
+
|
|
11
|
+
has_many :integration_mappings, class_name: 'SpreeCmCommissioner::IntegrationMapping', dependent: :destroy, inverse_of: :integration
|
|
12
|
+
has_many :integration_sync_sessions, class_name: 'SpreeCmCommissioner::IntegrationSyncSession', dependent: :destroy, inverse_of: :integration
|
|
13
|
+
|
|
14
|
+
validates :incremental_sync_interval_seconds, presence: true, numericality: { only_integer: true, greater_than: 0, less_than_or_equal_to: 3600 }
|
|
15
|
+
validates :full_sync_interval_hours, presence: true, numericality: { only_integer: true, greater_than: 0, less_than_or_equal_to: 168 }
|
|
16
|
+
|
|
17
|
+
def sync_manager
|
|
18
|
+
raise NotImplementedError, 'Subclasses must implement the sync_manager method'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def restock_external_inventory!(_order, _line_items)
|
|
22
|
+
raise NotImplementedError, 'Subclasses must implement the restock_external_inventory! method'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def unstock_external_inventory!(_order, _line_items)
|
|
26
|
+
raise NotImplementedError, 'Subclasses must implement the unstock_external_inventory! method'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class IntegrationMapping < Base
|
|
3
|
+
include StoreMetadata
|
|
4
|
+
|
|
5
|
+
enum status: { active: 0, archived: 1 }
|
|
6
|
+
|
|
7
|
+
# polymorphic (Spree::Taxon, Spree::Product, Spree::Variant, Spree::Vendor)
|
|
8
|
+
belongs_to :internal, polymorphic: true, optional: false
|
|
9
|
+
belongs_to :integration, class_name: 'SpreeCmCommissioner::Integration', inverse_of: :integration_mappings, optional: false
|
|
10
|
+
|
|
11
|
+
validates :external_id, presence: true, uniqueness: { scope: %i[integration_id internal_type internal_id date] }
|
|
12
|
+
validate :validate_internal_exists, if: -> { internal_type.present? && internal_id.present? }
|
|
13
|
+
|
|
14
|
+
# QR data for check-in. If external_wins? is true, use their QR data (they have their own check-in system).
|
|
15
|
+
# Otherwise, use our system's QR data. Only applicable to map with internal that has QR support (e.g., line_item, guest).
|
|
16
|
+
store_public_metadata :external_qr_data, :string, default: nil
|
|
17
|
+
|
|
18
|
+
def mark_as_archived!
|
|
19
|
+
self.status = :archived
|
|
20
|
+
self.last_synced_at = Time.zone.now
|
|
21
|
+
|
|
22
|
+
save!
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def mark_as_active!(external_payload:)
|
|
26
|
+
self.external_payload = external_payload
|
|
27
|
+
self.last_synced_at = Time.zone.now
|
|
28
|
+
self.status = :active
|
|
29
|
+
|
|
30
|
+
save!
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def validate_internal_exists
|
|
36
|
+
return if internal_type.safe_constantize&.exists?(id: internal_id)
|
|
37
|
+
|
|
38
|
+
errors.add(:internal, "record (#{internal_type}##{internal_id}) does not exist")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class IntegrationSyncSession < Base
|
|
3
|
+
include StoreMetadata
|
|
4
|
+
|
|
5
|
+
enum status: { pending: 0, in_progress: 1, completed: 2, failed: 3, canceled: 4 }
|
|
6
|
+
enum :sync_type, {
|
|
7
|
+
full: 0, # on initial setup or periodic complete refresh
|
|
8
|
+
incremental: 1, # on scheduled intervals to fetch recent changes
|
|
9
|
+
webhook_triggered: 2 # immediately when an external webhook event is received
|
|
10
|
+
}, prefix: true
|
|
11
|
+
|
|
12
|
+
belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant', optional: true
|
|
13
|
+
belongs_to :integration, class_name: 'SpreeCmCommissioner::Integration', inverse_of: :integration_sync_sessions, optional: false
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class SpreeCmCommissioner::Integrations::StadiumXV1 < SpreeCmCommissioner::Integration
|
|
2
|
+
store_private_metadata :public_key, :string
|
|
3
|
+
store_private_metadata :private_key, :string
|
|
4
|
+
store_private_metadata :base_url, :string # e.g. 'https://api.stadiumx.com'
|
|
5
|
+
|
|
6
|
+
# override
|
|
7
|
+
def sync_manager
|
|
8
|
+
SpreeCmCommissioner::Integrations::StadiumXV1::SyncManager.new(
|
|
9
|
+
integration: self,
|
|
10
|
+
client: client
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# override
|
|
15
|
+
def unstock_external_inventory!(order, line_items)
|
|
16
|
+
result = SpreeCmCommissioner::Integrations::StadiumXV1::Inventory::UnstockInventory.new.call(
|
|
17
|
+
integration: self,
|
|
18
|
+
order: order,
|
|
19
|
+
line_items: line_items
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
raise SpreeCmCommissioner::Integrations::SyncError, result.error unless result.success?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# override
|
|
26
|
+
def restock_external_inventory!(_order, _line_items)
|
|
27
|
+
raise SpreeCmCommissioner::Integrations::SyncError, 'Ticket cannot be cancelled'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def client
|
|
31
|
+
SpreeCmCommissioner::Integrations::StadiumXV1::ExternalClient::Client.new(
|
|
32
|
+
public_key: public_key,
|
|
33
|
+
private_key: private_key,
|
|
34
|
+
base_url: base_url
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -56,8 +56,12 @@ module SpreeCmCommissioner
|
|
|
56
56
|
"inventory:#{id}"
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
def quantity_in_redis
|
|
60
|
+
SpreeCmCommissioner.inventory_redis_pool.with { |redis| redis.get(redis_key).to_i }
|
|
61
|
+
end
|
|
62
|
+
|
|
59
63
|
def adjust_quantity_in_redis(quantity)
|
|
60
|
-
SpreeCmCommissioner.
|
|
64
|
+
SpreeCmCommissioner.inventory_redis_pool.with do |redis|
|
|
61
65
|
# Always update Redis cache, even if it doesn't exist yet.
|
|
62
66
|
# This prevents admin adjustments from being lost when cache is later initialized.
|
|
63
67
|
script = <<~LUA
|
|
@@ -72,10 +72,12 @@ module SpreeCmCommissioner
|
|
|
72
72
|
def self.include_modules(base)
|
|
73
73
|
base.include Spree::Core::NumberGenerator.new(prefix: 'L')
|
|
74
74
|
base.include SpreeCmCommissioner::StoreMetadata
|
|
75
|
+
base.include SpreeCmCommissioner::LineItemIntegration
|
|
75
76
|
base.include SpreeCmCommissioner::LineItemDurationable
|
|
76
77
|
base.include SpreeCmCommissioner::LineItemsFilterScope
|
|
77
78
|
base.include SpreeCmCommissioner::LineItemGuestsConcern
|
|
78
79
|
base.include SpreeCmCommissioner::LineItemTransitable
|
|
80
|
+
base.include SpreeCmCommissioner::Integrations::IntegrationMappable
|
|
79
81
|
base.include SpreeCmCommissioner::ProductType
|
|
80
82
|
base.include SpreeCmCommissioner::ProductDelegation
|
|
81
83
|
base.include SpreeCmCommissioner::KycBitwise
|
|
@@ -198,11 +200,21 @@ module SpreeCmCommissioner
|
|
|
198
200
|
end
|
|
199
201
|
|
|
200
202
|
def qr_data
|
|
203
|
+
return external_qr_data if external_qr_data.present?
|
|
201
204
|
return nil if order.nil?
|
|
202
205
|
|
|
203
206
|
"#{order.number}-#{order.token}-L#{id}"
|
|
204
207
|
end
|
|
205
208
|
|
|
209
|
+
# QR data for check-in. If external_wins? is true, use their QR data (they have their own check-in system).
|
|
210
|
+
# Otherwise, use our system's QR data. Only applicable to models with QR support (e.g., line_item, guest).
|
|
211
|
+
def external_qr_data
|
|
212
|
+
return nil unless integration?
|
|
213
|
+
|
|
214
|
+
mapping = external_wins_integration_mappings.first
|
|
215
|
+
mapping.external_qr_data if mapping.present?
|
|
216
|
+
end
|
|
217
|
+
|
|
206
218
|
def generate_completion_steps
|
|
207
219
|
generate_completion_steps!
|
|
208
220
|
true
|
|
@@ -255,7 +267,7 @@ module SpreeCmCommissioner
|
|
|
255
267
|
end
|
|
256
268
|
|
|
257
269
|
def update_vendor_id
|
|
258
|
-
self.vendor_id = variant
|
|
270
|
+
self.vendor_id = variant&.vendor_id
|
|
259
271
|
end
|
|
260
272
|
|
|
261
273
|
def subscription?
|
|
@@ -22,6 +22,14 @@ module SpreeCmCommissioner
|
|
|
22
22
|
def base.rules_option_type
|
|
23
23
|
Spree::OptionType.find_by(name: RULES_OPTION_TYPE_NAME)
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
# override
|
|
27
|
+
def base.color
|
|
28
|
+
Spree::OptionType.find_or_create_by!(name: 'color') do |ot|
|
|
29
|
+
ot.presentation = 'Color'
|
|
30
|
+
ot.kind = :variant
|
|
31
|
+
end
|
|
32
|
+
end
|
|
25
33
|
end
|
|
26
34
|
|
|
27
35
|
private
|
|
@@ -3,6 +3,36 @@ module SpreeCmCommissioner
|
|
|
3
3
|
def self.prepended(base)
|
|
4
4
|
base.include SpreeCmCommissioner::OptionValueAttrType
|
|
5
5
|
base.has_many :option_value_vehicles, class_name: 'SpreeCmCommissioner::OptionValueVehicle', foreign_key: :option_value_id, dependent: :destroy
|
|
6
|
+
|
|
7
|
+
base.validates :name, presence: true, uniqueness: { scope: :option_type_id, case_sensitive: -> { name_case_sensitive? } }
|
|
8
|
+
|
|
9
|
+
# Ticket types: case-SENSITIVE matching (preserve external API casing)
|
|
10
|
+
# Other types: case-INSENSITIVE storage (prevent duplicates from varying API casing; presentation keeps original)
|
|
11
|
+
def base.find_or_create_by_name!(option_type, name)
|
|
12
|
+
name = name.strip
|
|
13
|
+
if option_type.ticket_type?
|
|
14
|
+
where(option_type_id: option_type.id, name: name).first_or_create! do |ov|
|
|
15
|
+
ov.option_type = option_type
|
|
16
|
+
ov.name = name
|
|
17
|
+
ov.presentation = name
|
|
18
|
+
end
|
|
19
|
+
else
|
|
20
|
+
where(option_type_id: option_type.id).where('LOWER(name) = ?', name.downcase).first_or_create! do |ov|
|
|
21
|
+
ov.option_type = option_type
|
|
22
|
+
ov.name = name.downcase
|
|
23
|
+
ov.presentation = name
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Override Spree's name validation to make it case-sensitive only for ticket-type option values.
|
|
30
|
+
# Spree's default is case-insensitive (false), but we enforce case-sensitivity (true) for ticket-types.
|
|
31
|
+
# Which means ticket type "STANDARD" and "Standard" are different option values.
|
|
32
|
+
def name_case_sensitive?
|
|
33
|
+
return true if ticket_type?
|
|
34
|
+
|
|
35
|
+
false
|
|
6
36
|
end
|
|
7
37
|
|
|
8
38
|
def display_icon
|
|
@@ -14,5 +44,9 @@ module SpreeCmCommissioner
|
|
|
14
44
|
end
|
|
15
45
|
|
|
16
46
|
unless Spree::OptionValue.included_modules.include?(SpreeCmCommissioner::OptionValueDecorator)
|
|
47
|
+
# remove all name validations so we can override them in the decorator.
|
|
48
|
+
Spree::OptionValue._validators.reject! { |key, _| key == :name }
|
|
49
|
+
Spree::OptionValue._validate_callbacks.each { |c| c.filter.attributes.delete(:name) if c.filter.respond_to?(:attributes) }
|
|
50
|
+
|
|
17
51
|
Spree::OptionValue.prepend SpreeCmCommissioner::OptionValueDecorator
|
|
18
52
|
end
|
|
@@ -3,6 +3,7 @@ module SpreeCmCommissioner
|
|
|
3
3
|
def self.prepended(base) # rubocop:disable Metrics/MethodLength
|
|
4
4
|
base.include SpreeCmCommissioner::StoreMetadata
|
|
5
5
|
base.include SpreeCmCommissioner::PhoneNumberSanitizer
|
|
6
|
+
base.include SpreeCmCommissioner::OrderIntegration
|
|
6
7
|
base.include SpreeCmCommissioner::OrderSeatable
|
|
7
8
|
base.include SpreeCmCommissioner::OrderStateMachine
|
|
8
9
|
base.include SpreeCmCommissioner::RouteOrderCountable
|
|
@@ -8,6 +8,7 @@ module SpreeCmCommissioner
|
|
|
8
8
|
base.include SpreeCmCommissioner::TenantUpdatable
|
|
9
9
|
base.include SpreeCmCommissioner::ServiceType
|
|
10
10
|
base.include SpreeCmCommissioner::ServiceRecommendations
|
|
11
|
+
base.include SpreeCmCommissioner::Integrations::IntegrationMappable
|
|
11
12
|
|
|
12
13
|
base.has_many :variant_kind_option_types, -> { where(kind: :variant).order(:position) },
|
|
13
14
|
through: :product_option_types, source: :option_type
|
|
@@ -89,7 +90,7 @@ module SpreeCmCommissioner
|
|
|
89
90
|
request_to_book: 8
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
base.
|
|
93
|
+
base.belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant'
|
|
93
94
|
base.before_save :set_tenant
|
|
94
95
|
end
|
|
95
96
|
|
|
@@ -142,7 +143,7 @@ module SpreeCmCommissioner
|
|
|
142
143
|
end
|
|
143
144
|
|
|
144
145
|
def set_event_id
|
|
145
|
-
self.event_id
|
|
146
|
+
self.event_id ||= taxons.select(&:event?).first&.parent_id
|
|
146
147
|
end
|
|
147
148
|
|
|
148
149
|
def update_variants_vendor_id
|
|
@@ -150,7 +151,7 @@ module SpreeCmCommissioner
|
|
|
150
151
|
end
|
|
151
152
|
|
|
152
153
|
def sync_event_id_to_children
|
|
153
|
-
::SpreeCmCommissioner::ProductEventIdToChildrenSyncerJob.perform_later(id)
|
|
154
|
+
::SpreeCmCommissioner::ProductEventIdToChildrenSyncerJob.perform_later(product_id: id)
|
|
154
155
|
end
|
|
155
156
|
|
|
156
157
|
def validate_event_taxons
|
|
@@ -12,7 +12,7 @@ module SpreeCmCommissioner
|
|
|
12
12
|
keys = inventory_items.map { |item| "inventory:#{item.id}" }
|
|
13
13
|
return [] unless keys.any?
|
|
14
14
|
|
|
15
|
-
counts = SpreeCmCommissioner.
|
|
15
|
+
counts = SpreeCmCommissioner.inventory_redis_pool.with { |redis| redis.mget(*keys) }
|
|
16
16
|
inventory_items.map.with_index do |inventory_item, i|
|
|
17
17
|
::SpreeCmCommissioner::CachedInventoryItem.new(
|
|
18
18
|
inventory_key: keys[i],
|
|
@@ -32,7 +32,7 @@ module SpreeCmCommissioner
|
|
|
32
32
|
|
|
33
33
|
# Use atomic SET NX to prevent race condition where multiple concurrent reads
|
|
34
34
|
# initialize cache with stale values. Only the first thread wins.
|
|
35
|
-
SpreeCmCommissioner.
|
|
35
|
+
SpreeCmCommissioner.inventory_redis_pool.with do |redis|
|
|
36
36
|
redis.eval(set_nx_with_expiry_script, keys: [key], argv: [inventory_item.quantity_available, inventory_item.redis_expired_in])
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -51,13 +51,13 @@ module SpreeCmCommissioner
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def unstock(keys, quantities)
|
|
54
|
-
SpreeCmCommissioner.
|
|
54
|
+
SpreeCmCommissioner.inventory_redis_pool.with do |redis|
|
|
55
55
|
redis.eval(unstock_redis_script, keys: keys, argv: quantities)
|
|
56
56
|
end.positive?
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def restock(keys, quantities)
|
|
60
|
-
SpreeCmCommissioner.
|
|
60
|
+
SpreeCmCommissioner.inventory_redis_pool.with do |redis|
|
|
61
61
|
redis.eval(restock_redis_script, keys: keys, argv: quantities)
|
|
62
62
|
end.positive?
|
|
63
63
|
end
|
|
@@ -119,7 +119,10 @@ module SpreeCmCommissioner
|
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
def schedule_sync_inventory(inventory_id_and_quantities)
|
|
122
|
-
SpreeCmCommissioner::InventoryItemSyncerJob.perform_later(
|
|
122
|
+
SpreeCmCommissioner::InventoryItemSyncerJob.perform_later(
|
|
123
|
+
inventory_id_and_quantities: inventory_id_and_quantities,
|
|
124
|
+
line_item_ids: @line_item_ids
|
|
125
|
+
)
|
|
123
126
|
end
|
|
124
127
|
end
|
|
125
128
|
end
|
|
@@ -9,7 +9,7 @@ module SpreeCmCommissioner
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def update_vendor_total_inventory
|
|
12
|
-
SpreeCmCommissioner::VendorJob.perform_later(vendor.id) if vendor.present?
|
|
12
|
+
SpreeCmCommissioner::VendorJob.perform_later(vendor_id: vendor.id) if vendor.present?
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
private
|
|
@@ -20,9 +20,9 @@ module SpreeCmCommissioner
|
|
|
20
20
|
|
|
21
21
|
# When admin delete stock item, it will deduct stock from inventory item
|
|
22
22
|
def adjust_inventory_items_async
|
|
23
|
-
|
|
24
|
-
CmAppLogger.log(label: "#{self.class.name}#adjust_inventory_items_async", data:
|
|
25
|
-
SpreeCmCommissioner::Stock::InventoryItemsAdjusterJob.perform_later(**
|
|
23
|
+
args = { variant_id: variant.id, quantity: -count_on_hand }
|
|
24
|
+
CmAppLogger.log(label: "#{self.class.name}#adjust_inventory_items_async", data: args) do
|
|
25
|
+
SpreeCmCommissioner::Stock::InventoryItemsAdjusterJob.perform_later(**args)
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -5,6 +5,7 @@ module SpreeCmCommissioner
|
|
|
5
5
|
base.include SpreeCmCommissioner::TaxonKind
|
|
6
6
|
base.include SpreeCmCommissioner::ParticipationTypeBitwise
|
|
7
7
|
base.include SpreeCmCommissioner::EventMetadata
|
|
8
|
+
base.include SpreeCmCommissioner::Integrations::IntegrationMappable
|
|
8
9
|
|
|
9
10
|
base.has_many :taxon_vendors, class_name: 'SpreeCmCommissioner::TaxonVendor'
|
|
10
11
|
base.has_many :vendors, through: :taxon_vendors
|
|
@@ -134,7 +135,7 @@ module SpreeCmCommissioner
|
|
|
134
135
|
def sync_event_dates_to_line_items
|
|
135
136
|
return unless event? && depth == 1
|
|
136
137
|
|
|
137
|
-
::SpreeCmCommissioner::EventLineItemsDateSyncerJob.perform_later(id)
|
|
138
|
+
::SpreeCmCommissioner::EventLineItemsDateSyncerJob.perform_later(event_id: id)
|
|
138
139
|
end
|
|
139
140
|
|
|
140
141
|
private
|