spree_cm_commissioner 2.8.15.pre.pre8 → 2.8.16

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +16 -0
  3. data/.github/workflows/test_and_build_gem.yml +2 -1
  4. data/.gitignore +0 -6
  5. data/Gemfile.lock +1 -1
  6. data/app/controllers/concerns/spree_cm_commissioner/content_cachable.rb +0 -2
  7. data/app/controllers/spree/admin/homepage_section_controller.rb +1 -4
  8. data/app/controllers/spree/admin/import_new_orders_controller.rb +25 -0
  9. data/app/controllers/spree/admin/inventory_holds_controller.rb +21 -1
  10. data/app/controllers/spree/admin/system/maintenance_tasks_controller.rb +64 -0
  11. data/app/controllers/spree/admin/system/waiting_room_controller.rb +22 -0
  12. data/app/controllers/spree/admin/taxons_controller_decorator.rb +5 -19
  13. data/app/controllers/spree/api/v2/storefront/account/orders_controller_decorator.rb +5 -0
  14. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +7 -5
  15. data/app/controllers/spree/api/v2/storefront/homepage_sections_controller.rb +0 -1
  16. data/app/controllers/spree/api/v2/storefront/order_histories_controller.rb +14 -2
  17. data/app/controllers/spree/api/v2/storefront/ticket_transfers_controller.rb +4 -3
  18. data/app/controllers/spree/api/v2/tenant/base_controller.rb +0 -4
  19. data/app/controllers/spree/api/v2/tenant/homepage_sections_controller.rb +0 -1
  20. data/app/controllers/spree/api/v2/tenant/order_histories_controller.rb +14 -2
  21. data/app/controllers/spree/api/v2/tenant/products_controller.rb +1 -1
  22. data/app/controllers/spree/api/v2/tenant/taxons_controller.rb +1 -1
  23. data/app/controllers/spree_cm_commissioner/admin/products_controller_decorator.rb +0 -19
  24. data/app/finders/spree_cm_commissioner/events/find_matches.rb +0 -1
  25. data/app/finders/spree_cm_commissioner/orders/find.rb +33 -3
  26. data/app/finders/spree_cm_commissioner/orders/find_by_all_state.rb +11 -0
  27. data/app/helpers/spree_cm_commissioner/admin/homepage_segment_helper.rb +0 -2
  28. data/app/interactors/spree_cm_commissioner/payment_incomplete_notification_sender.rb +25 -0
  29. data/app/interactors/spree_cm_commissioner/release_inventory_item_notification_sender.rb +24 -0
  30. data/app/interactors/spree_cm_commissioner/waiting_guests_caller.rb +163 -20
  31. data/app/interactors/spree_cm_commissioner/waiting_room_latest_system_metadata_puller.rb +5 -3
  32. data/app/interactors/spree_cm_commissioner/waiting_room_session_creator.rb +25 -6
  33. data/app/jobs/concerns/spree_cm_commissioner/idempotent_job.rb +12 -0
  34. data/app/jobs/spree_cm_commissioner/cancel_import_order_job.rb +11 -0
  35. data/app/jobs/spree_cm_commissioner/idempotency_keys/prune_job.rb +20 -0
  36. data/app/jobs/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_job.rb +21 -3
  37. data/app/jobs/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_on_hold_job.rb +34 -3
  38. data/app/jobs/spree_cm_commissioner/maintenance_tasks/refinalize_guests_batch_job.rb +36 -0
  39. data/app/jobs/spree_cm_commissioner/payment_incomplete_notification_job.rb +12 -0
  40. data/app/jobs/spree_cm_commissioner/telegram_alerts/order_integrity_check_job.rb +17 -0
  41. data/app/jobs/spree_cm_commissioner/waiting_guests_caller_job.rb +6 -1
  42. data/app/jobs/spree_cm_commissioner/waiting_room/publish_lobby_path_job.rb +17 -0
  43. data/app/jobs/spree_cm_commissioner/waiting_room/stamp_queue_positions_job.rb +14 -0
  44. data/app/jobs/spree_cm_commissioner/waiting_room_latest_system_metadata_puller_job.rb +1 -1
  45. data/app/mailers/spree/order_mailer_decorator.rb +2 -0
  46. data/app/models/concerns/spree_cm_commissioner/homepage_section_bitwise.rb +1 -2
  47. data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +16 -2
  48. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +1 -2
  49. data/app/models/concerns/spree_cm_commissioner/order_holdable.rb +6 -0
  50. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +32 -10
  51. data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +2 -0
  52. data/app/models/concerns/spree_cm_commissioner/product_type.rb +1 -1
  53. data/app/models/concerns/spree_cm_commissioner/store_metadata.rb +0 -3
  54. data/app/models/concerns/spree_cm_commissioner/store_preference.rb +1 -0
  55. data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +1 -3
  56. data/app/models/spree_cm_commissioner/idempotency_key.rb +21 -0
  57. data/app/models/spree_cm_commissioner/import.rb +3 -2
  58. data/app/models/spree_cm_commissioner/imported_order.rb +6 -0
  59. data/app/models/spree_cm_commissioner/imports/import_order.rb +21 -0
  60. data/app/models/spree_cm_commissioner/inventory_hold.rb +1 -1
  61. data/app/models/spree_cm_commissioner/line_item_decorator.rb +0 -26
  62. data/app/models/spree_cm_commissioner/maintenance_task.rb +10 -0
  63. data/app/models/spree_cm_commissioner/maintenance_tasks/event.rb +6 -13
  64. data/app/models/spree_cm_commissioner/notification.rb +1 -0
  65. data/app/models/spree_cm_commissioner/order_decorator.rb +18 -0
  66. data/app/models/spree_cm_commissioner/payment_decorator.rb +11 -0
  67. data/app/models/spree_cm_commissioner/product_decorator.rb +2 -52
  68. data/app/models/spree_cm_commissioner/role_decorator.rb +1 -4
  69. data/app/models/spree_cm_commissioner/taxon_ad_banner.rb +12 -0
  70. data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -23
  71. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +1 -19
  72. data/app/models/spree_cm_commissioner/tenant.rb +0 -9
  73. data/app/models/spree_cm_commissioner/user_decorator.rb +0 -5
  74. data/app/models/spree_cm_commissioner/variant_decorator.rb +0 -4
  75. data/app/models/spree_cm_commissioner/variant_options.rb +0 -4
  76. data/app/models/spree_cm_commissioner/vendor_decorator.rb +0 -5
  77. data/app/notifications/spree_cm_commissioner/order_general_notification.rb +15 -0
  78. data/app/overrides/spree/admin/orders/_order_actions/actions.html.erb.deface +7 -0
  79. data/app/overrides/spree/admin/orders/_search/payment_number_search_field.html.erb.deface +8 -0
  80. data/app/overrides/spree/admin/products/_form/allow_gift_transfer.html.erb.deface +1 -1
  81. data/app/overrides/spree/admin/products/_form/allow_transfer.html.erb.deface +1 -1
  82. data/app/overrides/spree/admin/products/_form/enable_send_receipt.html.erb.deface +13 -0
  83. data/app/overrides/spree/admin/products/_form/enable_telegram_alert.html.erb.deface +14 -0
  84. data/app/overrides/spree/admin/stores/_form/store_preferences.html.erb.deface +9 -0
  85. data/app/overrides/spree/admin/taxons/_form/assets_form.html.erb.deface +10 -1
  86. data/app/overrides/spree/admin/vendors/_form/term_of_use.html.erb.deface +6 -0
  87. data/app/serializers/spree/v2/storefront/homepage_section_serializer.rb +1 -1
  88. data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +1 -2
  89. data/app/serializers/spree/v2/storefront/role_serializer.rb +1 -1
  90. data/app/serializers/spree/v2/storefront/taxon_serializer_decorator.rb +3 -2
  91. data/app/serializers/spree/v2/tenant/guest_serializer.rb +2 -1
  92. data/app/serializers/spree/v2/tenant/homepage_section_serializer.rb +1 -1
  93. data/app/serializers/spree/v2/tenant/role_serializer.rb +1 -1
  94. data/app/services/spree_cm_commissioner/api_caches/invalidate.rb +0 -12
  95. data/app/services/spree_cm_commissioner/cart/add_guest.rb +30 -3
  96. data/app/services/spree_cm_commissioner/cart/add_item_decorator.rb +22 -0
  97. data/app/services/spree_cm_commissioner/cart/create_guest.rb +80 -0
  98. data/app/services/spree_cm_commissioner/cart/empty_decorator.rb +23 -0
  99. data/app/services/spree_cm_commissioner/cart/remove_guest.rb +26 -1
  100. data/app/services/spree_cm_commissioner/cart/remove_item_decorator.rb +17 -0
  101. data/app/services/spree_cm_commissioner/cart/remove_line_item_decorator.rb +17 -0
  102. data/app/services/spree_cm_commissioner/cart/set_quantity_decorator.rb +17 -0
  103. data/app/services/spree_cm_commissioner/imports/orders/cancel.rb +63 -0
  104. data/app/services/spree_cm_commissioner/imports/orders/create.rb +1 -0
  105. data/app/services/spree_cm_commissioner/inventory_holds/release.rb +18 -0
  106. data/app/services/spree_cm_commissioner/telegram_alerts/checks/order_complete_payment_not_paid.rb +21 -0
  107. data/app/services/spree_cm_commissioner/telegram_alerts/checks/payment_paid_order_not_complete.rb +21 -0
  108. data/app/services/spree_cm_commissioner/telegram_alerts/order_integrity_alert.rb +112 -0
  109. data/app/services/spree_cm_commissioner/telegram_alerts/order_integrity_checks_runner.rb +32 -0
  110. data/app/services/spree_cm_commissioner/waiting_room/publish_lobby_path.rb +57 -0
  111. data/app/services/spree_cm_commissioner/waiting_room/stamp_queue_positions.rb +185 -0
  112. data/app/services/spree_cm_commissioner/waiting_room_lobby_metadata_fetcher.rb +47 -0
  113. data/app/services/spree_cm_commissioner/waiting_room_system_metadata_fetcher.rb +19 -5
  114. data/app/services/spree_cm_commissioner/waiting_room_system_metadata_setter.rb +28 -5
  115. data/app/views/spree/admin/homepage_section/_form.html.erb +0 -5
  116. data/app/views/spree/admin/import_new_orders/_cancel_modal.html.erb +35 -0
  117. data/app/views/spree/admin/import_new_orders/index.html.erb +4 -0
  118. data/app/views/spree/admin/import_new_orders/show.html.erb +30 -0
  119. data/app/views/spree/admin/imports/index.html.erb +2 -0
  120. data/app/views/spree/admin/inventory_holds/index.html.erb +8 -3
  121. data/app/views/spree/admin/shared/_system_tabs.html.erb +7 -0
  122. data/app/views/spree/admin/system/maintenance_tasks/_search.html.erb +28 -0
  123. data/app/views/spree/admin/system/maintenance_tasks/index.html.erb +71 -0
  124. data/app/views/spree/admin/system/waiting_room/show.html.erb +58 -0
  125. data/app/views/spree/order_mailer/confirm_email.html.erb +10 -0
  126. data/app/views/spree_cm_commissioner/order_mailer/_mailer_stylesheets.html.erb +12 -0
  127. data/app/views/spree_cm_commissioner/order_mailer/purchased_items/_items.html.erb +12 -9
  128. data/config/initializers/spree_permitted_attributes.rb +6 -8
  129. data/config/locales/en.yml +23 -55
  130. data/config/locales/km.yml +13 -42
  131. data/config/routes.rb +10 -30
  132. data/db/migrate/20260616000001_add_canceled_by_id_to_cm_imports.rb +5 -0
  133. data/db/migrate/20260617000002_create_cm_imported_orders.rb +12 -0
  134. data/db/migrate/20260619000001_create_cm_idempotency_keys.rb +11 -0
  135. data/db/migrate/20260629000001_add_term_of_use_to_spree_vendors.rb +5 -0
  136. data/lib/spree_cm_commissioner/version.rb +1 -1
  137. data/lib/spree_cm_commissioner.rb +1 -7
  138. data/spree_cm_commissioner.gemspec +1 -1
  139. metadata +44 -135
  140. data/app/controllers/spree/api/v2/storefront/preview_products_controller.rb +0 -48
  141. data/app/controllers/spree/api/v2/storefront/preview_sections_controller.rb +0 -27
  142. data/app/controllers/spree/api/v2/storefront/preview_taxons_controller.rb +0 -18
  143. data/app/controllers/spree/api/v2/storefront/products_controller_decorator.rb +0 -15
  144. data/app/controllers/spree/api/v2/storefront/taxons_controller_decorator.rb +0 -15
  145. data/app/controllers/spree/api/v2/tenant/ad_campaigns_controller.rb +0 -25
  146. data/app/controllers/spree/api/v2/tenant/episodes_controller.rb +0 -38
  147. data/app/controllers/spree/api/v2/tenant/preview_products_controller.rb +0 -47
  148. data/app/controllers/spree/api/v2/tenant/preview_sections_controller.rb +0 -26
  149. data/app/controllers/spree/api/v2/tenant/preview_shows_controller.rb +0 -19
  150. data/app/controllers/spree/api/v2/tenant/preview_taxons_controller.rb +0 -19
  151. data/app/controllers/spree/api/v2/tenant/show_contestants_controller.rb +0 -52
  152. data/app/controllers/spree/api/v2/tenant/show_elimination_sessions_controller.rb +0 -57
  153. data/app/controllers/spree/api/v2/tenant/show_people_controller.rb +0 -49
  154. data/app/controllers/spree/api/v2/tenant/show_person_assignments_controller.rb +0 -36
  155. data/app/controllers/spree/api/v2/tenant/shows_controller.rb +0 -36
  156. data/app/controllers/spree/api/v2/tenant/vote_packages_controller.rb +0 -81
  157. data/app/controllers/spree/api/v2/tenant/votes_controller.rb +0 -94
  158. data/app/controllers/spree/api/v2/tenant/voting_contestants_controller.rb +0 -43
  159. data/app/controllers/spree/api/v2/tenant/voting_credit_transactions_controller.rb +0 -41
  160. data/app/controllers/spree/api/v2/tenant/voting_credits_controller.rb +0 -31
  161. data/app/jobs/spree_cm_commissioner/show_contestants/import_job.rb +0 -9
  162. data/app/jobs/spree_cm_commissioner/vote_fraud_event_job.rb +0 -9
  163. data/app/jobs/spree_cm_commissioner/voting_credit_allocation_job.rb +0 -10
  164. data/app/jobs/spree_cm_commissioner/voting_credit_de_allocation_job.rb +0 -10
  165. data/app/models/concerns/spree_cm_commissioner/voting_session_live_stream_concern.rb +0 -41
  166. data/app/models/spree_cm_commissioner/claim.rb +0 -27
  167. data/app/models/spree_cm_commissioner/imports/import_contestant.rb +0 -7
  168. data/app/models/spree_cm_commissioner/maintenance_tasks/voting_session.rb +0 -36
  169. data/app/models/spree_cm_commissioner/preview_role.rb +0 -8
  170. data/app/models/spree_cm_commissioner/role_user_decorator.rb +0 -8
  171. data/app/models/spree_cm_commissioner/show.rb +0 -171
  172. data/app/models/spree_cm_commissioner/show_contestant.rb +0 -39
  173. data/app/models/spree_cm_commissioner/show_contestant_image.rb +0 -11
  174. data/app/models/spree_cm_commissioner/show_contestant_video.rb +0 -15
  175. data/app/models/spree_cm_commissioner/show_episode.rb +0 -122
  176. data/app/models/spree_cm_commissioner/show_person.rb +0 -15
  177. data/app/models/spree_cm_commissioner/show_person_assignment.rb +0 -21
  178. data/app/models/spree_cm_commissioner/show_person_image.rb +0 -11
  179. data/app/models/spree_cm_commissioner/vote.rb +0 -16
  180. data/app/models/spree_cm_commissioner/vote_fraud_event.rb +0 -20
  181. data/app/models/spree_cm_commissioner/voting_contestant.rb +0 -100
  182. data/app/models/spree_cm_commissioner/voting_credit.rb +0 -84
  183. data/app/models/spree_cm_commissioner/voting_credit_transaction.rb +0 -55
  184. data/app/models/spree_cm_commissioner/voting_session.rb +0 -217
  185. data/app/models/spree_cm_commissioner/voting_session_stat.rb +0 -8
  186. data/app/overrides/spree/admin/products/_form/preview_checkbox.html.erb.deface +0 -9
  187. data/app/overrides/spree/admin/taxons/_form/preview_checkbox.html.erb.deface +0 -7
  188. data/app/serializers/spree/v2/tenant/ad_campaign_serializer.rb +0 -13
  189. data/app/serializers/spree/v2/tenant/advertisement_serializer.rb +0 -11
  190. data/app/serializers/spree/v2/tenant/show_contestant_serializer.rb +0 -21
  191. data/app/serializers/spree/v2/tenant/show_episode_serializer.rb +0 -20
  192. data/app/serializers/spree/v2/tenant/show_parent_serializer.rb +0 -13
  193. data/app/serializers/spree/v2/tenant/show_person_assignment_serializer.rb +0 -16
  194. data/app/serializers/spree/v2/tenant/show_person_serializer.rb +0 -13
  195. data/app/serializers/spree/v2/tenant/show_serializer.rb +0 -23
  196. data/app/serializers/spree/v2/tenant/video_serializer.rb +0 -9
  197. data/app/serializers/spree/v2/tenant/vote_package_serializer.rb +0 -15
  198. data/app/serializers/spree/v2/tenant/vote_serializer.rb +0 -14
  199. data/app/serializers/spree/v2/tenant/voting_contestant_serializer.rb +0 -23
  200. data/app/serializers/spree/v2/tenant/voting_credit_serializer.rb +0 -10
  201. data/app/serializers/spree/v2/tenant/voting_credit_transaction_serializer.rb +0 -14
  202. data/app/serializers/spree/v2/tenant/voting_session_serializer.rb +0 -21
  203. data/app/services/spree_cm_commissioner/fraud_check.rb +0 -299
  204. data/app/services/spree_cm_commissioner/imports/contestants/create.rb +0 -153
  205. data/app/services/spree_cm_commissioner/show_contestants/normalize_video_highlights.rb +0 -57
  206. data/app/services/spree_cm_commissioner/show_persons/contestant_assigner.rb +0 -51
  207. data/app/services/spree_cm_commissioner/url_embed/youtube_embed.rb +0 -44
  208. data/app/services/spree_cm_commissioner/vote_counters/audit_counters.rb +0 -43
  209. data/app/services/spree_cm_commissioner/vote_counters/base.rb +0 -31
  210. data/app/services/spree_cm_commissioner/vote_counters/increment.rb +0 -44
  211. data/app/services/spree_cm_commissioner/vote_counters/per_contestant_counter.rb +0 -68
  212. data/app/services/spree_cm_commissioner/vote_counters/rebuild_from_db.rb +0 -70
  213. data/app/services/spree_cm_commissioner/vote_counters/snapshot_to_db.rb +0 -113
  214. data/app/services/spree_cm_commissioner/vote_credit_deductor.rb +0 -68
  215. data/app/services/spree_cm_commissioner/vote_package/create.rb +0 -150
  216. data/app/services/spree_cm_commissioner/vote_package/update.rb +0 -97
  217. data/app/services/spree_cm_commissioner/vote_processor.rb +0 -144
  218. data/app/services/spree_cm_commissioner/voting_contestants/advancer.rb +0 -335
  219. data/app/services/spree_cm_commissioner/voting_contestants/assigner.rb +0 -40
  220. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +0 -109
  221. data/app/services/spree_cm_commissioner/voting_credits/admin_grant.rb +0 -37
  222. data/app/services/spree_cm_commissioner/voting_credits/allocate.rb +0 -123
  223. data/app/services/spree_cm_commissioner/voting_credits/claimable_scope_resolver.rb +0 -64
  224. data/app/services/spree_cm_commissioner/voting_credits/credit_calculator.rb +0 -35
  225. data/app/services/spree_cm_commissioner/voting_credits/de_allocate.rb +0 -87
  226. data/app/services/spree_cm_commissioner/voting_leaderboards/calculate_score.rb +0 -67
  227. data/app/services/spree_cm_commissioner/voting_leaderboards/combined_result.rb +0 -190
  228. data/app/services/spree_cm_commissioner/voting_sessions/finalize.rb +0 -105
  229. data/db/migrate/20260309230148_create_cm_show_people.rb +0 -14
  230. data/db/migrate/20260309230149_create_cm_show_people_assignments.rb +0 -16
  231. data/db/migrate/20260310082711_create_cm_show_contestants.rb +0 -28
  232. data/db/migrate/20260310082720_create_cm_voting_sessions.rb +0 -21
  233. data/db/migrate/20260310082721_create_cm_voting_contestants.rb +0 -23
  234. data/db/migrate/20260310082734_add_voting_fields_to_spree_taxons.rb +0 -9
  235. data/db/migrate/20260310082735_add_type_to_spree_products.rb +0 -6
  236. data/db/migrate/20260310082749_create_cm_voting_credits.rb +0 -27
  237. data/db/migrate/20260326080200_create_cm_voting_credit_transactions.rb +0 -27
  238. data/db/migrate/20260330160000_create_cm_votes.rb +0 -25
  239. data/db/migrate/20260401072500_add_advanced_from_to_cm_voting_contestants.rb +0 -7
  240. data/db/migrate/20260402000001_add_voting_credit_scope_to_spree_taxons.rb +0 -6
  241. data/db/migrate/20260402000002_rename_scopeable_to_votable_in_cm_voting_credits.rb +0 -12
  242. data/db/migrate/20260403070000_add_name_to_cm_voting_sessions.rb +0 -5
  243. data/db/migrate/20260406000001_add_vendor_id_to_voting_tables.rb +0 -6
  244. data/db/migrate/20260406000001_rename_votes_remaining_to_amount_in_cm_voting_credits.rb +0 -11
  245. data/db/migrate/20260408085255_add_show_id_and_vendor_id_to_cm_voting_sessions.rb +0 -9
  246. data/db/migrate/20260420000001_rename_type_to_credit_type_in_cm_voting_credits.rb +0 -25
  247. data/db/migrate/20260422000001_create_cm_vote_fraud_events.rb +0 -23
  248. data/db/migrate/20260423000001_add_preview_to_taxons_products_and_sections.rb +0 -11
  249. data/db/migrate/20260423000002_create_preview_roles.rb +0 -24
  250. data/db/migrate/20260515120000_add_public_metadata_to_cm_voting_sessions.rb +0 -5
  251. data/db/migrate/20260518090920_add_unique_voter_count_to_voting_contestants.rb +0 -5
  252. data/db/migrate/20260518094322_create_cm_voting_session_stats.rb +0 -17
  253. data/db/migrate/20260520000001_add_scoring_model_to_cm_voting_sessions.rb +0 -5
  254. data/db/migrate/20260520000001_optimize_cm_votes_indexes.rb +0 -22
  255. data/db/migrate/20260525042257_add_vote_number_to_cm_voting_contestants.rb +0 -18
  256. data/db/migrate/20260527035430_add_confirmed_rank_to_cm_voting_contestants.rb +0 -5
  257. data/db/migrate/20260527062005_add_eliminated_at_to_cm_show_contestants.rb +0 -5
  258. data/db/migrate/20260603063652_add_parent_to_voting_sessions.rb +0 -9
  259. data/db/migrate/20260603090000_add_session_type_to_cm_voting_sessions.rb +0 -6
  260. data/db/migrate/20260608000000_add_display_to_cm_voting_sessions.rb +0 -5
  261. data/db/migrate/20260623082233_create_cm_claims.rb +0 -14
  262. data/db/migrate/20260624175658_add_unique_index_to_cm_claims.rb +0 -11
  263. data/docs/sql/jsonb_query_guide.md +0 -57
  264. data/lib/spree_cm_commissioner/test_helper/factories/claim_factory.rb +0 -14
  265. data/lib/spree_cm_commissioner/test_helper/factories/show_episode_factory.rb +0 -12
  266. data/lib/spree_cm_commissioner/test_helper/factories/show_factory.rb +0 -120
  267. data/lib/spree_cm_commissioner/test_helper/factories/vote_credit_factory.rb +0 -37
  268. data/lib/spree_cm_commissioner/test_helper/factories/vote_factory.rb +0 -28
  269. data/lib/spree_cm_commissioner/test_helper/factories/voting_credit_transaction_factory.rb +0 -11
  270. 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: 0f0d6bc194265bc170fa7f5d480c4c3aead23d86827c1f80896237f8c3864d6c
4
- data.tar.gz: 7fb03f4121f2cdead7cbb774489c675663dc172bb62c9b6c3a7b06c67c52c08a
3
+ metadata.gz: 793be478c9e769be1ddebd446fb98201ed4277176ca0cc64880a1fdeb71297b2
4
+ data.tar.gz: fe71e91c4f124dcb730cad8ff27dd87dddd92e0ffab66aaf292845e797b3fa01
5
5
  SHA512:
6
- metadata.gz: cb11254307ddad72b7941b7474ee8fc473474dac0abfaa95a3d6eb15c803fe86a7bafb60b8705d40a93c00e83d39836846ed6ed16bf45453e47301f5666ce058
7
- data.tar.gz: 1880e96a3b09bc6fb3efcc72649221b0603ab1a87d1774dd13badf47ba38f57d94b875a9261f369ab839ada7c35d698ffe4230c1d6b327654ecec693e74cc41d
6
+ metadata.gz: c15e41fc7108a69dd080a6610af697f6b1a669a4b830de63dbb725242b3c0ca899fc00e47b1086b9eb1c3da2df0567d94f95cdab60e230994f9abfc031dc2cb8
7
+ data.tar.gz: 1f25bae14db105a7b0db5225fe2df2fd232e6d507940bac7876cd038ed2eb71fff35799d9809a39c208972e70d2c2c9ce90f51ca78c86b904cc7cfe6f3edd6a5
data/.env.example CHANGED
@@ -20,6 +20,13 @@ WAITING_ROOM_SESSION_SIGNATURE="e6b2********************26e3"
20
20
  WAITING_ROOM_SESSION_EXPIRE_DURATION_IN_SECOND=
21
21
  WAITING_ROOM_MIN_SESSIONS_COUNT=5
22
22
  WAITING_ROOM_DISABLED=no
23
+ WAITING_ROOM_POSITION_STAMP_LIMIT=1000
24
+ WAITING_ROOM_FIRESTORE_BATCH_SIZE=500
25
+ WAITING_ROOM_MIN_WAIT_TO_ENTER_SECONDS=600 # Waiting Room step floor (10 min)
26
+ WAITING_ROOM_MIN_QUEUE_TO_ENTER_SECONDS=300 # Queue step floor (5 min)
27
+ WAITING_ROOM_MAX_WAIT_TO_DISPLAY_SECONDS=3600 # above this the ETA is hidden (1 h)
28
+ WAITING_ROOM_CALLER_INTERVAL_SECONDS=60 # how often the caller runs; match the waiting_guests_caller cron
29
+ WAITING_ROOM_MAX_ETA_BATCH_SIZE=50 # cap on batch size assumed when estimating the ETA
23
30
 
24
31
  # Vattanac Bank
25
32
  VATTANAC_AES_SECRET_KEY= ""
@@ -45,6 +52,9 @@ CACHE_DEFAULT_MAX_AGE=300 # Default for unlisted controllers - 5 minutes
45
52
  # Batch size for processing maintenance tasks in app/jobs/spree_cm_commissioner/maintenance_tasks/orchestrate_job.rb
46
53
  MAINTENANCE_TASKS_BATCH_SIZE=100
47
54
 
55
+ # Batch size for slicing guest_ids when enqueuing RefinalizeGuestsBatchJob in app/models/spree_cm_commissioner/maintenance_tasks/event.rb
56
+ MAINTENANCE_TASKS_REFINALIZE_GUESTS_BATCH_SIZE=300
57
+
48
58
  # Export related:
49
59
  OPERATOR_GUEST_JSON_GZIP_CACHE_HOURS=24
50
60
  EXPORT_PRESIGNED_URL_EXPIRATION_MINUTES=15
@@ -63,3 +73,9 @@ PAYMENT_LOCK_MIN_DURATION_IN_MINUTES=5 # Minimum remaining hold time requir
63
73
  MAX_ACTIVE_HOLDS_PER_USER=3 # Max concurrent active holds allowed per user across all orders
64
74
  MAX_HOLDS_PER_IP_PER_HOUR=5 # Max hold attempts per IP address within a rolling 1-hour window (abuse prevention)
65
75
  HOLD_COOLDOWN_AFTER_EXPIRY_IN_MINUTES=2 # Cooldown period before a user can re-acquire a hold after one expired on them
76
+
77
+ # See: app/models/spree_cm_commissioner/payment_decorator.rb
78
+ PAYMENT_INCOMPLETE_NOTIFICATION_DELAY_IN_MINUTES=5 # Delay before notifying a customer that their order is still unpaid after payment is created
79
+
80
+ # See: app/jobs/spree_cm_commissioner/telegram_alerts/order_integrity_check_job.rb
81
+ ORDER_INTEGRITY_TELEGRAM_ALERT_ENABLED="no" # Set to yes to enable the order integrity Telegram alert job (off by default to avoid flooding Telegram rate limits during traffic spikes)
@@ -163,8 +163,9 @@ jobs:
163
163
  - name: Security
164
164
  env:
165
165
  DATABASE_URL: postgres://myuser:mypassword@localhost:5432/test_db
166
+
167
+ # Using --no-threads to bypass a known Ruby 3.2.0 GC segmentation fault in CI.
166
168
  run: |
167
- # Using --no-threads to bypass a known Ruby 3.2.0 GC segmentation fault in CI.
168
169
  bundle exec brakeman --no-threads --no-exit-on-warn
169
170
 
170
171
  test:
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.15.pre.pre8)
37
+ spree_cm_commissioner (2.8.16)
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
@@ -23,6 +23,31 @@ module Spree
23
23
  end
24
24
  end
25
25
  end
26
+
27
+ # POST: /admin/orders/import_new_orders/:id/cancel
28
+ def cancel
29
+ import = model_class.find(params[:id])
30
+ show_url = spree.admin_import_new_order_url(import.id)
31
+
32
+ unless import.cancellable?
33
+ flash[:error] = 'These orders cannot be canceled.' # rubocop:disable Rails/I18nLocaleTexts
34
+ redirect_to show_url and return
35
+ end
36
+
37
+ if params[:confirm_name].to_s.strip != import.name.to_s.strip
38
+ flash[:error] = 'Import name did not match. Cancellation aborted.' # rubocop:disable Rails/I18nLocaleTexts
39
+ redirect_to show_url and return
40
+ end
41
+
42
+ SpreeCmCommissioner::CancelImportOrderJob.perform_later(
43
+ import_order_id: import.id,
44
+ canceled_by_user_id: spree_current_user.id,
45
+ cancellation_reason: params[:cancellation_reason].to_s.strip.presence
46
+ )
47
+
48
+ flash[:success] = "Canceling orders from \"#{import.name}\". This runs in the background."
49
+ redirect_to show_url
50
+ end
26
51
  end
27
52
  end
28
53
  end
@@ -9,6 +9,7 @@ module Spree
9
9
  q['s'] ||= 'created_at desc'
10
10
  q['created_at_gt'] = parse_time_or_nil(q['created_at_gt'], :beginning_of_day) if q['created_at_gt'].present?
11
11
  q['created_at_lt'] = parse_time_or_nil(q['created_at_lt'], :end_of_day) if q['created_at_lt'].present?
12
+ normalize_enum_filters!(q)
12
13
 
13
14
  @search = scope.ransack(q)
14
15
  result_scope = @search.result(distinct: true)
@@ -18,7 +19,11 @@ module Spree
18
19
  .page(params[:page])
19
20
  .per(params[:per_page] || Spree::Backend::Config[:admin_orders_per_page])
20
21
 
21
- @status_counts = result_scope.reorder(nil).group(:status).count
22
+ # Status tab counts must reflect every other filter but NOT the status filter, so
23
+ # each tab shows how many holds it would return (otherwise selecting one status
24
+ # zeroes out all the other tabs).
25
+ @status_counts = scope.ransack(q.except('status_eq')).result(distinct: true)
26
+ .reorder(nil).group(:status).count
22
27
  end
23
28
 
24
29
  def release
@@ -44,8 +49,23 @@ module Spree
44
49
 
45
50
  private
46
51
 
52
+ # `status` and `release_reason` are integer-backed enums. Ransack casts a string
53
+ # value for an integer column with String#to_i, so "payment_locked" becomes 0
54
+ # (== :pending) and every label silently filters to the wrong status. Translate
55
+ # enum labels to their stored integer before searching.
56
+ def normalize_enum_filters!(query)
57
+ {
58
+ 'status_eq' => SpreeCmCommissioner::InventoryHold.statuses,
59
+ 'release_reason_eq' => SpreeCmCommissioner::InventoryHold.release_reasons
60
+ }.each do |key, mapping|
61
+ value = query[key]
62
+ query[key] = mapping[value.to_s] if value.present? && mapping.key?(value.to_s)
63
+ end
64
+ end
65
+
47
66
  def back_params
48
67
  raw_params = params[:back_params].presence || params
68
+ raw_params = raw_params.to_unsafe_h if raw_params.respond_to?(:to_unsafe_h)
49
69
  ActionController::Parameters.new(raw_params).permit(:page, :per_page, q: {})
50
70
  end
51
71
 
@@ -0,0 +1,64 @@
1
+ module Spree
2
+ module Admin
3
+ module System
4
+ class MaintenanceTasksController < Spree::Admin::BaseController
5
+ def index
6
+ authorize! :manage, SpreeCmCommissioner::MaintenanceTask
7
+
8
+ @search = scope.ransack(params[:q])
9
+ @tasks = @search.result(distinct: true)
10
+ .order(created_at: :desc)
11
+ .page(params[:page])
12
+ .per(params[:per_page] || Spree::Backend::Config[:admin_orders_per_page])
13
+ end
14
+
15
+ def run_now
16
+ authorize! :manage, SpreeCmCommissioner::MaintenanceTask
17
+
18
+ task = SpreeCmCommissioner::MaintenanceTask.find(params[:id])
19
+
20
+ if task.completed_at.present?
21
+ flash[:error] = "Task ##{task.id} is already completed."
22
+ else
23
+ task.update!(manually_triggered: true)
24
+ task.execute
25
+
26
+ if task.completed_at.present?
27
+ flash[:success] = "Task ##{task.id} (#{task.type.demodulize}) ran successfully."
28
+ else
29
+ flash[:error] = "Task ##{task.id} (#{task.type.demodulize}) failed: #{task.last_error}"
30
+ end
31
+ end
32
+
33
+ redirect_to admin_system_maintenance_tasks_path(back_params)
34
+ end
35
+
36
+ def destroy
37
+ authorize! :manage, SpreeCmCommissioner::MaintenanceTask
38
+
39
+ task = SpreeCmCommissioner::MaintenanceTask.find(params[:id])
40
+
41
+ if task.destroy
42
+ flash[:success] = "Task ##{task.id} has been deleted."
43
+ else
44
+ flash[:error] = task.errors.full_messages.to_sentence.presence || "Failed to delete task ##{task.id}."
45
+ end
46
+
47
+ redirect_to admin_system_maintenance_tasks_path(back_params)
48
+ end
49
+
50
+ private
51
+
52
+ def scope
53
+ SpreeCmCommissioner::MaintenanceTask.accessible_by(current_ability, :manage)
54
+ end
55
+
56
+ def back_params
57
+ raw_params = params[:back_params].presence || params
58
+ raw_params = raw_params.to_unsafe_h if raw_params.respond_to?(:to_unsafe_h)
59
+ ActionController::Parameters.new(raw_params).permit(:page, :per_page, q: {})
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -4,7 +4,10 @@ module Spree
4
4
  class WaitingRoomController < Spree::Admin::BaseController
5
5
  def show
6
6
  @fetcher = SpreeCmCommissioner::WaitingRoomSystemMetadataFetcher.new
7
+ @lobby_fetcher = SpreeCmCommissioner::WaitingRoomLobbyMetadataFetcher.new
8
+
7
9
  @fetcher.load_document_data
10
+ @lobby_fetcher.load_document_data
8
11
 
9
12
  @active_sesions_count = SpreeCmCommissioner::WaitingRoomSession.active.count
10
13
  end
@@ -23,12 +26,31 @@ module Spree
23
26
  redirect_back fallback_location: admin_system_waiting_room_path
24
27
  end
25
28
 
29
+ def modify_max_sessions_count_cap
30
+ modifier = params[:max_sessions_count_cap]&.to_i || 0
31
+ SpreeCmCommissioner::WaitingRoomSystemMetadataSetter.new.modify_max_sessions_count_cap(modifier)
32
+
33
+ redirect_back fallback_location: admin_system_waiting_room_path
34
+ end
35
+
26
36
  def force_pull
27
37
  SpreeCmCommissioner::WaitingRoomLatestSystemMetadataPullerJob.perform_now
28
38
  SpreeCmCommissioner::WaitingGuestsCallerJob.perform_now
29
39
 
30
40
  redirect_back fallback_location: admin_system_waiting_room_path
31
41
  end
42
+
43
+ def publish_lobby_path
44
+ result = SpreeCmCommissioner::WaitingRoom::PublishLobbyPath.call
45
+
46
+ if result.success?
47
+ flash[:success] = "Published waiting guests records path: #{result.value[:records_path]}"
48
+ else
49
+ flash[:error] = result.error.to_s
50
+ end
51
+
52
+ redirect_back fallback_location: admin_system_waiting_room_path
53
+ end
32
54
  end
33
55
  end
34
56
  end
@@ -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
@@ -44,6 +44,11 @@ module Spree
44
44
  def collection_finder
45
45
  SpreeCmCommissioner::Orders::FindByState
46
46
  end
47
+
48
+ # this allows fetching a single order regardless of its state.
49
+ def resource_finder
50
+ SpreeCmCommissioner::Orders::FindByAllState
51
+ end
47
52
  end
48
53
  end
49
54
  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
@@ -30,13 +30,25 @@ module Spree
30
30
  private
31
31
 
32
32
  def collection
33
+ # WARNING: Do NOT remove .order(id: :desc).
34
+ # Mobile relies on this ordering for paginated order_histories.
35
+ # Removing it will cause mobile to paginate by oldest records first (last 10 oldest),
36
+ # breaking the "most recent orders" display on the order history screen.
37
+ # It related to user cancel or complete order flow, which relies on the most recent orders being returned first.
33
38
  if spree_current_user.present?
34
- spree_current_user.orders.payment.not_archived
39
+ spree_current_user.orders
40
+ .not_archived
41
+ .incomplete
42
+ .order(id: :desc)
35
43
  else
36
44
  order_tokens = Array(params[:order_tokens])
37
45
  return Spree::Order.none if order_tokens.empty?
38
46
 
39
- Spree::Order.payment.not_archived.without_user.where(token: order_tokens)
47
+ Spree::Order.not_archived
48
+ .incomplete
49
+ .without_user
50
+ .where(token: order_tokens)
51
+ .order(id: :desc)
40
52
  end
41
53
  end
42
54
 
@@ -86,9 +86,10 @@ module Spree
86
86
  end
87
87
 
88
88
  def collection
89
- SpreeCmCommissioner::TicketTransfer.includes(:order,
90
- from_guest: [:event, { line_item: :product }]
91
- ).where(from_user_id: spree_current_user.id)
89
+ SpreeCmCommissioner::TicketTransfer
90
+ .includes(:order, from_guest: [:event, { line_item: :product }])
91
+ .where(from_user_id: spree_current_user.id)
92
+ .order(id: :desc)
92
93
  end
93
94
 
94
95
  def resource_serializer
@@ -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
@@ -37,13 +37,25 @@ module Spree
37
37
  end
38
38
 
39
39
  def collection
40
+ # WARNING: Do NOT remove .order(id: :desc).
41
+ # Mobile relies on this ordering for paginated order_histories.
42
+ # Removing it will cause mobile to paginate by oldest records first (last 10 oldest),
43
+ # breaking the "most recent orders" display on the order history screen.
44
+ # It related to user cancel or complete order flow, which relies on the most recent orders being returned first.
40
45
  if spree_current_user.present?
41
- spree_current_user.orders.payment.not_archived
46
+ spree_current_user.orders
47
+ .not_archived
48
+ .incomplete
49
+ .order(id: :desc)
42
50
  else
43
51
  order_tokens = Array(params[:order_tokens])
44
52
  return Spree::Order.none if order_tokens.empty?
45
53
 
46
- Spree::Order.payment.not_archived.without_user.where(token: order_tokens)
54
+ Spree::Order.not_archived
55
+ .incomplete
56
+ .without_user
57
+ .where(token: order_tokens)
58
+ .order(id: :desc)
47
59
  end
48
60
  end
49
61
 
@@ -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
@@ -4,14 +4,30 @@
4
4
  module SpreeCmCommissioner
5
5
  module Orders
6
6
  class Find
7
+ CURRENT_CART_STATES = %w[cart address].freeze
8
+ CART_MAX_AGE_IN_MINUTES = ENV.fetch('CART_MAX_AGE_IN_MINUTES', '720').to_i # Default: 12 hours
9
+
7
10
  def execute(store:, user:, currency:, token: nil, state: nil)
11
+ state = Array(state).map(&:to_s)
12
+
8
13
  params = { store_id: store.id, currency: currency }
9
14
  params[:state] = state if state.present?
10
15
 
11
- return find_by_token(params, token) if token.present?
12
- return find_by_user(params, user) if user.present?
16
+ order = if token.present?
17
+ find_by_token(params, token)
18
+ elsif user.present?
19
+ find_by_user(params, user)
20
+ end
21
+
22
+ # Only enforce hold and age expiration when fetching current cart states ('cart' or 'address').
23
+ # For other states (like 'payment,complete'), we want to return the order even if it's old or expired
24
+ # because some pages on client still need some specific state of order to display.
25
+ if state.intersect?(CURRENT_CART_STATES)
26
+ return nil if hold_expired?(order)
27
+ return nil if cart_too_old?(order)
28
+ end
13
29
 
14
- nil
30
+ order
15
31
  end
16
32
 
17
33
  def find_by_token(params, token)
@@ -24,6 +40,20 @@ module SpreeCmCommissioner
24
40
  scope.order(created_at: :desc).find_by(params)
25
41
  end
26
42
 
43
+ def hold_expired?(order)
44
+ return false if order.nil?
45
+
46
+ # Check if the order has a hold_expires_at column and if it has already passed
47
+ order.hold_expires_at.present? && order.hold_expires_at < Time.current
48
+ end
49
+
50
+ def cart_too_old?(order)
51
+ return false if order.nil?
52
+
53
+ # Treat the cart as active based on its last update time, not its creation time.
54
+ order.updated_at < CART_MAX_AGE_IN_MINUTES.minutes.ago
55
+ end
56
+
27
57
  private
28
58
 
29
59
  def scope
@@ -0,0 +1,11 @@
1
+ module SpreeCmCommissioner
2
+ module Orders
3
+ class FindByAllState < Spree::Orders::FindComplete
4
+ private
5
+
6
+ def scope
7
+ user? ? user.orders.includes(scope_includes) : Spree::Order.includes(scope_includes)
8
+ end
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,25 @@
1
+ module SpreeCmCommissioner
2
+ class PaymentIncompleteNotificationSender < BaseInteractor
3
+ def call
4
+ order = context.notificable
5
+ return if order.user.blank?
6
+ return if order.reload.payment_fulfilled?
7
+
8
+ SpreeCmCommissioner::OrderGeneralNotification.with(
9
+ notificable: order,
10
+ title: title,
11
+ message: message(order)
12
+ ).deliver_later(order.user)
13
+ end
14
+
15
+ private
16
+
17
+ def title
18
+ I18n.t('notifications.spree_cm_commissioner.payment_incomplete_notification.title')
19
+ end
20
+
21
+ def message(order)
22
+ I18n.t('notifications.spree_cm_commissioner.payment_incomplete_notification.message', order_number: order.number)
23
+ end
24
+ end
25
+ end