spree_cm_commissioner 1.21.0 → 2.0.0
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 -5
- data/app/assets/images/mailer/mail.png +0 -0
- data/app/assets/images/mailer/tenant_phone.png +0 -0
- data/app/assets/images/mailer/tenant_user.png +0 -0
- data/app/controllers/spree/api/v2/storefront/guests_controller.rb +13 -13
- data/app/factory/spree_cm_commissioner/invite_guest_claimed_telegram_message_factory.rb +27 -38
- data/app/interactors/spree_cm_commissioner/create_ticket.rb +6 -5
- data/app/mailers/spree/order_mailer_decorator.rb +18 -3
- data/app/models/concerns/spree_cm_commissioner/tenant_preference.rb +1 -0
- data/app/models/spree_cm_commissioner/dynamic_field.rb +20 -0
- data/app/models/spree_cm_commissioner/guest.rb +56 -0
- data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +41 -1
- data/app/models/spree_cm_commissioner/product_decorator.rb +22 -0
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +3 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_serializer.rb +1 -1
- data/app/views/spree/admin/tenant_vendors/index.html.erb +9 -2
- data/app/views/spree/admin/tenants/_form.html.erb +9 -0
- data/app/views/spree/admin/tenants/edit.html.erb +2 -1
- data/app/views/spree/admin/tenants/index.html.erb +7 -1
- data/app/views/spree/admin/vendors/_form.html.erb +14 -0
- data/app/views/spree/order_mailer/confirm_email.html.erb +27 -16
- data/app/views/spree_cm_commissioner/layouts/order_mailer.html.erb +5 -1
- data/app/views/spree_cm_commissioner/order_mailer/_mailer_stylesheets.html.erb +41 -4
- data/app/views/spree_cm_commissioner/order_mailer/tenant/_customer_info.html.erb +42 -0
- data/app/views/spree_cm_commissioner/order_mailer/tenant/_footer.html.erb +25 -0
- data/app/views/spree_cm_commissioner/order_mailer/tenant/_greeting.html.erb +19 -0
- data/app/views/spree_cm_commissioner/order_mailer/tenant/_support_contact.html.erb +33 -0
- data/config/locales/en.yml +5 -1
- data/db/migrate/20250709073455_add_email_fields_to_spree_vendors.rb +6 -0
- data/db/migrate/20250718071620_add_data_fill_stage_to_dynamic_fields.rb +5 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f153e6dedc0923e77cd5fb9e53f99fb8b5f18f1289acc2961df248054621bbc8
|
4
|
+
data.tar.gz: efc85b32c83368f26e02db04b67c14e71c430baafcedcf997ee5961a6217d7d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f13f470efb8892b55fac8bdbb0e6f180dd08ebc12a3d6639ded76855526849890cc02f17d7bcdc592e4528eaad619da94f82b403084a1e697afd7e2fd0100b2
|
7
|
+
data.tar.gz: a6646ac4739b414ffab2890f2230f0e07c6401d78ed77482e394303234a6d67e102132ca0ad589a879c6370eac0d1efc947f0fba4a115ebc10622950c09ecbfe
|
data/Gemfile.lock
CHANGED
@@ -34,7 +34,7 @@ GIT
|
|
34
34
|
PATH
|
35
35
|
remote: .
|
36
36
|
specs:
|
37
|
-
spree_cm_commissioner (
|
37
|
+
spree_cm_commissioner (2.0.0)
|
38
38
|
activerecord-multi-tenant
|
39
39
|
activerecord_json_validator (~> 2.1, >= 2.1.3)
|
40
40
|
aws-sdk-cloudfront
|
@@ -572,10 +572,6 @@ GEM
|
|
572
572
|
nokogiri (1.15.4)
|
573
573
|
mini_portile2 (~> 2.8.2)
|
574
574
|
racc (~> 1.4)
|
575
|
-
nokogiri (1.15.4-x86_64-darwin)
|
576
|
-
racc (~> 1.4)
|
577
|
-
nokogiri (1.15.4-x86_64-linux)
|
578
|
-
racc (~> 1.4)
|
579
575
|
noticed (1.6.3)
|
580
576
|
http (>= 4.0.0)
|
581
577
|
rails (>= 5.2.0)
|
Binary file
|
Binary file
|
Binary file
|
@@ -39,22 +39,22 @@ module Spree
|
|
39
39
|
spree_authorize! :update, spree_current_order, order_token
|
40
40
|
|
41
41
|
begin
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
ActiveRecord::Base.transaction do
|
43
|
+
if guest_params[:guest_dynamic_fields_attributes]
|
44
|
+
dynamic_field_ids = guest_params[:guest_dynamic_fields_attributes].pluck(:dynamic_field_id)
|
45
|
+
resource.guest_dynamic_fields.where(dynamic_field_id: dynamic_field_ids).destroy_all
|
46
|
+
|
47
|
+
guest_params[:guest_dynamic_fields_attributes].each do |attr|
|
48
|
+
field = build_dynamic_field(attr)
|
49
|
+
field.save!
|
50
|
+
end
|
48
51
|
end
|
49
|
-
end
|
50
52
|
|
51
|
-
|
52
|
-
|
53
|
-
if resource.save
|
54
|
-
render_serialized_payload { serialize_resource(resource) }
|
55
|
-
else
|
56
|
-
render_error_payload(resource.errors, 400)
|
53
|
+
resource.assign_attributes(guest_params.except(:guest_dynamic_fields_attributes))
|
54
|
+
resource.save!
|
57
55
|
end
|
56
|
+
|
57
|
+
render_serialized_payload { serialize_resource(resource) }
|
58
58
|
rescue ActiveRecord::RecordInvalid => e
|
59
59
|
render_error_payload(e.record.errors, 400)
|
60
60
|
end
|
@@ -1,17 +1,16 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# <
|
4
|
-
|
5
|
-
# <
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
# <
|
10
|
-
# <i
|
11
|
-
#
|
12
|
-
|
13
|
-
# <
|
14
|
-
# <code>R172627517</code></p>
|
1
|
+
# 🎫 --- [NEW INVITATION CLAIMED] ---
|
2
|
+
#
|
3
|
+
# <b>🙍 Claimed By</b>
|
4
|
+
# Name: Orng SreyMoch
|
5
|
+
# Tel: <code>+85570760548</code>
|
6
|
+
#
|
7
|
+
# <b>5km Running Ticket</b>
|
8
|
+
# Quantity: 1
|
9
|
+
# <i>👉 Distance: 5km, T-shirt: S</i>
|
10
|
+
# <i>🗓️ Nov 15, 2023 -> Nov 17, 2023</i>
|
11
|
+
#
|
12
|
+
# Order Number:
|
13
|
+
# <code>R621016753</code>
|
15
14
|
|
16
15
|
module SpreeCmCommissioner
|
17
16
|
class InviteGuestClaimedTelegramMessageFactory < TelegramMessageFactory
|
@@ -27,40 +26,30 @@ module SpreeCmCommissioner
|
|
27
26
|
end
|
28
27
|
|
29
28
|
def selected_line_items
|
30
|
-
|
31
|
-
|
32
|
-
order.line_items
|
29
|
+
vendor.present? ? order.line_items.for_vendor(vendor) : order.line_items
|
33
30
|
end
|
34
31
|
|
35
32
|
# override
|
36
33
|
def body
|
37
34
|
text = []
|
38
|
-
|
39
|
-
text << '
|
40
|
-
text <<
|
41
|
-
text << "
|
42
|
-
text <<
|
35
|
+
|
36
|
+
text << bold('🙍 Claimed By')
|
37
|
+
text << "Name: #{guest.first_name} #{guest.last_name}"
|
38
|
+
text << "Tel: #{inline_code(guest.phone_number)}"
|
39
|
+
text << ''
|
43
40
|
|
44
41
|
selected_line_items.each do |item|
|
45
|
-
text <<
|
42
|
+
text << bold(item.product.name.to_s)
|
43
|
+
text << "🎟️ Quantity: #{item.quantity}"
|
44
|
+
text << italic("👉 #{item.options_text}") if item.options_text.present?
|
45
|
+
text << italic(pretty_date_for(item)) if item.date_present?
|
46
|
+
text << ''
|
46
47
|
end
|
47
48
|
|
48
|
-
text <<
|
49
|
-
|
50
|
-
text.join("\n")
|
51
|
-
end
|
52
|
-
|
53
|
-
def line_item_block(item)
|
54
|
-
parts = []
|
55
|
-
parts << "<p><b>#{item.product.name}</b><br>"
|
56
|
-
|
57
|
-
details = []
|
58
|
-
details << "👉 #{item.options_text}" if item.options_text.present?
|
59
|
-
details << pretty_date_for(item) if item.date_present?
|
49
|
+
text << bold('Order Number:')
|
50
|
+
text << inline_code(order.number)
|
60
51
|
|
61
|
-
|
62
|
-
parts << '</p>'
|
63
|
-
parts.join("\n")
|
52
|
+
text.compact.join("\n")
|
64
53
|
end
|
65
54
|
|
66
55
|
def pretty_date_for(line_item)
|
@@ -9,7 +9,8 @@ module SpreeCmCommissioner
|
|
9
9
|
set_option_value
|
10
10
|
create_variant
|
11
11
|
create_stock_item
|
12
|
-
|
12
|
+
upload_image_to(@ticket.master)
|
13
|
+
upload_image_to(@variant)
|
13
14
|
create_place
|
14
15
|
end
|
15
16
|
end
|
@@ -77,13 +78,13 @@ module SpreeCmCommissioner
|
|
77
78
|
context.fail!(message: @stock_item.errors.full_messages.join(', '))
|
78
79
|
end
|
79
80
|
|
80
|
-
def
|
81
|
+
def upload_image_to(target)
|
81
82
|
return if context.params[:ticket_image].blank?
|
82
83
|
|
83
|
-
|
84
|
-
return if
|
84
|
+
image = target.images.new(attachment: context.params[:ticket_image])
|
85
|
+
return if image.save
|
85
86
|
|
86
|
-
context.fail!(message:
|
87
|
+
context.fail!(message: image.errors.full_messages.join(', '))
|
87
88
|
end
|
88
89
|
|
89
90
|
def create_place
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Spree
|
2
2
|
module OrderMailerDecorator
|
3
|
-
# overrided
|
4
3
|
def cancel_email(order, resend: false)
|
5
4
|
@order = order.respond_to?(:id) ? order : Spree::Order.find(order)
|
6
5
|
return false if @order.email.blank?
|
@@ -12,18 +11,34 @@ module Spree
|
|
12
11
|
@order = order.respond_to?(:id) ? order : Spree::Order.find(order)
|
13
12
|
return false if @order.email.blank?
|
14
13
|
|
14
|
+
@tenant = @order.tenant
|
15
|
+
if @tenant.present?
|
16
|
+
@brand_color = @tenant.preferences[:brand_primary_color]
|
17
|
+
@vendor_logo_url = @tenant.active_vendor&.logo&.original_url
|
18
|
+
end
|
19
|
+
|
15
20
|
@current_store = @order.store
|
16
21
|
@product_type = @order.products.first&.product_type || 'accommodation'
|
17
22
|
|
18
|
-
subject =
|
23
|
+
subject = resend ? "[#{Spree.t(:resend).upcase}] " : ''
|
19
24
|
subject += "#{@current_store&.name} Booking Confirmation ##{@order.number}"
|
20
25
|
|
21
|
-
mail(to: @order.email, from:
|
26
|
+
mail(to: @order.email, from: from_email_address, subject: subject, store_url: @current_store.url) do |format|
|
22
27
|
format.html { render layout: 'spree_cm_commissioner/layouts/order_mailer' }
|
23
28
|
format.text
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
32
|
+
private
|
33
|
+
|
34
|
+
def from_email_address
|
35
|
+
if @order.tenant.nil?
|
36
|
+
from_address
|
37
|
+
else
|
38
|
+
@order.tenant.active_vendor&.from_email
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
27
42
|
def ticket_email(guest, email)
|
28
43
|
@guest = guest
|
29
44
|
@event = @guest.event
|
@@ -9,6 +9,7 @@ module SpreeCmCommissioner
|
|
9
9
|
preference :payment_failed_image, :string, default: ''
|
10
10
|
preference :payment_success_image, :string, default: ''
|
11
11
|
preference :payment_loader, :string, default: ''
|
12
|
+
preference :brand_primary_color, :string, default: ''
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
@@ -9,12 +9,14 @@ module SpreeCmCommissioner
|
|
9
9
|
has_many :product_dynamic_fields, class_name: 'SpreeCmCommissioner::ProductDynamicField', dependent: :destroy
|
10
10
|
|
11
11
|
enum data_type: { text: 0, number: 1, boolean: 2, checkbox: 3, radio: 4, selection: 5, textarea: 6 }
|
12
|
+
enum data_fill_stage: { pre_registration: 0, post_registration: 1, during_check_in: 2 }
|
12
13
|
|
13
14
|
accepts_nested_attributes_for :dynamic_field_options, allow_destroy: true, reject_if: :all_blank
|
14
15
|
|
15
16
|
validates :label, presence: true
|
16
17
|
validates :data_type, presence: true
|
17
18
|
validates :configurations, presence: true, allow_blank: false
|
19
|
+
validate :validate_data_fill_stage_phase
|
18
20
|
|
19
21
|
def requires_dynamic_field_options?
|
20
22
|
checkbox? || radio? || selection?
|
@@ -30,5 +32,23 @@ module SpreeCmCommissioner
|
|
30
32
|
self.configurations ||= {}
|
31
33
|
self.configurations['multiple_select'] = ActiveModel::Type::Boolean.new.cast(value)
|
32
34
|
end
|
35
|
+
|
36
|
+
def required_at_stage?(stage)
|
37
|
+
data_fill_stage == stage.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def display_label
|
41
|
+
label + " (#{data_fill_stage.humanize})"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def validate_data_fill_stage_phase
|
47
|
+
return if data_fill_stage.blank?
|
48
|
+
|
49
|
+
return if data_fill_stage.in?(self.class.data_fill_stages.keys)
|
50
|
+
|
51
|
+
errors.add(:data_fill_stage, "must be one of: #{self.class.data_fill_stages.keys.join(', ')}")
|
52
|
+
end
|
33
53
|
end
|
34
54
|
end
|
@@ -213,6 +213,62 @@ module SpreeCmCommissioner
|
|
213
213
|
save!
|
214
214
|
end
|
215
215
|
|
216
|
+
def missing_dynamic_fields_for_stage(stage)
|
217
|
+
required_fields = line_item.product.dynamic_fields.where(data_fill_stage: stage)
|
218
|
+
filled_ids = guest_dynamic_fields.map(&:dynamic_field_id)
|
219
|
+
|
220
|
+
required_fields.reject { |field| filled_ids.include?(field.id) }
|
221
|
+
end
|
222
|
+
|
223
|
+
def all_required_dynamic_fields_completed?(stage)
|
224
|
+
missing_dynamic_fields_for_stage(stage).blank?
|
225
|
+
end
|
226
|
+
|
227
|
+
def validate_dynamic_fields_for_phase(phase)
|
228
|
+
required_fields = line_item.product.dynamic_fields.where(data_fill_stage: phase)
|
229
|
+
filled_ids = guest_dynamic_fields.map(&:dynamic_field_id)
|
230
|
+
|
231
|
+
required_fields.each do |field|
|
232
|
+
errors.add(:base, "#{field.label} is required for #{phase} phase") unless filled_ids.include?(field.id)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def pre_registration_completed?
|
237
|
+
return true unless line_item.product.dynamic_fields.pre_registration.any?
|
238
|
+
|
239
|
+
pre_registration_fields_completed?
|
240
|
+
end
|
241
|
+
|
242
|
+
def post_registration_completed?
|
243
|
+
return true unless line_item.product.dynamic_fields.post_registration.any?
|
244
|
+
|
245
|
+
post_registration_fields_completed?
|
246
|
+
end
|
247
|
+
|
248
|
+
def check_in_completed?
|
249
|
+
return true unless line_item.product.dynamic_fields.during_check_in.any?
|
250
|
+
|
251
|
+
check_in_fields_completed?
|
252
|
+
end
|
253
|
+
|
254
|
+
def current_collection_phase
|
255
|
+
if check_in.present?
|
256
|
+
:during_check_in
|
257
|
+
elsif line_item.order.completed?
|
258
|
+
:post_registration
|
259
|
+
else
|
260
|
+
:pre_registration
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def phase_completion_status
|
265
|
+
{
|
266
|
+
pre_registration: pre_registration_completed?,
|
267
|
+
post_registration: post_registration_completed?,
|
268
|
+
during_check_in: check_in_completed?
|
269
|
+
}
|
270
|
+
end
|
271
|
+
|
216
272
|
# bib_number: 345, bib_prefix: 5KM, bib_zerofill: 5 => return 5KM00345
|
217
273
|
# bib_number: 345, bib_prefix: 5KM, bib_zerofill: 2 => return 5KM345
|
218
274
|
def formatted_bib_number
|
@@ -7,6 +7,7 @@ module SpreeCmCommissioner
|
|
7
7
|
validates :value, presence: true
|
8
8
|
validate :validate_value_format, if: -> { value.present? && dynamic_field.present? }
|
9
9
|
validate :validate_option_reference, if: -> { dynamic_field_option.present? }
|
10
|
+
validate :check_required_fields_based_on_phase
|
10
11
|
|
11
12
|
private
|
12
13
|
|
@@ -34,10 +35,49 @@ module SpreeCmCommissioner
|
|
34
35
|
|
35
36
|
def validate_option_reference
|
36
37
|
return if dynamic_field.blank? || dynamic_field_option.blank?
|
37
|
-
|
38
38
|
return if dynamic_field_option.dynamic_field_id == dynamic_field_id
|
39
39
|
|
40
40
|
errors.add(:dynamic_field_option, 'must belong to the same dynamic field')
|
41
41
|
end
|
42
|
+
|
43
|
+
def before_checkin_phase?
|
44
|
+
guest.present? && guest.line_item.present? && guest.check_in.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def after_purchase_phase?
|
48
|
+
guest.present? && guest.line_item.present? && guest.line_item.completed? && guest.check_in.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
def during_checkin_phase?
|
52
|
+
guest.present? && guest.check_in.present?
|
53
|
+
end
|
54
|
+
|
55
|
+
def pre_registration_required?
|
56
|
+
dynamic_field.data_fill_stage.to_sym == :pre_registration &&
|
57
|
+
guest.line_item.order.completed? && guest.check_in.blank?
|
58
|
+
end
|
59
|
+
|
60
|
+
def post_registration_required?
|
61
|
+
dynamic_field.data_fill_stage.to_sym == :post_registration &&
|
62
|
+
guest.line_item.order.completed? && guest.check_in.blank?
|
63
|
+
end
|
64
|
+
|
65
|
+
def during_check_in_required?
|
66
|
+
dynamic_field.data_fill_stage.to_sym == :during_check_in &&
|
67
|
+
guest.check_in.present?
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_required_fields_based_on_phase
|
71
|
+
return if dynamic_field.blank? || value.present?
|
72
|
+
|
73
|
+
case dynamic_field.data_fill_stage.to_sym
|
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
|
81
|
+
end
|
42
82
|
end
|
43
83
|
end
|
@@ -86,6 +86,28 @@ module SpreeCmCommissioner
|
|
86
86
|
"#{Spree::Store.default.formatted_url}/tickets/#{slug}"
|
87
87
|
end
|
88
88
|
|
89
|
+
def dynamic_fields_by_collection_phase
|
90
|
+
{
|
91
|
+
pre_registration: dynamic_fields.pre_registration.order(:position),
|
92
|
+
post_registration: dynamic_fields.post_registration.order(:position),
|
93
|
+
during_check_in: dynamic_fields.during_check_in.order(:position)
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def required_dynamic_fields_completed?(guest, phase)
|
98
|
+
required_fields = dynamic_fields.where(data_fill_stage: phase)
|
99
|
+
return true if required_fields.empty?
|
100
|
+
|
101
|
+
filled_ids = guest.guest_dynamic_fields.where(dynamic_field_id: required_fields.select(:id)).pluck(:dynamic_field_id)
|
102
|
+
(required_fields.pluck(:id) - filled_ids).empty?
|
103
|
+
end
|
104
|
+
|
105
|
+
def required_fields_for_guest(guest)
|
106
|
+
dynamic_fields_by_collection_phase.transform_values do |fields|
|
107
|
+
fields.select { |field| guest.guest_dynamic_fields.where(dynamic_field: field).empty? }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
89
111
|
private
|
90
112
|
|
91
113
|
def set_tenant
|
@@ -93,6 +93,7 @@ module SpreeCmCommissioner
|
|
93
93
|
}
|
94
94
|
|
95
95
|
base.validates :commission_rate, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }
|
96
|
+
base.validates :from_email, presence: true, if: :tenant_present?
|
96
97
|
|
97
98
|
def base.by_vendor_id!(vendor_id)
|
98
99
|
if vendor_id.to_s =~ /^\d+$/
|
@@ -195,6 +196,8 @@ module SpreeCmCommissioner
|
|
195
196
|
|
196
197
|
vendor_kind_option_values.where(option_type_id: rules_option_type.id)
|
197
198
|
end
|
199
|
+
|
200
|
+
delegate :present?, to: :tenant, prefix: true
|
198
201
|
end
|
199
202
|
end
|
200
203
|
|
@@ -2,7 +2,7 @@ module SpreeCmCommissioner
|
|
2
2
|
module V2
|
3
3
|
module Storefront
|
4
4
|
class DynamicFieldSerializer < BaseSerializer
|
5
|
-
attributes :id, :label, :data_type, :vendor_id, :multiple_select, :created_at, :updated_at, :position
|
5
|
+
attributes :id, :label, :data_type, :vendor_id, :multiple_select, :created_at, :updated_at, :position, :data_fill_stage
|
6
6
|
|
7
7
|
has_many :dynamic_field_options, serializer: SpreeCmCommissioner::V2::Storefront::DynamicFieldOptionSerializer
|
8
8
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<% content_for :page_title do %>
|
2
2
|
<%= page_header_back_button spree.admin_tenants_url %>
|
3
|
-
<%= link_to @tenant.name, spree.admin_tenants_url
|
3
|
+
<%= link_to Spree.t('tenants'), spree.admin_tenants_url %> / <%= link_to @tenant.name, spree.admin_tenants_url%> / <%= Spree.t('vendors') %>
|
4
4
|
<% end %>
|
5
5
|
|
6
6
|
<% content_for :page_actions do %>
|
@@ -24,13 +24,20 @@
|
|
24
24
|
<tbody>
|
25
25
|
<% @vendors.each do |vendor| %>
|
26
26
|
<tr id="<%= spree_dom_id vendor %>" data-hook="admin_vendors_index_rows">
|
27
|
-
<td
|
27
|
+
<td>
|
28
|
+
<% if can?(:edit, vendor) %>
|
29
|
+
<%= link_to vendor.name, edit_admin_vendor_path(vendor.slug) %>
|
30
|
+
<% else %>
|
31
|
+
<td><%= vendor.name %></td>
|
32
|
+
<% end %>
|
33
|
+
</td>
|
28
34
|
<td><%= vendor.slug %></td>
|
29
35
|
<td><%= vendor.created_at %></td>
|
30
36
|
<td><%= vendor.updated_at %></td>
|
31
37
|
<td><%= vendor.tenant.name %></td>
|
32
38
|
<td data-hook="admin_tenants_index_row_actions" class="actions">
|
33
39
|
<span class="d-flex justify-content-end">
|
40
|
+
<%= link_to_edit vendor, url: edit_admin_vendor_path(vendor.slug), no_text: true if can?(:edit, vendor) %>
|
34
41
|
<%= link_to_delete vendor, url: admin_tenant_vendor_path(@tenant, vendor.id), no_text: true if can?(:delete, vendor) %>
|
35
42
|
</span>
|
36
43
|
</td>
|
@@ -101,6 +101,15 @@
|
|
101
101
|
<% end %>
|
102
102
|
</div>
|
103
103
|
|
104
|
+
<!-- Brand Primary Color Field -->
|
105
|
+
<div class="col-md-6">
|
106
|
+
<%= f.label :preferred_brand_primary_color, Spree.t(:brand_primary_color), class: 'form-label' %>
|
107
|
+
<%= f.text_field :preferred_brand_primary_color, class: 'form-control color-picker', placeholder: '#FF5733', value: @object.preferred_brand_primary_color %>
|
108
|
+
<div class="color-preview" style="margin-top: 10px;">
|
109
|
+
<%= content_tag :div, nil, style: "background-color: #{@object.preferred_brand_primary_color}; width: 60px; height: 60px; border: 1px solid #ccc; box-sizing: border-box; display: block;" %>
|
110
|
+
</div>
|
111
|
+
</div>
|
112
|
+
|
104
113
|
<!-- State Field -->
|
105
114
|
<div class="col-6">
|
106
115
|
<%= f.field_container :state do %>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
<% content_for :page_title do %>
|
2
2
|
<%= page_header_back_button spree.admin_tenants_url %>
|
3
|
-
|
3
|
+
<%= link_to Spree.t('tenants'), spree.admin_tenants_url %> /
|
4
|
+
<%= @object.name %>
|
4
5
|
<% end %>
|
5
6
|
|
6
7
|
<%= render partial: 'tabs', locals: { current: :edit } %>
|
@@ -40,7 +40,13 @@
|
|
40
40
|
<tbody>
|
41
41
|
<% @collection.each do |tenant| %>
|
42
42
|
<tr id="<%= spree_dom_id tenant %>" data-hook="admin_tenants_index_rows">
|
43
|
-
<td
|
43
|
+
<td>
|
44
|
+
<% if can?(:edit, tenant) %>
|
45
|
+
<%= link_to tenant.name, edit_admin_tenant_path(tenant.slug) %>
|
46
|
+
<% else %>
|
47
|
+
<%= tenant.name %>
|
48
|
+
<% end %>
|
49
|
+
</td>
|
44
50
|
<td><%= tenant.slug %></td>
|
45
51
|
<td><%= tenant.description %></td>
|
46
52
|
<td><%= tenant.created_at %></td>
|
@@ -60,4 +60,18 @@
|
|
60
60
|
<%= f.label :notification_email %>
|
61
61
|
<%= f.email_field :notification_email, class: 'form-control' %>
|
62
62
|
<% end %>
|
63
|
+
<%= f.field_container :from_email do %>
|
64
|
+
<%= f.label :from_email, Spree.t(:from_email)%>
|
65
|
+
<%= f.email_field :from_email, class: 'form-control' %>
|
66
|
+
<small class="form-text text-muted">
|
67
|
+
This is the email which will be the sender of all your Store emails (Order Confirmation, Shipment notification etc)
|
68
|
+
</small>
|
69
|
+
<% end %>
|
70
|
+
<%= f.field_container :support_email do %>
|
71
|
+
<%= f.label :support_email, Spree.t(:support_email) %>
|
72
|
+
<%= f.email_field :support_email, class: 'form-control' %>
|
73
|
+
<small class="form-text text-muted">
|
74
|
+
This email is visible to your Store visitors in the Footer section
|
75
|
+
</small>
|
76
|
+
<% end %>
|
63
77
|
</div>
|
@@ -1,22 +1,33 @@
|
|
1
1
|
<tr>
|
2
|
-
|
3
|
-
|
4
|
-
<!-- Body content -->
|
2
|
+
<td class="email-body" width="570" cellpadding="0" cellspacing="0">
|
3
|
+
<table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
|
5
4
|
<tbody>
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
<tr>
|
6
|
+
<td>
|
7
|
+
<% if @order.tenant.nil? %>
|
8
|
+
<div class="f-fallback">
|
9
|
+
<%= render 'spree_cm_commissioner/order_mailer/greeting', order: @order %>
|
10
|
+
<div class="content">
|
11
11
|
<%= render 'spree_cm_commissioner/order_mailer/order_total', order: @order %>
|
12
12
|
<%= render 'spree_cm_commissioner/order_mailer/your_booking', order: @order, show_booking_header: true %>
|
13
13
|
<%= render 'spree_cm_commissioner/order_mailer/customer_info', order: @order %>
|
14
|
-
<%= render 'spree_cm_commissioner/order_mailer/support_contact'%>
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
<%= render 'spree_cm_commissioner/order_mailer/support_contact' %>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
<% else %>
|
18
|
+
<div class="f-fallback">
|
19
|
+
<%= render 'spree_cm_commissioner/order_mailer/tenant/greeting', order: @order %>
|
20
|
+
<div class="content">
|
21
|
+
<%= render 'spree_cm_commissioner/order_mailer/order_total', order: @order %>
|
22
|
+
<%= render 'spree_cm_commissioner/order_mailer/your_booking', order: @order, show_booking_header: true %>
|
23
|
+
<%= render 'spree_cm_commissioner/order_mailer/tenant/customer_info', order: @order %>
|
24
|
+
<%= render 'spree_cm_commissioner/order_mailer/tenant/support_contact' %>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
</td>
|
29
|
+
</tr>
|
19
30
|
</tbody>
|
20
|
-
|
21
|
-
|
22
|
-
</tr>
|
31
|
+
</table>
|
32
|
+
</td>
|
33
|
+
</tr>
|
@@ -23,7 +23,11 @@
|
|
23
23
|
<table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
|
24
24
|
<tr>
|
25
25
|
<td>
|
26
|
-
|
26
|
+
<% if @order.tenant.nil? %>
|
27
|
+
<%= render 'spree_cm_commissioner/order_mailer/footer', store: @order.store %>
|
28
|
+
<% else %>
|
29
|
+
<%= render 'spree_cm_commissioner/order_mailer/tenant/footer', store: @order.store %>
|
30
|
+
<% end %>
|
27
31
|
</td>
|
28
32
|
</tr>
|
29
33
|
</table>
|
@@ -55,10 +55,10 @@
|
|
55
55
|
border-radius: 1.5625rem 1.5625rem 0 0;
|
56
56
|
background: #653ed7;
|
57
57
|
background: url(<%= image_path("mailer/event-mailer-bg.png") %>) center center / cover,
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
linear-gradient(45deg, #653ed7, rgba(0, 0, 255, 0) 70.71%),
|
59
|
+
linear-gradient(225deg, #653ed7, rgba(0, 0, 255, 0) 70.71%),
|
60
|
+
linear-gradient(330deg, #35ace0, rgba(0, 0, 255, 0) 70.71%),
|
61
|
+
linear-gradient(150deg, #35ace0, rgba(0, 0, 255, 0) 70.71%);
|
62
62
|
}
|
63
63
|
#confirm-email #greeting-card p,
|
64
64
|
#confirm-email #greeting-card .booking-confirmm,
|
@@ -66,6 +66,24 @@
|
|
66
66
|
#confirm-email #greeting-card .description {
|
67
67
|
color: #fff;
|
68
68
|
}
|
69
|
+
|
70
|
+
#confirm-email #greeting-card-1 {
|
71
|
+
color: #fff;
|
72
|
+
padding: 1.5rem;
|
73
|
+
background-size: cover;
|
74
|
+
background-position: center;
|
75
|
+
background-repeat: no-repeat;
|
76
|
+
border-radius: 1.5625rem 1.5625rem 0 0;
|
77
|
+
background: #<%= @brand_color %>;
|
78
|
+
}
|
79
|
+
#confirm-email #greeting-card-1 p,
|
80
|
+
#confirm-email #greeting-card-1 .header,
|
81
|
+
#confirm-email #greeting-card-1 .booking-confirm,
|
82
|
+
#confirm-email #greeting-card-1 .hello,
|
83
|
+
#confirm-email #greeting-card-1 .description {
|
84
|
+
color: #fff;
|
85
|
+
}
|
86
|
+
|
69
87
|
#confirm-email .align-right {
|
70
88
|
vertical-align: top;
|
71
89
|
}
|
@@ -74,6 +92,15 @@
|
|
74
92
|
margin-top: 1.25rem;
|
75
93
|
margin-bottom: 0.625rem;
|
76
94
|
}
|
95
|
+
#confirm-email .icon-hang-meas {
|
96
|
+
width: 6.25rem;
|
97
|
+
}
|
98
|
+
#confirm-email .header {
|
99
|
+
display: flex;
|
100
|
+
align-items: center;
|
101
|
+
justify-content: space-between;
|
102
|
+
width: 100%;
|
103
|
+
}
|
77
104
|
#confirm-email #greeting-card .hello,
|
78
105
|
.booking-confirm {
|
79
106
|
font-size: 1.375rem;
|
@@ -83,6 +110,15 @@
|
|
83
110
|
margin-bottom: 0.25rem;
|
84
111
|
margin-top: 1.25rem;
|
85
112
|
}
|
113
|
+
#confirm-email #greeting-card-1 .booking-confirm {
|
114
|
+
font-size: 1.375rem;
|
115
|
+
font-style: normal;
|
116
|
+
font-weight: 700;
|
117
|
+
line-height: 1.75rem;
|
118
|
+
margin-bottom: 0.25rem;
|
119
|
+
margin-top: 1.25rem;
|
120
|
+
color: #fff;
|
121
|
+
}
|
86
122
|
#confirm-email #greeting-card .booking-confirm {
|
87
123
|
font-size: 1.5rem;
|
88
124
|
padding: 0.625rem 0;
|
@@ -233,6 +269,7 @@
|
|
233
269
|
}
|
234
270
|
#confirm-email .notice-info .description {
|
235
271
|
padding-left: 0.75rem;
|
272
|
+
color: #939393;
|
236
273
|
}
|
237
274
|
#confirm-email .notice-info a {
|
238
275
|
color: #6444D8;
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<div class="content-cell">
|
2
|
+
<div class="container">
|
3
|
+
<h2><%= I18n.t('mail.order_mailer.customer_info') %></h2>
|
4
|
+
<div class="flex two-columns">
|
5
|
+
<div class="two-columns-item">
|
6
|
+
<div class="flex two-columns-item_detail">
|
7
|
+
<div class="two-columns_icon"><%= image_tag "mailer/tenant_user.png", class: "mail-icon" %></div>
|
8
|
+
<div class="two-columns_text-container">
|
9
|
+
<p class="two-columns_title">Name</p>
|
10
|
+
<p class="two-columns_description"><%= user_full_name(order) %></p>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
<div class="flex two-columns-item_detail">
|
14
|
+
<div class="two-columns_icon"><%= image_tag "mailer/mail.png", class: "mail-icon" %></div>
|
15
|
+
<div class="two-columns_text-container">
|
16
|
+
<p class="two-columns_title">Email</p>
|
17
|
+
<% if order.email.present? %>
|
18
|
+
<p class="two-columns_description"><%= link_to order.email, "mailto:#{order.email}" %></p>
|
19
|
+
<% end %>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
<div class="vertical-separater"></div>
|
24
|
+
<div class="two-columns-item">
|
25
|
+
<div class="flex two-columns-item_detail">
|
26
|
+
<div class="two-columns_icon"><%= image_tag "mailer/tenant_phone.png", class: "mail-icon" %></div>
|
27
|
+
<div class="two-columns_text-container">
|
28
|
+
<p class="two-columns_title">Contact</p>
|
29
|
+
<% if order.phone_number.present? || order.intel_phone_number.present? %>
|
30
|
+
<p class="two-columns_description">
|
31
|
+
<%= link_to(
|
32
|
+
order.phone_number || order.intel_phone_number,
|
33
|
+
"tel:#{order.phone_number || order.intel_phone_number}") %>
|
34
|
+
</p>
|
35
|
+
<% end %>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
<hr>
|
41
|
+
</div>
|
42
|
+
</div>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<div class="email-footer_inner">
|
2
|
+
<div class="mb-24"><%= store.description%></div>
|
3
|
+
<div class="mb-24 f-14"><%= store.address%></div>
|
4
|
+
<h2 class="mb-24">Connect with us</h2>
|
5
|
+
<table class="mb-24 social_icons">
|
6
|
+
<tbody>
|
7
|
+
<tr>
|
8
|
+
<% if store.facebook? %>
|
9
|
+
<td class="social_icon">
|
10
|
+
<%= link_to store.facebook, target: :_blank do %>
|
11
|
+
<%= image_tag "mailer/facebook.png", class: "mail-icon"%>
|
12
|
+
<% end %>
|
13
|
+
</td>
|
14
|
+
<% end %>
|
15
|
+
<% if store.instagram?%>
|
16
|
+
<td class="social_icon">
|
17
|
+
<%= link_to store.instagram, target: :_blank do %>
|
18
|
+
<%= image_tag "mailer/instagram.png", class: "mail-icon"%>
|
19
|
+
<% end %>
|
20
|
+
</td>
|
21
|
+
<% end %>
|
22
|
+
</tr>
|
23
|
+
</tbody>
|
24
|
+
</table>
|
25
|
+
</div>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<div id="greeting-card-1">
|
2
|
+
<div>
|
3
|
+
<div class="header">
|
4
|
+
<h1><%=@order.store.name %></h1>
|
5
|
+
<% if @vendor_logo_url.present? %>
|
6
|
+
<img src="<%= @vendor_logo_url %>" alt="Vendor Logo" class="icon-hang-meas">
|
7
|
+
<% end %>
|
8
|
+
</div>
|
9
|
+
<div class="booking-confirm">
|
10
|
+
<%= I18n.t('mail.order_mailer.booking_confirm') %>
|
11
|
+
</div>
|
12
|
+
<div class="hello">
|
13
|
+
<%= I18n.t('mail.order_mailer.hello', full_name: user_full_name(order)) %>
|
14
|
+
</div>
|
15
|
+
<div class="description">
|
16
|
+
<%= I18n.t('mail.order_mailer.booking_event', order_number: @order.number || 'NA') %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<div class="content-cell">
|
2
|
+
<div class="container">
|
3
|
+
<h2><%= I18n.t('mail.order_mailer.bookmeplus_support')%></h2>
|
4
|
+
<div class="flex two-columns">
|
5
|
+
<div class="two-columns-item">
|
6
|
+
<div class="flex two-columns-item_detail">
|
7
|
+
<div class="two-columns_icon"><%= image_tag "mailer/tenant_phone.png", class: "mail-icon"%></div>
|
8
|
+
<div class="two-columns_text-container">
|
9
|
+
<p class="two-columns_title">Contact</p>
|
10
|
+
<% if current_store.contact_phone.present? %>
|
11
|
+
<p class="two-columns_description">
|
12
|
+
<%= link_to current_store.contact_phone, "tel:#{current_store.contact_phone}" %>
|
13
|
+
</p>
|
14
|
+
<% end %>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
<div class="vertical-separater"></div>
|
19
|
+
<div class="two-columns-item">
|
20
|
+
<div class="flex two-columns-item_detail">
|
21
|
+
<div class="two-columns_icon"><%= image_tag "mailer/mail.png", class: "mail-icon"%></div>
|
22
|
+
<div class="two-columns_text-container">
|
23
|
+
<p class="two-columns_title">Email</p>
|
24
|
+
<p class="two-columns_description">
|
25
|
+
<%= @vendor&.support_email.present? ? link_to(@vendor.support_email, "mailto:#{@vendor.support_email}") : "N/A" %>
|
26
|
+
</p>
|
27
|
+
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
</div>
|
data/config/locales/en.yml
CHANGED
@@ -54,7 +54,11 @@ en:
|
|
54
54
|
guest_card_classes:
|
55
55
|
empty_info: "No guest card classes information available."
|
56
56
|
background_image: "Background Image"
|
57
|
-
|
57
|
+
guest_dynamic_field:
|
58
|
+
errors:
|
59
|
+
pre_registration_required: "is required before ticket issuance"
|
60
|
+
post_registration_required: "must be completed after purchase"
|
61
|
+
during_check_in_required: "is required during check-in"
|
58
62
|
google_wallet:
|
59
63
|
note: "Click <b>Create</b> or <b> Update</b> to connect to Google Wallet after filled all information "
|
60
64
|
google_wallet_class_created: "Google Wallet class created successfully."
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spree_cm_commissioner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- You
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: spree
|
@@ -652,8 +652,11 @@ files:
|
|
652
652
|
- app/assets/images/mailer/facebook.png
|
653
653
|
- app/assets/images/mailer/instagram.png
|
654
654
|
- app/assets/images/mailer/line_item-mailer-bg.png
|
655
|
+
- app/assets/images/mailer/mail.png
|
655
656
|
- app/assets/images/mailer/map-marker.png
|
656
657
|
- app/assets/images/mailer/phone.png
|
658
|
+
- app/assets/images/mailer/tenant_phone.png
|
659
|
+
- app/assets/images/mailer/tenant_user.png
|
657
660
|
- app/assets/images/mailer/twitter.png
|
658
661
|
- app/assets/images/mailer/user.png
|
659
662
|
- app/assets/images/payment_methods/cm-payment-affirm.svg
|
@@ -2187,6 +2190,10 @@ files:
|
|
2187
2190
|
- app/views/spree_cm_commissioner/order_mailer/hotel/_booking_detail.html.erb
|
2188
2191
|
- app/views/spree_cm_commissioner/order_mailer/purchased_items/_items.html.erb
|
2189
2192
|
- app/views/spree_cm_commissioner/order_mailer/purchased_items/_summary.html.erb
|
2193
|
+
- app/views/spree_cm_commissioner/order_mailer/tenant/_customer_info.html.erb
|
2194
|
+
- app/views/spree_cm_commissioner/order_mailer/tenant/_footer.html.erb
|
2195
|
+
- app/views/spree_cm_commissioner/order_mailer/tenant/_greeting.html.erb
|
2196
|
+
- app/views/spree_cm_commissioner/order_mailer/tenant/_support_contact.html.erb
|
2190
2197
|
- app/views/spree_cm_commissioner/pin_code_mailer/send_pin_code.html.erb
|
2191
2198
|
- app/views/spree_cm_commissioner/team_invite_mailer/_mailer_stylesheets.html.erb
|
2192
2199
|
- app/views/spree_cm_commissioner/team_invite_mailer/send_team_invite_email.html.erb
|
@@ -2533,11 +2540,13 @@ files:
|
|
2533
2540
|
- db/migrate/20250702091305_add_dynamic_field_option_to_guest_dynamic_field.rb
|
2534
2541
|
- db/migrate/20250702091935_add_status_to_dynamic_field_option.rb
|
2535
2542
|
- db/migrate/20250707032008_add_vendor_id_to_spree_category.rb
|
2543
|
+
- db/migrate/20250709073455_add_email_fields_to_spree_vendors.rb
|
2536
2544
|
- db/migrate/20250711092937_add_position_to_cm_dynamic_fields.rb
|
2537
2545
|
- db/migrate/20250711093045_add_position_to_cm_dynamic_field_options.rb
|
2538
2546
|
- db/migrate/20250714121508_rename_cm_taxon_blazer_query_to_blazer_queryables.rb
|
2539
2547
|
- db/migrate/20250714124323_make_cm_blazer_queryables_polymorphic.rb
|
2540
2548
|
- db/migrate/20250715103333_remove_indexes_from_cm_user_identity_providers.rb
|
2549
|
+
- db/migrate/20250718071620_add_data_fill_stage_to_dynamic_fields.rb
|
2541
2550
|
- docker-compose.yml
|
2542
2551
|
- docs/option_types/attr_types.md
|
2543
2552
|
- docs/private_key.pem
|