spree_cm_commissioner 2.8.3 → 2.8.4.pre.pre2

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 (312) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test_and_build_gem.yml +2 -1
  3. data/.gitignore +6 -0
  4. data/Gemfile.lock +1 -1
  5. data/app/controllers/concerns/spree_cm_commissioner/content_cachable.rb +2 -0
  6. data/app/controllers/spree/admin/guests_controller.rb +1 -1
  7. data/app/controllers/spree/admin/homepage_section_controller.rb +4 -1
  8. data/app/controllers/spree/admin/order_ticket_transfers_controller.rb +25 -0
  9. data/app/controllers/spree/admin/stock_managements_controller.rb +1 -1
  10. data/app/controllers/spree/admin/system/waiting_room_controller.rb +15 -0
  11. data/app/controllers/spree/admin/taxons_controller_decorator.rb +24 -0
  12. data/app/controllers/spree/admin/ticket_transfer_rules_controller.rb +47 -0
  13. data/app/controllers/spree/admin/ticket_transfers_controller.rb +61 -0
  14. data/app/controllers/spree/api/v2/storefront/account/recipients_controller.rb +32 -0
  15. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +7 -5
  16. data/app/controllers/spree/api/v2/storefront/homepage_sections_controller.rb +1 -0
  17. data/app/controllers/spree/api/v2/storefront/preview_products_controller.rb +48 -0
  18. data/app/controllers/spree/api/v2/storefront/preview_sections_controller.rb +27 -0
  19. data/app/controllers/spree/api/v2/storefront/preview_taxons_controller.rb +18 -0
  20. data/app/controllers/spree/api/v2/storefront/products_controller_decorator.rb +15 -0
  21. data/app/controllers/spree/api/v2/storefront/taxons_controller_decorator.rb +15 -0
  22. data/app/controllers/spree/api/v2/storefront/ticket_transfer_acceptances_controller.rb +32 -0
  23. data/app/controllers/spree/api/v2/storefront/ticket_transfers_controller.rb +117 -0
  24. data/app/controllers/spree/api/v2/storefront/transit/draft_orders_controller.rb +3 -1
  25. data/app/controllers/spree/api/v2/tenant/ad_campaigns_controller.rb +25 -0
  26. data/app/controllers/spree/api/v2/tenant/base_controller.rb +4 -0
  27. data/app/controllers/spree/api/v2/tenant/episodes_controller.rb +38 -0
  28. data/app/controllers/spree/api/v2/tenant/free_vote_claim_controller.rb +58 -0
  29. data/app/controllers/spree/api/v2/tenant/homepage_sections_controller.rb +1 -0
  30. data/app/controllers/spree/api/v2/tenant/preview_products_controller.rb +47 -0
  31. data/app/controllers/spree/api/v2/tenant/preview_sections_controller.rb +26 -0
  32. data/app/controllers/spree/api/v2/tenant/preview_shows_controller.rb +19 -0
  33. data/app/controllers/spree/api/v2/tenant/preview_taxons_controller.rb +19 -0
  34. data/app/controllers/spree/api/v2/tenant/products_controller.rb +1 -1
  35. data/app/controllers/spree/api/v2/tenant/show_contestants_controller.rb +52 -0
  36. data/app/controllers/spree/api/v2/tenant/show_elimination_sessions_controller.rb +57 -0
  37. data/app/controllers/spree/api/v2/tenant/show_people_controller.rb +49 -0
  38. data/app/controllers/spree/api/v2/tenant/show_person_assignments_controller.rb +36 -0
  39. data/app/controllers/spree/api/v2/tenant/shows_controller.rb +36 -0
  40. data/app/controllers/spree/api/v2/tenant/taxons_controller.rb +1 -1
  41. data/app/controllers/spree/api/v2/tenant/transit/draft_orders_controller.rb +3 -1
  42. data/app/controllers/spree/api/v2/tenant/trips_controller.rb +11 -0
  43. data/app/controllers/spree/api/v2/tenant/vote_packages_controller.rb +33 -0
  44. data/app/controllers/spree/api/v2/tenant/votes_controller.rb +94 -0
  45. data/app/controllers/spree/api/v2/tenant/voting_contestants_controller.rb +43 -0
  46. data/app/controllers/spree/api/v2/tenant/voting_credit_transactions_controller.rb +41 -0
  47. data/app/controllers/spree/api/v2/tenant/voting_credits_controller.rb +31 -0
  48. data/app/controllers/spree_cm_commissioner/admin/orders_controller_decorator.rb +7 -3
  49. data/app/controllers/spree_cm_commissioner/admin/products_controller_decorator.rb +19 -0
  50. data/app/finders/spree_cm_commissioner/events/find_matches.rb +1 -0
  51. data/app/helpers/spree_cm_commissioner/admin/guest_helper.rb +10 -0
  52. data/app/helpers/spree_cm_commissioner/admin/homepage_segment_helper.rb +2 -0
  53. data/app/helpers/spree_cm_commissioner/admin/ticket_transfers_helper.rb +32 -0
  54. data/app/interactors/spree_cm_commissioner/pin_code_sender.rb +62 -5
  55. data/app/interactors/spree_cm_commissioner/waiting_guests_caller.rb +86 -10
  56. data/app/jobs/spree_cm_commissioner/expire_ticket_transfer_job.rb +10 -0
  57. data/app/jobs/spree_cm_commissioner/show_contestants/import_job.rb +9 -0
  58. data/app/jobs/spree_cm_commissioner/telegram_gateway/pin_code_sender_job.rb +18 -0
  59. data/app/jobs/spree_cm_commissioner/vendor_route_metrics/decrease_trip_count_job.rb +17 -0
  60. data/app/jobs/spree_cm_commissioner/vendor_route_metrics/increase_trip_count_job.rb +14 -0
  61. data/app/jobs/spree_cm_commissioner/vote_fraud_event_job.rb +9 -0
  62. data/app/jobs/spree_cm_commissioner/voting_credit_allocation_job.rb +10 -0
  63. data/app/jobs/spree_cm_commissioner/voting_credit_de_allocation_job.rb +10 -0
  64. data/app/jobs/spree_cm_commissioner/waiting_room/publish_lobby_path_job.rb +17 -0
  65. data/app/jobs/spree_cm_commissioner/waiting_room/stamp_queue_positions_job.rb +84 -0
  66. data/app/models/concerns/spree_cm_commissioner/homepage_section_bitwise.rb +2 -1
  67. data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +16 -2
  68. data/app/models/concerns/spree_cm_commissioner/line_item_open_dated_trippable.rb +50 -7
  69. data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +0 -1
  70. data/app/models/concerns/spree_cm_commissioner/line_items_filter_scope.rb +5 -0
  71. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +2 -1
  72. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +10 -0
  73. data/app/models/concerns/spree_cm_commissioner/product_type.rb +1 -1
  74. data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +3 -1
  75. data/app/models/concerns/spree_cm_commissioner/ticket_transferable.rb +15 -0
  76. data/app/models/concerns/spree_cm_commissioner/voting_session_live_stream_concern.rb +41 -0
  77. data/app/models/spree_cm_commissioner/guest.rb +20 -0
  78. data/app/models/spree_cm_commissioner/import.rb +1 -1
  79. data/app/models/spree_cm_commissioner/imports/import_contestant.rb +7 -0
  80. data/app/models/spree_cm_commissioner/line_item_decorator.rb +7 -0
  81. data/app/models/spree_cm_commissioner/maintenance_tasks/voting_session.rb +36 -0
  82. data/app/models/spree_cm_commissioner/notification.rb +10 -1
  83. data/app/models/spree_cm_commissioner/order_decorator.rb +13 -3
  84. data/app/models/spree_cm_commissioner/payment_decorator.rb +19 -0
  85. data/app/models/spree_cm_commissioner/payment_method_decorator.rb +8 -0
  86. data/app/models/spree_cm_commissioner/pin_code.rb +62 -9
  87. data/app/models/spree_cm_commissioner/preview_role.rb +8 -0
  88. data/app/models/spree_cm_commissioner/product_decorator.rb +56 -0
  89. data/app/models/spree_cm_commissioner/reserved_block.rb +2 -0
  90. data/app/models/spree_cm_commissioner/role_decorator.rb +4 -1
  91. data/app/models/spree_cm_commissioner/role_user_decorator.rb +8 -0
  92. data/app/models/spree_cm_commissioner/show.rb +169 -0
  93. data/app/models/spree_cm_commissioner/show_contestant.rb +39 -0
  94. data/app/models/spree_cm_commissioner/show_contestant_image.rb +11 -0
  95. data/app/models/spree_cm_commissioner/show_contestant_video.rb +15 -0
  96. data/app/models/spree_cm_commissioner/show_episode.rb +108 -0
  97. data/app/models/spree_cm_commissioner/show_person.rb +15 -0
  98. data/app/models/spree_cm_commissioner/show_person_assignment.rb +21 -0
  99. data/app/models/spree_cm_commissioner/show_person_image.rb +11 -0
  100. data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +4 -0
  101. data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +3 -0
  102. data/app/models/spree_cm_commissioner/taxon_ad_banner.rb +12 -0
  103. data/app/models/spree_cm_commissioner/taxon_decorator.rb +24 -0
  104. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +19 -1
  105. data/app/models/spree_cm_commissioner/tenant.rb +9 -0
  106. data/app/models/spree_cm_commissioner/ticket_transfer.rb +191 -0
  107. data/app/models/spree_cm_commissioner/ticket_transfer_rule.rb +88 -0
  108. data/app/models/spree_cm_commissioner/trip.rb +33 -12
  109. data/app/models/spree_cm_commissioner/user_decorator.rb +18 -0
  110. data/app/models/spree_cm_commissioner/variant_decorator.rb +4 -0
  111. data/app/models/spree_cm_commissioner/variant_options.rb +4 -0
  112. data/app/models/spree_cm_commissioner/vendor_decorator.rb +5 -0
  113. data/app/models/spree_cm_commissioner/vendor_route_metric.rb +25 -0
  114. data/app/models/spree_cm_commissioner/vote.rb +16 -0
  115. data/app/models/spree_cm_commissioner/vote_fraud_event.rb +20 -0
  116. data/app/models/spree_cm_commissioner/voting_contestant.rb +100 -0
  117. data/app/models/spree_cm_commissioner/voting_credit.rb +72 -0
  118. data/app/models/spree_cm_commissioner/voting_credit_transaction.rb +55 -0
  119. data/app/models/spree_cm_commissioner/voting_session.rb +216 -0
  120. data/app/models/spree_cm_commissioner/voting_session_stat.rb +8 -0
  121. data/app/notifications/spree_cm_commissioner/ticket_transfer_accepted_notification.rb +48 -0
  122. data/app/notifications/spree_cm_commissioner/ticket_transfer_completed_notification.rb +48 -0
  123. data/app/notifications/spree_cm_commissioner/ticket_transfer_expired_notification.rb +46 -0
  124. data/app/notifications/spree_cm_commissioner/ticket_transfer_received_notification.rb +48 -0
  125. data/app/notifications/spree_cm_commissioner/ticket_transfer_rejected_notification.rb +48 -0
  126. data/app/overrides/spree/admin/products/_form/allow_gift_transfer.html.erb.deface +9 -0
  127. data/app/overrides/spree/admin/products/_form/allow_transfer.html.erb.deface +9 -0
  128. data/app/overrides/spree/admin/products/_form/preview_checkbox.html.erb.deface +9 -0
  129. data/app/overrides/spree/admin/shared/_order_tabs/ticket_transfers.html.erb.deface +10 -0
  130. data/app/overrides/spree/admin/shared/sub_menu/_product/ticket_transfers_tab.html.erb.deface +3 -0
  131. data/app/overrides/spree/admin/taxons/_form/assets_form.html.erb.deface +10 -1
  132. data/app/overrides/spree/admin/taxons/_form/preview_checkbox.html.erb.deface +7 -0
  133. data/app/queries/spree_cm_commissioner/multi_leg_trips_query.rb +31 -8
  134. data/app/queries/spree_cm_commissioner/recipient_searcher_query.rb +14 -0
  135. data/app/queries/spree_cm_commissioner/single_leg_trips_query.rb +57 -5
  136. data/app/serializers/spree/v2/storefront/homepage_section_serializer.rb +1 -1
  137. data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +4 -2
  138. data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +5 -2
  139. data/app/serializers/spree/v2/storefront/role_serializer.rb +1 -1
  140. data/app/serializers/spree/v2/storefront/taxon_serializer_decorator.rb +4 -1
  141. data/app/serializers/spree/v2/tenant/ad_campaign_serializer.rb +13 -0
  142. data/app/serializers/spree/v2/tenant/advertisement_serializer.rb +11 -0
  143. data/app/serializers/spree/v2/tenant/dynamic_field_serializer.rb +1 -1
  144. data/app/serializers/spree/v2/tenant/free_vote_claim_serializer.rb +9 -0
  145. data/app/serializers/spree/v2/tenant/homepage_section_serializer.rb +1 -1
  146. data/app/serializers/spree/v2/tenant/role_serializer.rb +1 -1
  147. data/app/serializers/spree/v2/tenant/show_contestant_serializer.rb +21 -0
  148. data/app/serializers/spree/v2/tenant/show_episode_serializer.rb +20 -0
  149. data/app/serializers/spree/v2/tenant/show_person_assignment_serializer.rb +16 -0
  150. data/app/serializers/spree/v2/tenant/show_person_serializer.rb +13 -0
  151. data/app/serializers/spree/v2/tenant/show_serializer.rb +21 -0
  152. data/app/serializers/spree/v2/tenant/video_serializer.rb +9 -0
  153. data/app/serializers/spree/v2/tenant/vote_package_serializer.rb +12 -0
  154. data/app/serializers/spree/v2/tenant/vote_serializer.rb +14 -0
  155. data/app/serializers/spree/v2/tenant/voting_contestant_serializer.rb +23 -0
  156. data/app/serializers/spree/v2/tenant/voting_credit_serializer.rb +10 -0
  157. data/app/serializers/spree/v2/tenant/voting_credit_transaction_serializer.rb +14 -0
  158. data/app/serializers/spree/v2/tenant/voting_session_serializer.rb +21 -0
  159. data/app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_serializer.rb +1 -1
  160. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_minimal_serializer.rb +30 -0
  161. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +3 -1
  162. data/app/serializers/spree_cm_commissioner/v2/storefront/line_item_minimal_serializer.rb +57 -0
  163. data/app/serializers/spree_cm_commissioner/v2/storefront/pin_code_serializer.rb +1 -1
  164. data/app/serializers/spree_cm_commissioner/v2/storefront/recipient_serializer.rb +13 -0
  165. data/app/serializers/spree_cm_commissioner/v2/storefront/reserved_block_serializer.rb +1 -1
  166. data/app/serializers/spree_cm_commissioner/v2/storefront/ticket_transfer_minimal_serializer.rb +17 -0
  167. data/app/serializers/spree_cm_commissioner/v2/storefront/ticket_transfer_serializer.rb +20 -0
  168. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_query_result_serializer.rb +4 -1
  169. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_result_serializer.rb +2 -1
  170. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_stop_serializer.rb +1 -0
  171. data/app/services/spree_cm_commissioner/api_caches/invalidate.rb +12 -0
  172. data/app/services/spree_cm_commissioner/cart/add_guest.rb +6 -1
  173. data/app/services/spree_cm_commissioner/cart/create_guest.rb +61 -0
  174. data/app/services/spree_cm_commissioner/cart/remove_guest.rb +6 -1
  175. data/app/services/spree_cm_commissioner/check_ins/create_bulk.rb +11 -5
  176. data/app/services/spree_cm_commissioner/checkout/complete_decorator.rb +22 -0
  177. data/app/services/spree_cm_commissioner/fraud_check.rb +299 -0
  178. data/app/services/spree_cm_commissioner/imports/contestants/create.rb +153 -0
  179. data/app/services/spree_cm_commissioner/inventory_items/reset.rb +1 -1
  180. data/app/services/spree_cm_commissioner/open_dated_trips/redeem.rb +80 -36
  181. data/app/services/spree_cm_commissioner/reserved_blocks/reserve.rb +2 -1
  182. data/app/services/spree_cm_commissioner/show_contestants/normalize_video_highlights.rb +57 -0
  183. data/app/services/spree_cm_commissioner/show_persons/contestant_assigner.rb +51 -0
  184. data/app/services/spree_cm_commissioner/telegram_gateway/pin_code_sender.rb +99 -0
  185. data/app/services/spree_cm_commissioner/ticket_transfers/accept.rb +132 -0
  186. data/app/services/spree_cm_commissioner/ticket_transfers/cancel.rb +54 -0
  187. data/app/services/spree_cm_commissioner/ticket_transfers/complete.rb +68 -0
  188. data/app/services/spree_cm_commissioner/ticket_transfers/eligibility_checker.rb +99 -0
  189. data/app/services/spree_cm_commissioner/ticket_transfers/expire.rb +47 -0
  190. data/app/services/spree_cm_commissioner/ticket_transfers/fee_calculator.rb +57 -0
  191. data/app/services/spree_cm_commissioner/ticket_transfers/initiate.rb +98 -0
  192. data/app/services/spree_cm_commissioner/ticket_transfers/preview_rule.rb +38 -0
  193. data/app/services/spree_cm_commissioner/ticket_transfers/reject.rb +55 -0
  194. data/app/services/spree_cm_commissioner/ticket_transfers/transfer_guest.rb +29 -0
  195. data/app/services/spree_cm_commissioner/transit_order/create.rb +48 -14
  196. data/app/services/spree_cm_commissioner/trips/add_ons/create.rb +124 -0
  197. data/app/services/spree_cm_commissioner/trips/add_ons/update_price.rb +36 -0
  198. data/app/services/spree_cm_commissioner/trips/create_multi_leg.rb +1 -2
  199. data/app/services/spree_cm_commissioner/trips/variants/create.rb +1 -2
  200. data/app/services/spree_cm_commissioner/url_embed/youtube_embed.rb +44 -0
  201. data/app/services/spree_cm_commissioner/vendor_route_metrics/decrease_trip_count.rb +19 -0
  202. data/app/services/spree_cm_commissioner/vendor_route_metrics/increase_trip_count.rb +24 -0
  203. data/app/services/spree_cm_commissioner/vote_counters/audit_counters.rb +43 -0
  204. data/app/services/spree_cm_commissioner/vote_counters/base.rb +31 -0
  205. data/app/services/spree_cm_commissioner/vote_counters/increment.rb +44 -0
  206. data/app/services/spree_cm_commissioner/vote_counters/per_contestant_counter.rb +68 -0
  207. data/app/services/spree_cm_commissioner/vote_counters/rebuild_from_db.rb +70 -0
  208. data/app/services/spree_cm_commissioner/vote_counters/snapshot_to_db.rb +113 -0
  209. data/app/services/spree_cm_commissioner/vote_credit_deductor.rb +68 -0
  210. data/app/services/spree_cm_commissioner/vote_package/create.rb +145 -0
  211. data/app/services/spree_cm_commissioner/vote_package/update.rb +91 -0
  212. data/app/services/spree_cm_commissioner/vote_processor.rb +144 -0
  213. data/app/services/spree_cm_commissioner/voting_contestants/advancer.rb +335 -0
  214. data/app/services/spree_cm_commissioner/voting_contestants/assigner.rb +40 -0
  215. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +106 -0
  216. data/app/services/spree_cm_commissioner/voting_credits/allocate.rb +77 -0
  217. data/app/services/spree_cm_commissioner/voting_credits/claim_free_votes.rb +116 -0
  218. data/app/services/spree_cm_commissioner/voting_credits/credit_calculator.rb +35 -0
  219. data/app/services/spree_cm_commissioner/voting_credits/de_allocate.rb +87 -0
  220. data/app/services/spree_cm_commissioner/voting_leaderboards/calculate_score.rb +67 -0
  221. data/app/services/spree_cm_commissioner/voting_leaderboards/combined_result.rb +190 -0
  222. data/app/services/spree_cm_commissioner/voting_sessions/finalize.rb +105 -0
  223. data/app/services/spree_cm_commissioner/waiting_room/publish_lobby_path.rb +48 -0
  224. data/app/services/spree_cm_commissioner/waiting_room_lobby_metadata_fetcher.rb +47 -0
  225. data/app/services/telegram_gateway_adapter/client.rb +124 -0
  226. data/app/views/spree/admin/guests/_table.html.erb +82 -87
  227. data/app/views/spree/admin/homepage_section/_form.html.erb +5 -0
  228. data/app/views/spree/admin/order_ticket_transfers/show.html.erb +7 -0
  229. data/app/views/spree/admin/shared/_ticket_transfer_details.html.erb +226 -0
  230. data/app/views/spree/admin/shared/_ticket_transfer_tabs.html.erb +14 -0
  231. data/app/views/spree/admin/system/waiting_room/show.html.erb +53 -0
  232. data/app/views/spree/admin/ticket_transfer_rules/_form.html.erb +193 -0
  233. data/app/views/spree/admin/ticket_transfer_rules/edit.html.erb +11 -0
  234. data/app/views/spree/admin/ticket_transfer_rules/index.html.erb +79 -0
  235. data/app/views/spree/admin/ticket_transfer_rules/new.html.erb +11 -0
  236. data/app/views/spree/admin/ticket_transfers/_search_form.html.erb +70 -0
  237. data/app/views/spree/admin/ticket_transfers/_tabs.html.erb +14 -0
  238. data/app/views/spree/admin/ticket_transfers/index.html.erb +74 -0
  239. data/app/views/spree/admin/ticket_transfers/show.html.erb +13 -0
  240. data/app/views/spree/admin/ticket_transfers/state_changes.html.erb +47 -0
  241. data/config/initializers/spree_permitted_attributes.rb +8 -0
  242. data/config/locales/en.yml +111 -7
  243. data/config/locales/km.yml +105 -4
  244. data/config/routes.rb +51 -0
  245. data/db/migrate/20260303101440_add_allow_transfer_to_spree_products.rb +5 -0
  246. data/db/migrate/20260303101907_create_cm_ticket_transfers.rb +32 -0
  247. data/db/migrate/20260303102316_add_state_to_cm_guests.rb +7 -0
  248. data/db/migrate/20260309230148_create_cm_show_people.rb +14 -0
  249. data/db/migrate/20260309230149_create_cm_show_people_assignments.rb +16 -0
  250. data/db/migrate/20260310082711_create_cm_show_contestants.rb +28 -0
  251. data/db/migrate/20260310082720_create_cm_voting_sessions.rb +21 -0
  252. data/db/migrate/20260310082721_create_cm_voting_contestants.rb +23 -0
  253. data/db/migrate/20260310082734_add_voting_fields_to_spree_taxons.rb +9 -0
  254. data/db/migrate/20260310082735_add_type_to_spree_products.rb +6 -0
  255. data/db/migrate/20260310082749_create_cm_voting_credits.rb +27 -0
  256. data/db/migrate/20260326080200_create_cm_voting_credit_transactions.rb +27 -0
  257. data/db/migrate/20260330160000_create_cm_votes.rb +25 -0
  258. data/db/migrate/20260401072500_add_advanced_from_to_cm_voting_contestants.rb +7 -0
  259. data/db/migrate/20260402000001_add_voting_credit_scope_to_spree_taxons.rb +6 -0
  260. data/db/migrate/20260402000002_rename_scopeable_to_votable_in_cm_voting_credits.rb +12 -0
  261. data/db/migrate/20260403070000_add_name_to_cm_voting_sessions.rb +5 -0
  262. data/db/migrate/20260406000001_add_vendor_id_to_voting_tables.rb +6 -0
  263. data/db/migrate/20260406000001_rename_votes_remaining_to_amount_in_cm_voting_credits.rb +11 -0
  264. data/db/migrate/20260408085255_add_show_id_and_vendor_id_to_cm_voting_sessions.rb +9 -0
  265. data/db/migrate/20260408100000_create_cm_ticket_transfer_rules.rb +28 -0
  266. data/db/migrate/20260410120000_add_transfer_type_to_cm_ticket_transfers.rb +5 -0
  267. data/db/migrate/20260420000001_rename_type_to_credit_type_in_cm_voting_credits.rb +25 -0
  268. data/db/migrate/20260422000001_create_cm_vote_fraud_events.rb +23 -0
  269. data/db/migrate/20260422120000_add_settlement_status_to_cm_ticket_transfers.rb +6 -0
  270. data/db/migrate/20260423000001_add_preview_to_taxons_products_and_sections.rb +11 -0
  271. data/db/migrate/20260423000002_create_preview_roles.rb +24 -0
  272. data/db/migrate/20260507000000_add_index_to_cm_ticket_transfers_completed_at.rb +5 -0
  273. data/db/migrate/20260515120000_add_public_metadata_to_cm_voting_sessions.rb +5 -0
  274. data/db/migrate/20260518090920_add_unique_voter_count_to_voting_contestants.rb +5 -0
  275. data/db/migrate/20260518094322_create_cm_voting_session_stats.rb +17 -0
  276. data/db/migrate/20260520000000_add_number_to_cm_ticket_transfers.rb +6 -0
  277. data/db/migrate/20260520000001_add_scoring_model_to_cm_voting_sessions.rb +5 -0
  278. data/db/migrate/20260520000001_optimize_cm_votes_indexes.rb +22 -0
  279. data/db/migrate/20260525042257_add_vote_number_to_cm_voting_contestants.rb +18 -0
  280. data/db/migrate/20260527035430_add_confirmed_rank_to_cm_voting_contestants.rb +5 -0
  281. data/db/migrate/20260527062005_add_eliminated_at_to_cm_show_contestants.rb +5 -0
  282. data/db/migrate/20260603063652_add_parent_to_voting_sessions.rb +9 -0
  283. data/db/migrate/20260603090000_add_session_type_to_cm_voting_sessions.rb +6 -0
  284. data/db/migrate/20260605120908_add_description_to_cm_dynamic_fields.rb +5 -0
  285. data/db/migrate/20260608000000_add_allow_gift_transfer_to_spree_products.rb +5 -0
  286. data/db/migrate/20260608000000_add_display_to_cm_voting_sessions.rb +5 -0
  287. data/db/migrate/20260608000000_create_cm_vendor_route_metrics.rb +25 -0
  288. data/db/migrate/20260608152251_add_gender_to_cm_reserved_blocks.rb +5 -0
  289. data/db/migrate/20260610000001_add_delivery_channel_to_cm_pin_codes.rb +6 -0
  290. data/db/migrate/20260610000001_drop_is_open_dated_from_cm_trips.rb +6 -0
  291. data/db/migrate/20260614000001_change_code_limit_in_cm_pin_codes.rb +5 -0
  292. data/db/migrate/20260615000002_add_index_to_code_on_cm_pin_codes.rb +5 -0
  293. data/docs/sql/jsonb_query_guide.md +57 -0
  294. data/lib/spree_cm_commissioner/test_helper/factories/show_episode_factory.rb +12 -0
  295. data/lib/spree_cm_commissioner/test_helper/factories/show_factory.rb +120 -0
  296. data/lib/spree_cm_commissioner/test_helper/factories/ticket_transfer_factory.rb +18 -0
  297. data/lib/spree_cm_commissioner/test_helper/factories/vendor_route_metric_factory.rb +10 -0
  298. data/lib/spree_cm_commissioner/test_helper/factories/vote_credit_factory.rb +37 -0
  299. data/lib/spree_cm_commissioner/test_helper/factories/vote_factory.rb +28 -0
  300. data/lib/spree_cm_commissioner/test_helper/factories/voting_credit_transaction_factory.rb +11 -0
  301. data/lib/spree_cm_commissioner/test_helper/factories/voting_session_factory.rb +11 -0
  302. data/lib/spree_cm_commissioner/transit/trip_form.rb +0 -13
  303. data/lib/spree_cm_commissioner/trip_query_result.rb +46 -6
  304. data/lib/spree_cm_commissioner/trip_result.rb +9 -7
  305. data/lib/spree_cm_commissioner/version.rb +1 -1
  306. data/lib/spree_cm_commissioner.rb +7 -1
  307. data/lib/tasks/backfill_route_metrics.rake +21 -0
  308. data/lib/tasks/backfill_vendor_route_metrics.rake +23 -0
  309. data/spree_cm_commissioner.gemspec +1 -1
  310. metadata +217 -6
  311. data/app/services/spree_cm_commissioner/trips/create_open_dated_trip.rb +0 -98
  312. data/app/services/spree_cm_commissioner/trips/update_open_dated_trip.rb +0 -67
@@ -0,0 +1,25 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class AdCampaignsController < BaseController
6
+ private
7
+
8
+ def scope
9
+ Spree::Taxon.ad_campaigns
10
+ .joins(:vendor)
11
+ .includes(:advertisements)
12
+ .where(spree_vendors: { tenant_id: @tenant.id })
13
+ .where('spree_taxons.from_date <= ? OR spree_taxons.from_date IS NULL', Time.current)
14
+ .where('spree_taxons.to_date >= ? OR spree_taxons.to_date IS NULL', Time.current)
15
+ .order(created_at: :asc)
16
+ end
17
+
18
+ def collection_serializer
19
+ Spree::V2::Tenant::AdCampaignSerializer
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -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,38 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class EpisodesController < BaseController
6
+ private
7
+
8
+ def model_class
9
+ SpreeCmCommissioner::ShowEpisode
10
+ end
11
+
12
+ def resource
13
+ @resource ||= scope.find(params[:id])
14
+ end
15
+
16
+ def scope
17
+ current_season.episodes.where(product_type: :show_episode).includes(:voting_sessions, :vote_packages)
18
+ end
19
+
20
+ def current_season
21
+ @current_season ||= SpreeCmCommissioner::Show
22
+ .where(vendor_id: @tenant.vendors.select(:id))
23
+ .where.not(parent_id: nil)
24
+ .find_by!(slug: params[:show_id])
25
+ end
26
+
27
+ def resource_serializer
28
+ Spree::V2::Tenant::ShowEpisodeSerializer
29
+ end
30
+
31
+ def collection_serializer
32
+ Spree::V2::Tenant::ShowEpisodeSerializer
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,58 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class FreeVoteClaimController < BaseController
6
+ before_action :require_spree_current_user
7
+
8
+ def show
9
+ load_effective_config_onto_show
10
+
11
+ render_serialized_payload { serialize_resource(current_show) }
12
+ end
13
+
14
+ def create
15
+ result = SpreeCmCommissioner::VotingCredits::ClaimFreeVotes.new(
16
+ show: current_show,
17
+ user: spree_current_user,
18
+ tenant_id: MultiTenant.current_tenant_id,
19
+ votable_id: voting_session.id
20
+ ).call
21
+
22
+ if result.failure?
23
+ render_error_payload(result.error.to_s)
24
+ elsif result.value.nil?
25
+ head :no_content
26
+ else
27
+ render_serialized_payload { Spree::V2::Tenant::VotingCreditSerializer.new(result.value).serializable_hash }
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def resource_serializer
34
+ Spree::V2::Tenant::FreeVoteClaimSerializer
35
+ end
36
+
37
+ def load_effective_config_onto_show
38
+ config = voting_session.effective_voting_config(show_config: current_show.effective_voting_config)
39
+
40
+ current_show.claimed = !spree_current_user.free_vote_claimable?(show: current_show, votable_id: voting_session.id)
41
+ current_show.effective_free_vote_limit = config['free_vote_limit']
42
+ current_show.effective_free_vote_limit_type = config['free_vote_limit_type']
43
+ rescue ArgumentError
44
+ current_show.claimed = false
45
+ end
46
+
47
+ def voting_session
48
+ @voting_session ||= current_vendor.voting_sessions.find(params[:voting_session_id])
49
+ end
50
+
51
+ def current_show
52
+ @current_show ||= voting_session.show
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ 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
@@ -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,52 @@
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
+ :show_contestant_videos,
22
+ :current_voting_session,
23
+ :voting_contestants,
24
+ assigned_show_person: :show_person_images,
25
+ show: [
26
+ :parent,
27
+ { episodes: :voting_sessions },
28
+ { seasons: { episodes: :voting_sessions } }
29
+ ]
30
+ )
31
+ end
32
+
33
+ def current_show
34
+ @current_show ||= show_scope.find_by!(slug: params[:show_id])
35
+ end
36
+
37
+ def show_scope
38
+ vendor_ids = @tenant.vendors.select(:id)
39
+ return SpreeCmCommissioner::Show.none if vendor_ids.blank?
40
+
41
+ SpreeCmCommissioner::Show.where(vendor_id: vendor_ids)
42
+ end
43
+
44
+ # override
45
+ def resource_serializer
46
+ Spree::V2::Tenant::ShowContestantSerializer
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,57 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class ShowEliminationSessionsController < BaseController
6
+ # override
7
+ def collection
8
+ @collection ||= scope
9
+ .includes(
10
+ :episode,
11
+ :show,
12
+ eliminated_voting_contestants: [
13
+ :show_contestant,
14
+ { show_contestant: %i[show_contestant_images show_contestant_videos] }
15
+ ]
16
+ )
17
+ .order('cm_voting_sessions.closes_at DESC')
18
+ end
19
+
20
+ # override
21
+ def collection_serializer
22
+ Spree::V2::Tenant::VotingSessionSerializer
23
+ end
24
+
25
+ private
26
+
27
+ # override
28
+ def model_class
29
+ SpreeCmCommissioner::VotingSession
30
+ end
31
+
32
+ # override
33
+ def scope
34
+ return model_class.none unless current_show
35
+
36
+ current_show.voting_sessions
37
+ .joins(:episode)
38
+ .joins(:voting_contestants)
39
+ .where(voting_contestants: { eliminated: true })
40
+ .distinct
41
+ end
42
+
43
+ def current_show
44
+ @current_show ||= show_scope.find_by!(slug: params[:show_id])
45
+ end
46
+
47
+ def show_scope
48
+ vendor_ids = @tenant.vendors.select(:id)
49
+ return SpreeCmCommissioner::Show.none if vendor_ids.blank?
50
+
51
+ SpreeCmCommissioner::Show.where(vendor_id: vendor_ids)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ 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
@@ -0,0 +1,36 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class ShowsController < BaseController
6
+ private
7
+
8
+ # override
9
+ def model_class
10
+ SpreeCmCommissioner::Show
11
+ end
12
+
13
+ def resource
14
+ @resource ||= scope.find_by!(slug: params[:id])
15
+ end
16
+
17
+ # override
18
+ def scope
19
+ vendor_ids = @tenant.vendors.select(:id)
20
+ return model_class.none if vendor_ids.blank?
21
+
22
+ model_class.where(vendor_id: vendor_ids, preview: false)
23
+ .includes(:parent, :app_banner, show_people: :show_person_images,
24
+ episodes: :voting_sessions, seasons: { episodes: :voting_sessions }
25
+ )
26
+ end
27
+
28
+ # override
29
+ def resource_serializer
30
+ Spree::V2::Tenant::ShowSerializer
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -31,7 +31,7 @@ module Spree
31
31
 
32
32
  def scope
33
33
  MultiTenant.with(@tenant) do
34
- model_class
34
+ model_class.where(preview: false)
35
35
  end
36
36
  end
37
37
 
@@ -11,6 +11,7 @@ module Spree
11
11
  # - inbound_date: Date of inbound transit (optional)
12
12
  # - outbound_legs: Array of outbound leg details (required)
13
13
  # - inbound_legs: Array of inbound leg details (optional)
14
+ # - include_return: Whether to add the trip's "return included" add-on as a line item (optional)
14
15
  def create
15
16
  @outbound_legs = params[:outbound_legs].is_a?(Array) && params[:outbound_legs].any? ? build_legs(:outbound, params[:outbound_legs]) : []
16
17
  @inbound_legs = params[:inbound_legs].is_a?(Array) && params[:inbound_legs].any? ? build_legs(:inbound, params[:inbound_legs]) : []
@@ -20,7 +21,8 @@ module Spree
20
21
  inbound_date: params[:inbound_date]&.to_date,
21
22
  outbound_legs: @outbound_legs,
22
23
  inbound_legs: @inbound_legs,
23
- user: spree_current_user
24
+ user: spree_current_user,
25
+ include_return: ActiveModel::Type::Boolean.new.cast(params[:include_return])
24
26
  )
25
27
 
26
28
  if result.success?
@@ -25,6 +25,17 @@ module Spree
25
25
  def resource_serializer
26
26
  Spree::V2::Tenant::TripSerializer
27
27
  end
28
+
29
+ # override
30
+ def serializer_params
31
+ super.merge(
32
+ include_details: include_details?
33
+ )
34
+ end
35
+
36
+ def include_details?
37
+ params.fetch(:include_details, 'true') == 'true'
38
+ end
28
39
  end
29
40
  end
30
41
  end
@@ -0,0 +1,33 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class VotePackagesController < BaseController
6
+ def index
7
+ render_serialized_payload { serialize_collection(scope) }
8
+ end
9
+
10
+ private
11
+
12
+ def scope
13
+ current_vendor.vote_packages.where(status: :active, event_id: current_season.id)
14
+ end
15
+
16
+ def current_season
17
+ @current_season ||= current_vendor.shows
18
+ .where.not(parent_id: nil)
19
+ .find_by!(slug: params[:show_id])
20
+ end
21
+
22
+ def serialize_collection(collection)
23
+ collection_serializer.new(collection, include: resource_includes).serializable_hash
24
+ end
25
+
26
+ def collection_serializer
27
+ Spree::V2::Tenant::VotePackageSerializer
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,94 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class VotesController < BaseController
6
+ before_action :require_spree_current_user
7
+
8
+ def index
9
+ render_serialized_payload do
10
+ serialize_collection(collection)
11
+ end
12
+ end
13
+
14
+ def create
15
+ voting_session = current_vendor.voting_sessions.find(params[:voting_session_id])
16
+ contestant = voting_session.voting_contestants.find(params[:contestant_id])
17
+
18
+ processor_params = vote_params.merge(
19
+ device_fingerprint: device_params[:fingerprint],
20
+ voter_identifier: device_params[:identifier],
21
+ public_metadata: params[:public_metadata] || {},
22
+ tenant_id: MultiTenant.current_tenant_id,
23
+ vendor_id: current_vendor.id
24
+ )
25
+
26
+ result = SpreeCmCommissioner::VoteProcessor.call(
27
+ voting_session: voting_session,
28
+ contestant: contestant,
29
+ user: spree_current_user,
30
+ params: processor_params,
31
+ request: request
32
+ )
33
+
34
+ if result.success?
35
+ render_serialized_payload(201) { serialize_resource(result.value) }
36
+ else
37
+ render_error_payload(result.error)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def collection
44
+ @collection ||= scope.page(params[:page])
45
+ .per(params[:per_page])
46
+ end
47
+
48
+ def scope
49
+ MultiTenant.with(@tenant) do
50
+ scope = spree_current_user.votes
51
+ .includes(:contestant, :voting_session, :vote_credit)
52
+ .order(created_at: :desc)
53
+
54
+ scope = scope.for_session(params[:voting_session_id]) if params[:voting_session_id]
55
+ scope
56
+ end
57
+ end
58
+
59
+ def model_class
60
+ SpreeCmCommissioner::Vote
61
+ end
62
+
63
+ def resource_serializer
64
+ Spree::V2::Tenant::VoteSerializer
65
+ end
66
+
67
+ def collection_serializer
68
+ Spree::V2::Tenant::VoteSerializer
69
+ end
70
+
71
+ # {
72
+ # "contestant_id": 1,
73
+ # "vote": {
74
+ # "quantity": 1,
75
+ # "channel": "mobile"
76
+ # },
77
+ # "device": {
78
+ # "fingerprint": "fp-xyz",
79
+ # "identifier": "device-abc",
80
+ # "platform": "android"
81
+ # }
82
+ # }
83
+ def vote_params
84
+ params.require(:vote).permit(:quantity, :channel)
85
+ end
86
+
87
+ def device_params
88
+ params.require(:device).permit(:fingerprint, :identifier, :platform)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end