spree_cm_commissioner 2.9.2 → 2.9.4

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/controllers/concerns/spree_cm_commissioner/load_test_account_scope.rb +14 -21
  4. data/app/controllers/concerns/spree_cm_commissioner/load_test_bypassable.rb +29 -0
  5. data/app/controllers/spree/api/chatrace/guests_controller.rb +1 -1
  6. data/app/controllers/spree/api/v2/storefront/account/guest_dynamic_fields_controller.rb +19 -48
  7. data/app/controllers/spree/api/v2/storefront/account/mark_guest_info_complete_controller.rb +2 -2
  8. data/app/controllers/spree/api/v2/storefront/account/orders_controller_decorator.rb +5 -15
  9. data/app/controllers/spree/api/v2/storefront/account/saved_guests_controller.rb +65 -0
  10. data/app/controllers/spree/api/v2/storefront/draft_orders_controller.rb +3 -0
  11. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +10 -9
  12. data/app/controllers/spree/api/v2/storefront/order_histories_controller.rb +0 -1
  13. data/app/controllers/spree/api/v2/tenant/account/saved_guests_controller.rb +70 -0
  14. data/app/controllers/spree/api/v2/tenant/episodes_controller.rb +3 -1
  15. data/app/controllers/spree/api/v2/tenant/guests_controller.rb +11 -21
  16. data/app/controllers/spree/api/v2/tenant/order_histories_controller.rb +0 -1
  17. data/app/controllers/spree_cm_commissioner/admin/variants_controller_decorator.rb +7 -1
  18. data/app/controllers/spree_cm_commissioner/api/v2/storefront/checkout_controller_decorator.rb +3 -14
  19. data/app/jobs/spree_cm_commissioner/maintenance_tasks/guest_data_fill_stage_batch_job.rb +28 -0
  20. data/app/models/concerns/spree_cm_commissioner/guest_data_fill_stage_concern.rb +82 -0
  21. data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +4 -0
  22. data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +1 -1
  23. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +13 -31
  24. data/app/models/spree_cm_commissioner/current.rb +6 -3
  25. data/app/models/spree_cm_commissioner/dynamic_field.rb +12 -0
  26. data/app/models/spree_cm_commissioner/guest.rb +1 -144
  27. data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +43 -71
  28. data/app/models/spree_cm_commissioner/maintenance_tasks/guest_data_fill_stage.rb +21 -0
  29. data/app/models/spree_cm_commissioner/order_decorator.rb +26 -0
  30. data/app/models/spree_cm_commissioner/product_decorator.rb +0 -22
  31. data/app/models/spree_cm_commissioner/product_dynamic_field.rb +17 -0
  32. data/app/models/spree_cm_commissioner/request_guard.rb +19 -0
  33. data/app/models/spree_cm_commissioner/user_decorator.rb +26 -1
  34. data/app/models/spree_cm_commissioner/voting_contestant.rb +13 -2
  35. data/app/queries/spree_cm_commissioner/event_chart_queries.rb +2 -2
  36. data/app/queries/spree_cm_commissioner/pie_chart_event_aggregator_queries.rb +2 -2
  37. data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +2 -2
  38. data/app/serializers/spree/v2/storefront/user_serializer_decorator.rb +3 -1
  39. data/app/serializers/spree/v2/tenant/saved_guest_serializer.rb +23 -0
  40. data/app/serializers/spree_cm_commissioner/v2/storefront/cart_serializer_decorator.rb +1 -0
  41. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +3 -6
  42. data/app/serializers/spree_cm_commissioner/v2/storefront/ticket_transfer_serializer.rb +2 -2
  43. data/app/services/spree_cm_commissioner/{cart/create_guest.rb → guests/create.rb} +12 -10
  44. data/app/services/spree_cm_commissioner/guests/refresh_data_fill_stage.rb +20 -0
  45. data/app/services/spree_cm_commissioner/guests/send_dynamic_field_notification.rb +15 -0
  46. data/app/services/spree_cm_commissioner/guests/update.rb +68 -0
  47. data/app/services/spree_cm_commissioner/inventory_holds/validate_limits.rb +8 -3
  48. data/app/services/spree_cm_commissioner/load_test/destroy_accounts.rb +7 -10
  49. data/app/services/spree_cm_commissioner/load_test/generate_booking_ticket_data.rb +83 -19
  50. data/app/services/spree_cm_commissioner/order/guests/update.rb +5 -8
  51. data/app/services/spree_cm_commissioner/voting_contestants/advancer.rb +10 -3
  52. data/app/services/spree_cm_commissioner/voting_contestants/assigner.rb +20 -2
  53. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +15 -9
  54. data/app/views/spree/admin/variants/fixture.html.erb +1 -1
  55. data/config/initializers/spree_permitted_attributes.rb +19 -0
  56. data/config/load_test_flows/tenant.yml +47 -0
  57. data/config/locales/en.yml +2 -5
  58. data/config/locales/km.yml +2 -0
  59. data/config/routes.rb +3 -1
  60. data/db/migrate/20260713022227_add_advanced_to_episode_id_to_cm_voting_contestants.rb +8 -0
  61. data/db/migrate/20260714002626_rename_data_fill_stage_phase_on_cm_guests.rb +5 -0
  62. data/lib/spree_cm_commissioner/version.rb +1 -1
  63. data/lib/tasks/recompute_guest_data_fill_stage.rake +19 -0
  64. metadata +17 -12
  65. data/app/controllers/spree/api/v2/storefront/saved_guests_controller.rb +0 -77
  66. data/app/interactors/spree_cm_commissioner/guest_dynamic_field_notification_sender.rb +0 -11
  67. data/app/interactors/spree_cm_commissioner/guest_dynamic_fields_manager.rb +0 -33
  68. data/app/serializers/spree/v2/storefront/order_serializer_decorator.rb +0 -63
  69. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_minimal_serializer.rb +0 -30
  70. data/app/serializers/spree_cm_commissioner/v2/storefront/line_item_minimal_serializer.rb +0 -57
  71. data/app/serializers/spree_cm_commissioner/v2/storefront/ticket_transfer_minimal_serializer.rb +0 -17
  72. data/app/services/spree_cm_commissioner/update_guest_service.rb +0 -129
  73. data/app/services/spree_cm_commissioner/users/incomplete_guest_checker_service.rb +0 -34
@@ -1,30 +0,0 @@
1
- module SpreeCmCommissioner
2
- module V2
3
- module Storefront
4
- class GuestMinimalSerializer < BaseSerializer
5
- set_type :guest
6
-
7
- attributes :first_name, :last_name, :dob, :gender, :kyc_fields, :other_occupation, :created_at, :updated_at,
8
- :qr_data, :social_contact_platform, :social_contact, :available_social_contact_platforms,
9
- :age, :emergency_contact, :other_organization, :expectation, :upload_later, :address, :formatted_bib_number, :phone_number,
10
- :token, :country_code, :contact, :data_fill_stage_phase,
11
- :saved_guest_id, :state
12
-
13
- attribute :seat_number do |object|
14
- object.seat_number || object.formatted_bib_number
15
- end
16
-
17
- attribute :allowed_checkout, &:allowed_checkout?
18
- attribute :allowed_upload_later, &:allowed_upload_later?
19
- attribute :require_kyc_field, &:require_kyc_field?
20
-
21
- belongs_to :line_item, serializer: SpreeCmCommissioner::V2::Storefront::LineItemMinimalSerializer
22
-
23
- has_many :check_ins, serializer: SpreeCmCommissioner::V2::Storefront::CheckInSerializer
24
- has_many :ticket_transfers, serializer: SpreeCmCommissioner::V2::Storefront::TicketTransferMinimalSerializer
25
-
26
- cache_options store: nil
27
- end
28
- end
29
- end
30
- end
@@ -1,57 +0,0 @@
1
- module SpreeCmCommissioner
2
- module V2
3
- module Storefront
4
- # Mirrors LineItemSerializer + its decorator attributes and relationships,
5
- # but omits has_many :guests, :pending_guests, and :saved_guests to prevent
6
- # a circular serialization cycle: LineItemSerializer embeds guests via
7
- # GuestMinimalSerializer, which in turn embeds this LineItemMinimalSerializer.
8
- class LineItemMinimalSerializer < BaseSerializer
9
- set_type :line_item
10
-
11
- attributes :name, :quantity, :price, :slug, :options_text, :currency,
12
- :display_price, :total, :display_total, :adjustment_total,
13
- :display_adjustment_total, :additional_tax_total,
14
- :discounted_amount, :display_discounted_amount,
15
- :display_additional_tax_total, :promo_total, :display_promo_total,
16
- :included_tax_total, :display_included_tax_total,
17
- :pre_tax_amount, :display_pre_tax_amount, :public_metadata,
18
- :from_date, :to_date, :need_confirmation, :product_type, :event_status, :amount, :display_amount,
19
- :checkin_date, :checkout_date,
20
- :number, :qr_data,
21
- :kyc, :kyc_fields, :remaining_total_guests, :number_of_guests,
22
- :completion_steps, :available_social_contact_platforms, :allow_anonymous_booking, :discontinue_on,
23
- :high_demand, :jwt_token,
24
- :direction, :trip_id, :boarding_trip_stop_id, :drop_off_trip_stop_id
25
-
26
- attribute :required_self_check_in_location, &:required_self_check_in_location?
27
- attribute :allowed_self_check_in, &:allowed_self_check_in?
28
- attribute :allowed_upload_later, &:allowed_upload_later?
29
- attribute :delivery_required, &:delivery_required?
30
- attribute :sufficient_stock, &:sufficient_stock?
31
-
32
- attribute :pickup_map_place do |line_item|
33
- line_item.pickup_map_place&.to_h
34
- end
35
-
36
- attribute :dropoff_map_place do |line_item|
37
- line_item.dropoff_map_place&.to_h
38
- end
39
-
40
- attribute :distance do |line_item|
41
- line_item.distance&.to_h
42
- end
43
-
44
- belongs_to :variant, serializer: Spree::V2::Storefront::VariantSerializer
45
- has_many :digital_links, serializer: Spree::V2::Storefront::DigitalLinkSerializer
46
-
47
- has_one :vendor, serializer: Spree::V2::Storefront::VendorSerializer
48
- belongs_to :order, serializer: Spree::V2::Storefront::OrderSerializer
49
- has_one :google_wallet, serializer: SpreeCmCommissioner::V2::Storefront::GoogleWalletSerializer
50
- has_one :product, serializer: Spree::V2::Storefront::ProductSerializer
51
- has_one :event, serializer: Spree::V2::Storefront::TaxonSerializer
52
-
53
- cache_options store: nil
54
- end
55
- end
56
- end
57
- end
@@ -1,17 +0,0 @@
1
- module SpreeCmCommissioner
2
- module V2
3
- module Storefront
4
- class TicketTransferMinimalSerializer < BaseSerializer
5
- set_type :ticket_transfer
6
-
7
- attributes :number, :state, :price, :platform_fee, :seller_net, :total, :currency, :token,
8
- :transfer_type, :settlement_status, :completed_at, :expires_at, :created_at, :updated_at
9
-
10
- belongs_to :from_user, serializer: ::Spree::V2::Storefront::UserSerializer
11
- belongs_to :to_user, serializer: ::Spree::V2::Storefront::UserSerializer
12
- belongs_to :event, serializer: Spree::V2::Storefront::TaxonSerializer
13
- belongs_to :product, serializer: Spree::V2::Storefront::ProductSerializer
14
- end
15
- end
16
- end
17
- end
@@ -1,129 +0,0 @@
1
- module SpreeCmCommissioner
2
- # Updates guest records with dynamic fields.
3
- # Handles create/update/delete of dynamic fields with automatic cleanup of removed fields.
4
- class UpdateGuestService
5
- attr_reader :guest, :guest_params
6
-
7
- def initialize(guest, guest_params)
8
- @guest = guest
9
- @guest_params = guest_params
10
- end
11
-
12
- # Updates guest within transaction: process dynamic fields → update attributes → move to next stage
13
- def call
14
- ActiveRecord::Base.transaction do
15
- process_dynamic_fields(guest_params[:guest_dynamic_fields_attributes]) if guest_params[:guest_dynamic_fields_attributes]
16
-
17
- guest.assign_attributes(guest_params.except(:guest_dynamic_fields_attributes))
18
- guest.save!
19
-
20
- guest.save_and_move_to_next_stage
21
- end
22
- guest
23
- end
24
-
25
- private
26
-
27
- # Processes dynamic fields: destroy marked fields, upsert valid ones, cleanup unlisted fields
28
- def process_dynamic_fields(dynamic_fields_attributes)
29
- sent_keys = []
30
-
31
- dynamic_fields_attributes.each do |raw_attributes|
32
- attributes = raw_attributes.to_h.symbolize_keys
33
- should_destroy = ActiveModel::Type::Boolean.new.cast(attributes[:_destroy])
34
-
35
- if should_destroy
36
- destroy_guest_dynamic_field(attributes[:id])
37
- elsif attributes[:id].blank? || guest.guest_dynamic_fields.exists?(attributes[:id])
38
- field = upsert_guest_dynamic_field(attributes)
39
- sent_keys << field_key(field)
40
- end
41
- end
42
-
43
- # Auto-cleanup: delete existing fields not in current submission
44
- guest.guest_dynamic_fields.includes(:dynamic_field).find_each do |field|
45
- field.destroy! unless sent_keys.include?(field_key(field))
46
- end
47
- end
48
-
49
- def field_key(field)
50
- if field.dynamic_field.requires_dynamic_field_options?
51
- [field.dynamic_field_id, field.dynamic_field_option_id]
52
- else
53
- [field.dynamic_field_id]
54
- end
55
- end
56
-
57
- # Creates/updates field with validation: prevents dynamic_field_id changes, loads associations, sets options
58
- def upsert_guest_dynamic_field(attributes)
59
- field = find_or_initialize_guest_dynamic_field(attributes)
60
-
61
- if attributes[:id].present? && attributes[:dynamic_field_id].present? && field.dynamic_field_id.to_i != attributes[:dynamic_field_id].to_i
62
- field.errors.add(:base, "Cannot change dynamic_field_id for existing GuestDynamicField (ID: #{attributes[:id]})")
63
- raise ActiveRecord::RecordInvalid, field
64
- end
65
-
66
- if attributes[:dynamic_field_id].present? && field.dynamic_field.blank?
67
- field.dynamic_field = SpreeCmCommissioner::DynamicField.find_by(id: attributes[:dynamic_field_id])
68
- unless field.dynamic_field
69
- field.errors.add(:dynamic_field, 'not found')
70
- raise ActiveRecord::RecordInvalid, field
71
- end
72
- end
73
-
74
- field.assign_attributes(attributes.except(:id, :_destroy, :dynamic_field_option_id))
75
-
76
- field.dynamic_field_option_id = attributes[:dynamic_field_option_id].to_i if attributes[:dynamic_field_option_id].present?
77
-
78
- associate_dynamic_field_option(field) if field.dynamic_field&.requires_dynamic_field_options?
79
-
80
- field.save!
81
- field
82
- end
83
-
84
- # Finds and associates option by ID or value, sets field value if empty
85
- def associate_dynamic_field_option(field)
86
- return unless field.dynamic_field&.requires_dynamic_field_options?
87
-
88
- option_id = field.dynamic_field_option_id.presence || field.value
89
-
90
- option_lookup_id = option_id.to_s.match?(/\A\d+\z/) ? option_id.to_i : option_id
91
-
92
- option = if option_lookup_id.is_a?(Integer)
93
- field.dynamic_field.dynamic_field_options.find_by(id: option_lookup_id)
94
- else
95
- field.dynamic_field.dynamic_field_options.find_by(value: option_lookup_id)
96
- end
97
-
98
- raise ActiveRecord::RecordNotFound, 'Option not found' unless option
99
-
100
- field.dynamic_field_option = option
101
- field.value = option.value if field.value.blank?
102
- end
103
-
104
- def find_or_initialize_guest_dynamic_field(attributes)
105
- if attributes[:id].present?
106
- guest.guest_dynamic_fields.find(attributes[:id])
107
-
108
- elsif attributes[:dynamic_field_option_id].present?
109
- guest.guest_dynamic_fields.find_by(
110
- dynamic_field_id: attributes[:dynamic_field_id],
111
- dynamic_field_option_id: attributes[:dynamic_field_option_id]
112
- ) || guest.guest_dynamic_fields.build
113
-
114
- else
115
- guest.guest_dynamic_fields.find_by(
116
- dynamic_field_id: attributes[:dynamic_field_id],
117
- dynamic_field_option_id: nil
118
- ) || guest.guest_dynamic_fields.build
119
- end
120
- end
121
-
122
- def destroy_guest_dynamic_field(id)
123
- return if id.blank?
124
-
125
- field = guest.guest_dynamic_fields.find_by(id: id)
126
- field&.destroy!
127
- end
128
- end
129
- end
@@ -1,34 +0,0 @@
1
- module SpreeCmCommissioner
2
- module Users
3
- class IncompleteGuestCheckerService
4
- attr_reader :user
5
-
6
- def initialize(user)
7
- @user = user
8
- end
9
-
10
- def call
11
- return if user.blank? || incomplete_guest_info?
12
-
13
- user.public_metadata['has_incomplete_guest_info'] = false
14
- user.save!
15
- end
16
-
17
- private
18
-
19
- def incomplete_guest_info?
20
- guests =
21
- SpreeCmCommissioner::Guest
22
- .joins(line_item: :order)
23
- .includes(:guest_dynamic_fields, line_item: { product: :dynamic_fields })
24
- .where(spree_orders: { user_id: user.id, state: 'complete' })
25
-
26
- guests.any? do |guest|
27
- guest.pre_registration_completed? &&
28
- guest.post_registration_fields? &&
29
- !guest.post_registration_completed?
30
- end
31
- end
32
- end
33
- end
34
- end