spree_cm_commissioner 2.0.3.pre.pre5 → 2.0.3.pre.pre8
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/Gemfile.lock +1 -1
- data/app/controllers/spree/admin/locations_controller.rb +62 -0
- data/app/controllers/spree/api/v2/operator/event_charts_controller.rb +2 -8
- data/app/controllers/spree/api/v2/platform/places_controller.rb +4 -1
- data/app/controllers/spree/api/v2/storefront/dynamic_fields_controller.rb +42 -0
- data/app/controllers/spree/api/v2/storefront/guests_controller.rb +2 -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 +3 -1
- data/app/controllers/spree/api/v2/storefront/trips_controller.rb +24 -0
- data/app/controllers/spree_cm_commissioner/admin/products_controller_decorator.rb +14 -0
- data/app/interactors/spree_cm_commissioner/billing_address_creator.rb +33 -0
- data/app/interactors/spree_cm_commissioner/create_vendor.rb +11 -1
- 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/transit/draft_order_creator.rb +17 -4
- data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +1 -1
- data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +1 -0
- data/app/models/spree_cm_commissioner/address_decorator.rb +17 -3
- data/app/models/spree_cm_commissioner/guest.rb +105 -56
- data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +37 -27
- data/app/models/spree_cm_commissioner/order/address_book_decorator.rb +30 -12
- data/app/models/spree_cm_commissioner/order_decorator.rb +8 -1
- data/app/models/spree_cm_commissioner/place.rb +2 -0
- data/app/models/spree_cm_commissioner/product_decorator.rb +29 -0
- data/app/models/spree_cm_commissioner/saved_guest.rb +2 -0
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +7 -0
- data/app/models/spree_cm_commissioner/trip.rb +4 -2
- data/app/models/spree_cm_commissioner/user_decorator.rb +1 -1
- data/app/models/spree_cm_commissioner/variant_options.rb +4 -0
- data/app/models/spree_cm_commissioner/vehicle.rb +2 -0
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +3 -0
- data/app/overrides/spree/admin/products/_form/industry_taxons.html.erb.deface +26 -0
- data/app/overrides/spree/admin/products/_form/taxons.html.erb.deface +26 -0
- 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 +18 -18
- data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +2 -0
- data/app/serializers/{spree → spree_cm_commissioner}/v2/storefront/amenity_serializer.rb +2 -2
- data/app/serializers/spree_cm_commissioner/v2/storefront/block_serializer.rb +9 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +1 -3
- 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 → spree_cm_commissioner}/v2/storefront/trip_query_result_serializer.rb +2 -2
- 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 +17 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_stop_serializer.rb +9 -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 → spree_cm_commissioner}/v2/storefront/trip_vendor_serializer.rb +4 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/variant_block_serializer.rb +9 -0
- data/app/views/shared/_map.html.erb +5 -4
- 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/config/locales/en.yml +2 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20250812015522_remove_unique_indexes_from_cm_user_identity_providers.rb +8 -0
- data/db/migrate/20250812121745_add_data_fill_stage_phase_to_cm_guests.rb +5 -0
- data/db/migrate/20250814073854_add_call_to_action_to_spree_products.rb +5 -0
- data/lib/spree_cm_commissioner/transit/leg.rb +14 -0
- data/lib/spree_cm_commissioner/transit/seat_selection.rb +9 -1
- data/lib/spree_cm_commissioner/trip_query_result.rb +34 -0
- data/lib/spree_cm_commissioner/trip_result.rb +8 -1
- data/lib/spree_cm_commissioner/version.rb +1 -1
- metadata +31 -7
- data/app/serializers/spree/v2/storefront/trip_result_serializer.rb +0 -16
- data/app/serializers/spree/v2/storefront/trip_vehicle_serializer.rb +0 -11
@@ -226,62 +226,6 @@ module SpreeCmCommissioner
|
|
226
226
|
save!
|
227
227
|
end
|
228
228
|
|
229
|
-
def missing_dynamic_fields_for_stage(stage)
|
230
|
-
required_fields = line_item.product.dynamic_fields.where(data_fill_stage: stage)
|
231
|
-
filled_ids = guest_dynamic_fields.map(&:dynamic_field_id)
|
232
|
-
|
233
|
-
required_fields.reject { |field| filled_ids.include?(field.id) }
|
234
|
-
end
|
235
|
-
|
236
|
-
def all_required_dynamic_fields_completed?(stage)
|
237
|
-
missing_dynamic_fields_for_stage(stage).blank?
|
238
|
-
end
|
239
|
-
|
240
|
-
def validate_dynamic_fields_for_phase(phase)
|
241
|
-
required_fields = line_item.product.dynamic_fields.where(data_fill_stage: phase)
|
242
|
-
filled_ids = guest_dynamic_fields.map(&:dynamic_field_id)
|
243
|
-
|
244
|
-
required_fields.each do |field|
|
245
|
-
errors.add(:base, "#{field.label} is required for #{phase} phase") unless filled_ids.include?(field.id)
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
def pre_registration_completed?
|
250
|
-
return true unless line_item.product.dynamic_fields.pre_registration.any?
|
251
|
-
|
252
|
-
pre_registration_fields_completed?
|
253
|
-
end
|
254
|
-
|
255
|
-
def post_registration_completed?
|
256
|
-
return true unless line_item.product.dynamic_fields.post_registration.any?
|
257
|
-
|
258
|
-
post_registration_fields_completed?
|
259
|
-
end
|
260
|
-
|
261
|
-
def check_in_completed?
|
262
|
-
return true unless line_item.product.dynamic_fields.during_check_in.any?
|
263
|
-
|
264
|
-
check_in_fields_completed?
|
265
|
-
end
|
266
|
-
|
267
|
-
def current_collection_phase
|
268
|
-
if check_in.present?
|
269
|
-
:during_check_in
|
270
|
-
elsif line_item.order.completed?
|
271
|
-
:post_registration
|
272
|
-
else
|
273
|
-
:pre_registration
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
def phase_completion_status
|
278
|
-
{
|
279
|
-
pre_registration: pre_registration_completed?,
|
280
|
-
post_registration: post_registration_completed?,
|
281
|
-
during_check_in: check_in_completed?
|
282
|
-
}
|
283
|
-
end
|
284
|
-
|
285
229
|
# bib_number: 345, bib_prefix: 5KM, bib_zerofill: 5 => return 5KM00345
|
286
230
|
# bib_number: 345, bib_prefix: 5KM, bib_zerofill: 2 => return 5KM345
|
287
231
|
def formatted_bib_number
|
@@ -318,6 +262,111 @@ module SpreeCmCommissioner
|
|
318
262
|
block_ids = line_item.order.blocks.pluck(:id)
|
319
263
|
line_item.order.update(preload_block_ids: block_ids)
|
320
264
|
end
|
265
|
+
|
266
|
+
def all_required_dynamic_fields_completed?(stage)
|
267
|
+
missing_dynamic_fields_for_stage(stage).blank?
|
268
|
+
end
|
269
|
+
|
270
|
+
state_machine :data_fill_stage_phase, initial: 'pre_registration' do
|
271
|
+
state 'pre_registration', value: 'pre_registration'
|
272
|
+
state 'post_registration', value: 'post_registration'
|
273
|
+
state 'during_check_in', value: 'during_check_in'
|
274
|
+
state 'completed', value: 'completed'
|
275
|
+
|
276
|
+
event :complete_pre_registration do
|
277
|
+
transition 'pre_registration' => 'post_registration',
|
278
|
+
if: -> (guest) { guest.pre_registration_completed? && guest.post_registration_fields? }
|
279
|
+
transition 'pre_registration' => 'during_check_in',
|
280
|
+
if: -> (guest) { guest.pre_registration_completed? && !guest.post_registration_fields? && guest.during_check_in_fields? }
|
281
|
+
transition 'pre_registration' => 'completed',
|
282
|
+
if: -> (guest) { guest.pre_registration_completed? && !guest.post_registration_fields? && !guest.during_check_in_fields? }
|
283
|
+
end
|
284
|
+
|
285
|
+
event :complete_post_registration do
|
286
|
+
transition 'post_registration' => 'during_check_in',
|
287
|
+
if: -> (guest) { guest.post_registration_completed? && guest.during_check_in_fields? }
|
288
|
+
transition 'post_registration' => 'completed',
|
289
|
+
if: -> (guest) { guest.post_registration_completed? && !guest.during_check_in_fields? }
|
290
|
+
end
|
291
|
+
|
292
|
+
event :complete_check_in do
|
293
|
+
transition 'during_check_in' => 'completed',
|
294
|
+
if: -> (guest) { guest.check_in_completed? }
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def save_and_move_to_next_stage(_transition = nil)
|
299
|
+
# Trigger state machine transitions based on completion status
|
300
|
+
case data_fill_stage_phase
|
301
|
+
when 'pre_registration'
|
302
|
+
complete_pre_registration! if pre_registration_completed?
|
303
|
+
when 'post_registration'
|
304
|
+
complete_post_registration! if post_registration_completed?
|
305
|
+
when 'during_check_in'
|
306
|
+
complete_check_in! if check_in_completed?
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def completed_phases
|
311
|
+
phases = []
|
312
|
+
phases << 'pre_registration' if pre_registration_completed?
|
313
|
+
phases << 'post_registration' if post_registration_completed?
|
314
|
+
phases << 'during_check_in' if check_in_completed?
|
315
|
+
phases
|
316
|
+
end
|
317
|
+
|
318
|
+
def pre_registration_completed?
|
319
|
+
return true unless line_item&.product&.dynamic_fields&.pre_registration&.any?
|
320
|
+
|
321
|
+
required_fields = line_item.product.dynamic_fields.pre_registration.pluck(:id)
|
322
|
+
filled_fields = guest_dynamic_fields.where(dynamic_field_id: required_fields).pluck(:dynamic_field_id)
|
323
|
+
(required_fields - filled_fields).empty?
|
324
|
+
end
|
325
|
+
|
326
|
+
def post_registration_completed?
|
327
|
+
return true unless line_item&.product&.dynamic_fields&.post_registration&.any?
|
328
|
+
|
329
|
+
required_fields = line_item.product.dynamic_fields.post_registration.pluck(:id)
|
330
|
+
filled_fields = guest_dynamic_fields.where(dynamic_field_id: required_fields).pluck(:dynamic_field_id)
|
331
|
+
(required_fields - filled_fields).empty?
|
332
|
+
end
|
333
|
+
|
334
|
+
def check_in_completed?
|
335
|
+
return true unless line_item&.product&.dynamic_fields&.during_check_in&.any?
|
336
|
+
|
337
|
+
required_fields = line_item.product.dynamic_fields.during_check_in.pluck(:id)
|
338
|
+
filled_fields = guest_dynamic_fields.where(dynamic_field_id: required_fields).pluck(:dynamic_field_id)
|
339
|
+
(required_fields - filled_fields).empty?
|
340
|
+
end
|
341
|
+
|
342
|
+
def pre_registration_fields?
|
343
|
+
line_item&.product&.dynamic_fields&.pre_registration&.any?
|
344
|
+
end
|
345
|
+
|
346
|
+
def post_registration_fields?
|
347
|
+
line_item&.product&.dynamic_fields&.post_registration&.any?
|
348
|
+
end
|
349
|
+
|
350
|
+
def during_check_in_fields?
|
351
|
+
line_item&.product&.dynamic_fields&.during_check_in&.any?
|
352
|
+
end
|
353
|
+
|
354
|
+
private
|
355
|
+
|
356
|
+
def product_dynamic_fields
|
357
|
+
@product_dynamic_fields ||= line_item.product.dynamic_fields
|
358
|
+
end
|
359
|
+
|
360
|
+
def missing_dynamic_fields_for_stage(stage)
|
361
|
+
return [] if line_item.blank? || line_item.product.blank?
|
362
|
+
|
363
|
+
# Cache product dynamic fields to avoid multiple queries
|
364
|
+
@product_dynamic_fields ||= line_item.product.dynamic_fields
|
365
|
+
required_fields = @product_dynamic_fields.where(data_fill_stage: stage)
|
366
|
+
filled_ids = guest_dynamic_fields&.pluck(:dynamic_field_id) || []
|
367
|
+
|
368
|
+
required_fields.reject { |field| filled_ids.include?(field.id) }
|
369
|
+
end
|
321
370
|
end
|
322
371
|
end
|
323
372
|
# rubocop:enable Metrics/ClassLength
|
@@ -4,10 +4,13 @@ module SpreeCmCommissioner
|
|
4
4
|
belongs_to :dynamic_field, class_name: 'SpreeCmCommissioner::DynamicField', optional: false
|
5
5
|
belongs_to :dynamic_field_option, class_name: 'SpreeCmCommissioner::DynamicFieldOption', optional: true
|
6
6
|
|
7
|
-
validates :value, presence: true
|
8
7
|
validate :validate_value_format, if: -> { value.present? && dynamic_field.present? }
|
9
8
|
validate :validate_option_reference, if: -> { dynamic_field_option.present? }
|
9
|
+
validate :validate_phase_sequence
|
10
10
|
validate :check_required_fields_based_on_phase
|
11
|
+
validate :reject_empty_string_for_text_fields
|
12
|
+
|
13
|
+
after_commit :sync_guest_data_fill_stage_phase
|
11
14
|
|
12
15
|
private
|
13
16
|
|
@@ -15,6 +18,8 @@ module SpreeCmCommissioner
|
|
15
18
|
return if dynamic_field.blank?
|
16
19
|
|
17
20
|
case dynamic_field.data_type.to_s
|
21
|
+
when 'text', 'textarea'
|
22
|
+
errors.add(:value, "can't be blank") if value.is_a?(String) && value.strip == ''
|
18
23
|
when 'number'
|
19
24
|
errors.add(:value, 'must be a number') unless value.to_s.match?(/\A\d+\z/)
|
20
25
|
when 'boolean'
|
@@ -40,44 +45,49 @@ module SpreeCmCommissioner
|
|
40
45
|
errors.add(:dynamic_field_option, 'must belong to the same dynamic field')
|
41
46
|
end
|
42
47
|
|
43
|
-
def
|
44
|
-
|
45
|
-
end
|
48
|
+
def validate_phase_sequence
|
49
|
+
return if dynamic_field.blank? || guest.blank?
|
46
50
|
|
47
|
-
|
48
|
-
|
51
|
+
case dynamic_field.data_fill_stage.to_sym
|
52
|
+
when :post_registration
|
53
|
+
errors.add(:base, 'Must complete pre_registration fields first') unless guest.pre_registration_completed?
|
54
|
+
when :during_check_in
|
55
|
+
unless guest.post_registration_completed? || !guest.post_registration_fields?
|
56
|
+
errors.add(:base, 'Must complete post_registration fields first')
|
57
|
+
end
|
58
|
+
end
|
49
59
|
end
|
50
60
|
|
51
|
-
def
|
52
|
-
|
53
|
-
end
|
61
|
+
def field_required_in_current_phase?
|
62
|
+
return false if dynamic_field.blank? || guest.blank?
|
54
63
|
|
55
|
-
|
56
|
-
|
64
|
+
case dynamic_field.data_fill_stage.to_sym
|
65
|
+
when :pre_registration, :post_registration
|
57
66
|
guest.line_item.order.completed? && guest.check_in.blank?
|
67
|
+
when :during_check_in
|
68
|
+
guest.check_in.present?
|
69
|
+
else
|
70
|
+
false
|
71
|
+
end
|
58
72
|
end
|
59
73
|
|
60
|
-
def
|
61
|
-
dynamic_field.
|
62
|
-
|
74
|
+
def check_required_fields_based_on_phase
|
75
|
+
return if dynamic_field.blank? || value.present?
|
76
|
+
return unless field_required_in_current_phase?
|
77
|
+
|
78
|
+
errors.add(:value, I18n.t("guest_dynamic_field.errors.#{dynamic_field.data_fill_stage}_required"))
|
63
79
|
end
|
64
80
|
|
65
|
-
def
|
66
|
-
|
67
|
-
guest.check_in.present?
|
81
|
+
def sync_guest_data_fill_stage_phase
|
82
|
+
guest&.save_and_move_to_next_stage
|
68
83
|
end
|
69
84
|
|
70
|
-
def
|
71
|
-
return if dynamic_field.blank?
|
85
|
+
def reject_empty_string_for_text_fields
|
86
|
+
return if dynamic_field.blank?
|
87
|
+
return unless %w[text textarea].include?(dynamic_field.data_type.to_s)
|
88
|
+
return unless value.is_a?(String)
|
72
89
|
|
73
|
-
|
74
|
-
when :pre_registration
|
75
|
-
errors.add(:value, I18n.t('guest_dynamic_field.errors.pre_registration_required')) if pre_registration_required?
|
76
|
-
when :post_registration
|
77
|
-
errors.add(:value, I18n.t('guest_dynamic_field.errors.post_registration_required')) if post_registration_required?
|
78
|
-
when :during_check_in
|
79
|
-
errors.add(:value, I18n.t('guest_dynamic_field.errors.during_check_in_required')) if during_check_in_required?
|
80
|
-
end
|
90
|
+
errors.add(:value, "can't be blank") if value.strip == ''
|
81
91
|
end
|
82
92
|
end
|
83
93
|
end
|
@@ -5,30 +5,48 @@
|
|
5
5
|
module SpreeCmCommissioner
|
6
6
|
module Order
|
7
7
|
module AddressBookDecorator
|
8
|
-
def guest_order? = user.blank?
|
9
|
-
|
10
8
|
# override
|
11
9
|
def bill_address_attributes=(attributes)
|
12
|
-
attributes[:id] =
|
13
|
-
|
10
|
+
attributes[:id] = bill_address_id if attributes[:id].blank?
|
11
|
+
attributes[:phone] = intel_phone_number if intel_phone_number.present?
|
14
12
|
|
15
|
-
|
13
|
+
self.bill_address = assign_address_attributes(attributes)
|
14
|
+
user.bill_address = bill_address if user && user.bill_address.nil?
|
16
15
|
end
|
17
16
|
|
18
17
|
# override
|
19
18
|
def ship_address_attributes=(attributes)
|
20
|
-
attributes[:id] =
|
21
|
-
|
19
|
+
attributes[:id] = ship_address_id if attributes[:id].blank?
|
20
|
+
attributes[:phone] = intel_phone_number if intel_phone_number.present?
|
22
21
|
|
23
|
-
|
22
|
+
self.ship_address = assign_address_attributes(attributes)
|
23
|
+
user.ship_address = ship_address if user && user.ship_address.nil?
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
def assign_address_attributes(attributes = {})
|
27
|
+
return if attributes.blank?
|
28
|
+
|
29
|
+
attributes.transform_values! { |v| v == '' ? nil : v }
|
30
|
+
attributes = attributes.to_h.symbolize_keys
|
27
31
|
|
28
|
-
|
29
|
-
|
32
|
+
existing_address = attributes[:id].present? ? find_existing_address(attributes[:id]) : nil
|
33
|
+
|
34
|
+
if existing_address&.editable?
|
35
|
+
existing_address.assign_attributes(attributes)
|
36
|
+
existing_address
|
37
|
+
else
|
38
|
+
::Spree::Address.new(attributes.except(:id, :updated_at, :created_at))
|
39
|
+
end
|
40
|
+
end
|
30
41
|
|
31
|
-
|
42
|
+
def find_existing_address(id)
|
43
|
+
if user.present?
|
44
|
+
::Spree::Address.where('(user_id = ? OR user_id IS NULL) AND deleted_at IS NULL', user.id)
|
45
|
+
.find_by(id: id)
|
46
|
+
else
|
47
|
+
::Spree::Address.where(user_id: nil, deleted_at: nil)
|
48
|
+
.find_by(id: id)
|
49
|
+
end
|
32
50
|
end
|
33
51
|
end
|
34
52
|
end
|
@@ -43,7 +43,12 @@ module SpreeCmCommissioner
|
|
43
43
|
base.has_many :vendors, through: :products, class_name: 'Spree::Vendor'
|
44
44
|
base.has_many :taxons, through: :products, class_name: 'Spree::Taxon'
|
45
45
|
base.has_many :guests, through: :line_items, class_name: 'SpreeCmCommissioner::Guest'
|
46
|
-
|
46
|
+
|
47
|
+
base.has_many :saved_guests, -> { distinct.reorder('cm_saved_guests.created_at DESC') },
|
48
|
+
through: :guests,
|
49
|
+
source: :saved_guest,
|
50
|
+
class_name: 'SpreeCmCommissioner::SavedGuest'
|
51
|
+
|
47
52
|
base.has_many :blocks, through: :guests, class_name: 'SpreeCmCommissioner::Block', source: :block
|
48
53
|
base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
|
49
54
|
base.has_many :guest_card_classes, class_name: 'SpreeCmCommissioner::GuestCardClass', through: :variants
|
@@ -53,6 +58,8 @@ module SpreeCmCommissioner
|
|
53
58
|
base.whitelisted_ransackable_associations |= %w[customer taxon payments guests invoice]
|
54
59
|
base.whitelisted_ransackable_attributes |= %w[intel_phone_number phone_number email number state]
|
55
60
|
|
61
|
+
base.accepts_nested_attributes_for :saved_guests, allow_destroy: true
|
62
|
+
|
56
63
|
def base.search_by_qr_data!(data)
|
57
64
|
token = data.match(/^R\d{9,}-([A-Za-z0-9_\-]+)$/)&.captures
|
58
65
|
|
@@ -14,6 +14,8 @@ module SpreeCmCommissioner
|
|
14
14
|
has_many :product_places, class_name: 'SpreeCmCommissioner::ProductPlace', dependent: :destroy
|
15
15
|
has_many :products, through: :product_places
|
16
16
|
|
17
|
+
has_many :location_vendor_places, -> { where(place_type: :location) }, class_name: 'SpreeCmCommissioner::VendorPlace'
|
18
|
+
|
17
19
|
has_many :children, -> { order(:lft) }, class_name: 'SpreeCmCommissioner::Place', foreign_key: :parent_id, dependent: :destroy
|
18
20
|
|
19
21
|
has_many :taxon_places, class_name: 'SpreeCmCommissioner::TaxonPlace', dependent: :destroy
|
@@ -48,6 +48,9 @@ module SpreeCmCommissioner
|
|
48
48
|
|
49
49
|
base.belongs_to :event, class_name: 'Spree::Taxon', optional: true
|
50
50
|
|
51
|
+
base.has_many :industry_classifications, -> { joins(:taxon).where(spree_taxons: { kind: :industry }) }, class_name: 'Spree::Classification'
|
52
|
+
base.has_many :industry_taxons, through: :industry_classifications, source: :taxon
|
53
|
+
|
51
54
|
base.scope :min_price, lambda { |vendor|
|
52
55
|
joins(:prices_including_master)
|
53
56
|
.where(vendor_id: vendor.id, product_type: vendor.primary_product_type)
|
@@ -74,6 +77,16 @@ module SpreeCmCommissioner
|
|
74
77
|
base.after_update :sync_event_id_to_children, if: :saved_change_to_event_id?
|
75
78
|
|
76
79
|
base.enum purchasable_on: { both: 0, web: 1, app: 2 }
|
80
|
+
base.enum call_to_action: { buy_now: 0,
|
81
|
+
book_now: 1,
|
82
|
+
reserve: 2,
|
83
|
+
register: 3,
|
84
|
+
apply: 4,
|
85
|
+
get_ticket: 5,
|
86
|
+
secure_your_seat: 6,
|
87
|
+
join_the_event: 7,
|
88
|
+
request_to_book: 8
|
89
|
+
}
|
77
90
|
|
78
91
|
base.multi_tenant :tenant, class_name: 'SpreeCmCommissioner::Tenant'
|
79
92
|
base.before_save :set_tenant
|
@@ -83,6 +96,22 @@ module SpreeCmCommissioner
|
|
83
96
|
"#{Spree::Store.default.formatted_url}/tickets/#{slug}"
|
84
97
|
end
|
85
98
|
|
99
|
+
def action_button
|
100
|
+
return :request_to_book if need_confirmation?
|
101
|
+
return :reserve if free?
|
102
|
+
return call_to_action.to_sym if call_to_action.present?
|
103
|
+
|
104
|
+
:buy_now
|
105
|
+
end
|
106
|
+
|
107
|
+
def free?
|
108
|
+
return false if prices_including_master.empty?
|
109
|
+
|
110
|
+
prices_including_master.all? do |master_price|
|
111
|
+
master_price.price.zero? && (master_price.compare_at_price.nil? || master_price.compare_at_price.zero?)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
86
115
|
def dynamic_fields_by_collection_phase
|
87
116
|
{
|
88
117
|
pre_registration: dynamic_fields.pre_registration.order(:position),
|
@@ -46,6 +46,7 @@ module SpreeCmCommissioner
|
|
46
46
|
base.validates_associated :category_icon
|
47
47
|
base.before_save :set_kind
|
48
48
|
base.before_save :set_slug
|
49
|
+
base.before_save :normalize_custom_redirect_url
|
49
50
|
|
50
51
|
base.after_update :sync_event_dates_to_line_items, if: -> { saved_change_to_from_date? || saved_change_to_to_date? }
|
51
52
|
|
@@ -140,6 +141,12 @@ module SpreeCmCommissioner
|
|
140
141
|
|
141
142
|
::SpreeCmCommissioner::EventLineItemsDateSyncerJob.perform_later(id)
|
142
143
|
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def normalize_custom_redirect_url
|
148
|
+
self.custom_redirect_url = nil if custom_redirect_url.blank?
|
149
|
+
end
|
143
150
|
end
|
144
151
|
end
|
145
152
|
|
@@ -8,6 +8,7 @@ module SpreeCmCommissioner
|
|
8
8
|
|
9
9
|
belongs_to :vendor, class_name: 'Spree::Vendor', inverse_of: :trips, optional: false
|
10
10
|
belongs_to :product, class_name: 'Spree::Product', inverse_of: :trip, optional: false
|
11
|
+
|
11
12
|
belongs_to :vehicle, class_name: 'SpreeCmCommissioner::Vehicle', optional: false
|
12
13
|
|
13
14
|
belongs_to :origin_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
@@ -17,8 +18,8 @@ module SpreeCmCommissioner
|
|
17
18
|
has_many :blazer_queries, through: :trip_blazer_queries, source: :blazer_query, class_name: 'Blazer::Query'
|
18
19
|
|
19
20
|
has_many :trip_stops, class_name: 'SpreeCmCommissioner::TripStop', dependent: :destroy
|
20
|
-
has_many :boarding_trip_stops, -> { boarding }, class_name: 'SpreeCmCommissioner::TripStop'
|
21
|
-
has_many :drop_off_trip_stops, -> { drop_off }, class_name: 'SpreeCmCommissioner::TripStop'
|
21
|
+
has_many :boarding_trip_stops, -> { boarding.order('departure_time ASC NULLS LAST, id ASC') }, class_name: 'SpreeCmCommissioner::TripStop'
|
22
|
+
has_many :drop_off_trip_stops, -> { drop_off.order('arrival_time ASC NULLS LAST') }, class_name: 'SpreeCmCommissioner::TripStop'
|
22
23
|
|
23
24
|
has_many :variants, through: :product
|
24
25
|
has_many :inventory_items, through: :variants
|
@@ -32,6 +33,7 @@ module SpreeCmCommissioner
|
|
32
33
|
accepts_nested_attributes_for :trip_stops, :product, allow_destroy: true
|
33
34
|
|
34
35
|
self.whitelisted_ransackable_associations = %w[product vehicle]
|
36
|
+
self.whitelisted_ransackable_attributes = %w[origin_place_id destination_place_id]
|
35
37
|
|
36
38
|
def convert_duration_to_seconds
|
37
39
|
return if hours.blank? && minutes.blank? && seconds.blank?
|
@@ -139,6 +139,10 @@ module SpreeCmCommissioner
|
|
139
139
|
@seat_number_layouts ||= option_value_name_for(option_type_name: 'seat-number-layouts')&.split(',')
|
140
140
|
end
|
141
141
|
|
142
|
+
def seat_type
|
143
|
+
@seat_type ||= option_value_name_for(option_type_name: 'seat-type')
|
144
|
+
end
|
145
|
+
|
142
146
|
# can consider as customers.
|
143
147
|
def number_of_guests
|
144
148
|
number_of_adults + number_of_kids
|
@@ -12,6 +12,8 @@ module SpreeCmCommissioner
|
|
12
12
|
has_many :vehicle_option_types, class_name: 'SpreeCmCommissioner::VehicleOptionType', dependent: :destroy
|
13
13
|
has_many :option_value_vehicles, class_name: 'SpreeCmCommissioner::OptionValueVehicle', dependent: :destroy
|
14
14
|
has_many :option_values, through: :option_value_vehicles, class_name: 'Spree::OptionValue'
|
15
|
+
has_many :amenities, through: :option_value_vehicles, source: :option_value
|
16
|
+
|
15
17
|
validates :code, uniqueness: { scope: :vendor_id }, presence: true
|
16
18
|
validates :license_plate, uniqueness: true, allow_blank: true
|
17
19
|
|
@@ -84,6 +84,9 @@ module SpreeCmCommissioner
|
|
84
84
|
|
85
85
|
base.has_many :vehicles, class_name: 'SpreeCmCommissioner::Vehicle', dependent: :destroy
|
86
86
|
base.has_many :trips, class_name: 'SpreeCmCommissioner::Trip', dependent: :destroy
|
87
|
+
base.has_many :trip_stops, through: :trips, class_name: 'SpreeCmCommissioner::TripStop'
|
88
|
+
base.has_many :boarding_trip_stops, through: :trips, class_name: 'SpreeCmCommissioner::TripStop', source: :boarding_trip_stops
|
89
|
+
base.has_many :drop_off_trip_stops, through: :trips, class_name: 'SpreeCmCommissioner::TripStop', source: :drop_off_trip_stops
|
87
90
|
|
88
91
|
base.validates :account_name, :account_number, presence: true, if: lambda {
|
89
92
|
payment_qrcode.present? && Spree::Store.default.code.include?('billing')
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!-- insert_after "[data-hook='admin_product_form_taxons']" -->
|
2
|
+
|
3
|
+
<div data-hook="admin_product_form_industry_taxons">
|
4
|
+
<%= f.field_container :industry_taxons do %>
|
5
|
+
<%= f.label :industry_taxon_ids, Spree.t(:Industries) %>
|
6
|
+
|
7
|
+
<% if can? :modify, Spree::Classification %>
|
8
|
+
<%= f.select :industry_taxon_ids, options_from_collection_for_select(@product.industry_taxons, :id, :pretty_name, @product.industry_taxon_ids),
|
9
|
+
{ include_hidden: true },
|
10
|
+
multiple: true,
|
11
|
+
data: { autocomplete_url_value: 'taxons_api_v2',
|
12
|
+
autocomplete_return_attr_value: 'pretty_name',
|
13
|
+
autocomplete_multiple_value: true,
|
14
|
+
autocomplete_additional_url_params_value: "q[kind_eq]=7" } %>
|
15
|
+
<% elsif @product.industry_taxons.any? %>
|
16
|
+
<ul class="text_list">
|
17
|
+
<% @product.industry_taxons.each do |taxon| %>
|
18
|
+
<li><%= taxon.name %></li>
|
19
|
+
<% end %>
|
20
|
+
</ul>
|
21
|
+
<% else %>
|
22
|
+
<div class="alert alert-info"><%= Spree.t(:no_resource_found, resource: :taxons) %></div>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<% end %>
|
26
|
+
</div>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!-- replace "[data-hook='admin_product_form_taxons']" -->
|
2
|
+
|
3
|
+
<div data-hook="admin_product_form_taxons">
|
4
|
+
<%= f.field_container :taxons do %>
|
5
|
+
<%= f.label :taxon_ids, Spree.t(:taxons) %>
|
6
|
+
|
7
|
+
<% if can? :modify, Spree::Classification %>
|
8
|
+
<%= f.select :taxon_ids, options_from_collection_for_select(@product.taxons, :id, :pretty_name, @product.taxon_ids.reject { |id| @product.industry_taxon_ids.include?(id) }),
|
9
|
+
{ include_hidden: true },
|
10
|
+
multiple: true,
|
11
|
+
data: { autocomplete_url_value: 'taxons_api_v2',
|
12
|
+
autocomplete_return_attr_value: 'pretty_name',
|
13
|
+
autocomplete_multiple_value: true,
|
14
|
+
autocomplete_additional_url_params_value: "q[kind_not_eq]=7" } %>
|
15
|
+
<% elsif @product.taxons.any? %>
|
16
|
+
<ul class="text_list">
|
17
|
+
<% @product.taxons.each do |taxon| %>
|
18
|
+
<li><%= taxon.name %></li>
|
19
|
+
<% end %>
|
20
|
+
</ul>
|
21
|
+
<% else %>
|
22
|
+
<div class="alert alert-info"><%= Spree.t(:no_resource_found, resource: :taxons) %></div>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<% end %>
|
26
|
+
</div>
|