spree_cm_commissioner 1.16.0 → 1.17.0.pre.pre

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -12
  3. data/app/controllers/spree/api/v2/storefront/dynamic_field_options_controller.rb +28 -0
  4. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +2 -1
  5. data/app/interactors/spree_cm_commissioner/create_event.rb +2 -1
  6. data/app/mailers/spree_cm_commissioner/team_invite_mailer.rb +13 -0
  7. data/app/models/concerns/spree_cm_commissioner/participation_type_bitwise.rb +47 -0
  8. data/app/models/spree_cm_commissioner/dynamic_field.rb +20 -0
  9. data/app/models/spree_cm_commissioner/dynamic_field_option.rb +18 -0
  10. data/app/models/spree_cm_commissioner/guest.rb +4 -2
  11. data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +25 -0
  12. data/app/models/spree_cm_commissioner/invite_team.rb +44 -0
  13. data/app/models/spree_cm_commissioner/product_decorator.rb +2 -0
  14. data/app/models/spree_cm_commissioner/product_dynamic_field.rb +8 -0
  15. data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -0
  16. data/app/models/spree_cm_commissioner/user_decorator.rb +1 -0
  17. data/app/models/spree_cm_commissioner/vendor_decorator.rb +1 -0
  18. data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +1 -0
  19. data/app/serializers/spree/v2/storefront/taxon_serializer_decorator.rb +2 -0
  20. data/app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_option_serializer.rb +11 -0
  21. data/app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_serializer.rb +13 -0
  22. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_dynamic_field_serializer.rb +13 -0
  23. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +3 -2
  24. data/app/serializers/spree_cm_commissioner/v2/storefront/product_dynamic_field_serializer.rb +13 -0
  25. data/app/services/spree_cm_commissioner/user_roles_assigner.rb +0 -6
  26. data/app/views/spree_cm_commissioner/layouts/team_invite_mailer.html.erb +15 -0
  27. data/app/views/spree_cm_commissioner/team_invite_mailer/_mailer_stylesheets.html.erb +79 -0
  28. data/app/views/spree_cm_commissioner/team_invite_mailer/send_team_invite_email.html.erb +42 -0
  29. data/config/routes.rb +1 -0
  30. data/db/migrate/20250512072817_create_spree_cm_commissioner_invite_team.rb +15 -0
  31. data/db/migrate/20250605024523_add_participation_type_to_spree_taxon.rb +5 -0
  32. data/db/migrate/20250606020914_create_cm_dynamic_fields.rb +11 -0
  33. data/db/migrate/20250606020958_create_cm_guest_dynamic_fields.rb +11 -0
  34. data/db/migrate/20250606021044_create_cm_dynamic_field_options.rb +10 -0
  35. data/db/migrate/20250606021045_create_cm_product_dynamic_fields.rb +10 -0
  36. data/lib/spree_cm_commissioner/version.rb +1 -1
  37. metadata +25 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 169845d2403406e562178fb3b438559b9d4cc42d93776513b5b7235399f69e2a
4
- data.tar.gz: 5d7526b7df7150bddd97deb2989f08a014437b4c4c9efc8a318405d335e35e27
3
+ metadata.gz: 6cc0c166a073d01107caea18b4b7f2381d12b9372ac67aa80b570687aaf59702
4
+ data.tar.gz: 0d736865e66226bed4f07171d02879c6d009d760595d88f6f63605e57bc228a6
5
5
  SHA512:
6
- metadata.gz: ba5ff297f04ed5f749794f56b8c38900d36ce76d5b78a7778c0e06007816004190745ad3664b038be3c84e30a540deb57715652ed6d8012593b57126a14dba9c
7
- data.tar.gz: d83b272f1fe458cc17fa833e2edd1a643ffa9c25f888c8432bc4e08d10ce1b16e8a2e870b52532995448043dda00eab8473f50e8f687dbf11ee6e45eca58556e
6
+ metadata.gz: e55841d41f47a5aedd68cb9c81309f356f1731d24c1771d8955f6d20d0cb8050f5aefe867bbe3d1501b4fb421aca87daea26a9314281efda5d2b89792f332c63
7
+ data.tar.gz: 2f6b56fb52a8cf35206c8b24c99d0b991fbed3343c8ca56377f53febc7080c25af53ff1d839ae63c6bfa6ca6a148ffcb427c88fce10e58f60892d536106a14bb
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (1.16.0)
37
+ spree_cm_commissioner (1.17.0.pre.pre)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -446,14 +446,14 @@ GEM
446
446
  google-cloud-recaptcha_enterprise-v1beta1 (0.10.0)
447
447
  gapic-common (>= 0.20.0, < 2.a)
448
448
  google-cloud-errors (~> 1.0)
449
- google-protobuf (3.25.6)
450
- google-protobuf (3.25.6-x86_64-darwin)
451
- google-protobuf (3.25.6-x86_64-linux)
449
+ google-protobuf (3.25.8)
450
+ google-protobuf (3.25.8-x86_64-darwin)
451
+ google-protobuf (3.25.8-x86_64-linux)
452
452
  googleapis-common-protos (1.4.0)
453
453
  google-protobuf (~> 3.14)
454
454
  googleapis-common-protos-types (~> 1.2)
455
455
  grpc (~> 1.27)
456
- googleapis-common-protos-types (1.18.0)
456
+ googleapis-common-protos-types (1.20.0)
457
457
  google-protobuf (>= 3.18, < 5.a)
458
458
  googleauth (1.8.1)
459
459
  faraday (>= 0.17.3, < 3.a)
@@ -461,13 +461,13 @@ GEM
461
461
  multi_json (~> 1.11)
462
462
  os (>= 0.9, < 2.0)
463
463
  signet (>= 0.16, < 2.a)
464
- grpc (1.70.1)
464
+ grpc (1.72.0)
465
465
  google-protobuf (>= 3.25, < 5.0)
466
466
  googleapis-common-protos-types (~> 1.0)
467
- grpc (1.70.1-x86_64-darwin)
467
+ grpc (1.72.0-x86_64-darwin)
468
468
  google-protobuf (>= 3.25, < 5.0)
469
469
  googleapis-common-protos-types (~> 1.0)
470
- grpc (1.70.1-x86_64-linux)
470
+ grpc (1.72.0-x86_64-linux)
471
471
  google-protobuf (>= 3.25, < 5.0)
472
472
  googleapis-common-protos-types (~> 1.0)
473
473
  hana (1.3.7)
@@ -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)
@@ -0,0 +1,28 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ class DynamicFieldOptionsController < ::Spree::Api::V2::ResourceController
6
+ # override
7
+ def collection
8
+ return @collection if defined?(@collection)
9
+ return SpreeCmCommissioner::DynamicFieldOption.none if params[:dynamic_field_id].blank?
10
+
11
+ @collection = SpreeCmCommissioner::DynamicFieldOption.where(dynamic_field_id: params[:dynamic_field_id])
12
+ @collection = @collection.where('value LIKE ?', "%#{params[:query]}%") if params[:query].present?
13
+ @collection
14
+ end
15
+
16
+ # override
17
+ def collection_serializer
18
+ SpreeCmCommissioner::V2::Storefront::DynamicFieldOptionSerializer
19
+ end
20
+
21
+ def model_class
22
+ SpreeCmCommissioner::DynamicFieldOption
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -75,7 +75,8 @@ module Spree
75
75
  :expectation,
76
76
  :upload_later,
77
77
  :country_code,
78
- :contact
78
+ :contact,
79
+ guest_dynamic_fields_attributes: %i[id dynamic_field_id value _destroy]
79
80
  )
80
81
  end
81
82
  end
@@ -23,7 +23,8 @@ module SpreeCmCommissioner
23
23
  from_date: context.params[:from_date],
24
24
  to_date: context.params[:to_date],
25
25
  parent_id: context.params[:parent_id],
26
- taxonomy_id: context.params[:taxonomy_id]
26
+ taxonomy_id: context.params[:taxonomy_id],
27
+ vendor_id: context.current_vendor.id
27
28
  )
28
29
 
29
30
  if @parent_taxon.save
@@ -0,0 +1,13 @@
1
+ module SpreeCmCommissioner
2
+ class TeamInviteMailer < Spree::BaseMailer
3
+ layout 'spree_cm_commissioner/layouts/team_invite_mailer'
4
+
5
+ def send_team_invite_email(invite_team_id)
6
+ @invite_team = SpreeCmCommissioner::InviteTeam.find(invite_team_id)
7
+
8
+ subject = Spree::Store.default.name.to_s
9
+
10
+ mail(from: from_address, to: @invite_team.email, subject: subject)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,47 @@
1
+ module SpreeCmCommissioner
2
+ module ParticipationTypeBitwise
3
+ extend ActiveSupport::Concern
4
+
5
+ BIT_FIELDS = {
6
+ invitation_only: 0b1,
7
+ public: 0b10,
8
+ private: 0b100,
9
+ virtual: 0b1000,
10
+ free: 0b10000,
11
+ internal: 0b100000
12
+ }.freeze
13
+
14
+ ORDERED_BIT_FIELDS = %i[
15
+ invitation_only
16
+ public
17
+ private
18
+ virtual
19
+ free
20
+ internal
21
+ ].freeze
22
+
23
+ def participation_type? = participation_type != 0
24
+
25
+ BIT_FIELDS.each do |field, bit_value|
26
+ define_method "#{field}?" do
27
+ participation_type_enabled?(bit_value)
28
+ end
29
+ end
30
+
31
+ def unordered_participation_type_fields
32
+ BIT_FIELDS.filter_map do |field, bit_value|
33
+ field if participation_type & bit_value != 0
34
+ end
35
+ end
36
+
37
+ def participation_type_fields
38
+ unordered_participation_type_fields.sort_by { |item| ORDERED_BIT_FIELDS.index(item) }
39
+ end
40
+
41
+ def participation_type_enabled?(bit_value)
42
+ return false if participation_type.nil?
43
+
44
+ participation_type & bit_value != 0
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ module SpreeCmCommissioner
2
+ class DynamicField < SpreeCmCommissioner::Base
3
+ belongs_to :vendor, class_name: 'Spree::Vendor', optional: false
4
+
5
+ has_many :dynamic_field_options, class_name: 'SpreeCmCommissioner::DynamicFieldOption', dependent: :destroy
6
+ has_many :guest_dynamic_fields, class_name: 'SpreeCmCommissioner::GuestDynamicField', dependent: :destroy
7
+ has_many :product_dynamic_fields, class_name: 'SpreeCmCommissioner::ProductDynamicField', dependent: :destroy
8
+
9
+ enum data_type: { string: 0, integer: 1, boolean: 2, checkbox: 3, radio: 4 }
10
+
11
+ accepts_nested_attributes_for :dynamic_field_options, allow_destroy: true, reject_if: :all_blank
12
+
13
+ validates :label, presence: true
14
+ validates :data_type, presence: true
15
+
16
+ def selection?
17
+ checkbox? || radio?
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ module SpreeCmCommissioner
2
+ class DynamicFieldOption < SpreeCmCommissioner::Base
3
+ belongs_to :dynamic_field, class_name: 'SpreeCmCommissioner::DynamicField', optional: false
4
+
5
+ validates :value, presence: true, uniqueness: { scope: :dynamic_field_id }
6
+ validate :parent_field_must_be_selection_type
7
+
8
+ private
9
+
10
+ def parent_field_must_be_selection_type
11
+ return unless dynamic_field
12
+
13
+ return if dynamic_field.selection?
14
+
15
+ errors.add(:dynamic_field, 'must be a selection type field')
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,6 @@
1
1
  # rubocop:disable Metrics/ClassLength
2
2
  module SpreeCmCommissioner
3
- class Guest < SpreeCmCommissioner::Base
3
+ class Guest < SpreeCmCommissioner::Base # rubocop:disable Metrics/ClassLength
4
4
  include SpreeCmCommissioner::KycBitwise
5
5
  include SpreeCmCommissioner::PhoneNumberSanitizer
6
6
 
@@ -32,6 +32,8 @@ module SpreeCmCommissioner
32
32
  scope :no_show, -> { left_outer_joins(:check_in).where(cm_check_ins: { id: nil }) }
33
33
 
34
34
  has_many :state_changes, as: :stateful, class_name: 'Spree::StateChange'
35
+ has_many :guest_dynamic_fields, dependent: :destroy, class_name: 'SpreeCmCommissioner::GuestDynamicField'
36
+ accepts_nested_attributes_for :guest_dynamic_fields, allow_destroy: true
35
37
 
36
38
  belongs_to :event, class_name: 'Spree::Taxon'
37
39
 
@@ -44,7 +46,7 @@ module SpreeCmCommissioner
44
46
  before_validation :set_event_id
45
47
  before_validation :assign_seat_number, if: -> { bib_number.present? }
46
48
 
47
- before_create :generate_bib, if: -> { variant.bib_pre_generation_on_create? }
49
+ before_create :generate_bib, if: -> { line_item.reload && variant.bib_pre_generation_on_create? }
48
50
 
49
51
  validates :seat_number, uniqueness: { scope: :event_id }, allow_nil: true, if: -> { event_id.present? }
50
52
  validates :bib_index, uniqueness: true, allow_nil: true
@@ -0,0 +1,25 @@
1
+ module SpreeCmCommissioner
2
+ class GuestDynamicField < SpreeCmCommissioner::Base
3
+ belongs_to :guest, class_name: 'SpreeCmCommissioner::Guest', optional: false
4
+ belongs_to :dynamic_field, class_name: 'SpreeCmCommissioner::DynamicField', optional: false
5
+
6
+ validates :value, presence: true
7
+ validate :validate_value_format, if: -> { value.present? && dynamic_field.present? }
8
+
9
+ private
10
+
11
+ def validate_value_format
12
+ return if dynamic_field.blank?
13
+
14
+ case dynamic_field.data_type.to_s
15
+ when 'integer'
16
+ errors.add(:value, 'must be a number') unless value.to_s.match?(/\A\d+\z/)
17
+ when 'boolean'
18
+ errors.add(:value, 'must be true or false') unless %w[true false 1 0].include?(value.to_s.downcase)
19
+ when 'checkbox', 'radio'
20
+ valid_options = dynamic_field.dynamic_field_options.pluck(:id).map(&:to_s)
21
+ errors.add(:value, 'is not a valid option') unless valid_options.include?(value)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,44 @@
1
+ module SpreeCmCommissioner
2
+ class InviteTeam < SpreeCmCommissioner::Base
3
+ belongs_to :user, class_name: 'Spree::User', optional: true
4
+ belongs_to :inviter, class_name: 'Spree::User'
5
+ belongs_to :vendor, class_name: 'Spree::Vendor'
6
+
7
+ attr_reader :user_id, :vendor_id
8
+
9
+ enum status: { pending: 0, accepted: 1 }, _default: 0
10
+
11
+ preference :role_ids, :array, default: []
12
+
13
+ validate :validate_roles
14
+
15
+ after_create :set_expiration
16
+ after_create :send_team_invite_email
17
+
18
+ def roles
19
+ Spree::Role.where(id: preferred_role_ids)
20
+ end
21
+
22
+ def validate_roles
23
+ return if preferred_role_ids.present?
24
+
25
+ errors.add(:base, I18n.t('user_roles_assigner.roles_required'))
26
+ end
27
+
28
+ def send_team_invite_email
29
+ SpreeCmCommissioner::TeamInviteMailer.send_team_invite_email(id).deliver_now
30
+ end
31
+
32
+ def set_expiration
33
+ update(expires_at: 3.days.from_now)
34
+ end
35
+
36
+ def invitation_link
37
+ "http://#{ENV.fetch('APP_HOST')}/organizer/invite_teams/#{token}?utm_source=email"
38
+ end
39
+
40
+ def url_valid?
41
+ expires_at.present? && expires_at > Time.current
42
+ end
43
+ end
44
+ end
@@ -37,6 +37,8 @@ module SpreeCmCommissioner
37
37
 
38
38
  base.has_many :product_places, class_name: 'SpreeCmCommissioner::ProductPlace', dependent: :destroy
39
39
  base.has_many :places, through: :product_places
40
+ base.has_many :product_dynamic_fields, class_name: 'SpreeCmCommissioner::ProductDynamicField', dependent: :destroy
41
+ base.has_many :dynamic_fields, through: :product_dynamic_fields, class_name: 'SpreeCmCommissioner::DynamicField'
40
42
 
41
43
  base.has_one :venue, -> { where(type: :venue) }, class_name: 'SpreeCmCommissioner::ProductPlace', dependent: :destroy
42
44
 
@@ -0,0 +1,8 @@
1
+ module SpreeCmCommissioner
2
+ class ProductDynamicField < SpreeCmCommissioner::Base
3
+ belongs_to :product, class_name: 'Spree::Product', optional: false
4
+ belongs_to :dynamic_field, class_name: 'SpreeCmCommissioner::DynamicField', optional: false
5
+
6
+ validates :dynamic_field_id, uniqueness: { scope: :product_id }
7
+ end
8
+ end
@@ -3,6 +3,7 @@ module SpreeCmCommissioner
3
3
  def self.prepended(base) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
4
4
  base.include SpreeCmCommissioner::TaxonKind
5
5
  base.include SpreeCmCommissioner::Transit::TaxonBitwise
6
+ base.include SpreeCmCommissioner::ParticipationTypeBitwise
6
7
 
7
8
  base.preference :background_color, :string
8
9
  base.preference :foreground_color, :string
@@ -33,6 +33,7 @@ module SpreeCmCommissioner
33
33
 
34
34
  base.multi_tenant :tenant, class_name: 'SpreeCmCommissioner::Tenant'
35
35
  base.scope :by_tenant, -> (tenant_id) { where(tenant_id: tenant_id) }
36
+ base.scope :vendor_users, -> (vendor_id) { joins(:role_users => :role).where(spree_roles: { vendor_id: vendor_id }).distinct }
36
37
 
37
38
  base.whitelisted_ransackable_attributes = %w[email first_name last_name gender phone_number]
38
39
 
@@ -51,6 +51,7 @@ module SpreeCmCommissioner
51
51
  through: :vendor_stops, source: :stop, class_name: 'SpreeCmCommissioner::Place'
52
52
  base.has_many :drop_off_points, -> { where(cm_vendor_stops: { stop_type: 1 }) },
53
53
  through: :vendor_stops, source: :stop, class_name: 'SpreeCmCommissioner::Place'
54
+ base.has_many :dynamic_fields, class_name: 'SpreeCmCommissioner::DynamicField', foreign_key: :vendor_id, dependent: :destroy
54
55
 
55
56
  base.has_one :logo, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::VendorLogo'
56
57
  base.has_one :payment_qrcode, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::VendorPaymentQrcode'
@@ -7,6 +7,7 @@ module Spree
7
7
  base.has_many :product_kind_option_types, serializer: :option_type
8
8
  base.has_many :promoted_option_types, serializer: :option_type
9
9
  base.has_many :possible_promotions, serializer: ::SpreeCmCommissioner::V2::Storefront::PromotionSerializer
10
+ base.has_many :dynamic_fields, serializer: SpreeCmCommissioner::V2::Storefront::DynamicFieldSerializer
10
11
 
11
12
  base.has_one :default_state, serializer: :state
12
13
  base.has_one :venue, serializer: ::SpreeCmCommissioner::V2::Storefront::ProductPlaceSerializer
@@ -25,6 +25,8 @@ module Spree
25
25
  taxon.purchasable_on == 'web' || taxon.purchasable_on == 'both'
26
26
  end
27
27
 
28
+ base.attribute :participation_type_fields
29
+
28
30
  base.cache_options store: nil
29
31
 
30
32
  base.attribute :event_url, &:event_url
@@ -0,0 +1,11 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class DynamicFieldOptionSerializer < BaseSerializer
5
+ set_type :dynamic_field_option
6
+
7
+ attributes :id, :value, :dynamic_field_id, :created_at, :updated_at
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class DynamicFieldSerializer < BaseSerializer
5
+ set_type :dynamic_field
6
+
7
+ attributes :id, :label, :data_type, :vendor_id, :created_at, :updated_at
8
+
9
+ has_many :dynamic_field_options, serializer: SpreeCmCommissioner::V2::Storefront::DynamicFieldOptionSerializer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class GuestDynamicFieldSerializer < BaseSerializer
5
+ set_type :guest_dynamic_field
6
+
7
+ attributes :id, :value, :guest_id, :dynamic_field_id, :created_at, :updated_at
8
+
9
+ belongs_to :dynamic_field, serializer: SpreeCmCommissioner::V2::Storefront::DynamicFieldSerializer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -20,12 +20,13 @@ module SpreeCmCommissioner
20
20
 
21
21
  belongs_to :occupation, serializer: Spree::V2::Storefront::TaxonSerializer
22
22
  belongs_to :nationality, serializer: Spree::V2::Storefront::TaxonSerializer
23
+ belongs_to :line_item, serializer: Spree::V2::Storefront::LineItemSerializer
24
+
25
+ has_many :guest_dynamic_fields, serializer: SpreeCmCommissioner::V2::Storefront::GuestDynamicFieldSerializer
23
26
 
24
27
  has_one :id_card, serializer: Spree::V2::Storefront::IdCardSerializer
25
28
  has_one :check_in
26
29
 
27
- belongs_to :line_item, serializer: Spree::V2::Storefront::LineItemSerializer
28
-
29
30
  # allowed_checkout updates frequently
30
31
  cache_options store: nil
31
32
  end
@@ -0,0 +1,13 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class ProductDynamicFieldSerializer < BaseSerializer
5
+ set_type :product_dynamic_field
6
+
7
+ attributes :id, :product_id, :dynamic_field_id, :created_at, :updated_at
8
+
9
+ belongs_to :dynamic_field, serializer: SpreeCmCommissioner::V2::Storefront::DynamicFieldSerializer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -19,17 +19,11 @@ module SpreeCmCommissioner
19
19
  end
20
20
 
21
21
  def create
22
- return { success: false, message: I18n.t('user_roles_assigner.user_not_found') } unless user
23
- return { success: false, message: I18n.t('user_roles_assigner.user_already_assigned') } if user.vendors.exists?(id: vendor_id)
24
- return { success: false, message: I18n.t('user_roles_assigner.roles_required') } if role_ids.blank?
25
-
26
22
  create_roles
27
23
  { success: true }
28
24
  end
29
25
 
30
26
  def update
31
- return { success: false, message: I18n.t('user_roles_assigner.roles_required') } if role_ids.blank?
32
-
33
27
  update_roles
34
28
  { success: true }
35
29
  end
@@ -0,0 +1,15 @@
1
+
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html>
4
+ <head>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <meta name="x-apple-disable-message-reformatting"/>
7
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
8
+ <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
10
+ <%= render partial: 'spree_cm_commissioner/team_invite_mailer/mailer_stylesheets' %>
11
+ </head>
12
+ <body>
13
+ <%= yield %>
14
+ </body>
15
+ </html>
@@ -0,0 +1,79 @@
1
+ <style>
2
+ body, table, td {
3
+ font-family: 'Poppins', Arial, sans-serif;
4
+ margin: 0;
5
+ padding: 0;
6
+ }
7
+
8
+ .content-wrapper {
9
+ max-width: 500px;
10
+ margin: 0 auto;
11
+ border: 1px solid grey;
12
+ border-top: none;
13
+ }
14
+
15
+ .main-content{
16
+ padding-top: 10px;
17
+ padding-bottom: 25px;
18
+ }
19
+
20
+ .heading-1 {
21
+ font-size: 24px;
22
+ text-align: center;
23
+ line-height: 1.4;
24
+ margin-top: 10px;
25
+ margin-bottom: 15px;
26
+ padding-left: 5px;
27
+ padding-right: 5px;
28
+
29
+ }
30
+
31
+ .bar-large {
32
+ height: 10px;
33
+ background-color: #5D54D9;
34
+ margin-bottom: 20px;
35
+
36
+ }
37
+
38
+ .bar-thin {
39
+ height: 1px;
40
+ background-color: grey;
41
+ width: 100%;
42
+ margin: 20px auto;
43
+ }
44
+
45
+ .heading-2 {
46
+ font-size: 16px;
47
+ text-align: center;
48
+ line-height: 1.5;
49
+ }
50
+
51
+ .title-bold {
52
+ font-weight: bold;
53
+ color: #000;
54
+ }
55
+
56
+ .action-button {
57
+ display: inline-block;
58
+ background-color: #5D54D9;
59
+ border-radius: 24px;
60
+ font-size: 14px;
61
+ width: 222px;
62
+ height: 50px;
63
+ text-align: center;
64
+ line-height: 50px;
65
+ text-decoration: none;
66
+ cursor: pointer;
67
+ margin: 15px 0;
68
+ color: white !important;
69
+ text-decoration: none;
70
+ }
71
+
72
+ .heading-3 {
73
+ font-size: 12px;
74
+ text-align: center;
75
+ margin-bottom: 15px;
76
+ color: #888;
77
+ }
78
+ </style>
79
+
@@ -0,0 +1,42 @@
1
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%">
2
+ <tr>
3
+ <td align="center">
4
+ <div class="content-wrapper">
5
+ <div class="bar-large"></div>
6
+ <div class="main-content">
7
+ <div class="content">
8
+ <div>
9
+ <%= image_tag(main_app.rails_blob_url(Spree::StoreLogo.first.attachment), style: "width: 120px; height: 120px;") %>
10
+ </div>
11
+ <div class="heading-1">
12
+ You're invited to join
13
+ <span class="title-bold">
14
+ BookMe+
15
+ </span>
16
+ Business.
17
+ </div>
18
+ <div class="bar-thin"></div>
19
+ <div class="heading-2">
20
+ <span class="title-bold"><%= @invite_team.inviter.full_name.presence || @invite_team.inviter.email %></span> has invited you to manage bookings and grow together on the platform. <br>
21
+ </div>
22
+ <div style="text-align: center;">
23
+ <a href="<%= @invite_team.invitation_link %>" class="action-button">
24
+ Accept Invitation
25
+ </a>
26
+ </div>
27
+
28
+ <div class="heading-3">
29
+ Use this email <span class="title-bold"><%= @invite_team.email %></span> to log in or <br>create an account on BookMe+ Platform
30
+ </div>
31
+
32
+ <div class="heading-3">
33
+ This invitation will expire<br>
34
+ in <%= ((@invite_team.expires_at - Time.current) / 1.hour).round %> hours.
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ </td>
40
+ </tr>
41
+ </table>
42
+
data/config/routes.rb CHANGED
@@ -619,6 +619,7 @@ Spree::Core::Engine.add_routes do
619
619
  resources :guests, only: %i[create update show] do
620
620
  resources :id_cards
621
621
  end
622
+ resources :dynamic_field_options
622
623
  resources :user_guests do
623
624
  resources :id_cards
624
625
  end
@@ -0,0 +1,15 @@
1
+ class CreateSpreeCmCommissionerInviteTeam < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cm_invite_teams, if_not_exists: true do |t|
4
+ t.string :email, null: false
5
+ t.string :token, null: false, unique: true, index: true
6
+ t.references :inviter, null: false, foreign_key: { to_table: :spree_users }, index: true
7
+ t.references :vendor, null:false, foreign_key: { to_table: :spree_vendors }, index: true
8
+ t.integer :status, default: 0, null: false
9
+ t.text :preferences
10
+ t.datetime :expires_at
11
+ t.datetime :confirmed_at
12
+ t.timestamps
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ class AddParticipationTypeToSpreeTaxon < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :spree_taxons , :participation_type, :integer, default: 0, null: false, if_not_exists: true
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ class CreateCmDynamicFields < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cm_dynamic_fields, if_not_exists: true do |t|
4
+ t.string :label, null: false
5
+ t.integer :data_type, null: false
6
+ t.references :vendor, null: false, foreign_key: { to_table: :spree_vendors }
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class CreateCmGuestDynamicFields < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cm_guest_dynamic_fields, if_not_exists: true do |t|
4
+ t.references :guest, null: false, foreign_key: { to_table: :cm_guests }
5
+ t.references :dynamic_field, null: false, foreign_key: { to_table: :cm_dynamic_fields }
6
+ t.jsonb :value, default: [], null: false
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ class CreateCmDynamicFieldOptions < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cm_dynamic_field_options, if_not_exists: true do |t|
4
+ t.references :dynamic_field, null: false, foreign_key: { to_table: :cm_dynamic_fields }
5
+ t.string :value, null: false
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class CreateCmProductDynamicFields < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cm_product_dynamic_fields, if_not_exists: true do |t|
4
+ t.references :product, null: false, foreign_key: { to_table: :spree_products }
5
+ t.references :dynamic_field, null: false, foreign_key: { to_table: :cm_dynamic_fields }
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '1.16.0'.freeze
2
+ VERSION = '1.17.0-pre'.freeze
3
3
 
4
4
  module_function
5
5
 
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: 1.16.0
4
+ version: 1.17.0.pre.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-20 00:00:00.000000000 Z
11
+ date: 2025-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -839,6 +839,7 @@ files:
839
839
  - app/controllers/spree/api/v2/storefront/check_ins_controller.rb
840
840
  - app/controllers/spree/api/v2/storefront/confirm_pin_code_checkers_controller.rb
841
841
  - app/controllers/spree/api/v2/storefront/customer_notifications_controller.rb
842
+ - app/controllers/spree/api/v2/storefront/dynamic_field_options_controller.rb
842
843
  - app/controllers/spree/api/v2/storefront/events_controller.rb
843
844
  - app/controllers/spree/api/v2/storefront/google_wallet_object_tokens_controller.rb
844
845
  - app/controllers/spree/api/v2/storefront/guest_card_classes_controller.rb
@@ -1176,6 +1177,7 @@ files:
1176
1177
  - app/mailers/spree_cm_commissioner/crew_invite_mailer.rb
1177
1178
  - app/mailers/spree_cm_commissioner/event_transactional_mailer.rb
1178
1179
  - app/mailers/spree_cm_commissioner/pin_code_mailer.rb
1180
+ - app/mailers/spree_cm_commissioner/team_invite_mailer.rb
1179
1181
  - app/models/.gitkeep
1180
1182
  - app/models/concerns/spree_cm_commissioner/homepage_section_bitwise.rb
1181
1183
  - app/models/concerns/spree_cm_commissioner/json_preference_validator.rb
@@ -1188,6 +1190,7 @@ files:
1188
1190
  - app/models/concerns/spree_cm_commissioner/option_value_attr_type.rb
1189
1191
  - app/models/concerns/spree_cm_commissioner/order_state_machine.rb
1190
1192
  - app/models/concerns/spree_cm_commissioner/parameterize_name.rb
1193
+ - app/models/concerns/spree_cm_commissioner/participation_type_bitwise.rb
1191
1194
  - app/models/concerns/spree_cm_commissioner/phone_number_sanitizer.rb
1192
1195
  - app/models/concerns/spree_cm_commissioner/product_delegation.rb
1193
1196
  - app/models/concerns/spree_cm_commissioner/product_type.rb
@@ -1226,6 +1229,8 @@ files:
1226
1229
  - app/models/spree_cm_commissioner/customer_taxon.rb
1227
1230
  - app/models/spree_cm_commissioner/device_token.rb
1228
1231
  - app/models/spree_cm_commissioner/digital_decorator.rb
1232
+ - app/models/spree_cm_commissioner/dynamic_field.rb
1233
+ - app/models/spree_cm_commissioner/dynamic_field_option.rb
1229
1234
  - app/models/spree_cm_commissioner/event_ticket_google_wallet.rb
1230
1235
  - app/models/spree_cm_commissioner/export.rb
1231
1236
  - app/models/spree_cm_commissioner/exports/export_guest_csv.rb
@@ -1240,6 +1245,7 @@ files:
1240
1245
  - app/models/spree_cm_commissioner/guest_card_classes/bib_card_class.rb
1241
1246
  - app/models/spree_cm_commissioner/guest_card_classes/booking_card_background_image.rb
1242
1247
  - app/models/spree_cm_commissioner/guest_card_classes/booking_card_class.rb
1248
+ - app/models/spree_cm_commissioner/guest_dynamic_field.rb
1243
1249
  - app/models/spree_cm_commissioner/guest_occupation_promotion_rule.rb
1244
1250
  - app/models/spree_cm_commissioner/homepage_background.rb
1245
1251
  - app/models/spree_cm_commissioner/homepage_background_app_image.rb
@@ -1259,6 +1265,7 @@ files:
1259
1265
  - app/models/spree_cm_commissioner/imports/import_order.rb
1260
1266
  - app/models/spree_cm_commissioner/invite.rb
1261
1267
  - app/models/spree_cm_commissioner/invite_guest.rb
1268
+ - app/models/spree_cm_commissioner/invite_team.rb
1262
1269
  - app/models/spree_cm_commissioner/invite_user_event.rb
1263
1270
  - app/models/spree_cm_commissioner/invite_user_taxon.rb
1264
1271
  - app/models/spree_cm_commissioner/invoice.rb
@@ -1292,6 +1299,7 @@ files:
1292
1299
  - app/models/spree_cm_commissioner/product_completion_step.rb
1293
1300
  - app/models/spree_cm_commissioner/product_completion_steps/chatrace_telegram.rb
1294
1301
  - app/models/spree_cm_commissioner/product_decorator.rb
1302
+ - app/models/spree_cm_commissioner/product_dynamic_field.rb
1295
1303
  - app/models/spree_cm_commissioner/product_google_wallet.rb
1296
1304
  - app/models/spree_cm_commissioner/product_place.rb
1297
1305
  - app/models/spree_cm_commissioner/promotion/actions/create_date_specific_item_adjustments.rb
@@ -1649,10 +1657,13 @@ files:
1649
1657
  - app/serializers/spree_cm_commissioner/v2/storefront/calculator_serializer.rb
1650
1658
  - app/serializers/spree_cm_commissioner/v2/storefront/category_taxon_serializer.rb
1651
1659
  - app/serializers/spree_cm_commissioner/v2/storefront/check_in_serializer.rb
1660
+ - app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_option_serializer.rb
1661
+ - app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_serializer.rb
1652
1662
  - app/serializers/spree_cm_commissioner/v2/storefront/event_option_value_serializer.rb
1653
1663
  - app/serializers/spree_cm_commissioner/v2/storefront/event_variant_serializer.rb
1654
1664
  - app/serializers/spree_cm_commissioner/v2/storefront/google_wallet_serializer.rb
1655
1665
  - app/serializers/spree_cm_commissioner/v2/storefront/guest_card_class_serializer.rb
1666
+ - app/serializers/spree_cm_commissioner/v2/storefront/guest_dynamic_field_serializer.rb
1656
1667
  - app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb
1657
1668
  - app/serializers/spree_cm_commissioner/v2/storefront/homepage_background_serializer.rb
1658
1669
  - app/serializers/spree_cm_commissioner/v2/storefront/homepage_banner_serializer.rb
@@ -1661,6 +1672,7 @@ files:
1661
1672
  - app/serializers/spree_cm_commissioner/v2/storefront/menu_item_serializer_decorator.rb
1662
1673
  - app/serializers/spree_cm_commissioner/v2/storefront/payment_method_group_serializer.rb
1663
1674
  - app/serializers/spree_cm_commissioner/v2/storefront/pin_code_serializer.rb
1675
+ - app/serializers/spree_cm_commissioner/v2/storefront/product_dynamic_field_serializer.rb
1664
1676
  - app/serializers/spree_cm_commissioner/v2/storefront/product_place_serializer.rb
1665
1677
  - app/serializers/spree_cm_commissioner/v2/storefront/promotion_action_serializer.rb
1666
1678
  - app/serializers/spree_cm_commissioner/v2/storefront/promotion_rule_serializer.rb
@@ -2140,6 +2152,7 @@ files:
2140
2152
  - app/views/spree_cm_commissioner/layouts/event_transactional_mailer.html.erb
2141
2153
  - app/views/spree_cm_commissioner/layouts/line_item_mailer.html.erb
2142
2154
  - app/views/spree_cm_commissioner/layouts/order_mailer.html.erb
2155
+ - app/views/spree_cm_commissioner/layouts/team_invite_mailer.html.erb
2143
2156
  - app/views/spree_cm_commissioner/layouts/telegram.html.erb
2144
2157
  - app/views/spree_cm_commissioner/line_item_mailer/_greeting.html.erb
2145
2158
  - app/views/spree_cm_commissioner/line_item_mailer/_mailer_stylesheets.html.erb
@@ -2156,6 +2169,8 @@ files:
2156
2169
  - app/views/spree_cm_commissioner/order_mailer/purchased_items/_items.html.erb
2157
2170
  - app/views/spree_cm_commissioner/order_mailer/purchased_items/_summary.html.erb
2158
2171
  - app/views/spree_cm_commissioner/pin_code_mailer/send_pin_code.html.erb
2172
+ - app/views/spree_cm_commissioner/team_invite_mailer/_mailer_stylesheets.html.erb
2173
+ - app/views/spree_cm_commissioner/team_invite_mailer/send_team_invite_email.html.erb
2159
2174
  - bin/rails
2160
2175
  - config/brakeman.yml
2161
2176
  - config/initializers/assets.rb
@@ -2471,6 +2486,7 @@ files:
2471
2486
  - db/migrate/20250506092929_add_trip_count_to_cm_vendor_stops.rb
2472
2487
  - db/migrate/20250509033437_create_spree_cm_commissioner_transactional_emails.rb
2473
2488
  - db/migrate/20250509075429_add_max_order_quantity_to_spree_product.rb
2489
+ - db/migrate/20250512072817_create_spree_cm_commissioner_invite_team.rb
2474
2490
  - db/migrate/20250512075319_add_tenant_id_to_spree_cms_pages.rb
2475
2491
  - db/migrate/20250520042602_add_event_to_spree_products.rb
2476
2492
  - db/migrate/20250520044533_add_event_to_spree_line_items.rb
@@ -2483,6 +2499,11 @@ files:
2483
2499
  - db/migrate/20250531074036_create_spree_cm_commissioner_option_value_vehicle.rb
2484
2500
  - db/migrate/20250531074258_create_spree_cm_commissioner_vehicle_option_types.rb
2485
2501
  - db/migrate/20250602094751_add_host_to_cm_tenants.rb
2502
+ - db/migrate/20250605024523_add_participation_type_to_spree_taxon.rb
2503
+ - db/migrate/20250606020914_create_cm_dynamic_fields.rb
2504
+ - db/migrate/20250606020958_create_cm_guest_dynamic_fields.rb
2505
+ - db/migrate/20250606021044_create_cm_dynamic_field_options.rb
2506
+ - db/migrate/20250606021045_create_cm_product_dynamic_fields.rb
2486
2507
  - db/migrate/20250609015216_remove_claimed_at_and_expires_at_from_cm_invite_guest.rb
2487
2508
  - db/migrate/20250610080108_add_contact_to_cm_guests.rb
2488
2509
  - db/migrate/20250611023548_add_country_code_to_guests.rb
@@ -2639,9 +2660,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
2639
2660
  version: '2.7'
2640
2661
  required_rubygems_version: !ruby/object:Gem::Requirement
2641
2662
  requirements:
2642
- - - ">="
2663
+ - - ">"
2643
2664
  - !ruby/object:Gem::Version
2644
- version: '0'
2665
+ version: 1.3.1
2645
2666
  requirements:
2646
2667
  - none
2647
2668
  rubygems_version: 3.4.1