spree_cm_commissioner 2.5.14 → 2.5.15
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/concerns/spree/admin/service_calendars_concern.rb +93 -0
- data/app/controllers/spree/admin/product_service_calendars_controller.rb +48 -0
- data/app/controllers/spree/admin/sprite_import_controller.rb +84 -0
- data/app/controllers/spree/admin/taxons_controller_decorator.rb +6 -0
- data/app/controllers/spree/admin/vendor_service_calendars_controller.rb +7 -68
- data/app/helpers/spree_cm_commissioner/admin/homepage_segment_helper.rb +2 -0
- data/app/helpers/spree_cm_commissioner/admin/service_calendars_helper.rb +8 -1
- data/app/models/concerns/spree_cm_commissioner/homepage_section_bitwise.rb +2 -1
- data/app/models/concerns/spree_cm_commissioner/line_item_open_dated_trippable.rb +32 -0
- data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +15 -2
- data/app/models/spree_cm_commissioner/line_item_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/menu_decorator.rb +33 -0
- data/app/models/spree_cm_commissioner/order_decorator.rb +1 -0
- data/app/overrides/spree/admin/menus/edit/add_import_sprite_button.html.erb.deface +94 -0
- data/app/overrides/spree/admin/shared/_product_tabs/service_calendars.html.erb.deface +8 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/menu_serializer_decorator.rb +32 -0
- data/app/services/spree_cm_commissioner/api_caches/invalidate.rb +10 -4
- data/app/services/spree_cm_commissioner/check_ins/create_bulk.rb +2 -2
- data/app/services/spree_cm_commissioner/sprite_data_loader_service.rb +46 -0
- data/app/services/spree_cm_commissioner/sprite_import_service.rb +101 -0
- data/app/services/spree_cm_commissioner/transit_order/create.rb +32 -15
- data/app/services/spree_cm_commissioner/trips/create_open_dated_trip.rb +0 -1
- data/app/views/spree/admin/homepage_background/index.html.erb +1 -0
- data/app/views/spree/admin/product_service_calendars/index.html.erb +70 -0
- data/app/views/spree/admin/product_service_calendars/new.html.erb +9 -0
- data/app/views/spree/admin/{vendor_service_calendars → shared/service_calendars}/_form.html.erb +1 -1
- data/app/views/spree/admin/sprite_import/_auto_fill_script.html.erb +27 -0
- data/app/views/spree/admin/sprite_import/_positions_table.html.erb +42 -0
- data/app/views/spree/admin/sprite_import/edit.html.erb +72 -0
- data/app/views/spree/admin/sprite_import/new.html.erb +72 -0
- data/app/views/spree/admin/sprite_import/show.html.erb +194 -0
- data/app/views/spree/admin/taxon_childrens/index.html.erb +4 -0
- data/app/views/spree/admin/vendor_service_calendars/new.html.erb +2 -2
- data/config/locales/en.yml +2 -0
- data/config/routes.rb +11 -1
- data/db/migrate/20260220041100_add_public_metadata_to_spree_menus.rb +6 -0
- data/docs/sprite_icon_implementation_prompt.md +717 -0
- data/docs/sprite_import_implementation_guide.md +181 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- metadata +24 -4
- /data/app/views/spree/admin/{vendor_service_calendars → shared/service_calendars}/_exception_rules.html.erb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e1489014b8629a83035954b981e4b2e7cdfdcb70159c2e871e9152c3916668ae
|
|
4
|
+
data.tar.gz: ee0ec5e1f58355695e006f00d7952a09ca379283eab18591bba435d1c535fffb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1f3cafbb00e42a98ec6f80ad52266e476cde61f2d4d6215f80cdc95c7af604c5f754aea35139331a8dcf98ccbc25f43378d94c815732cbc0fa8185ae8373e58a
|
|
7
|
+
data.tar.gz: 6562e8994dde887a43e598a29239ca6e8295967db6bfc0d8fa506ec56a69097ad293f1f83355c8db6db671ad433d3cc07f7009e67688450418c868e9c9de3814
|
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
module ServiceCalendarsConcern
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
new_action.before :set_exception_rules
|
|
8
|
+
|
|
9
|
+
helper 'spree_cm_commissioner/admin/service_calendars'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def update_status
|
|
13
|
+
if @object.update(active: !@object.active)
|
|
14
|
+
flash[:success] = flash_message_for(@object, :successfully_updated)
|
|
15
|
+
else
|
|
16
|
+
flash[:error] = @object.errors.full_messages.to_sentence
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
redirect_to collection_url
|
|
20
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
21
|
+
flash[:error] = e.message
|
|
22
|
+
redirect_to collection_url
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
protected
|
|
26
|
+
|
|
27
|
+
def model_class
|
|
28
|
+
SpreeCmCommissioner::ServiceCalendar
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def object_name
|
|
32
|
+
'spree_cm_commissioner_service_calendars'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def permitted_resource_params
|
|
36
|
+
service_calendar_params = params.require(:spree_cm_commissioner_service_calendar)
|
|
37
|
+
.permit(:calendarable_id, :calendarable_type, :start_date, :end_date,
|
|
38
|
+
:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
|
|
39
|
+
)
|
|
40
|
+
service_calendar_params[:exception_rules] = build_exception_rules(params[:spree_cm_commissioner_service_calendar][:exception_rules])
|
|
41
|
+
service_calendar_params
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def build_exception_rules(exception_rules)
|
|
47
|
+
exception_rules.values.reject! { |rule| rule['from'].blank? || rule['to'].blank? || rule['type'].blank? } || exception_rules.values
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def collection
|
|
51
|
+
load_calendarable
|
|
52
|
+
|
|
53
|
+
@objects = model_class.where(
|
|
54
|
+
calendarable_type: calendarable_type,
|
|
55
|
+
calendarable_id: calendarable_id
|
|
56
|
+
).order(id: :desc)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def set_exception_rules
|
|
60
|
+
@exception_rules = [{ from: DateTime.now, to: DateTime.now, type: 'exclusion', reason: nil }]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def build_resource
|
|
64
|
+
today = Time.zone.today
|
|
65
|
+
model_class.new(start_date: today, end_date: today.next_year(3),
|
|
66
|
+
exception_rules: [{ from: nil, to: nil, type: 'inclusion' }]
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def set_calendarable
|
|
71
|
+
@object.calendarable_type = calendarable_type
|
|
72
|
+
@object.calendarable_id = calendarable_id
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# To be implemented by including controllers
|
|
76
|
+
def load_calendarable
|
|
77
|
+
raise NotImplementedError, 'must implement load_calendarable'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def calendarable
|
|
81
|
+
raise NotImplementedError, 'must implement calendarable'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def calendarable_id
|
|
85
|
+
calendarable.id
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def calendarable_type
|
|
89
|
+
calendarable.class.name
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
class ProductServiceCalendarsController < Spree::Admin::ResourceController
|
|
4
|
+
include Spree::Admin::ServiceCalendarsConcern
|
|
5
|
+
|
|
6
|
+
before_action :load_product
|
|
7
|
+
before_action :ensure_product_type_supports_calendar
|
|
8
|
+
before_action :ensure_product_has_no_calendar, only: %i[new create]
|
|
9
|
+
|
|
10
|
+
create.before :set_calendarable
|
|
11
|
+
update.before :set_calendarable
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def collection_url(options = {})
|
|
16
|
+
admin_product_product_service_calendars_url(options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def load_product
|
|
22
|
+
@product ||= (Spree::Product.find_by(slug: params[:product_id]) || Spree::Product.find_by(id: params[:product_id]))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ensure_product_type_supports_calendar
|
|
26
|
+
return if @product.permanent_stock?
|
|
27
|
+
|
|
28
|
+
flash[:error] = I18n.t('vendor.service_calendars.not_available_for_product_type')
|
|
29
|
+
redirect_to edit_admin_product_url(@product)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def ensure_product_has_no_calendar
|
|
33
|
+
return if @product.service_calendar.blank?
|
|
34
|
+
|
|
35
|
+
flash[:error] = I18n.t('vendor.service_calendars.already_has_calendar')
|
|
36
|
+
redirect_to admin_product_product_service_calendars_url(@product)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def load_calendarable
|
|
40
|
+
load_product
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def calendarable
|
|
44
|
+
@product
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
class SpriteImportController < BaseController
|
|
4
|
+
before_action :load_menu
|
|
5
|
+
before_action :reload_menu_with_attachment, only: [:show]
|
|
6
|
+
before_action :load_sprite_data, only: %i[show new edit create update]
|
|
7
|
+
|
|
8
|
+
def show; end
|
|
9
|
+
|
|
10
|
+
def new; end
|
|
11
|
+
|
|
12
|
+
def edit; end
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
result = sprite_import_service.call
|
|
16
|
+
handle_service_result(result, :new)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update
|
|
20
|
+
result = sprite_import_service.update
|
|
21
|
+
handle_service_result(result, :edit)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def destroy
|
|
25
|
+
@menu.sprite_file.purge if @menu.sprite_file.attached?
|
|
26
|
+
@menu.sprite_positions = {}
|
|
27
|
+
@menu.sprite_padding = 16
|
|
28
|
+
@menu.sprite_gap = 16
|
|
29
|
+
@menu.sprite_icon_size = 64
|
|
30
|
+
@menu.save!
|
|
31
|
+
flash[:success] = 'Sprite removed successfully!' # rubocop:disable Rails/I18nLocaleTexts
|
|
32
|
+
redirect_to spree.admin_menu_sprite_import_path(@menu)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def load_menu
|
|
38
|
+
@menu = Spree::Menu.find(params[:menu_id])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def reload_menu_with_attachment
|
|
42
|
+
data_loader = sprite_data_loader_service
|
|
43
|
+
result = data_loader.reload_menu_with_attachment
|
|
44
|
+
@menu = result[:menu]
|
|
45
|
+
@sprite_url = result[:sprite_url]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def load_sprite_data
|
|
49
|
+
data_loader = sprite_data_loader_service
|
|
50
|
+
sprite_data = data_loader.load_sprite_data
|
|
51
|
+
@menu_items = sprite_data[:menu_items]
|
|
52
|
+
@existing_positions = sprite_data[:existing_positions]
|
|
53
|
+
@sprite_url = sprite_data[:sprite_url] if sprite_data[:sprite_url]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def sprite_import_service
|
|
57
|
+
SpreeCmCommissioner::SpriteImportService.new(
|
|
58
|
+
menu: @menu,
|
|
59
|
+
sprite_file: params[:sprite_file],
|
|
60
|
+
sprite_settings: {
|
|
61
|
+
padding: params[:sprite_padding],
|
|
62
|
+
gap: params[:sprite_gap],
|
|
63
|
+
icon_size: params[:sprite_icon_size]
|
|
64
|
+
},
|
|
65
|
+
positions_params: params[:positions]
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def sprite_data_loader_service
|
|
70
|
+
SpreeCmCommissioner::SpriteDataLoaderService.new(@menu)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def handle_service_result(result, render_action)
|
|
74
|
+
if result.success?
|
|
75
|
+
flash[:success] = result.value[:message]
|
|
76
|
+
redirect_to spree.admin_menu_sprite_import_path(@menu)
|
|
77
|
+
else
|
|
78
|
+
flash[:error] = result.value
|
|
79
|
+
render render_action
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -5,6 +5,12 @@ module Spree
|
|
|
5
5
|
base.before_action :build_assets, only: %i[create update]
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
# override
|
|
9
|
+
def new
|
|
10
|
+
@taxon.parent_id = params[:parent_id] if params[:parent_id].present?
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
8
14
|
def remove_category_icon
|
|
9
15
|
remove_asset(@taxon.category_icon)
|
|
10
16
|
end
|
|
@@ -1,92 +1,31 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
module Admin
|
|
3
3
|
class VendorServiceCalendarsController < Spree::Admin::ResourceController
|
|
4
|
-
|
|
5
|
-
new_action.before :set_exception_rules
|
|
6
|
-
|
|
7
|
-
create.before :set_vendor
|
|
8
|
-
update.before :set_vendor
|
|
9
|
-
|
|
10
|
-
helper 'spree_cm_commissioner/admin/service_calendars'
|
|
4
|
+
include Spree::Admin::ServiceCalendarsConcern
|
|
11
5
|
|
|
12
|
-
|
|
13
|
-
if @object.update(active: !@object.active)
|
|
14
|
-
flash[:success] = flash_message_for(@object, :successfully_updated)
|
|
15
|
-
else
|
|
16
|
-
flash[:error] = @object.errors.full_messages.to_sentence
|
|
17
|
-
end
|
|
6
|
+
before_action :load_vendor
|
|
18
7
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
flash[:error] = e.message
|
|
22
|
-
redirect_to admin_vendor_vendor_service_calendars_url
|
|
23
|
-
end
|
|
8
|
+
create.before :set_calendarable
|
|
9
|
+
update.before :set_calendarable
|
|
24
10
|
|
|
25
11
|
protected
|
|
26
12
|
|
|
27
|
-
def model_class
|
|
28
|
-
SpreeCmCommissioner::ServiceCalendar
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def object_name
|
|
32
|
-
'spree_cm_commissioner_service_calendars'
|
|
33
|
-
end
|
|
34
|
-
|
|
35
13
|
def collection_url(options = {})
|
|
36
14
|
admin_vendor_vendor_service_calendars_url(options)
|
|
37
15
|
end
|
|
38
16
|
|
|
39
|
-
def permitted_resource_params
|
|
40
|
-
service_calendar_params = params.require(:spree_cm_commissioner_service_calendar)
|
|
41
|
-
.permit(:calendarable_id, :calendarable_type, :start_date, :end_date,
|
|
42
|
-
:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
|
|
43
|
-
)
|
|
44
|
-
service_calendar_params[:exception_rules] = build_exception_rules(params[:spree_cm_commissioner_service_calendar][:exception_rules])
|
|
45
|
-
service_calendar_params
|
|
46
|
-
end
|
|
47
|
-
|
|
48
17
|
private
|
|
49
18
|
|
|
50
19
|
def load_vendor
|
|
51
20
|
@vendor ||= (Spree::Vendor.find_by(slug: params[:vendor_id]) || Spree::Vendor.find_by(id: params[:vendor_id]))
|
|
52
21
|
end
|
|
53
22
|
|
|
54
|
-
def
|
|
55
|
-
@object.calendarable_type = calendarable_type
|
|
56
|
-
@object.calendarable_id = calendarable_id
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def build_exception_rules(exception_rules)
|
|
60
|
-
exception_rules.values.reject! { |rule| rule['from'].blank? || rule['to'].blank? || rule['type'].blank? } || exception_rules.values
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def collection
|
|
23
|
+
def load_calendarable
|
|
64
24
|
load_vendor
|
|
65
|
-
|
|
66
|
-
@objects = model_class.where(
|
|
67
|
-
calendarable_type: calendarable_type,
|
|
68
|
-
calendarable_id: calendarable_id
|
|
69
|
-
).order(id: :desc)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def set_exception_rules
|
|
73
|
-
@exception_rules = [{ from: DateTime.now, to: DateTime.now, type: 'exclusion', reason: nil }]
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# it load before :load_vendor
|
|
77
|
-
def build_resource
|
|
78
|
-
today = Time.zone.today
|
|
79
|
-
model_class.new(start_date: today, end_date: today.next_year(3),
|
|
80
|
-
exception_rules: [{ from: nil, to: nil, type: 'inclusion' }]
|
|
81
|
-
)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def calendarable_id
|
|
85
|
-
@vendor.id
|
|
86
25
|
end
|
|
87
26
|
|
|
88
|
-
def
|
|
89
|
-
@vendor
|
|
27
|
+
def calendarable
|
|
28
|
+
@vendor
|
|
90
29
|
end
|
|
91
30
|
end
|
|
92
31
|
end
|
|
@@ -5,9 +5,16 @@ module SpreeCmCommissioner
|
|
|
5
5
|
label = resource.active ? 'Active' : 'Disabled'
|
|
6
6
|
btn_active_class = resource.active ? 'btn-primary' : 'btn-warning'
|
|
7
7
|
|
|
8
|
+
# Determine the correct URL based on the calendarable type
|
|
9
|
+
url = if resource.calendarable_type == 'Spree::Product'
|
|
10
|
+
update_status_admin_product_product_service_calendar_path(resource.calendarable, resource)
|
|
11
|
+
else
|
|
12
|
+
update_status_admin_vendor_vendor_service_calendar_url(resource.calendarable, resource)
|
|
13
|
+
end
|
|
14
|
+
|
|
8
15
|
button_to(
|
|
9
16
|
label,
|
|
10
|
-
|
|
17
|
+
url,
|
|
11
18
|
form: { data: { confirm: 'Are you sure?' }, class: "btn btn-sm btn-active #{btn_active_class}" },
|
|
12
19
|
method: :patch
|
|
13
20
|
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module LineItemOpenDatedTrippable
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
include SpreeCmCommissioner::StoreMetadata
|
|
7
|
+
|
|
8
|
+
# Open dated trip metadata
|
|
9
|
+
store_public_metadata :is_open_dated, :boolean, default: false
|
|
10
|
+
store_public_metadata :redeemed_trip_id, :integer # Which trip chosen for redemption
|
|
11
|
+
|
|
12
|
+
# Alias existing columns for better semantic meaning
|
|
13
|
+
alias_attribute :valid_until, :to_date # Expiration date
|
|
14
|
+
alias_attribute :redeemed_at, :accepted_at # Redemption timestamp
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Check if ticket has been redeemed
|
|
18
|
+
def redeemed?
|
|
19
|
+
redeemed_at.present?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Check if ticket is expired
|
|
23
|
+
def expired?
|
|
24
|
+
valid_until.present? && valid_until.to_date < Date.current
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Check if ticket can be redeemed
|
|
28
|
+
def can_redeem?
|
|
29
|
+
is_open_dated? && !redeemed? && !expired?
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -25,10 +25,10 @@ module SpreeCmCommissioner
|
|
|
25
25
|
included do
|
|
26
26
|
validates :direction, inclusion: { in: DIRECTION }, allow_nil: true
|
|
27
27
|
validates :trip_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
|
28
|
-
validates :boarding_trip_stop_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
|
29
|
-
validates :drop_off_trip_stop_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
|
30
28
|
validates :service_origin_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
|
31
29
|
|
|
30
|
+
validate :validate_trip_stops_for_scheduled_trips
|
|
31
|
+
|
|
32
32
|
validates :passenger_count, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
|
33
33
|
|
|
34
34
|
# Groups LineItems by trip fields. Some fields can be null,
|
|
@@ -125,6 +125,19 @@ module SpreeCmCommissioner
|
|
|
125
125
|
|
|
126
126
|
private
|
|
127
127
|
|
|
128
|
+
def validate_trip_stops_for_scheduled_trips
|
|
129
|
+
return if trip_id.blank? || trip_id.zero?
|
|
130
|
+
|
|
131
|
+
trip = SpreeCmCommissioner::Trip.find_by(id: trip_id)
|
|
132
|
+
return unless trip # Skip if trip doesn't exist (will be caught by other validations)
|
|
133
|
+
return if trip.open_dated? # Skip validation for open-dated trips
|
|
134
|
+
|
|
135
|
+
# For scheduled trips, require valid trip stops
|
|
136
|
+
errors.add(:boarding_trip_stop_id, 'must be greater than 0') if boarding_trip_stop_id.present? && boarding_trip_stop_id <= 0
|
|
137
|
+
|
|
138
|
+
errors.add(:drop_off_trip_stop_id, 'must be greater than 0') if drop_off_trip_stop_id.present? && drop_off_trip_stop_id <= 0
|
|
139
|
+
end
|
|
140
|
+
|
|
128
141
|
def set_public_metadata_object(key, value)
|
|
129
142
|
if value.nil?
|
|
130
143
|
public_metadata.delete(key)
|
|
@@ -80,6 +80,7 @@ module SpreeCmCommissioner
|
|
|
80
80
|
base.include SpreeCmCommissioner::Integrations::IntegrationMappable
|
|
81
81
|
base.include SpreeCmCommissioner::ProductType
|
|
82
82
|
base.include SpreeCmCommissioner::ProductDelegation
|
|
83
|
+
base.include SpreeCmCommissioner::LineItemOpenDatedTrippable
|
|
83
84
|
base.include SpreeCmCommissioner::KycBitwise
|
|
84
85
|
end
|
|
85
86
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module MenuDecorator
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
include SpreeCmCommissioner::StoreMetadata
|
|
7
|
+
|
|
8
|
+
store_public_metadata :sprite_positions, :hash, default: {}
|
|
9
|
+
store_public_metadata :sprite_padding, :integer, default: 16
|
|
10
|
+
store_public_metadata :sprite_gap, :integer, default: 16
|
|
11
|
+
store_public_metadata :sprite_icon_size, :integer, default: 64
|
|
12
|
+
|
|
13
|
+
has_one_attached :sprite_file
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def get_sprite_position(menu_item_id)
|
|
17
|
+
pos = sprite_positions[menu_item_id.to_s] || { 'x' => 0, 'y' => 0, 'width' => 64, 'height' => 64 }
|
|
18
|
+
pos.with_indifferent_access
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def update_sprite_positions(positions_hash)
|
|
22
|
+
self.sprite_positions = positions_hash
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def sprite_url
|
|
26
|
+
return nil unless sprite_file.attached?
|
|
27
|
+
|
|
28
|
+
Rails.application.routes.url_helpers.cdn_image_url(sprite_file)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Spree::Menu.include SpreeCmCommissioner::MenuDecorator unless Spree::Menu.included_modules.include?(SpreeCmCommissioner::MenuDecorator)
|
|
@@ -15,6 +15,7 @@ module SpreeCmCommissioner
|
|
|
15
15
|
base.after_commit :increment_route_order_count, on: :create
|
|
16
16
|
|
|
17
17
|
base.store_private_metadata :preload_trip_ids, :array, default: []
|
|
18
|
+
base.store_public_metadata :order_options, :array, default: []
|
|
18
19
|
|
|
19
20
|
base.validates :promo_total, base::MONEY_VALIDATION
|
|
20
21
|
base.validate :validate_channel_prefix, if: :channel_changed?
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<!-- insert_before "h5:contains('settings')" -->
|
|
2
|
+
<%
|
|
3
|
+
sprite_attached = @menu.respond_to?(:sprite_file) && @menu.sprite_file.attached?
|
|
4
|
+
sprite_url = @menu.respond_to?(:sprite_url) ? @menu.sprite_url : nil
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<div data-hook="sprite_management" class="card mb-3">
|
|
8
|
+
<div class="card-header">
|
|
9
|
+
<div class="row">
|
|
10
|
+
<div class="col d-flex">
|
|
11
|
+
<h5 class="mb-0 align-self-center">Sprite Management</h5>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="col d-flex justify-content-end">
|
|
14
|
+
<% if sprite_attached %>
|
|
15
|
+
<%= link_to spree.admin_menu_sprite_import_path(@menu), class: 'btn btn-outline-secondary align-self-center mr-2' do %>
|
|
16
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
|
17
|
+
View Sprite
|
|
18
|
+
<% end %>
|
|
19
|
+
<% end %>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="card-body">
|
|
25
|
+
<% if sprite_attached %>
|
|
26
|
+
<div class="row">
|
|
27
|
+
<div class="col-md-7">
|
|
28
|
+
<div class="card bg-light border-0">
|
|
29
|
+
<div class="card-body py-3">
|
|
30
|
+
<div class="row">
|
|
31
|
+
<div class="col-sm-6">
|
|
32
|
+
<dl class="mb-0">
|
|
33
|
+
<dt class="text-muted small text-uppercase">File</dt>
|
|
34
|
+
<dd class="mb-2"><%= @menu.sprite_file.filename %></dd>
|
|
35
|
+
|
|
36
|
+
<dt class="text-muted small text-uppercase">File Size</dt>
|
|
37
|
+
<dd class="mb-0"><%= number_to_human_size(@menu.sprite_file.byte_size) %></dd>
|
|
38
|
+
</dl>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="col-sm-6">
|
|
41
|
+
<dl class="mb-0">
|
|
42
|
+
<dt class="text-muted small text-uppercase">Icon Size</dt>
|
|
43
|
+
<dd class="mb-2"><%= @menu.sprite_icon_size || 64 %> x <%= @menu.sprite_icon_size || 64 %> px</dd>
|
|
44
|
+
|
|
45
|
+
<dt class="text-muted small text-uppercase">Total Icons</dt>
|
|
46
|
+
<dd class="mb-0">
|
|
47
|
+
<span class="badge badge-info" style="font-size: 0.85em;"><%= @menu.total_icons %></span>
|
|
48
|
+
</dd>
|
|
49
|
+
</dl>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="mt-2 pt-2 border-top">
|
|
53
|
+
<small class="text-muted">
|
|
54
|
+
Last updated: <%= @menu.sprite_file.created_at.strftime("%b %d, %Y at %H:%M") if @menu.sprite_file.created_at %>
|
|
55
|
+
</small>
|
|
56
|
+
</div>
|
|
57
|
+
<% if sprite_url %>
|
|
58
|
+
<div class="mt-1">
|
|
59
|
+
<small class="text-muted text-break" style="font-size: 0.75em; word-break: break-all;">CDN: <%= sprite_url %></small>
|
|
60
|
+
</div>
|
|
61
|
+
<% end %>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="col-md-5">
|
|
66
|
+
<div class="card border-0 bg-light h-100">
|
|
67
|
+
<div class="card-body d-flex align-items-center justify-content-center p-3">
|
|
68
|
+
<% if sprite_url %>
|
|
69
|
+
<%= image_tag sprite_url, class: "img-fluid", style: "max-height: 180px; border-radius: 4px;" %>
|
|
70
|
+
<% else %>
|
|
71
|
+
<span class="text-muted">No preview available</span>
|
|
72
|
+
<% end %>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<% else %>
|
|
78
|
+
<div class="text-center py-5">
|
|
79
|
+
<div class="mb-3">
|
|
80
|
+
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#adb5bd" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
81
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
|
|
82
|
+
<circle cx="8.5" cy="8.5" r="1.5"/>
|
|
83
|
+
<polyline points="21 15 16 10 5 21"/>
|
|
84
|
+
</svg>
|
|
85
|
+
</div>
|
|
86
|
+
<h5>No Sprite Imported Yet</h5>
|
|
87
|
+
<p class="text-muted mb-4" style="max-width: 360px; margin: 0 auto;">
|
|
88
|
+
Import a sprite sheet to serve all menu icons in a single optimized image.
|
|
89
|
+
</p>
|
|
90
|
+
<%= link_to "Import Sprite", spree.new_admin_menu_sprite_import_path(@menu), class: "btn btn-primary" %>
|
|
91
|
+
</div>
|
|
92
|
+
<% end %>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!-- insert_after "erb[loud]:contains('current == :stock')" -->
|
|
2
|
+
|
|
3
|
+
<%= content_tag :li, class: 'nav-item' do %>
|
|
4
|
+
<%= link_to_with_icon 'calendar.svg',
|
|
5
|
+
t('vendor.service_calendars.service_calendar'),
|
|
6
|
+
admin_product_product_service_calendars_path(@product),
|
|
7
|
+
class: "nav-link #{'active' if current == :service_calendars}" %>
|
|
8
|
+
<% end if can?(:create, SpreeCmCommissioner::ServiceCalendar) && !@product.deleted? && @product.permanent_stock? %>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module V2
|
|
3
|
+
module Storefront
|
|
4
|
+
module MenuSerializerDecorator
|
|
5
|
+
def self.prepended(base)
|
|
6
|
+
base.attributes :sprite_url
|
|
7
|
+
|
|
8
|
+
base.attribute :icon_positions do |menu|
|
|
9
|
+
positions = menu.sprite_positions || {}
|
|
10
|
+
ordered_items = menu.menu_items.where.not(parent_id: nil).order(:lft)
|
|
11
|
+
ordered_items.each_with_object({}) do |item, hash|
|
|
12
|
+
id = item.id.to_s
|
|
13
|
+
next unless positions.key?(id)
|
|
14
|
+
|
|
15
|
+
pos = positions[id]
|
|
16
|
+
hash[id] = {
|
|
17
|
+
'x' => pos['x'],
|
|
18
|
+
'y' => pos['y'],
|
|
19
|
+
'width' => pos['width'],
|
|
20
|
+
'height' => pos['height']
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if Spree::V2::Storefront::MenuSerializer.included_modules.exclude?(SpreeCmCommissioner::V2::Storefront::MenuSerializerDecorator)
|
|
31
|
+
Spree::V2::Storefront::MenuSerializer.prepend(SpreeCmCommissioner::V2::Storefront::MenuSerializerDecorator)
|
|
32
|
+
end
|