spree_cm_commissioner 2.8.0 → 2.8.1.pre.pre.1

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 (235) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +0 -12
  3. data/.gitignore +4 -0
  4. data/Gemfile.lock +1 -1
  5. data/app/controllers/concerns/spree_cm_commissioner/order_concern.rb +0 -1
  6. data/app/controllers/spree/admin/classifications_controller.rb +1 -1
  7. data/app/controllers/spree/admin/homepage_section_controller.rb +4 -1
  8. data/app/controllers/spree/admin/inventory_monitorings_controller.rb +3 -7
  9. data/app/controllers/spree/admin/stock_managements_controller.rb +1 -10
  10. data/app/controllers/spree/admin/taxons_controller_decorator.rb +19 -0
  11. data/app/controllers/spree/api/v2/operator/recalculate_tickets_controller.rb +1 -1
  12. data/app/controllers/spree/api/v2/storefront/homepage_sections_controller.rb +1 -0
  13. data/app/controllers/spree/api/v2/storefront/preview_products_controller.rb +48 -0
  14. data/app/controllers/spree/api/v2/storefront/preview_sections_controller.rb +27 -0
  15. data/app/controllers/spree/api/v2/storefront/preview_taxons_controller.rb +18 -0
  16. data/app/controllers/spree/api/v2/storefront/products_controller_decorator.rb +15 -0
  17. data/app/controllers/spree/api/v2/storefront/taxons_controller_decorator.rb +15 -0
  18. data/app/controllers/spree/api/v2/tenant/base_controller.rb +4 -0
  19. data/app/controllers/spree/api/v2/tenant/free_vote_claims_controller.rb +37 -0
  20. data/app/controllers/spree/api/v2/tenant/homepage_sections_controller.rb +1 -0
  21. data/app/controllers/spree/api/v2/tenant/intercity_taxi/draft_orders_controller.rb +0 -1
  22. data/app/controllers/spree/api/v2/tenant/preview_products_controller.rb +47 -0
  23. data/app/controllers/spree/api/v2/tenant/preview_sections_controller.rb +26 -0
  24. data/app/controllers/spree/api/v2/tenant/preview_shows_controller.rb +19 -0
  25. data/app/controllers/spree/api/v2/tenant/preview_taxons_controller.rb +19 -0
  26. data/app/controllers/spree/api/v2/tenant/products_controller.rb +1 -1
  27. data/app/controllers/spree/api/v2/tenant/show_contestants_controller.rb +51 -0
  28. data/app/controllers/spree/api/v2/tenant/show_people_controller.rb +49 -0
  29. data/app/controllers/spree/api/v2/tenant/show_person_assignments_controller.rb +36 -0
  30. data/app/controllers/spree/api/v2/tenant/shows_controller.rb +34 -0
  31. data/app/controllers/spree/api/v2/tenant/taxons_controller.rb +1 -1
  32. data/app/controllers/spree/api/v2/tenant/votes_controller.rb +94 -0
  33. data/app/controllers/spree/api/v2/tenant/voting_contestants_controller.rb +40 -0
  34. data/app/controllers/spree/api/v2/tenant/voting_credit_transactions_controller.rb +41 -0
  35. data/app/controllers/spree/api/v2/tenant/voting_credits_controller.rb +31 -0
  36. data/app/controllers/spree_cm_commissioner/admin/products_controller_decorator.rb +19 -0
  37. data/app/factory/spree_cm_commissioner/order_telegram_message_factory.rb +0 -88
  38. data/app/finders/spree_cm_commissioner/accommodations/find.rb +5 -6
  39. data/app/finders/spree_cm_commissioner/events/find_matches.rb +1 -0
  40. data/app/finders/spree_cm_commissioner/inventory_items/recently_changed_finder.rb +33 -43
  41. data/app/helpers/spree_cm_commissioner/admin/homepage_segment_helper.rb +2 -0
  42. data/app/interactors/spree_cm_commissioner/guest_seat_updater.rb +45 -0
  43. data/app/jobs/spree_cm_commissioner/vote_fraud_event_job.rb +9 -0
  44. data/app/jobs/spree_cm_commissioner/voting_credit_allocation_job.rb +10 -0
  45. data/app/jobs/spree_cm_commissioner/voting_credit_de_allocation_job.rb +10 -0
  46. data/app/models/concerns/spree_cm_commissioner/homepage_section_bitwise.rb +2 -1
  47. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +2 -1
  48. data/app/models/concerns/spree_cm_commissioner/order_seatable.rb +81 -0
  49. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +17 -13
  50. data/app/models/concerns/spree_cm_commissioner/product_type.rb +1 -1
  51. data/app/models/concerns/spree_cm_commissioner/store_metadata.rb +1 -10
  52. data/app/models/spree_cm_commissioner/homepage_background.rb +0 -3
  53. data/app/models/spree_cm_commissioner/homepage_section.rb +0 -3
  54. data/app/models/spree_cm_commissioner/inventory_item.rb +0 -8
  55. data/app/models/spree_cm_commissioner/line_item_decorator.rb +0 -10
  56. data/app/models/spree_cm_commissioner/maintenance_tasks/voting_session.rb +19 -0
  57. data/app/models/spree_cm_commissioner/menu_decorator.rb +0 -3
  58. data/app/models/spree_cm_commissioner/order_decorator.rb +6 -6
  59. data/app/models/spree_cm_commissioner/payment_decorator.rb +0 -12
  60. data/app/models/spree_cm_commissioner/preview_role.rb +8 -0
  61. data/app/models/spree_cm_commissioner/pricing_action.rb +2 -2
  62. data/app/models/spree_cm_commissioner/pricing_actions/create_guest_adjustments.rb +42 -34
  63. data/app/models/spree_cm_commissioner/pricing_actions/create_line_item_adjustments.rb +10 -17
  64. data/app/models/spree_cm_commissioner/pricing_actions/create_route_adjustments.rb +39 -38
  65. data/app/models/spree_cm_commissioner/pricing_model.rb +15 -13
  66. data/app/models/spree_cm_commissioner/pricing_model_handler/order.rb +73 -0
  67. data/app/models/spree_cm_commissioner/pricing_rule.rb +1 -1
  68. data/app/models/spree_cm_commissioner/pricing_rules/age_group.rb +12 -9
  69. data/app/models/spree_cm_commissioner/pricing_rules/extra_drop_off_distance.rb +2 -2
  70. data/app/models/spree_cm_commissioner/pricing_rules/extra_pick_up_distance.rb +2 -2
  71. data/app/models/spree_cm_commissioner/pricing_rules/nationality.rb +19 -18
  72. data/app/models/spree_cm_commissioner/pricing_rules/nationality_group.rb +16 -7
  73. data/app/models/spree_cm_commissioner/product_decorator.rb +43 -5
  74. data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +9 -16
  75. data/app/models/spree_cm_commissioner/reserved_block.rb +0 -4
  76. data/app/models/spree_cm_commissioner/role_decorator.rb +4 -1
  77. data/app/models/spree_cm_commissioner/role_user_decorator.rb +8 -0
  78. data/app/models/spree_cm_commissioner/route.rb +0 -3
  79. data/app/models/spree_cm_commissioner/show.rb +157 -0
  80. data/app/models/spree_cm_commissioner/show_contestant.rb +34 -0
  81. data/app/models/spree_cm_commissioner/show_contestant_image.rb +11 -0
  82. data/app/models/spree_cm_commissioner/show_contestant_video.rb +4 -0
  83. data/app/models/spree_cm_commissioner/show_episode.rb +135 -0
  84. data/app/models/spree_cm_commissioner/show_person.rb +15 -0
  85. data/app/models/spree_cm_commissioner/show_person_assignment.rb +20 -0
  86. data/app/models/spree_cm_commissioner/show_person_image.rb +11 -0
  87. data/app/models/spree_cm_commissioner/stock_item_decorator.rb +0 -3
  88. data/app/models/spree_cm_commissioner/taxon_decorator.rb +17 -3
  89. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +10 -1
  90. data/app/models/spree_cm_commissioner/tenant.rb +9 -0
  91. data/app/models/spree_cm_commissioner/user_decorator.rb +5 -0
  92. data/app/models/spree_cm_commissioner/variant_decorator.rb +0 -3
  93. data/app/models/spree_cm_commissioner/variant_options.rb +4 -0
  94. data/app/models/spree_cm_commissioner/vendor_decorator.rb +10 -4
  95. data/app/models/spree_cm_commissioner/vote.rb +16 -0
  96. data/app/models/spree_cm_commissioner/vote_fraud_event.rb +19 -0
  97. data/app/models/spree_cm_commissioner/voting_contestant.rb +34 -0
  98. data/app/models/spree_cm_commissioner/voting_credit.rb +72 -0
  99. data/app/models/spree_cm_commissioner/voting_credit_transaction.rb +55 -0
  100. data/app/models/spree_cm_commissioner/voting_session.rb +163 -0
  101. data/app/overrides/spree/admin/products/_form/preview_checkbox.html.erb.deface +9 -0
  102. data/app/overrides/spree/admin/taxons/_form/preview_checkbox.html.erb.deface +7 -0
  103. data/app/queries/spree_cm_commissioner/multi_leg_trips_query.rb +1 -1
  104. data/app/request_schemas/spree_cm_commissioner/intercity_taxi_draft_order_update_schema.rb +0 -1
  105. data/app/serializers/spree/v2/storefront/homepage_section_serializer.rb +1 -1
  106. data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +1 -1
  107. data/app/serializers/spree/v2/storefront/role_serializer.rb +1 -1
  108. data/app/serializers/spree/v2/storefront/taxon_serializer_decorator.rb +2 -1
  109. data/app/serializers/spree/v2/tenant/homepage_section_serializer.rb +1 -1
  110. data/app/serializers/spree/v2/tenant/role_serializer.rb +1 -1
  111. data/app/serializers/spree/v2/tenant/show_contestant_serializer.rb +21 -0
  112. data/app/serializers/spree/v2/tenant/show_episode_serializer.rb +17 -0
  113. data/app/serializers/spree/v2/tenant/show_person_assignment_serializer.rb +16 -0
  114. data/app/serializers/spree/v2/tenant/show_person_serializer.rb +13 -0
  115. data/app/serializers/spree/v2/tenant/show_serializer.rb +26 -0
  116. data/app/serializers/spree/v2/tenant/video_serializer.rb +9 -0
  117. data/app/serializers/spree/v2/tenant/vote_serializer.rb +14 -0
  118. data/app/serializers/spree/v2/tenant/voting_contestant_serializer.rb +18 -0
  119. data/app/serializers/spree/v2/tenant/voting_credit_serializer.rb +10 -0
  120. data/app/serializers/spree/v2/tenant/voting_credit_transaction_serializer.rb +14 -0
  121. data/app/serializers/spree/v2/tenant/voting_session_serializer.rb +15 -0
  122. data/app/services/spree_cm_commissioner/api_caches/invalidate.rb +8 -26
  123. data/app/services/spree_cm_commissioner/checkout/advance_decorator.rb +1 -1
  124. data/app/services/spree_cm_commissioner/checkout/update_decorator.rb +1 -1
  125. data/app/services/spree_cm_commissioner/fraud_check.rb +275 -0
  126. data/app/services/spree_cm_commissioner/intercity_taxi_order/update.rb +2 -5
  127. data/app/services/spree_cm_commissioner/inventory_items/reset.rb +1 -23
  128. data/app/services/spree_cm_commissioner/reserved_blocks/hold.rb +6 -4
  129. data/app/services/spree_cm_commissioner/show_contestants/normalize_video_highlights.rb +56 -0
  130. data/app/services/spree_cm_commissioner/url_embed/youtube_embed.rb +39 -0
  131. data/app/services/spree_cm_commissioner/vendor_places/base.rb +7 -2
  132. data/app/services/spree_cm_commissioner/vendor_places/bulk_create.rb +3 -3
  133. data/app/services/spree_cm_commissioner/vote_counters/audit_counters.rb +35 -0
  134. data/app/services/spree_cm_commissioner/vote_counters/base.rb +31 -0
  135. data/app/services/spree_cm_commissioner/vote_counters/increment.rb +34 -0
  136. data/app/services/spree_cm_commissioner/vote_counters/per_contestant_counter.rb +25 -0
  137. data/app/services/spree_cm_commissioner/vote_counters/rebuild_from_db.rb +41 -0
  138. data/app/services/spree_cm_commissioner/vote_credit_deductor.rb +68 -0
  139. data/app/services/spree_cm_commissioner/vote_package/create.rb +145 -0
  140. data/app/services/spree_cm_commissioner/vote_package/update.rb +91 -0
  141. data/app/services/spree_cm_commissioner/vote_processor.rb +133 -0
  142. data/app/services/spree_cm_commissioner/voting_contestants/advancer.rb +334 -0
  143. data/app/services/spree_cm_commissioner/voting_contestants/assigner.rb +32 -0
  144. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +104 -0
  145. data/app/services/spree_cm_commissioner/voting_credits/allocate.rb +77 -0
  146. data/app/services/spree_cm_commissioner/voting_credits/claim_free_votes.rb +119 -0
  147. data/app/services/spree_cm_commissioner/voting_credits/credit_calculator.rb +35 -0
  148. data/app/services/spree_cm_commissioner/voting_credits/de_allocate.rb +87 -0
  149. data/app/views/spree/admin/homepage_section/_form.html.erb +5 -0
  150. data/app/views/spree/admin/inventory_monitorings/index.html.erb +24 -45
  151. data/app/views/spree/admin/stock_managements/index.html.erb +2 -32
  152. data/config/initializers/spree_permitted_attributes.rb +8 -1
  153. data/config/locales/en.yml +12 -21
  154. data/config/locales/km.yml +6 -21
  155. data/config/routes.rb +25 -10
  156. data/db/migrate/20260309230148_create_cm_show_people.rb +14 -0
  157. data/db/migrate/20260309230149_create_cm_show_people_assignments.rb +16 -0
  158. data/db/migrate/20260310082711_create_cm_show_contestants.rb +28 -0
  159. data/db/migrate/20260310082720_create_cm_voting_sessions.rb +21 -0
  160. data/db/migrate/20260310082721_create_cm_voting_contestants.rb +23 -0
  161. data/db/migrate/20260310082734_add_voting_fields_to_spree_taxons.rb +9 -0
  162. data/db/migrate/20260310082735_add_type_to_spree_products.rb +6 -0
  163. data/db/migrate/20260310082749_create_cm_voting_credits.rb +27 -0
  164. data/db/migrate/20260326080200_create_cm_voting_credit_transactions.rb +27 -0
  165. data/db/migrate/20260330160000_create_cm_votes.rb +25 -0
  166. data/db/migrate/20260401072500_add_advanced_from_to_cm_voting_contestants.rb +7 -0
  167. data/db/migrate/20260402000001_add_voting_credit_scope_to_spree_taxons.rb +6 -0
  168. data/db/migrate/20260402000002_rename_scopeable_to_votable_in_cm_voting_credits.rb +12 -0
  169. data/db/migrate/20260403070000_add_name_to_cm_voting_sessions.rb +5 -0
  170. data/db/migrate/20260406000001_add_vendor_id_to_voting_tables.rb +6 -0
  171. data/db/migrate/20260406000001_rename_votes_remaining_to_amount_in_cm_voting_credits.rb +11 -0
  172. data/db/migrate/20260408085255_add_show_id_and_vendor_id_to_cm_voting_sessions.rb +9 -0
  173. data/db/migrate/20260420000001_rename_type_to_credit_type_in_cm_voting_credits.rb +25 -0
  174. data/db/migrate/20260422000001_create_cm_vote_fraud_events.rb +23 -0
  175. data/db/migrate/20260423000001_add_preview_to_taxons_products_and_sections.rb +11 -0
  176. data/db/migrate/20260423000002_create_preview_roles.rb +24 -0
  177. data/db/migrate/20260515120000_add_public_metadata_to_cm_voting_sessions.rb +5 -0
  178. data/docs/sql/jsonb_query_guide.md +57 -0
  179. data/lib/spree_cm_commissioner/cached_inventory_item.rb +1 -10
  180. data/lib/spree_cm_commissioner/test_helper/factories/pricing_action_factory.rb +0 -4
  181. data/lib/spree_cm_commissioner/test_helper/factories/pricing_rule_group_factory.rb +0 -1
  182. data/lib/spree_cm_commissioner/test_helper/factories/show_episode_factory.rb +12 -0
  183. data/lib/spree_cm_commissioner/test_helper/factories/show_factory.rb +96 -0
  184. data/lib/spree_cm_commissioner/test_helper/factories/vote_credit_factory.rb +37 -0
  185. data/lib/spree_cm_commissioner/test_helper/factories/vote_factory.rb +28 -0
  186. data/lib/spree_cm_commissioner/test_helper/factories/voting_credit_transaction_factory.rb +11 -0
  187. data/lib/spree_cm_commissioner/test_helper/factories/voting_session_factory.rb +11 -0
  188. data/lib/spree_cm_commissioner/version.rb +1 -1
  189. data/lib/spree_cm_commissioner.rb +7 -6
  190. metadata +106 -49
  191. data/app/controllers/spree/admin/inventory_holds_controller.rb +0 -64
  192. data/app/controllers/spree/api/v2/storefront/pricing_previews_controller.rb +0 -54
  193. data/app/controllers/spree/api/v2/tenant/pricing_previews_controller.rb +0 -60
  194. data/app/jobs/spree_cm_commissioner/inventory_holds/bulk_release_stale_job.rb +0 -11
  195. data/app/jobs/spree_cm_commissioner/inventory_holds/bulk_release_stale_payment_locked_job.rb +0 -11
  196. data/app/jobs/spree_cm_commissioner/inventory_holds/release_job.rb +0 -29
  197. data/app/jobs/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_on_hold_job.rb +0 -20
  198. data/app/models/concerns/spree_cm_commissioner/homepage_section_relatable_concern.rb +0 -25
  199. data/app/models/concerns/spree_cm_commissioner/order_holdable.rb +0 -71
  200. data/app/models/spree_cm_commissioner/inventory_hold.rb +0 -30
  201. data/app/models/spree_cm_commissioner/maintenance_tasks/cache_invalidation.rb +0 -14
  202. data/app/models/spree_cm_commissioner/menu_item_decorator.rb +0 -12
  203. data/app/overrides/spree/admin/products/_form/enable_inventory_hold.html.erb.deface +0 -18
  204. data/app/overrides/spree/admin/shared/sub_menu/_stock/inventory_holds_tab.html.erb.deface +0 -3
  205. data/app/serializers/spree/v2/tenant/preview_adjustment_serializer.rb +0 -10
  206. data/app/serializers/spree/v2/tenant/pricing_preview_serializer.rb +0 -13
  207. data/app/serializers/spree_cm_commissioner/v2/storefront/preview_adjustment_serializer.rb +0 -10
  208. data/app/serializers/spree_cm_commissioner/v2/storefront/pricing_preview_serializer.rb +0 -13
  209. data/app/services/spree_cm_commissioner/guests/update_seat.rb +0 -55
  210. data/app/services/spree_cm_commissioner/inventory_holds/acquire.rb +0 -175
  211. data/app/services/spree_cm_commissioner/inventory_holds/bulk_release_stale.rb +0 -41
  212. data/app/services/spree_cm_commissioner/inventory_holds/bulk_release_stale_payment_locked.rb +0 -11
  213. data/app/services/spree_cm_commissioner/inventory_holds/convert.rb +0 -86
  214. data/app/services/spree_cm_commissioner/inventory_holds/release.rb +0 -100
  215. data/app/services/spree_cm_commissioner/inventory_holds/validate_limits.rb +0 -65
  216. data/app/services/spree_cm_commissioner/order_holds/hold.rb +0 -71
  217. data/app/services/spree_cm_commissioner/order_holds/lock_for_payment.rb +0 -153
  218. data/app/services/spree_cm_commissioner/order_holds/release.rb +0 -56
  219. data/app/services/spree_cm_commissioner/order_holds/reserve.rb +0 -46
  220. data/app/services/spree_cm_commissioner/pricing_models/activate.rb +0 -41
  221. data/app/services/spree_cm_commissioner/pricing_models/preview.rb +0 -93
  222. data/app/views/spree/admin/inventory_holds/_search.html.erb +0 -128
  223. data/app/views/spree/admin/inventory_holds/index.html.erb +0 -122
  224. data/db/migrate/20260327090000_create_cm_inventory_holds.rb +0 -27
  225. data/db/migrate/20260327090001_add_quantity_on_hold_to_cm_inventory_items.rb +0 -5
  226. data/db/migrate/20260410080000_add_payment_locked_at_to_cm_reserved_blocks.rb +0 -5
  227. data/db/migrate/20260504100000_add_public_and_private_metadata_to_cm_routes.rb +0 -6
  228. data/db/migrate/20260506090000_remove_default_from_cm_guests_nationality_group.rb +0 -6
  229. data/docs/tenant/test.com.md +0 -88
  230. data/lib/spree_cm_commissioner/pricing_models/guest_context.rb +0 -81
  231. data/lib/spree_cm_commissioner/pricing_models/line_item_context.rb +0 -63
  232. data/lib/spree_cm_commissioner/pricing_models/order_context.rb +0 -62
  233. data/lib/spree_cm_commissioner/pricing_models/preview_adjustment.rb +0 -20
  234. data/lib/spree_cm_commissioner/pricing_models/pricing_preview.rb +0 -16
  235. data/lib/spree_cm_commissioner/test_helper/factories/inventory_hold_factory.rb +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a112e266f3450b307b12ea0ac4a28a4d5ee9a3eff8e2650d6de5c93c1b73df3
4
- data.tar.gz: 3285f85273a6c1d19e2eb4b23f087eccca371af1f6cd48282c22042b97d4d8d8
3
+ metadata.gz: 19fd000fa15ceffed974595795de236e66b34973806086d138bc5867183bc9c0
4
+ data.tar.gz: e9cc2d23feeb9fd6b66384c3b3e2febeadc51ecfac906a3e546613578db19156
5
5
  SHA512:
6
- metadata.gz: 81c02501bd52647acbc65cc34e6ebcfa309b349a1215a0eadde56101b8d508877cb96e08c044612863ea458be0e70ff018311dc5be59806bc67f97a7cff99061
7
- data.tar.gz: feb4e3ef254c32769245dd1053ab3ec987f73250db800bd36373bf40e5d9e9ea981586b92a57fbe8bbcfc22ab09bf5cf7343b1a9b8d35bf672e1057510be11ad
6
+ metadata.gz: 87e417d02f3082ee1ec8905db14343bfe33309f2d7b4b04274c7abf2f86e22cb8998374bc34c64361632afdff581198a725d281c8c0f2b2bbe0ce91419a7a1cc
7
+ data.tar.gz: 75e78fd7b59fc796318dc24a70483fb51ab8ade2dc6df5714bdf2c6266d2055d8438679e6edf6d5089d8382501f8dc52d0d8684334f4c73e6a92820db6c6f110
data/.env.example CHANGED
@@ -50,15 +50,3 @@ EXPORT_PRESIGNED_URL_EXPIRATION_MINUTES=15
50
50
 
51
51
  # import order batch size
52
52
  IMPORT_ORDERS_BATCH_SIZE=50
53
-
54
- # Inventory Hold System
55
- # See: app/services/spree_cm_commissioner/order_holds/hold.rb
56
- HOLD_DURATION_IN_MINUTES=8 # How long a hold is active after checkout begins (address step)
57
-
58
- # See: app/services/spree_cm_commissioner/order_holds/lock_for_payment.rb
59
- PAYMENT_LOCK_MIN_DURATION_IN_MINUTES=5 # Minimum remaining hold time required when entering the payment step; hold is extended if below this threshold
60
-
61
- # See: app/services/spree_cm_commissioner/inventory_holds/validate_limits.rb
62
- MAX_ACTIVE_HOLDS_PER_USER=3 # Max concurrent active holds allowed per user across all orders
63
- MAX_HOLDS_PER_IP_PER_HOUR=5 # Max hold attempts per IP address within a rolling 1-hour window (abuse prevention)
64
- HOLD_COOLDOWN_AFTER_EXPIRY_IN_MINUTES=2 # Cooldown period before a user can re-acquire a hold after one expired on them
data/.gitignore CHANGED
@@ -34,3 +34,7 @@ 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
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.8.0)
37
+ spree_cm_commissioner (2.8.1.pre.pre.1)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -11,7 +11,6 @@ module SpreeCmCommissioner
11
11
  raise CanCan::AccessDenied
12
12
  end
13
13
 
14
- @spree_current_order.last_ip_address = request.remote_ip
15
14
  @spree_current_order
16
15
  end
17
16
 
@@ -5,7 +5,7 @@ module Spree
5
5
 
6
6
  def recalculate_conversions
7
7
  if @taxon.parent.event?
8
- SpreeCmCommissioner::MaintenanceTasks::Event.pending.create_or_find_by(
8
+ SpreeCmCommissioner::MaintenanceTasks::Event.pending.find_or_create_by(
9
9
  maintainable_type: 'Spree::Taxon',
10
10
  maintainable_id: @taxon.parent.id
11
11
  ) do |task|
@@ -51,7 +51,10 @@ 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.require(:spree_cm_commissioner_homepage_section).permit(:title, :description, :active, :tenant_id).merge(segment: segment_value)
54
+ params
55
+ .require(:spree_cm_commissioner_homepage_section)
56
+ .permit(:title, :description, :active, :tenant_id, :preview)
57
+ .merge(segment: segment_value)
55
58
  end
56
59
 
57
60
  def load_tenants
@@ -5,20 +5,19 @@ module Spree
5
5
  authorize! :manage, SpreeCmCommissioner::InventoryItem
6
6
 
7
7
  @time_range = params[:time_range] || 7
8
- @product_type = params[:product_type].presence
8
+ @filter_type = params[:filter_type] || 'all'
9
9
  @vendor_id = params[:vendor_id]
10
10
 
11
11
  finder = SpreeCmCommissioner::InventoryItems::RecentlyChangedFinder.new(
12
12
  time_range: @time_range.to_i.days.ago,
13
13
  limit: 1000,
14
14
  vendor_id: @vendor_id,
15
- product_type: @product_type
15
+ filter_type: @filter_type
16
16
  )
17
17
 
18
18
  @inventory_items = finder.execute
19
19
  @total_count = @inventory_items.size
20
20
  @out_of_sync_count = @inventory_items.count { |item| item[:out_of_sync] }
21
- @on_hold_out_of_sync_count = @inventory_items.count { |item| item[:on_hold_out_of_sync] }
22
21
  end
23
22
 
24
23
  def reset
@@ -33,10 +32,7 @@ module Spree
33
32
  flash[:error] = "Failed to reset inventory: #{result.message}"
34
33
  end
35
34
 
36
- redirect_to action: :index,
37
- time_range: params[:time_range],
38
- product_type: params[:product_type],
39
- vendor_id: params[:vendor_id]
35
+ redirect_to action: :index, time_range: params[:time_range], filter_type: params[:filter_type]
40
36
  end
41
37
  end
42
38
  end
@@ -5,7 +5,7 @@ module Spree
5
5
 
6
6
  before_action :load_parent
7
7
 
8
- helper_method :inventory_item_message, :inventory_item_hold_message
8
+ helper_method :inventory_item_message
9
9
 
10
10
  def load_parent
11
11
  @product = Spree::Product.find_by(slug: params[:product_id])
@@ -75,15 +75,6 @@ module Spree
75
75
  end
76
76
  end
77
77
 
78
- def inventory_item_hold_message(inventory_item, cached_inventory_item)
79
- synced = inventory_item.quantity_on_hold == cached_inventory_item.quantity_on_hold
80
- if synced
81
- "Synced: Quantity on hold matches in both DB and Redis (#{cached_inventory_item.quantity_on_hold})."
82
- else
83
- "Out of sync: Redis shows #{cached_inventory_item.quantity_on_hold} on hold, which doesn't match the database."
84
- end
85
- end
86
-
87
78
  private
88
79
 
89
80
  def load_inventories
@@ -3,6 +3,7 @@ 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]
6
7
  end
7
8
 
8
9
  # override
@@ -50,6 +51,24 @@ module Spree
50
51
  @taxon.build_home_banner(attachment: permitted_resource_params.delete(:home_banner)) if permitted_resource_params[:home_banner]
51
52
  @taxon.build_video_banner(attachment: permitted_resource_params.delete(:video_banner)) if permitted_resource_params[:video_banner]
52
53
  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
53
72
  end
54
73
  end
55
74
  end
@@ -7,7 +7,7 @@ module Spree
7
7
  before_action :load_taxon, only: :create
8
8
 
9
9
  def create
10
- SpreeCmCommissioner::MaintenanceTasks::Event.pending.create_or_find_by(
10
+ SpreeCmCommissioner::MaintenanceTasks::Event.pending.find_or_create_by(
11
11
  maintainable: @taxon
12
12
  ).async_execute
13
13
 
@@ -19,6 +19,7 @@ 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)
22
23
  .order(position: :asc)
23
24
  end
24
25
  end
@@ -0,0 +1,48 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ class PreviewProductsController < ::Spree::Api::V2::Storefront::ProductsController
6
+ before_action :require_spree_current_user
7
+
8
+ private
9
+
10
+ def scope(**args)
11
+ taxon_type = model_class.reflect_on_association(:taxons).klass.polymorphic_name
12
+
13
+ # IDs of products that have been explicitly assigned their own PreviewRole.
14
+ products_with_own_roles = SpreeCmCommissioner::PreviewRole
15
+ .where(previewable_type: model_class.polymorphic_name)
16
+ .select(:previewable_id)
17
+
18
+ # Base: all active preview products from the parent scope.
19
+ base = super(**args).rewhere(preview: true).where(status: :active)
20
+
21
+ # Path A: product has its own PreviewRole → user must hold that role directly.
22
+ # Taxon membership is irrelevant for these products.
23
+ via_product_role = base
24
+ .where(id: products_with_own_roles)
25
+ .where(id: spree_current_user.preview_roles
26
+ .where(previewable_type: model_class.polymorphic_name)
27
+ .select(:previewable_id)
28
+ )
29
+
30
+ # Path B: product has no own PreviewRole → inherit access from its taxons.
31
+ # Accessible if the user holds a preview role for any taxon the product belongs to.
32
+ via_taxon = base
33
+ .where.not(id: products_with_own_roles)
34
+ .joins(:taxons)
35
+ .where(spree_taxons: { id: spree_current_user.preview_roles
36
+ .where(previewable_type: taxon_type)
37
+ .select(:previewable_id)
38
+ }
39
+ )
40
+
41
+ # via_taxon uses joins(:taxons) which is incompatible with or — wrap as subquery.
42
+ via_product_role.or(base.where(id: via_taxon.select(:id)))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ class PreviewSectionsController < HomepageSectionsController
6
+ before_action :require_spree_current_user
7
+
8
+ # override
9
+ def collection
10
+ allowed_ids = spree_current_user.preview_roles.where(previewable_type: Spree::Taxon.polymorphic_name).pluck(:previewable_id)
11
+
12
+ section_ids = SpreeCmCommissioner::HomepageSectionRelatable
13
+ .where(relatable_type: 'Spree::Taxon', relatable_id: allowed_ids.presence || [])
14
+ .select(:homepage_section_id)
15
+
16
+ @collection ||= model_class.filter_by_segment(params[:homepage_id] || :general)
17
+ .active
18
+ .where(tenant_id: nil)
19
+ .where(preview: true)
20
+ .where(id: section_ids)
21
+ .order(position: :asc)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ class PreviewTaxonsController < ::Spree::Api::V2::Storefront::TaxonsController
6
+ before_action :require_spree_current_user
7
+
8
+ private
9
+
10
+ def scope(**args)
11
+ allowed_ids = spree_current_user.preview_roles.where(previewable_type: model_class.polymorphic_name).select(:previewable_id)
12
+ super(**args).rewhere(preview: true).where(id: allowed_ids)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ module ProductsControllerDecorator
6
+ def scope
7
+ super.where(preview: false)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ Spree::Api::V2::Storefront::ProductsController.prepend(Spree::Api::V2::Storefront::ProductsControllerDecorator)
@@ -0,0 +1,15 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ module TaxonsControllerDecorator
6
+ def scope
7
+ super.where(preview: false)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ Spree::Api::V2::Storefront::TaxonsController.prepend(Spree::Api::V2::Storefront::TaxonsControllerDecorator)
@@ -16,6 +16,10 @@ 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
+
19
23
  def render_serialized_payload(status = 200)
20
24
  render json: yield, status: status, content_type: content_type
21
25
  end
@@ -0,0 +1,37 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class FreeVoteClaimsController < BaseController
6
+ before_action :require_spree_current_user
7
+
8
+ def create
9
+ show = current_vendor.shows.find(params[:show_id])
10
+
11
+ result = SpreeCmCommissioner::VotingCredits::ClaimFreeVotes.new(
12
+ show: show,
13
+ user: spree_current_user,
14
+ tenant_id: MultiTenant.current_tenant_id,
15
+ votable_type: params[:votable_type],
16
+ votable_id: params[:votable_id]
17
+ ).call
18
+
19
+ if result.failure?
20
+ render_error_payload(result.error.to_s)
21
+ elsif result.value.nil?
22
+ head :no_content
23
+ else
24
+ render_serialized_payload { serialize_resource(result.value) }
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def resource_serializer
31
+ Spree::V2::Tenant::VotingCreditSerializer
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -5,6 +5,7 @@ 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)
8
9
  .active
9
10
  .order(position: :asc)
10
11
  end
@@ -29,7 +29,6 @@ module Spree
29
29
  result = SpreeCmCommissioner::IntercityTaxiOrder::Update.call(
30
30
  order: spree_current_order,
31
31
  remark: params[:remark],
32
- passenger_count: params[:passenger_count],
33
32
  pickup_map_place_attributes: params[:pickup_map_place_attributes]&.permit(
34
33
  :place_name,
35
34
  :lat,
@@ -0,0 +1,47 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class PreviewProductsController < ProductsController
6
+ before_action :require_spree_current_user
7
+
8
+ # override
9
+ def scope
10
+ taxon_type = model_class.reflect_on_association(:taxons).klass.polymorphic_name
11
+
12
+ # IDs of products that have been explicitly assigned their own PreviewRole.
13
+ products_with_own_roles = SpreeCmCommissioner::PreviewRole
14
+ .where(previewable_type: model_class.polymorphic_name)
15
+ .select(:previewable_id)
16
+
17
+ # Base: all active preview products from the parent scope.
18
+ base = super.where(status: :active, preview: true)
19
+
20
+ # Path A: product has its own PreviewRole → user must hold that role directly.
21
+ # Taxon membership is irrelevant for these products.
22
+ via_product_role = base
23
+ .where(id: products_with_own_roles)
24
+ .where(id: spree_current_user.preview_roles
25
+ .where(previewable_type: model_class.polymorphic_name)
26
+ .select(:previewable_id)
27
+ )
28
+
29
+ # Path B: product has no own PreviewRole → inherit access from its taxons.
30
+ # Accessible if the user holds a preview role for any taxon the product belongs to.
31
+ via_taxon = base
32
+ .where.not(id: products_with_own_roles)
33
+ .joins(:taxons)
34
+ .where(spree_taxons: { id: spree_current_user.preview_roles
35
+ .where(previewable_type: taxon_type)
36
+ .select(:previewable_id)
37
+ }
38
+ )
39
+
40
+ # via_taxon uses joins(:taxons) which is incompatible with or — wrap as subquery.
41
+ via_product_role.or(base.where(id: via_taxon.select(:id)))
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,26 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class PreviewSectionsController < HomepageSectionsController
6
+ before_action :require_spree_current_user
7
+
8
+ # override
9
+ def collection
10
+ allowed_ids = spree_current_user.preview_roles.where(previewable_type: Spree::Taxon.polymorphic_name).pluck(:previewable_id)
11
+
12
+ section_ids = SpreeCmCommissioner::HomepageSectionRelatable
13
+ .where(relatable_type: 'Spree::Taxon', relatable_id: allowed_ids.presence || [])
14
+ .select(:homepage_section_id)
15
+
16
+ @collection ||= scope.filter_by_segment(params[:homepage_id] || :general)
17
+ .active
18
+ .where(preview: true)
19
+ .where(id: section_ids)
20
+ .order(position: :asc)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class PreviewShowsController < ShowsController
6
+ before_action :require_spree_current_user
7
+
8
+ # override
9
+ def scope
10
+ allowed_ids = spree_current_user.preview_roles
11
+ .where(previewable_type: SpreeCmCommissioner::Show.polymorphic_name)
12
+ .select(:previewable_id)
13
+ super.rewhere(preview: true).where(id: allowed_ids)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class PreviewTaxonsController < TaxonsController
6
+ before_action :require_spree_current_user
7
+
8
+ # override
9
+ def scope
10
+ allowed_ids = spree_current_user.preview_roles.where(previewable_type: model_class.polymorphic_name).select(:previewable_id)
11
+ MultiTenant.with(@tenant) do
12
+ model_class.where(preview: true, id: allowed_ids)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ 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)
24
+ model_class.where(tenant_id: MultiTenant.current_tenant_id, preview: false)
25
25
  end
26
26
  end
27
27
 
@@ -0,0 +1,51 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class ShowContestantsController < BaseController
6
+ private
7
+
8
+ # override
9
+ def model_class
10
+ SpreeCmCommissioner::ShowContestant
11
+ end
12
+
13
+ # override
14
+ def scope
15
+ return model_class.none unless current_show
16
+
17
+ model_class
18
+ .where(show_id: current_show.id)
19
+ .includes(
20
+ :show_contestant_images,
21
+ :current_voting_session,
22
+ :voting_contestants,
23
+ assigned_show_person: :show_person_images,
24
+ show: [
25
+ :parent,
26
+ { episodes: :voting_sessions },
27
+ { seasons: { episodes: :voting_sessions } }
28
+ ]
29
+ )
30
+ end
31
+
32
+ def current_show
33
+ @current_show ||= show_scope.find_by!(slug: params[:show_id])
34
+ end
35
+
36
+ def show_scope
37
+ vendor_ids = @tenant.vendors.select(:id)
38
+ return SpreeCmCommissioner::Show.none if vendor_ids.blank?
39
+
40
+ SpreeCmCommissioner::Show.where(vendor_id: vendor_ids)
41
+ end
42
+
43
+ # override
44
+ def resource_serializer
45
+ Spree::V2::Tenant::ShowContestantSerializer
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,49 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class ShowPeopleController < BaseController
6
+ private
7
+
8
+ # override
9
+ def model_class
10
+ SpreeCmCommissioner::ShowPerson
11
+ end
12
+
13
+ # override
14
+ def scope
15
+ scope = current_show.show_people
16
+ .joins(:assignments)
17
+ .distinct
18
+ .includes(
19
+ :assignments,
20
+ assigned_contestants: %i[show_contestant_images current_voting_session]
21
+ )
22
+
23
+ role = params[:role].presence
24
+ return scope if role.blank?
25
+
26
+ role_value = SpreeCmCommissioner::ShowPersonAssignment.roles[role.to_s]
27
+ return scope.none if role_value.nil?
28
+
29
+ scope.where(cm_show_people_assignments: { role: role_value })
30
+ end
31
+
32
+ # override
33
+ def collection_serializer
34
+ Spree::V2::Tenant::ShowPersonSerializer
35
+ end
36
+
37
+ def current_show
38
+ @current_show ||= show_scope.find_by!(slug: params[:show_id])
39
+ end
40
+
41
+ def show_scope
42
+ vendor_ids = @tenant.vendors.select(:id)
43
+ SpreeCmCommissioner::Show.where(vendor_id: vendor_ids)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,36 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class ShowPersonAssignmentsController < BaseController
6
+ private
7
+
8
+ def model_class
9
+ SpreeCmCommissioner::ShowPersonAssignment
10
+ end
11
+
12
+ def scope
13
+ vendor_ids = @tenant.vendors.select(:id)
14
+ show_ids = SpreeCmCommissioner::Show.where(vendor_id: vendor_ids).select(:id)
15
+
16
+ model_class.where(show_id: show_ids)
17
+ .where(show_person_id: params[:person_id], show_id: current_show.id)
18
+ .includes(:show_person, :show)
19
+ end
20
+
21
+ def current_show
22
+ @current_show ||= SpreeCmCommissioner::Show.find_by!(slug: params[:show_id])
23
+ end
24
+
25
+ def resource_serializer
26
+ Spree::V2::Tenant::ShowPersonAssignmentSerializer
27
+ end
28
+
29
+ def collection_serializer
30
+ Spree::V2::Tenant::ShowPersonAssignmentSerializer
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end