spree_cm_commissioner 2.5.2.pre.pre2 → 2.5.2.pre.pre3
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 +1 -1
- data/Gemfile.lock +1 -1
- data/app/controllers/concerns/spree/api/v2/product_list_includes_decorator.rb +37 -0
- data/app/controllers/spree/api/v2/storefront/active_homepage_events_controller.rb +6 -1
- data/app/controllers/spree/api/v2/storefront/homepage_sections_controller.rb +41 -4
- data/app/controllers/spree/api/v2/storefront/invite_guests_controller.rb +11 -2
- data/app/controllers/spree/api/v2/storefront/products_controller_decorator.rb +27 -0
- data/app/controllers/spree/api/v2/storefront/taxons_controller_decorator.rb +92 -0
- data/app/controllers/spree_cm_commissioner/application_controller_decorator.rb +0 -2
- data/app/jobs/spree_cm_commissioner/line_items/sync_event_date_job.rb +10 -0
- data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +30 -23
- data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +47 -6
- data/app/models/spree/stock/quantifier_decorator.rb +26 -0
- data/app/models/spree_cm_commissioner/export.rb +1 -3
- data/app/models/spree_cm_commissioner/guest.rb +3 -3
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +27 -1
- data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +36 -7
- data/app/services/spree_cm_commissioner/line_items/sync_event_date.rb +22 -0
- data/app/services/spree_cm_commissioner/trips/create_single_leg.rb +14 -19
- data/app/services/spree_cm_commissioner/trips/update_single_leg.rb +2 -4
- data/app/services/spree_cm_commissioner/trips/variants/create.rb +6 -6
- data/config/routes.rb +0 -27
- data/lib/spree_cm_commissioner/transit/route_stop_collection.rb +0 -28
- data/lib/spree_cm_commissioner/transit/trip_form.rb +0 -24
- data/lib/spree_cm_commissioner/transit/trip_stop_form.rb +1 -5
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +0 -1
- metadata +8 -33
- data/app/controllers/concerns/spree_cm_commissioner/events/role_authorization.rb +0 -36
- data/app/controllers/spree/events/base_controller.rb +0 -35
- data/app/controllers/spree/events/check_ins_controller.rb +0 -23
- data/app/controllers/spree/events/data_exports_controller.rb +0 -41
- data/app/controllers/spree/events/errors_controller.rb +0 -19
- data/app/controllers/spree/events/guests_controller.rb +0 -139
- data/app/controllers/spree/events/state_changes_controller.rb +0 -11
- data/app/errors/spree_cm_commissioner/unauthorized_event_error.rb +0 -4
- data/app/interactors/spree_cm_commissioner/event_line_items_date_syncer.rb +0 -19
- data/app/jobs/spree_cm_commissioner/event_line_items_date_syncer_job.rb +0 -8
- data/app/jobs/spree_cm_commissioner/export_csv_job.rb +0 -7
- data/app/models/spree_cm_commissioner/exports/export_guest_csv.rb +0 -33
- data/app/services/spree_cm_commissioner/exports/export_guest_csv_service.rb +0 -48
- data/app/views/spree/events/check_ins/index.html.erb +0 -59
- data/app/views/spree/events/data_exports/index.html.erb +0 -54
- data/app/views/spree/events/errors/_error.html.erb +0 -7
- data/app/views/spree/events/errors/forbidden.html.erb +0 -1
- data/app/views/spree/events/errors/resource_not_found.html.erb +0 -1
- data/app/views/spree/events/guests/_check_in_status.html.erb +0 -44
- data/app/views/spree/events/guests/_form.html.erb +0 -37
- data/app/views/spree/events/guests/_swap_guest_bib_number.html.erb +0 -18
- data/app/views/spree/events/guests/edit.html.erb +0 -86
- data/app/views/spree/events/guests/index.html.erb +0 -102
- data/app/views/spree/events/shared/_event_switcher.html.erb +0 -39
- data/app/views/spree/events/shared/_filters.html.erb +0 -50
- data/app/views/spree/events/shared/_guest_tabs.html.erb +0 -19
- data/app/views/spree/events/shared/_header.html.erb +0 -10
- data/app/views/spree/events/shared/_main_menu.html.erb +0 -22
- data/app/views/spree/events/state_changes/index.html.erb +0 -48
- data/lib/spree_cm_commissioner/test_helper/factories/export_guest_csv_factory.rb +0 -9
- data/lib/spree_cm_commissioner/transit/service_calendar_form.rb +0 -51
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa0e45576d6b86ad5c668c0ffe85f437e4e0e0ee01dcab1bef8c3cb4628950f9
|
|
4
|
+
data.tar.gz: b0d0683d2b81ede7e5200c270ac8d0b52d9c48dcb7e3223c94cf9f944bafe864
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6304eee33f234cd8bcd652faefe614e48060b4bb0b0d61a7e5343935d9228f5fd66fcf46a6a24877cac346c161f5863f4bc84f3fe0021715d668f5021e64343c
|
|
7
|
+
data.tar.gz: aaeb3660e2c2cd02e453e4fc83daae2be76cb7611c12ee2bc2f15de05a0172258a2bc336e05366544060611a827d04c19fa4726fe41c8b3ae5606909c7488eb9
|
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V2
|
|
4
|
+
module ProductListIncludesDecorator
|
|
5
|
+
# OVERRIDE: Extends base product_list_includes from Spree::Api::V2::ProductListIncludes
|
|
6
|
+
def product_list_includes
|
|
7
|
+
# Gets base from ProductListIncludes concern
|
|
8
|
+
base_includes = super
|
|
9
|
+
|
|
10
|
+
# Preload taxons with their taxonomies
|
|
11
|
+
base_includes[:classifications] = { taxon: :taxonomy }
|
|
12
|
+
|
|
13
|
+
# Add missing associations
|
|
14
|
+
base_includes[:vendor] = [:default_state]
|
|
15
|
+
base_includes[:venue] = []
|
|
16
|
+
base_includes[:variants_including_master] = { prices: [] }
|
|
17
|
+
base_includes[:product_option_types] = :option_type
|
|
18
|
+
base_includes[:product_promotion_rules] = {
|
|
19
|
+
promotion_rule: {
|
|
20
|
+
promotion: []
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
base_includes[:product_dynamic_fields] = :dynamic_field
|
|
24
|
+
|
|
25
|
+
%i[master variants variants_including_master].each do |key|
|
|
26
|
+
base_includes[key][:stock_items] = :stock_location if base_includes[key]
|
|
27
|
+
base_includes[key][:stock_locations] = []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
base_includes
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Spree::Api::V2::ProductListIncludes.prepend Spree::Api::V2::ProductListIncludesDecorator
|
|
@@ -6,7 +6,12 @@ module Spree
|
|
|
6
6
|
private
|
|
7
7
|
|
|
8
8
|
def collection
|
|
9
|
-
@collection ||= model_class.active_homepage_events
|
|
9
|
+
@collection ||= model_class.active_homepage_events.includes(category_icon: { attachment_attachment: :blob })
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def serialize_collection(collection)
|
|
13
|
+
model_class.preload_ancestors_for(collection)
|
|
14
|
+
super(collection)
|
|
10
15
|
end
|
|
11
16
|
|
|
12
17
|
def model_class
|
|
@@ -16,10 +16,47 @@ module Spree
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def collection
|
|
19
|
-
@collection
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
@collection = model_class.filter_by_segment(params[:homepage_id] || :general)
|
|
20
|
+
.active
|
|
21
|
+
.where(tenant_id: nil)
|
|
22
|
+
.order(position: :asc)
|
|
23
|
+
.includes(preload_associations)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def preload_associations
|
|
27
|
+
{
|
|
28
|
+
homepage_section_relatables: {
|
|
29
|
+
relatable: [
|
|
30
|
+
:icon,
|
|
31
|
+
{
|
|
32
|
+
home_banner: { attachment_attachment: :blob }
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
category_icon: { attachment_attachment: :blob }
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
video_banner: { attachment_attachment: :blob }
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
app_banner: { attachment_attachment: :blob }
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
web_banner: { attachment_attachment: :blob }
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
children: [
|
|
48
|
+
:icon,
|
|
49
|
+
{
|
|
50
|
+
vendors: [
|
|
51
|
+
{ photos: { attachment_attachment: :blob } },
|
|
52
|
+
:default_state
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
23
60
|
end
|
|
24
61
|
end
|
|
25
62
|
end
|
|
@@ -42,8 +42,17 @@ module Spree
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def load_invite_guest_by_token
|
|
45
|
-
@invite_guest = SpreeCmCommissioner::InviteGuest.
|
|
46
|
-
|
|
45
|
+
@invite_guest = SpreeCmCommissioner::InviteGuest.includes(
|
|
46
|
+
order: {
|
|
47
|
+
line_items: {
|
|
48
|
+
guests: %i[
|
|
49
|
+
guest_dynamic_fields
|
|
50
|
+
id_card
|
|
51
|
+
check_in
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
).find_by(token: params[:id])
|
|
47
56
|
render_error_payload(I18n.t('invite.url_not_found'))
|
|
48
57
|
end
|
|
49
58
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# gems/spree_cm_commissioner/app/controllers/spree/api/v2/storefront/products_controller_decorator.rb
|
|
2
|
+
module Spree
|
|
3
|
+
module Api
|
|
4
|
+
module V2
|
|
5
|
+
module Storefront
|
|
6
|
+
module ProductsControllerDecorator
|
|
7
|
+
def scope_includes
|
|
8
|
+
base_includes = super
|
|
9
|
+
|
|
10
|
+
base_includes[:vendor] = { default_state: [] }
|
|
11
|
+
base_includes[:venue] = []
|
|
12
|
+
base_includes[:variants_including_master] = { prices: [] }
|
|
13
|
+
|
|
14
|
+
%i[master variants variants_including_master].each do |key|
|
|
15
|
+
base_includes[key][:stock_items] = :stock_location if base_includes[key]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
base_includes
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Spree::Api::V2::Storefront::ProductsController
|
|
27
|
+
.prepend Spree::Api::V2::Storefront::ProductsControllerDecorator
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V2
|
|
4
|
+
module Storefront
|
|
5
|
+
module TaxonsControllerDecorator
|
|
6
|
+
def resource
|
|
7
|
+
@resource ||= begin
|
|
8
|
+
taxon = scope.find_by(permalink: params[:id]) || scope.find(params[:id])
|
|
9
|
+
|
|
10
|
+
if action_name == 'show' && should_include_products?
|
|
11
|
+
taxon.products = taxon.products
|
|
12
|
+
.includes(product_includes_for_show)
|
|
13
|
+
.order('spree_products_taxons.position ASC')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if action_name == 'show' && should_include_visible_products?
|
|
17
|
+
taxon.visible_products = taxon.visible_products
|
|
18
|
+
.includes(product_includes_for_show)
|
|
19
|
+
.order('spree_products_taxons.position ASC')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
taxon
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
def scope(skip_cancancan: false)
|
|
29
|
+
base_scope = super(skip_cancancan: skip_cancancan)
|
|
30
|
+
base_scope = base_scope.includes(asset_includes) if action_name == 'show'
|
|
31
|
+
base_scope
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def should_include_products?
|
|
37
|
+
params[:include]&.include?('products')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def should_include_visible_products?
|
|
41
|
+
params[:include]&.include?('visible_products')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def product_includes_for_show
|
|
45
|
+
{
|
|
46
|
+
product_properties: [],
|
|
47
|
+
option_types: [],
|
|
48
|
+
variant_images: [],
|
|
49
|
+
classifications: :taxon,
|
|
50
|
+
variants_including_master: product_variant_includes,
|
|
51
|
+
master: product_variant_includes,
|
|
52
|
+
variants: product_variant_includes,
|
|
53
|
+
vendor: { default_state: [] },
|
|
54
|
+
venue: []
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def product_variant_includes
|
|
59
|
+
{
|
|
60
|
+
prices: [],
|
|
61
|
+
option_values: :option_type,
|
|
62
|
+
images: [],
|
|
63
|
+
stock_items: :stock_location
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def asset_includes
|
|
68
|
+
{
|
|
69
|
+
category_icon: { attachment_attachment: :blob },
|
|
70
|
+
app_banner: { attachment_attachment: :blob },
|
|
71
|
+
web_banner: { attachment_attachment: :blob },
|
|
72
|
+
home_banner: { attachment_attachment: :blob },
|
|
73
|
+
video_banner: { attachment_attachment: :blob },
|
|
74
|
+
children: {
|
|
75
|
+
icon: { attachment_attachment: :blob },
|
|
76
|
+
category_icon: { attachment_attachment: :blob },
|
|
77
|
+
app_banner: { attachment_attachment: :blob },
|
|
78
|
+
web_banner: { attachment_attachment: :blob },
|
|
79
|
+
home_banner: { attachment_attachment: :blob },
|
|
80
|
+
video_banner: { attachment_attachment: :blob }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
Spree::Api::V2::Storefront::TaxonsController.prepend(
|
|
91
|
+
Spree::Api::V2::Storefront::TaxonsControllerDecorator
|
|
92
|
+
)
|
|
@@ -13,8 +13,6 @@ module SpreeCmCommissioner
|
|
|
13
13
|
def after_sign_in_path_for(_)
|
|
14
14
|
if spree_current_user.admin?
|
|
15
15
|
admin_path
|
|
16
|
-
elsif spree_current_user.organizer? && spree_current_user.events.present?
|
|
17
|
-
event_guests_path(spree_current_user.events.first.slug)
|
|
18
16
|
else
|
|
19
17
|
'/'
|
|
20
18
|
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module LineItems
|
|
3
|
+
class SyncEventDateJob < ApplicationJob
|
|
4
|
+
def perform(options = {})
|
|
5
|
+
event = Spree::Taxon.event.find(options[:event_id])
|
|
6
|
+
SpreeCmCommissioner::LineItems::SyncEventDate.call(event: event)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -52,30 +52,37 @@ module SpreeCmCommissioner
|
|
|
52
52
|
self.event_id ||= product.event_id
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
55
|
+
# Calculates line item duration with priority:
|
|
56
|
+
# - Date: variant date > event date > user input (from_date/to_date)
|
|
57
|
+
# - Time: always uses variant time configuration
|
|
58
|
+
#
|
|
59
|
+
# The variant date takes highest priority. If variant has no date configured,
|
|
60
|
+
# falls back to event date, then to user-provided date.
|
|
61
|
+
#
|
|
62
|
+
# Examples:
|
|
63
|
+
# 1. Variant has full date/time config:
|
|
64
|
+
# Variant: 2024-01-15 14:00 to 2024-01-16 18:00
|
|
65
|
+
# Event: 2024-07-20, User: 2024-06-15
|
|
66
|
+
# → Result: 2024-01-15 14:00 to 2024-01-16 18:00 (variant wins)
|
|
67
|
+
#
|
|
68
|
+
# 2. Variant has only time, event provides date:
|
|
69
|
+
# Variant: 14:00 (3 hours duration)
|
|
70
|
+
# Event: 2024-07-20, User: 2024-06-15
|
|
71
|
+
# → Result: 2024-07-20 14:00 to 2024-07-20 17:00 (event date + variant time)
|
|
72
|
+
#
|
|
73
|
+
# 3. Variant has only time, no event, user provides date:
|
|
74
|
+
# Variant: 14:00 (3 hours duration)
|
|
75
|
+
# No event, User: 2024-06-15
|
|
76
|
+
# → Result: 2024-06-15 14:00 to 2024-06-15 17:00 (user date + variant time)
|
|
58
77
|
def set_duration
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def apply_variant_time(field, variant_time)
|
|
69
|
-
field_value = send(field)
|
|
70
|
-
|
|
71
|
-
return unless field_value.present? && field_value.hour.zero? && variant_time.present?
|
|
72
|
-
|
|
73
|
-
send("#{field}=", field_value.change(
|
|
74
|
-
hour: variant_time.hour,
|
|
75
|
-
min: variant_time.min,
|
|
76
|
-
sec: variant_time.sec
|
|
77
|
-
)
|
|
78
|
-
)
|
|
78
|
+
# Prepare fallback dates: event date > user input
|
|
79
|
+
base_start_date = event&.from_date || from_date
|
|
80
|
+
base_end_date = event&.to_date || to_date
|
|
81
|
+
|
|
82
|
+
# Variant will use its own date if configured, otherwise uses base_*_date
|
|
83
|
+
# Variant time is always applied to the final date
|
|
84
|
+
self.from_date = variant.start_date_time(start_date: base_start_date)
|
|
85
|
+
self.to_date = variant.end_date_time(start_date: base_start_date, end_date: base_end_date)
|
|
79
86
|
end
|
|
80
87
|
end
|
|
81
88
|
end
|
|
@@ -53,9 +53,28 @@ module SpreeCmCommissioner
|
|
|
53
53
|
option_values.detect { |o| o.option_type.name.downcase.strip == option_type_name.downcase.strip }.try(:name)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
|
|
56
|
+
# Determines the start date/time with priority:
|
|
57
|
+
# - Date priority: variant date > event date > user input date
|
|
58
|
+
# - Time: always uses variant time (if configured)
|
|
59
|
+
#
|
|
60
|
+
# Examples:
|
|
61
|
+
# 1. Variant date takes priority:
|
|
62
|
+
# Variant: 2024-01-15, Event: 2024-02-20, User: 2024-03-10, Variant time: 14:00
|
|
63
|
+
# → Returns "2024-01-15 14:00:00" (variant date + variant time)
|
|
64
|
+
#
|
|
65
|
+
# 2. Event date used when variant has no date:
|
|
66
|
+
# Variant: only time (14:00), Event: 2024-02-20, User: 2024-03-10
|
|
67
|
+
# → Returns "2024-02-20 14:00:00" (event date + variant time)
|
|
68
|
+
#
|
|
69
|
+
# 3. User date used when no variant/event date:
|
|
70
|
+
# Variant: only time (14:00), No event, User: 2024-03-10
|
|
71
|
+
# → Returns "2024-03-10 14:00:00" (user date + variant time)
|
|
72
|
+
#
|
|
73
|
+
# Note: No need to fallback to event start date to avoid n+1.
|
|
74
|
+
# To get start_time duration of event, include event when needed instead.
|
|
75
|
+
def start_date_time(start_date: nil)
|
|
76
|
+
start_date = self.start_date if self.start_date.present?
|
|
77
|
+
|
|
59
78
|
return nil if start_date.blank? && start_time.blank?
|
|
60
79
|
return start_date if start_time.blank?
|
|
61
80
|
return start_time if start_date.blank?
|
|
@@ -63,9 +82,29 @@ module SpreeCmCommissioner
|
|
|
63
82
|
start_date.change(hour: start_time.hour, min: start_time.min, sec: start_time.sec)
|
|
64
83
|
end
|
|
65
84
|
|
|
66
|
-
#
|
|
85
|
+
# Determines the end date/time with priority:
|
|
86
|
+
# - Date priority: variant date > event date > user input date
|
|
87
|
+
# - Time: always uses variant time (if configured) or calculated from duration
|
|
88
|
+
#
|
|
89
|
+
# Examples:
|
|
90
|
+
# 1. Explicit variant end_date:
|
|
91
|
+
# Variant: end_date = 2024-01-20, end_time = 18:00, Event: 2024-02-25
|
|
92
|
+
# → Returns "2024-01-20 18:00:00" (variant date + variant time)
|
|
93
|
+
#
|
|
94
|
+
# 2. Duration-based calculation (no explicit end_date):
|
|
95
|
+
# Variant: start_date = 2024-01-15, start_time = 14:00, duration = 3 hours
|
|
96
|
+
# → Returns "2024-01-15 17:00:00" (start + duration)
|
|
97
|
+
#
|
|
98
|
+
# 3. Event date when variant has no date but has time:
|
|
99
|
+
# Variant: only end_time (18:00), Event: 2024-02-20
|
|
100
|
+
# → Returns "2024-02-20 18:00:00" (event date + variant time)
|
|
101
|
+
#
|
|
102
|
+
# Note: No need to fallback to event end date to avoid n+1.
|
|
67
103
|
# To get end_time duration of event, include event when needed instead.
|
|
68
|
-
def end_date_time
|
|
104
|
+
def end_date_time(start_date: nil, end_date: nil)
|
|
105
|
+
start_date = self.start_date if self.start_date.present?
|
|
106
|
+
end_date = self.end_date(start_date: start_date) if self.end_date(start_date: start_date).present?
|
|
107
|
+
|
|
69
108
|
return nil if end_date.blank? && end_time.blank?
|
|
70
109
|
return end_date if end_time.blank?
|
|
71
110
|
return end_time if end_date.blank?
|
|
@@ -73,7 +112,9 @@ module SpreeCmCommissioner
|
|
|
73
112
|
end_date.change(hour: end_time.hour, min: end_time.min, sec: end_time.sec)
|
|
74
113
|
end
|
|
75
114
|
|
|
76
|
-
def end_date
|
|
115
|
+
def end_date(start_date: nil)
|
|
116
|
+
start_date = self.start_date if self.start_date.present?
|
|
117
|
+
|
|
77
118
|
return start_date + options.total_duration_in_seconds.seconds if start_date.present? && options.total_duration_in_seconds.positive?
|
|
78
119
|
|
|
79
120
|
options.end_date
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Stock
|
|
3
|
+
module QuantifierDecorator
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def scope_to_location(collection)
|
|
7
|
+
# If stock_items are already loaded (preloaded via includes), filter in memory
|
|
8
|
+
if collection.loaded?
|
|
9
|
+
if stock_location.blank?
|
|
10
|
+
# Filter to only active stock locations in memory
|
|
11
|
+
collection.select { |si| si.stock_location&.active? }
|
|
12
|
+
else
|
|
13
|
+
collection.select { |si| si.stock_location_id == stock_location.id }
|
|
14
|
+
end
|
|
15
|
+
else
|
|
16
|
+
# Fall back to original behavior if not preloaded
|
|
17
|
+
return collection.with_active_stock_location if stock_location.blank?
|
|
18
|
+
|
|
19
|
+
collection.where(stock_location: stock_location)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Spree::Stock::Quantifier.prepend Spree::Stock::QuantifierDecorator
|
|
@@ -446,15 +446,15 @@ module SpreeCmCommissioner
|
|
|
446
446
|
end
|
|
447
447
|
|
|
448
448
|
def pre_registration_fields?
|
|
449
|
-
line_item&.product&.dynamic_fields&.pre_registration&.any?
|
|
449
|
+
line_item&.product&.dynamic_fields&.select(&:pre_registration?)&.any?
|
|
450
450
|
end
|
|
451
451
|
|
|
452
452
|
def post_registration_fields?
|
|
453
|
-
line_item&.product&.dynamic_fields&.post_registration&.any?
|
|
453
|
+
line_item&.product&.dynamic_fields&.select(&:post_registration?)&.any?
|
|
454
454
|
end
|
|
455
455
|
|
|
456
456
|
def during_check_in_fields?
|
|
457
|
-
line_item&.product&.dynamic_fields&.during_check_in&.any?
|
|
457
|
+
line_item&.product&.dynamic_fields&.select(&:during_check_in?)&.any?
|
|
458
458
|
end
|
|
459
459
|
|
|
460
460
|
def product_dynamic_fields
|
|
@@ -94,6 +94,32 @@ module SpreeCmCommissioner
|
|
|
94
94
|
def base.find_event(id)
|
|
95
95
|
find_by(slug: "events-#{id}")
|
|
96
96
|
end
|
|
97
|
+
|
|
98
|
+
def base.preload_ancestors_for(taxons)
|
|
99
|
+
return taxons if taxons.empty?
|
|
100
|
+
|
|
101
|
+
# Build a single query to fetch all ancestors for all taxons
|
|
102
|
+
conditions = taxons.map do |t|
|
|
103
|
+
sanitize_sql_array(['(lft <= ? AND rgt >= ?)', t.lft, t.rgt])
|
|
104
|
+
end.join(' OR ')
|
|
105
|
+
all_ancestors = where(conditions).distinct.order(:lft).to_a
|
|
106
|
+
|
|
107
|
+
# Store preloaded ancestors for each taxon
|
|
108
|
+
taxons.each do |t|
|
|
109
|
+
taxon_ancestors = all_ancestors.select { |a| a.lft <= t.lft && a.rgt >= t.rgt && a.id != t.id }
|
|
110
|
+
t.instance_variable_set(:@preloaded_ancestors, taxon_ancestors)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
taxons
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def pretty_name
|
|
118
|
+
ancestor_chain = @preloaded_ancestors || ancestors
|
|
119
|
+
ancestor_chain = ancestor_chain.inject('') do |chain, ancestor|
|
|
120
|
+
chain + "#{ancestor.name} -> "
|
|
121
|
+
end
|
|
122
|
+
ancestor_chain + name.to_s
|
|
97
123
|
end
|
|
98
124
|
|
|
99
125
|
def set_kind
|
|
@@ -136,7 +162,7 @@ module SpreeCmCommissioner
|
|
|
136
162
|
def sync_event_dates_to_line_items
|
|
137
163
|
return unless event? && depth == 1
|
|
138
164
|
|
|
139
|
-
::SpreeCmCommissioner::
|
|
165
|
+
::SpreeCmCommissioner::LineItems::SyncEventDateJob.perform_later(event_id: id)
|
|
140
166
|
end
|
|
141
167
|
|
|
142
168
|
private
|
|
@@ -2,24 +2,52 @@ module Spree
|
|
|
2
2
|
module V2
|
|
3
3
|
module Storefront
|
|
4
4
|
module ProductSerializerDecorator
|
|
5
|
-
def self.prepended(base)
|
|
5
|
+
def self.prepended(base)
|
|
6
|
+
add_option_type_associations(base)
|
|
7
|
+
add_promotion_associations(base)
|
|
8
|
+
add_dynamic_field_associations(base)
|
|
9
|
+
add_taxon_associations(base)
|
|
10
|
+
add_basic_attributes(base)
|
|
11
|
+
add_custom_attributes(base)
|
|
12
|
+
add_cache_and_action_button(base)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.add_option_type_associations(base)
|
|
6
16
|
base.has_many :variant_kind_option_types, serializer: :option_type
|
|
7
17
|
base.has_many :product_kind_option_types, serializer: :option_type
|
|
8
18
|
base.has_many :promoted_option_types, serializer: :option_type
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.add_promotion_associations(base)
|
|
9
22
|
base.has_many :possible_promotions, serializer: ::SpreeCmCommissioner::V2::Storefront::PromotionSerializer
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.add_dynamic_field_associations(base)
|
|
10
26
|
base.has_many :dynamic_fields, serializer: SpreeCmCommissioner::V2::Storefront::DynamicFieldSerializer
|
|
27
|
+
end
|
|
11
28
|
|
|
29
|
+
def self.add_taxon_associations(base)
|
|
30
|
+
base.has_many :taxons, serializer: :taxon, record_type: :taxon do |object, params|
|
|
31
|
+
filter_store_taxons(object, params)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.filter_store_taxons(object, params)
|
|
36
|
+
object.classifications
|
|
37
|
+
.map(&:taxon)
|
|
38
|
+
.select { |taxon| taxon.taxonomy&.store_id == params[:store]&.id }
|
|
39
|
+
.sort_by(&:id)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.add_basic_attributes(base)
|
|
12
43
|
base.has_one :default_state, serializer: :state
|
|
13
44
|
base.has_one :venue, serializer: ::SpreeCmCommissioner::V2::Storefront::ProductPlaceSerializer
|
|
14
|
-
|
|
15
45
|
base.attributes :need_confirmation, :product_type, :kyc, :kyc_fields, :allowed_upload_later, :allow_anonymous_booking, :use_video_as_default
|
|
16
46
|
base.attributes :reveal_description, :discontinue_on, :public_metadata, :purchasable_on
|
|
17
|
-
|
|
18
|
-
# Expose only the `event_id` here instead of the full event object.
|
|
19
|
-
# This lets the client fetch event details separately (usually already cached),
|
|
20
|
-
# avoids extra DB queries from a `has_one :event` association, and keeps this response lightweight.
|
|
21
47
|
base.attributes :event_id
|
|
48
|
+
end
|
|
22
49
|
|
|
50
|
+
def self.add_custom_attributes(base)
|
|
23
51
|
base.attribute :purchasable_on_app do |product|
|
|
24
52
|
product.purchasable_on == 'app' || product.purchasable_on == 'both'
|
|
25
53
|
end
|
|
@@ -47,9 +75,10 @@ module Spree
|
|
|
47
75
|
value = product.available?
|
|
48
76
|
[true, false].include?(value) ? value : nil
|
|
49
77
|
end
|
|
78
|
+
end
|
|
50
79
|
|
|
80
|
+
def self.add_cache_and_action_button(base)
|
|
51
81
|
base.cache_options store: nil
|
|
52
|
-
|
|
53
82
|
base.attribute :action_button, &:action_button
|
|
54
83
|
end
|
|
55
84
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module LineItems
|
|
3
|
+
class SyncEventDate
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(event:)
|
|
7
|
+
return failure(:invalid_event_kind) unless event.event?
|
|
8
|
+
return failure(:invalid_event_depth) unless event.depth == 1
|
|
9
|
+
|
|
10
|
+
event.event_line_items.includes(:variant).find_each do |line_item|
|
|
11
|
+
line_item.send(:set_duration)
|
|
12
|
+
|
|
13
|
+
# Update could be failed here if case line item does not allowed to change or no longer available.
|
|
14
|
+
# We can ignore this line item in this case.
|
|
15
|
+
line_item.save if line_item.from_date_changed? || line_item.to_date_changed?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
success(nil)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|