spree_cm_commissioner 2.8.3.pre.pre13 → 2.8.4.pre.pre1

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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test_and_build_gem.yml +1 -2
  3. data/.gitignore +0 -6
  4. data/Gemfile.lock +1 -1
  5. data/app/controllers/concerns/spree_cm_commissioner/content_cachable.rb +0 -2
  6. data/app/controllers/spree/admin/homepage_section_controller.rb +1 -4
  7. data/app/controllers/spree/admin/taxons_controller_decorator.rb +5 -19
  8. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +7 -5
  9. data/app/controllers/spree/api/v2/storefront/homepage_sections_controller.rb +0 -1
  10. data/app/controllers/spree/api/v2/tenant/base_controller.rb +0 -4
  11. data/app/controllers/spree/api/v2/tenant/homepage_sections_controller.rb +0 -1
  12. data/app/controllers/spree/api/v2/tenant/products_controller.rb +1 -1
  13. data/app/controllers/spree/api/v2/tenant/taxons_controller.rb +1 -1
  14. data/app/controllers/spree_cm_commissioner/admin/products_controller_decorator.rb +0 -19
  15. data/app/finders/spree_cm_commissioner/events/find_matches.rb +0 -1
  16. data/app/helpers/spree_cm_commissioner/admin/homepage_segment_helper.rb +0 -2
  17. data/app/interactors/spree_cm_commissioner/waiting_guests_caller.rb +38 -4
  18. data/app/jobs/spree_cm_commissioner/waiting_room/stamp_queue_positions_job.rb +84 -0
  19. data/app/models/concerns/spree_cm_commissioner/homepage_section_bitwise.rb +1 -2
  20. data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +16 -2
  21. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +1 -2
  22. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +0 -10
  23. data/app/models/concerns/spree_cm_commissioner/product_type.rb +1 -1
  24. data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +1 -3
  25. data/app/models/spree_cm_commissioner/import.rb +1 -1
  26. data/app/models/spree_cm_commissioner/product_decorator.rb +0 -52
  27. data/app/models/spree_cm_commissioner/role_decorator.rb +1 -4
  28. data/app/models/spree_cm_commissioner/taxon_ad_banner.rb +12 -0
  29. data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -23
  30. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +1 -19
  31. data/app/models/spree_cm_commissioner/tenant.rb +0 -9
  32. data/app/models/spree_cm_commissioner/user_decorator.rb +0 -5
  33. data/app/models/spree_cm_commissioner/variant_decorator.rb +0 -4
  34. data/app/models/spree_cm_commissioner/variant_options.rb +0 -4
  35. data/app/models/spree_cm_commissioner/vendor_decorator.rb +0 -4
  36. data/app/overrides/spree/admin/taxons/_form/assets_form.html.erb.deface +10 -1
  37. data/app/serializers/spree/v2/storefront/homepage_section_serializer.rb +1 -1
  38. data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +1 -2
  39. data/app/serializers/spree/v2/storefront/role_serializer.rb +1 -1
  40. data/app/serializers/spree/v2/storefront/taxon_serializer_decorator.rb +3 -2
  41. data/app/serializers/spree/v2/tenant/homepage_section_serializer.rb +1 -1
  42. data/app/serializers/spree/v2/tenant/role_serializer.rb +1 -1
  43. data/app/services/spree_cm_commissioner/api_caches/invalidate.rb +0 -12
  44. data/app/services/spree_cm_commissioner/cart/add_guest.rb +6 -1
  45. data/app/services/spree_cm_commissioner/cart/create_guest.rb +61 -0
  46. data/app/services/spree_cm_commissioner/cart/remove_guest.rb +6 -1
  47. data/app/views/spree/admin/homepage_section/_form.html.erb +0 -5
  48. data/config/initializers/spree_permitted_attributes.rb +0 -8
  49. data/config/locales/en.yml +4 -45
  50. data/config/locales/km.yml +2 -32
  51. data/config/routes.rb +1 -28
  52. data/lib/spree_cm_commissioner/version.rb +1 -1
  53. data/lib/spree_cm_commissioner.rb +1 -7
  54. data/spree_cm_commissioner.gemspec +1 -1
  55. metadata +4 -127
  56. data/app/controllers/spree/api/v2/storefront/preview_products_controller.rb +0 -48
  57. data/app/controllers/spree/api/v2/storefront/preview_sections_controller.rb +0 -27
  58. data/app/controllers/spree/api/v2/storefront/preview_taxons_controller.rb +0 -18
  59. data/app/controllers/spree/api/v2/storefront/products_controller_decorator.rb +0 -15
  60. data/app/controllers/spree/api/v2/storefront/taxons_controller_decorator.rb +0 -15
  61. data/app/controllers/spree/api/v2/tenant/ad_campaigns_controller.rb +0 -25
  62. data/app/controllers/spree/api/v2/tenant/episodes_controller.rb +0 -38
  63. data/app/controllers/spree/api/v2/tenant/free_vote_claims_controller.rb +0 -37
  64. data/app/controllers/spree/api/v2/tenant/preview_products_controller.rb +0 -47
  65. data/app/controllers/spree/api/v2/tenant/preview_sections_controller.rb +0 -26
  66. data/app/controllers/spree/api/v2/tenant/preview_shows_controller.rb +0 -19
  67. data/app/controllers/spree/api/v2/tenant/preview_taxons_controller.rb +0 -19
  68. data/app/controllers/spree/api/v2/tenant/show_contestants_controller.rb +0 -52
  69. data/app/controllers/spree/api/v2/tenant/show_elimination_sessions_controller.rb +0 -57
  70. data/app/controllers/spree/api/v2/tenant/show_people_controller.rb +0 -49
  71. data/app/controllers/spree/api/v2/tenant/show_person_assignments_controller.rb +0 -36
  72. data/app/controllers/spree/api/v2/tenant/shows_controller.rb +0 -36
  73. data/app/controllers/spree/api/v2/tenant/votes_controller.rb +0 -94
  74. data/app/controllers/spree/api/v2/tenant/voting_contestants_controller.rb +0 -43
  75. data/app/controllers/spree/api/v2/tenant/voting_credit_transactions_controller.rb +0 -41
  76. data/app/controllers/spree/api/v2/tenant/voting_credits_controller.rb +0 -31
  77. data/app/jobs/spree_cm_commissioner/show_contestants/import_job.rb +0 -9
  78. data/app/jobs/spree_cm_commissioner/vote_fraud_event_job.rb +0 -9
  79. data/app/jobs/spree_cm_commissioner/voting_credit_allocation_job.rb +0 -10
  80. data/app/jobs/spree_cm_commissioner/voting_credit_de_allocation_job.rb +0 -10
  81. data/app/models/concerns/spree_cm_commissioner/voting_session_live_stream_concern.rb +0 -41
  82. data/app/models/spree_cm_commissioner/imports/import_contestant.rb +0 -7
  83. data/app/models/spree_cm_commissioner/maintenance_tasks/voting_session.rb +0 -36
  84. data/app/models/spree_cm_commissioner/preview_role.rb +0 -8
  85. data/app/models/spree_cm_commissioner/role_user_decorator.rb +0 -8
  86. data/app/models/spree_cm_commissioner/show.rb +0 -163
  87. data/app/models/spree_cm_commissioner/show_contestant.rb +0 -39
  88. data/app/models/spree_cm_commissioner/show_contestant_image.rb +0 -11
  89. data/app/models/spree_cm_commissioner/show_contestant_video.rb +0 -15
  90. data/app/models/spree_cm_commissioner/show_episode.rb +0 -108
  91. data/app/models/spree_cm_commissioner/show_person.rb +0 -15
  92. data/app/models/spree_cm_commissioner/show_person_assignment.rb +0 -21
  93. data/app/models/spree_cm_commissioner/show_person_image.rb +0 -11
  94. data/app/models/spree_cm_commissioner/vote.rb +0 -16
  95. data/app/models/spree_cm_commissioner/vote_fraud_event.rb +0 -20
  96. data/app/models/spree_cm_commissioner/voting_contestant.rb +0 -100
  97. data/app/models/spree_cm_commissioner/voting_credit.rb +0 -72
  98. data/app/models/spree_cm_commissioner/voting_credit_transaction.rb +0 -55
  99. data/app/models/spree_cm_commissioner/voting_session.rb +0 -216
  100. data/app/models/spree_cm_commissioner/voting_session_stat.rb +0 -8
  101. data/app/overrides/spree/admin/products/_form/preview_checkbox.html.erb.deface +0 -9
  102. data/app/overrides/spree/admin/taxons/_form/preview_checkbox.html.erb.deface +0 -7
  103. data/app/serializers/spree/v2/tenant/ad_campaign_serializer.rb +0 -13
  104. data/app/serializers/spree/v2/tenant/advertisement_serializer.rb +0 -11
  105. data/app/serializers/spree/v2/tenant/show_contestant_serializer.rb +0 -21
  106. data/app/serializers/spree/v2/tenant/show_episode_serializer.rb +0 -20
  107. data/app/serializers/spree/v2/tenant/show_person_assignment_serializer.rb +0 -16
  108. data/app/serializers/spree/v2/tenant/show_person_serializer.rb +0 -13
  109. data/app/serializers/spree/v2/tenant/show_serializer.rb +0 -21
  110. data/app/serializers/spree/v2/tenant/video_serializer.rb +0 -9
  111. data/app/serializers/spree/v2/tenant/vote_package_serializer.rb +0 -9
  112. data/app/serializers/spree/v2/tenant/vote_serializer.rb +0 -14
  113. data/app/serializers/spree/v2/tenant/voting_contestant_serializer.rb +0 -23
  114. data/app/serializers/spree/v2/tenant/voting_credit_serializer.rb +0 -10
  115. data/app/serializers/spree/v2/tenant/voting_credit_transaction_serializer.rb +0 -14
  116. data/app/serializers/spree/v2/tenant/voting_session_serializer.rb +0 -21
  117. data/app/services/spree_cm_commissioner/fraud_check.rb +0 -299
  118. data/app/services/spree_cm_commissioner/imports/contestants/create.rb +0 -153
  119. data/app/services/spree_cm_commissioner/show_contestants/normalize_video_highlights.rb +0 -57
  120. data/app/services/spree_cm_commissioner/show_persons/contestant_assigner.rb +0 -51
  121. data/app/services/spree_cm_commissioner/url_embed/youtube_embed.rb +0 -44
  122. data/app/services/spree_cm_commissioner/vote_counters/audit_counters.rb +0 -43
  123. data/app/services/spree_cm_commissioner/vote_counters/base.rb +0 -31
  124. data/app/services/spree_cm_commissioner/vote_counters/increment.rb +0 -44
  125. data/app/services/spree_cm_commissioner/vote_counters/per_contestant_counter.rb +0 -68
  126. data/app/services/spree_cm_commissioner/vote_counters/rebuild_from_db.rb +0 -70
  127. data/app/services/spree_cm_commissioner/vote_counters/snapshot_to_db.rb +0 -113
  128. data/app/services/spree_cm_commissioner/vote_credit_deductor.rb +0 -68
  129. data/app/services/spree_cm_commissioner/vote_package/create.rb +0 -145
  130. data/app/services/spree_cm_commissioner/vote_package/update.rb +0 -91
  131. data/app/services/spree_cm_commissioner/vote_processor.rb +0 -144
  132. data/app/services/spree_cm_commissioner/voting_contestants/advancer.rb +0 -335
  133. data/app/services/spree_cm_commissioner/voting_contestants/assigner.rb +0 -40
  134. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +0 -106
  135. data/app/services/spree_cm_commissioner/voting_credits/allocate.rb +0 -77
  136. data/app/services/spree_cm_commissioner/voting_credits/claim_free_votes.rb +0 -119
  137. data/app/services/spree_cm_commissioner/voting_credits/credit_calculator.rb +0 -35
  138. data/app/services/spree_cm_commissioner/voting_credits/de_allocate.rb +0 -87
  139. data/app/services/spree_cm_commissioner/voting_leaderboards/calculate_score.rb +0 -67
  140. data/app/services/spree_cm_commissioner/voting_leaderboards/combined_result.rb +0 -190
  141. data/app/services/spree_cm_commissioner/voting_sessions/finalize.rb +0 -105
  142. data/db/migrate/20260309230148_create_cm_show_people.rb +0 -14
  143. data/db/migrate/20260309230149_create_cm_show_people_assignments.rb +0 -16
  144. data/db/migrate/20260310082711_create_cm_show_contestants.rb +0 -28
  145. data/db/migrate/20260310082720_create_cm_voting_sessions.rb +0 -21
  146. data/db/migrate/20260310082721_create_cm_voting_contestants.rb +0 -23
  147. data/db/migrate/20260310082734_add_voting_fields_to_spree_taxons.rb +0 -9
  148. data/db/migrate/20260310082735_add_type_to_spree_products.rb +0 -6
  149. data/db/migrate/20260310082749_create_cm_voting_credits.rb +0 -27
  150. data/db/migrate/20260326080200_create_cm_voting_credit_transactions.rb +0 -27
  151. data/db/migrate/20260330160000_create_cm_votes.rb +0 -25
  152. data/db/migrate/20260401072500_add_advanced_from_to_cm_voting_contestants.rb +0 -7
  153. data/db/migrate/20260402000001_add_voting_credit_scope_to_spree_taxons.rb +0 -6
  154. data/db/migrate/20260402000002_rename_scopeable_to_votable_in_cm_voting_credits.rb +0 -12
  155. data/db/migrate/20260403070000_add_name_to_cm_voting_sessions.rb +0 -5
  156. data/db/migrate/20260406000001_add_vendor_id_to_voting_tables.rb +0 -6
  157. data/db/migrate/20260406000001_rename_votes_remaining_to_amount_in_cm_voting_credits.rb +0 -11
  158. data/db/migrate/20260408085255_add_show_id_and_vendor_id_to_cm_voting_sessions.rb +0 -9
  159. data/db/migrate/20260420000001_rename_type_to_credit_type_in_cm_voting_credits.rb +0 -25
  160. data/db/migrate/20260422000001_create_cm_vote_fraud_events.rb +0 -23
  161. data/db/migrate/20260423000001_add_preview_to_taxons_products_and_sections.rb +0 -11
  162. data/db/migrate/20260423000002_create_preview_roles.rb +0 -24
  163. data/db/migrate/20260515120000_add_public_metadata_to_cm_voting_sessions.rb +0 -5
  164. data/db/migrate/20260518090920_add_unique_voter_count_to_voting_contestants.rb +0 -5
  165. data/db/migrate/20260518094322_create_cm_voting_session_stats.rb +0 -17
  166. data/db/migrate/20260520000001_add_scoring_model_to_cm_voting_sessions.rb +0 -5
  167. data/db/migrate/20260520000001_optimize_cm_votes_indexes.rb +0 -22
  168. data/db/migrate/20260525042257_add_vote_number_to_cm_voting_contestants.rb +0 -18
  169. data/db/migrate/20260527035430_add_confirmed_rank_to_cm_voting_contestants.rb +0 -5
  170. data/db/migrate/20260527062005_add_eliminated_at_to_cm_show_contestants.rb +0 -5
  171. data/db/migrate/20260603063652_add_parent_to_voting_sessions.rb +0 -9
  172. data/db/migrate/20260603090000_add_session_type_to_cm_voting_sessions.rb +0 -6
  173. data/db/migrate/20260608000000_add_display_to_cm_voting_sessions.rb +0 -5
  174. data/docs/sql/jsonb_query_guide.md +0 -57
  175. data/lib/spree_cm_commissioner/test_helper/factories/show_episode_factory.rb +0 -12
  176. data/lib/spree_cm_commissioner/test_helper/factories/show_factory.rb +0 -120
  177. data/lib/spree_cm_commissioner/test_helper/factories/vote_credit_factory.rb +0 -37
  178. data/lib/spree_cm_commissioner/test_helper/factories/vote_factory.rb +0 -28
  179. data/lib/spree_cm_commissioner/test_helper/factories/voting_credit_transaction_factory.rb +0 -11
  180. data/lib/spree_cm_commissioner/test_helper/factories/voting_session_factory.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eedbddb863eb9f58dad73a83892a225e971a89736c37af047df757d76bcfc058
4
- data.tar.gz: 59eaad5012be611640f1c27f6566bfb91cd7b5cea176d465be69c4230c8b9241
3
+ metadata.gz: 6b4cb4f14de6554d09bdd97872267ca1f23e73d144401b49a8969203e601b910
4
+ data.tar.gz: 454758bb34c6df3a4f1e2272b65bb19f57e7d829c06c045d7f748a72a56cb42f
5
5
  SHA512:
6
- metadata.gz: aa9db90a1c39aaa74f66135c5034cb8762e09123edaad154fb5fe6e013609b5344d23910bd8449380030c5b3e391b3a3792c92b569f5fbe2271d6e78420e55e6
7
- data.tar.gz: 80c51833f840ba8b4db0611309153c7a7723fd986f065113a06063ac7d5aee78cce2af29dd2eb591b64a90c57a75f1f4716b9d7daf2664903ff34ad031f663e4
6
+ metadata.gz: 3dea963b405471ddcf3a1b7819bab6d7ffca7b76f0567b6a0092262b5b8d980db83fc052c4913f06ff42921727bc4168c2c044beeeb38ddc65ef242071918f34
7
+ data.tar.gz: f9a841e7c01222124a041e65adf42b7e6d57b53fdc8e731c08e595dbceb601fb45fbe7ef6850df709d454b75220c4e58da2af1f8c2d0bb37d58ab00bc4c2031c
@@ -164,8 +164,7 @@ jobs:
164
164
  env:
165
165
  DATABASE_URL: postgres://myuser:mypassword@localhost:5432/test_db
166
166
  run: |
167
- # Using --no-threads to bypass a known Ruby 3.2.0 GC segmentation fault in CI.
168
- bundle exec brakeman --no-threads --no-exit-on-warn
167
+ bundle exec brakeman --no-exit-on-warn
169
168
 
170
169
  test:
171
170
  needs: [setup]
data/.gitignore CHANGED
@@ -34,9 +34,3 @@ vendor/bundle/
34
34
  # Cursor
35
35
  .cursor
36
36
  dump.rdb
37
- # Added by code-review-graph
38
- .code-review-graph/
39
- .cursorrules
40
- .claude
41
- CLAUDE.md
42
- AGENTS.md
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.8.3.pre.pre13)
37
+ spree_cm_commissioner (2.8.4.pre.pre1)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -16,7 +16,6 @@ module SpreeCmCommissioner
16
16
  GuestCardClassesController
17
17
  SeatLayoutController
18
18
  CmsPagesController
19
- AdvertisementsController
20
19
  ].freeze
21
20
 
22
21
  # Priority 2: Semi-Static (1 hour)
@@ -26,7 +25,6 @@ module SpreeCmCommissioner
26
25
  HomepageDataController
27
26
  PopularRoutesController
28
27
  RoutePlacesController
29
- ShowsController
30
28
  ].freeze
31
29
 
32
30
  # Priority 3: Moderate Freshness (30 minutes)
@@ -51,10 +51,7 @@ module Spree
51
51
  def permitted_resource_params
52
52
  segment_value = helpers.calculate_segment_value(params[:spree_cm_commissioner_homepage_section])
53
53
 
54
- params
55
- .require(:spree_cm_commissioner_homepage_section)
56
- .permit(:title, :description, :active, :tenant_id, :preview)
57
- .merge(segment: segment_value)
54
+ params.require(:spree_cm_commissioner_homepage_section).permit(:title, :description, :active, :tenant_id).merge(segment: segment_value)
58
55
  end
59
56
 
60
57
  def load_tenants
@@ -3,7 +3,6 @@ module Spree
3
3
  module TaxonsControllerDecorator
4
4
  def self.prepended(base)
5
5
  base.before_action :build_assets, only: %i[create update]
6
- base.before_action :normalize_sti_taxon_params, only: %i[create update]
7
6
  end
8
7
 
9
8
  # override
@@ -28,6 +27,10 @@ module Spree
28
27
  remove_asset(@taxon.home_banner)
29
28
  end
30
29
 
30
+ def remove_ad_banner
31
+ remove_asset(@taxon.ad_banner)
32
+ end
33
+
31
34
  def remove_video_banner
32
35
  remove_asset(@taxon.video_banner)
33
36
  end
@@ -49,26 +52,9 @@ module Spree
49
52
  @taxon.build_app_banner(attachment: permitted_resource_params.delete(:app_banner)) if permitted_resource_params[:app_banner]
50
53
  @taxon.build_web_banner(attachment: permitted_resource_params.delete(:web_banner)) if permitted_resource_params[:web_banner]
51
54
  @taxon.build_home_banner(attachment: permitted_resource_params.delete(:home_banner)) if permitted_resource_params[:home_banner]
55
+ @taxon.build_ad_banner(attachment: permitted_resource_params.delete(:ad_banner)) if permitted_resource_params[:ad_banner]
52
56
  @taxon.build_video_banner(attachment: permitted_resource_params.delete(:video_banner)) if permitted_resource_params[:video_banner]
53
57
  end
54
-
55
- # Some admin forms submit STI records under their class key
56
- # (e.g. :spree_cm_commissioner_show) while Spree update reads :taxon.
57
- # Merge both into :taxon so all edited fields are persisted.
58
- def normalize_sti_taxon_params
59
- return unless @taxon
60
-
61
- sti_key = @taxon.class.model_name.param_key.to_sym
62
- sti_params = params[sti_key]
63
- return unless sti_params.is_a?(::ActionController::Parameters)
64
-
65
- base_params = params[:taxon]
66
- base_hash = base_params.is_a?(::ActionController::Parameters) ? base_params.to_unsafe_h : {}
67
- sti_hash = sti_params.to_unsafe_h
68
- merged_params = ::ActionController::Parameters.new(base_hash.merge(sti_hash))
69
-
70
- params[:taxon] = merged_params
71
- end
72
58
  end
73
59
  end
74
60
  end
@@ -31,13 +31,15 @@ module Spree
31
31
  def create
32
32
  spree_authorize! :update, spree_current_order, order_token
33
33
 
34
- resource = scope.new(guest_params)
34
+ result = SpreeCmCommissioner::Cart::CreateGuest.call(
35
+ line_item: parent,
36
+ options: guest_params
37
+ )
35
38
 
36
- if resource.save
37
- resource.save_and_move_to_next_stage
38
- render_serialized_payload(201) { serialize_resource(resource) }
39
+ if result.success?
40
+ render_serialized_payload(201) { serialize_resource(result.value) }
39
41
  else
40
- render_error_payload(resource.errors, 422)
42
+ render_error_payload(result.value.errors, 422)
41
43
  end
42
44
  end
43
45
 
@@ -19,7 +19,6 @@ module Spree
19
19
  @collection ||= model_class.filter_by_segment(params[:homepage_id] || :general)
20
20
  .active
21
21
  .where(tenant_id: nil)
22
- .where(preview: false)
23
22
  .order(position: :asc)
24
23
  end
25
24
  end
@@ -16,10 +16,6 @@ module Spree
16
16
  set_current_tenant(@tenant)
17
17
  end
18
18
 
19
- def current_vendor
20
- @current_vendor ||= @tenant.active_vendor
21
- end
22
-
23
19
  def render_serialized_payload(status = 200)
24
20
  render json: yield, status: status, content_type: content_type
25
21
  end
@@ -5,7 +5,6 @@ module Spree
5
5
  class HomepageSectionsController < BaseController
6
6
  def collection
7
7
  @collection ||= scope.filter_by_segment(params[:homepage_id] || :general)
8
- .where(preview: false)
9
8
  .active
10
9
  .order(position: :asc)
11
10
  end
@@ -21,7 +21,7 @@ module Spree
21
21
 
22
22
  def scope
23
23
  MultiTenant.with(@tenant) do
24
- model_class.where(tenant_id: MultiTenant.current_tenant_id, preview: false)
24
+ model_class.where(tenant_id: MultiTenant.current_tenant_id)
25
25
  end
26
26
  end
27
27
 
@@ -31,7 +31,7 @@ module Spree
31
31
 
32
32
  def scope
33
33
  MultiTenant.with(@tenant) do
34
- model_class.where(preview: false)
34
+ model_class
35
35
  end
36
36
  end
37
37
 
@@ -6,7 +6,6 @@ module SpreeCmCommissioner
6
6
  base.around_action :set_writing_role, only: %i[index]
7
7
  base.after_action :set_tenant_after_update, only: %i[update]
8
8
  base.before_action :merge_industry_taxons_into_taxons, only: [:update]
9
- base.before_action :normalize_sti_product_params, only: %i[create update]
10
9
  end
11
10
 
12
11
  # Override
@@ -52,24 +51,6 @@ module SpreeCmCommissioner
52
51
 
53
52
  protected
54
53
 
55
- # Some admin forms submit STI records under their class key while
56
- # Spree update reads :product. Merge both into :product so all edited
57
- # fields are persisted for STI product subclasses.
58
- def normalize_sti_product_params
59
- return unless @product
60
-
61
- sti_key = @product.class.model_name.param_key.to_sym
62
- sti_params = params[sti_key]
63
- return unless sti_params.is_a?(::ActionController::Parameters)
64
-
65
- base_params = params[:product]
66
- base_hash = base_params.is_a?(::ActionController::Parameters) ? base_params.to_unsafe_h : {}
67
- sti_hash = sti_params.to_unsafe_h
68
- merged_params = ::ActionController::Parameters.new(base_hash.merge(sti_hash))
69
-
70
- params[:product] = merged_params
71
- end
72
-
73
54
  def merge_industry_taxons_into_taxons
74
55
  return if params[:product].blank?
75
56
 
@@ -7,7 +7,6 @@ module SpreeCmCommissioner
7
7
  def execute
8
8
  scope.joins(:integration_mappings).where(
9
9
  kind: :event,
10
- preview: false,
11
10
  integration_mappings: { status: :active }
12
11
  ).distinct
13
12
  end
@@ -15,8 +15,6 @@ module SpreeCmCommissioner
15
15
  'badge badge-success text-uppercase'
16
16
  when :football
17
17
  'badge badge-dark text-uppercase'
18
- when :show
19
- 'badge badge-danger text-uppercase'
20
18
  else
21
19
  'badge'
22
20
  end
@@ -3,6 +3,9 @@ require 'google/cloud/firestore'
3
3
  # TODO: alert when available_slots is negative.
4
4
  module SpreeCmCommissioner
5
5
  class WaitingGuestsCaller < BaseInteractor
6
+ MIN_WAIT_TO_ENTER_SECONDS = 120 # 2 min floor — Waiting Room step (full journey, more uncertainty)
7
+ MIN_QUEUE_TO_ENTER_SECONDS = 60 # 1 min floor — Queue step (position assigned, one caller cycle minimum)
8
+
6
9
  def call
7
10
  available_slots = fetch_available_slots
8
11
  return unless available_slots.positive?
@@ -10,7 +13,12 @@ module SpreeCmCommissioner
10
13
  long_waiting_guests = fetch_long_waiting_guests(available_slots)
11
14
  calling_all(long_waiting_guests)
12
15
 
13
- mark_as(full: long_waiting_guests.size >= available_slots, available_slots: available_slots - long_waiting_guests.size)
16
+ mark_as(
17
+ full: long_waiting_guests.size >= available_slots,
18
+ available_slots: available_slots - long_waiting_guests.size,
19
+ avg_wait_to_enter_seconds: compute_avg_wait_to_enter_seconds(long_waiting_guests),
20
+ avg_queue_to_enter_seconds: compute_avg_queue_to_enter_seconds(long_waiting_guests)
21
+ )
14
22
  end
15
23
 
16
24
  def fetch_available_slots
@@ -78,10 +86,36 @@ module SpreeCmCommissioner
78
86
  1.day.ago.strftime('%Y-%m-%d')
79
87
  end
80
88
 
81
- # When open app, app request to check whether room is full or not via Firebase instead of server to minimize server requests.
82
89
  # merge: true so we preserve the published `waiting_guests_records_path` on the lobby doc.
83
- def mark_as(full:, available_slots:)
84
- lobby_document.set({ full: full, available_slots: available_slots }, merge: true)
90
+ def mark_as(full:, available_slots:, avg_wait_to_enter_seconds: nil, avg_queue_to_enter_seconds: nil)
91
+ data = { full: full, available_slots: available_slots }
92
+ data[:avg_wait_to_enter_seconds] = avg_wait_to_enter_seconds if avg_wait_to_enter_seconds
93
+ data[:avg_queue_to_enter_seconds] = avg_queue_to_enter_seconds if avg_queue_to_enter_seconds
94
+ lobby_document.set(data, merge: true)
95
+ end
96
+
97
+ # Average total wait (queued_at → allow_to_enter_room_at) for just-called guests.
98
+ # Used for the Waiting Room step ETA: how long until I get in from when I joined.
99
+ def compute_avg_wait_to_enter_seconds(guests)
100
+ return nil if guests.empty?
101
+
102
+ now = Time.zone.now
103
+ total = guests.sum { |doc| (now - doc.data[:queued_at].to_time).to_f }
104
+ [(total / guests.size).round, MIN_WAIT_TO_ENTER_SECONDS].max
105
+ end
106
+
107
+ # Average queue wait (position_set_at → allow_to_enter_room_at) for just-called guests.
108
+ # Used for the Queue step ETA: how long after getting a position until I actually enter.
109
+ # Returns nil when none of the called guests had position_set_at (first run, or no prior stamp).
110
+ def compute_avg_queue_to_enter_seconds(guests)
111
+ return nil if guests.empty?
112
+
113
+ now = Time.zone.now
114
+ positioned = guests.select { |doc| doc.data[:position_set_at] }
115
+ return nil if positioned.empty?
116
+
117
+ total = positioned.sum { |doc| (now - doc.data[:position_set_at].to_time).to_f }
118
+ [(total / positioned.size).round, MIN_QUEUE_TO_ENTER_SECONDS].max
85
119
  end
86
120
 
87
121
  def lobby_data
@@ -0,0 +1,84 @@
1
+ require 'google/cloud/firestore'
2
+
3
+ module SpreeCmCommissioner
4
+ module WaitingRoom
5
+ class StampQueuePositionsJob < ApplicationJob
6
+ queue_as :waiting_room
7
+
8
+ STAMP_LIMIT = (ENV['WAITING_ROOM_POSITION_STAMP_LIMIT'] || 1000).to_i
9
+
10
+ def perform
11
+ paths = stamp_paths
12
+ avg_queue_to_enter = lobby_data[:avg_queue_to_enter_seconds].to_i
13
+ total = paths.sum { |p| waiting_count(p) }
14
+ return if total.zero?
15
+
16
+ stamped_at = Time.zone.now
17
+ global = 0
18
+
19
+ paths.each do |path|
20
+ remaining = STAMP_LIMIT - global
21
+ break if remaining <= 0
22
+
23
+ docs = waiting_query(path).order('queued_at').limit(remaining).get.to_a
24
+ docs.each_slice(500) do |slice|
25
+ firestore.batch do |b|
26
+ slice.each do |doc|
27
+ global += 1
28
+ data = {
29
+ position: global,
30
+ queue_total: total,
31
+ estimated_wait_seconds: avg_queue_to_enter,
32
+ status_updated_at: stamped_at
33
+ }
34
+ data[:position_set_at] = stamped_at unless doc.data[:position_set_at]
35
+ b.update(doc.ref, data)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def stamp_paths
45
+ [previous_records_path, records_path]
46
+ end
47
+
48
+ def records_path
49
+ default_records_path(Time.zone.now.strftime('%Y-%m-%d'))
50
+ end
51
+
52
+ def previous_records_path
53
+ default_records_path(1.day.ago.strftime('%Y-%m-%d'))
54
+ end
55
+
56
+ def default_records_path(date)
57
+ "waiting_guests/#{date}/records"
58
+ end
59
+
60
+ def waiting_count(path)
61
+ waiting_query(path).aggregate_query.add_count.get.first.get.to_i
62
+ end
63
+
64
+ def waiting_query(path)
65
+ firestore.col(path).where('allow_to_enter_room_at', '==', nil)
66
+ end
67
+
68
+ def lobby_data
69
+ @lobby_data ||= firestore.col('waiting_rooms').doc('lobby').get.data || {}
70
+ end
71
+
72
+ def firestore
73
+ @firestore ||= Google::Cloud::Firestore.new(
74
+ project_id: service_account[:project_id],
75
+ credentials: service_account
76
+ )
77
+ end
78
+
79
+ def service_account
80
+ @service_account ||= Rails.application.credentials.cloud_firestore_service_account
81
+ end
82
+ end
83
+ end
84
+ end
@@ -8,8 +8,7 @@ module SpreeCmCommissioner
8
8
  tour: 0b00100,
9
9
  accommodation: 0b01000,
10
10
  things_to_do: 0b10000,
11
- football: 0b100000,
12
- show: 0b1000000
11
+ football: 0b100000
13
12
  }.freeze
14
13
 
15
14
  BIT_SEGMENT.each do |segment, bit_value|
@@ -14,8 +14,8 @@ module SpreeCmCommissioner
14
14
  validate :validate_total_kids, if: -> { valid_integer_metadata?('number_of_kids') }
15
15
  end
16
16
 
17
- def number_of_adults = public_metadata['number_of_adults']&.to_i || (variant.number_of_adults * quantity)
18
- def number_of_kids = public_metadata['number_of_kids']&.to_i || (variant.number_of_kids * quantity)
17
+ def number_of_adults = metadata_guest_count('number_of_adults') || (variant.number_of_adults * quantity)
18
+ def number_of_kids = metadata_guest_count('number_of_kids') || (variant.number_of_kids * quantity)
19
19
  def number_of_guests = number_of_adults + number_of_kids
20
20
 
21
21
  def allowed_extra_adults = variant.allowed_extra_adults * quantity
@@ -26,6 +26,10 @@ module SpreeCmCommissioner
26
26
 
27
27
  def remaining_total_guests = [number_of_guests - guests.size, 0].max
28
28
 
29
+ # True when the guest count is set via the public_metadata override (accommodation/transit),
30
+ # i.e. decoupled from quantity rather than derived from variant.number_of_guests * quantity.
31
+ def custom_guest_count? = public_metadata['number_of_adults'].to_i.positive? || public_metadata['number_of_kids'].to_i.positive?
32
+
29
33
  def generate_remaining_guests
30
34
  return if remaining_total_guests.zero?
31
35
 
@@ -82,6 +86,16 @@ module SpreeCmCommissioner
82
86
  value.present? && value.to_s.match?(/\A-?\d+\z/)
83
87
  end
84
88
 
89
+ # public_metadata override for a guest count, only when it's a non-negative integer;
90
+ # nil otherwise so callers fall back to the variant default. Keeps number_of_guests >= 0
91
+ # (a negative would make custom_guest_count? false and spin the bump loop in Cart::CreateGuest).
92
+ def metadata_guest_count(key)
93
+ return nil unless valid_integer_metadata?(key)
94
+
95
+ value = public_metadata[key].to_i
96
+ value.negative? ? nil : value
97
+ end
98
+
85
99
  def validate_total_adults
86
100
  errors.add(:quantity, 'exceed_total_adults') if public_metadata['number_of_adults'].to_i > allowed_total_adults
87
101
  end
@@ -45,8 +45,7 @@ module SpreeCmCommissioner
45
45
  'color' => 'color',
46
46
  'ticket-type' => 'string',
47
47
  'seat-type' => 'string',
48
- 'intercity-taxi' => 'string',
49
- 'vote-package' => 'integer'
48
+ 'intercity-taxi' => 'string'
50
49
  }.freeze
51
50
 
52
51
  included do
@@ -26,10 +26,8 @@ module SpreeCmCommissioner
26
26
 
27
27
  state_machine.after_transition to: :canceled, do: :precalculate_conversion
28
28
  state_machine.after_transition to: :canceled, do: :restock_inventory!
29
- state_machine.after_transition to: :canceled, do: :de_allocate_resources
30
29
 
31
30
  state_machine.after_transition to: :complete, do: :increment_route_fulfilled_order_count
32
- state_machine.after_transition to: :complete, do: :allocate_resources
33
31
 
34
32
  scope :accepted, -> { where(request_state: 'accepted') }
35
33
 
@@ -330,13 +328,5 @@ module SpreeCmCommissioner
330
328
  factory = OrderTelegramMessageFactory.new(title: title, order: self)
331
329
  TelegramNotificationSenderJob.perform_later(chat_id: chat_id, message: factory.message, parse_mode: factory.parse_mode)
332
330
  end
333
-
334
- def allocate_resources
335
- SpreeCmCommissioner::VotingCreditAllocationJob.perform_later(order_id: id)
336
- end
337
-
338
- def de_allocate_resources
339
- SpreeCmCommissioner::VotingCreditDeAllocationJob.perform_later(order_id: id)
340
- end
341
331
  end
342
332
  end
@@ -5,7 +5,7 @@ module SpreeCmCommissioner
5
5
  module ProductType
6
6
  extend ActiveSupport::Concern
7
7
 
8
- PRODUCT_TYPES = %i[accommodation service ecommerce transit show_episode vote_package advertisement].freeze
8
+ PRODUCT_TYPES = %i[accommodation service ecommerce transit].freeze
9
9
  PERMANENT_STOCK_PRODUCT_TYPES = %w[accommodation service transit].freeze
10
10
  PRE_INVENTORY_DAYS = { 'transit' => 90, 'accommodation' => 365, 'service' => 30 }.freeze
11
11
 
@@ -3,9 +3,7 @@ module SpreeCmCommissioner
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- enum kind: { category: 0, cms: 1, event: 2, occupation: 3, nationality: 4, organization: 5, transit: 6, industry: 7, agency_category: 8,
7
- ads: 9
8
- }
6
+ enum kind: { category: 0, cms: 1, event: 2, occupation: 3, nationality: 4, organization: 5, transit: 6, industry: 7, agency_category: 8 }
9
7
  end
10
8
  end
11
9
  end
@@ -3,7 +3,7 @@ module SpreeCmCommissioner
3
3
  extend FriendlyId
4
4
 
5
5
  enum :status, { :queue => 0, :progress => 1, :done => 2, :failed => 3 }
6
- enum :import_type, { :new_order => 0, :existing_order => 1, :aba_payment_reference => 2, :contestant_import => 3 }
6
+ enum :import_type, { :new_order => 0, :existing_order => 1, :aba_payment_reference => 2 }
7
7
  has_one_attached :imported_file
8
8
  friendly_id :name, use: :slugged
9
9
 
@@ -12,10 +12,6 @@ module SpreeCmCommissioner
12
12
  base.include SpreeCmCommissioner::StoreMetadata
13
13
  base.include SpreeCmCommissioner::HomepageSectionRelatableConcern
14
14
 
15
- base.delegate :is_open_dated, :is_open_dated?, to: :trip, allow_nil: true
16
-
17
- base.has_many :voting_sessions, class_name: 'SpreeCmCommissioner::VotingSession', foreign_key: :episode_id, dependent: :destroy
18
-
19
15
  base.has_many :variant_kind_option_types, -> { where(kind: :variant).order(:position) },
20
16
  through: :product_option_types, source: :option_type
21
17
 
@@ -63,45 +59,8 @@ module SpreeCmCommissioner
63
59
 
64
60
  base.belongs_to :event, class_name: 'Spree::Taxon', optional: true
65
61
 
66
- base.has_many :preview_roles, class_name: 'SpreeCmCommissioner::PreviewRole', as: :previewable
67
62
  base.has_many :industry_classifications, -> { joins(:taxon).where(spree_taxons: { kind: :industry }) }, class_name: 'Spree::Classification'
68
63
  base.has_many :industry_taxons, through: :industry_classifications, source: :taxon
69
- base.scope :visible_to, lambda { |user|
70
- publicly_available = where(status: :active, preview: false)
71
-
72
- if user
73
- # Resolved through associations — avoids hardcoding class names.
74
- taxon_type = reflect_on_association(:taxons).klass.polymorphic_name
75
-
76
- # IDs of products that have been explicitly assigned their own PreviewRole.
77
- products_with_own_roles = SpreeCmCommissioner::PreviewRole
78
- .where(previewable_type: polymorphic_name)
79
- .select(:previewable_id)
80
-
81
- # Path A: product has its own PreviewRole → user must hold that role directly.
82
- # Taxon membership is irrelevant for these products.
83
- via_product_role = where(status: :active, preview: true)
84
- .where(id: products_with_own_roles)
85
- .where(id: user.preview_roles.where(previewable_type: polymorphic_name).select(:previewable_id))
86
-
87
- # Path B: product has no own PreviewRole → inherit access from its event or taxons.
88
- # Accessible if the user holds a preview role for the product's event_id or any
89
- # taxon the product belongs to via the classifications join table.
90
- allowed_taxon_ids = user.preview_roles.where(previewable_type: taxon_type).select(:previewable_id)
91
- preview_no_own = where(status: :active, preview: true).where.not(id: products_with_own_roles)
92
-
93
- via_event_id = preview_no_own.where(event_id: allowed_taxon_ids)
94
- via_taxon_join = preview_no_own.joins(:taxons).where(spree_taxons: { id: allowed_taxon_ids })
95
-
96
- publicly_available
97
- .or(via_product_role)
98
- .or(where(id: via_event_id.select(:id)))
99
- .or(where(id: via_taxon_join.select(:id)))
100
- else
101
- publicly_available
102
- end
103
- }
104
-
105
64
  base.scope :min_price, lambda { |vendor|
106
65
  joins(:prices_including_master)
107
66
  .where(vendor_id: vendor.id, product_type: vendor.primary_product_type)
@@ -114,12 +73,6 @@ module SpreeCmCommissioner
114
73
  .maximum('spree_prices.price').to_f
115
74
  }
116
75
  base.scope :subscribable, -> { where(subscribable: 1) }
117
- base.scope :advertisements, lambda {
118
- advertisement
119
- .available
120
- .where('spree_products.available_on IS NULL OR spree_products.available_on <= CURRENT_TIMESTAMP')
121
- .where('spree_products.discontinue_on IS NULL OR spree_products.discontinue_on > CURRENT_TIMESTAMP')
122
- }
123
76
 
124
77
  base.before_validation :set_event_id
125
78
 
@@ -133,11 +86,6 @@ module SpreeCmCommissioner
133
86
  base.store_public_metadata :open_dated_validity_days, :integer, default: 90
134
87
  base.store_public_metadata :enable_inventory_hold, :boolean, default: false
135
88
 
136
- base.store_private_metadata :advertise_weight, :integer, default: 1
137
- base.store_private_metadata :video_url, :string
138
- base.store_private_metadata :skip_after_seconds, :integer, default: 5
139
- base.store_private_metadata :duration_seconds, :integer, default: 30
140
-
141
89
  base.after_update :update_variants_vendor_id, if: :saved_change_to_vendor_id?
142
90
  base.after_update :sync_event_id_to_children, if: :saved_change_to_event_id?
143
91
 
@@ -1,11 +1,10 @@
1
1
  module SpreeCmCommissioner
2
2
  module RoleDecorator
3
3
  def self.prepended(base)
4
- base.enum role_type: { internal: 0, external: 1, preview: 2 }
4
+ base.enum role_type: { internal: 0, external: 1 }
5
5
 
6
6
  base.has_many :role_permissions, class_name: 'SpreeCmCommissioner::RolePermission'
7
7
  base.has_many :permissions, through: :role_permissions, class_name: 'SpreeCmCommissioner::Permission'
8
- base.has_many :preview_roles, class_name: 'SpreeCmCommissioner::PreviewRole'
9
8
 
10
9
  base.belongs_to :vendor, optional: true
11
10
 
@@ -14,8 +13,6 @@ module SpreeCmCommissioner
14
13
  where(vendor_id: vendor)
15
14
  }
16
15
  base.scope :filter_external, -> { where(role_type: :external) }
17
- base.scope :filter_internal, -> { where(role_type: :internal) }
18
- base.scope :filter_preview, -> { where(role_type: :preview) }
19
16
 
20
17
  base.accepts_nested_attributes_for :role_permissions, allow_destroy: true
21
18
 
@@ -0,0 +1,12 @@
1
+ module SpreeCmCommissioner
2
+ class TaxonAdBanner < Asset
3
+ # 3x1
4
+ def asset_styles
5
+ {
6
+ small: '480x160>',
7
+ medium: '960x320>',
8
+ large: '1200x400>'
9
+ }
10
+ end
11
+ end
12
+ end