spree_cm_commissioner 2.8.1.pre.3 → 2.8.1.pre.pre.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +1 -0
  3. data/Gemfile.lock +1 -1
  4. data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +0 -1
  5. data/app/controllers/spree/api/v2/tenant/eliminated_contestants_controller.rb +19 -0
  6. data/app/controllers/spree/api/v2/tenant/show_contestants_controller.rb +1 -0
  7. data/app/factory/spree_cm_commissioner/event_telegram_message_factory.rb +68 -0
  8. data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +2 -2
  9. data/app/jobs/spree_cm_commissioner/event_creation_telegram_alert_sender_job.rb +10 -0
  10. data/app/jobs/spree_cm_commissioner/oauth_access_tokens/cleanup_expired_job.rb +11 -0
  11. data/app/models/concerns/spree_cm_commissioner/store_preference.rb +1 -0
  12. data/app/models/concerns/spree_cm_commissioner/vehicle_kind.rb +1 -1
  13. data/app/models/spree_cm_commissioner/integration.rb +0 -31
  14. data/app/models/spree_cm_commissioner/integrations/stadium_x_v1.rb +10 -4
  15. data/app/models/spree_cm_commissioner/inventory_item.rb +17 -8
  16. data/app/models/spree_cm_commissioner/maintenance_tasks/cache_invalidation.rb +2 -0
  17. data/app/models/spree_cm_commissioner/maintenance_tasks/voting_session.rb +2 -0
  18. data/app/models/spree_cm_commissioner/order_decorator.rb +0 -1
  19. data/app/models/spree_cm_commissioner/place.rb +0 -2
  20. data/app/models/spree_cm_commissioner/route.rb +0 -1
  21. data/app/models/spree_cm_commissioner/seat_layout.rb +0 -2
  22. data/app/models/spree_cm_commissioner/show.rb +3 -1
  23. data/app/models/spree_cm_commissioner/show_contestant.rb +12 -0
  24. data/app/models/spree_cm_commissioner/stock_item_decorator.rb +0 -7
  25. data/app/models/spree_cm_commissioner/taxon_decorator.rb +7 -0
  26. data/app/models/spree_cm_commissioner/trip.rb +1 -2
  27. data/app/models/spree_cm_commissioner/trip_stop.rb +0 -2
  28. data/app/models/spree_cm_commissioner/variant_decorator.rb +0 -1
  29. data/app/models/spree_cm_commissioner/vehicle.rb +0 -3
  30. data/app/models/spree_cm_commissioner/vehicle_type.rb +0 -1
  31. data/app/models/spree_cm_commissioner/vendor_decorator.rb +0 -17
  32. data/app/models/spree_cm_commissioner/vendor_place.rb +0 -2
  33. data/app/models/spree_cm_commissioner/voting_contestant.rb +12 -0
  34. data/app/models/spree_cm_commissioner/voting_session.rb +34 -8
  35. data/app/models/spree_cm_commissioner/voting_session_stat.rb +8 -0
  36. data/app/overrides/spree/admin/stores/_form/store_preferences.html.erb.deface +9 -0
  37. data/app/queries/spree_cm_commissioner/multi_leg_trips_query.rb +26 -44
  38. data/app/queries/spree_cm_commissioner/single_leg_trips_query.rb +36 -31
  39. data/app/queries/spree_cm_commissioner/trip_query.rb +2 -4
  40. data/app/serializers/spree/v2/tenant/show_contestant_serializer.rb +1 -1
  41. data/app/serializers/spree/v2/tenant/voting_contestant_serializer.rb +1 -1
  42. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_result_serializer.rb +7 -2
  43. data/app/services/spree_cm_commissioner/integrations/base/sync_manager.rb +2 -1
  44. data/app/services/spree_cm_commissioner/integrations/base/sync_result.rb +0 -11
  45. data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/external_client/client.rb +15 -14
  46. data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_matches.rb +4 -7
  47. data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_zones.rb +3 -6
  48. data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_manager.rb +3 -0
  49. data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/full_sync_strategy.rb +3 -1
  50. data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/incremental_sync_strategy.rb +3 -1
  51. data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/webhook_sync_strategy.rb +2 -1
  52. data/app/services/spree_cm_commissioner/oauth_access_tokens/cleanup_expired.rb +53 -0
  53. data/app/services/spree_cm_commissioner/order_holds/hold.rb +0 -17
  54. data/app/services/spree_cm_commissioner/order_holds/release.rb +0 -17
  55. data/app/services/spree_cm_commissioner/show_contestants/normalize_video_highlights.rb +2 -1
  56. data/app/services/spree_cm_commissioner/telegram_alerts/event_creation.rb +35 -0
  57. data/app/services/spree_cm_commissioner/url_embed/youtube_embed.rb +30 -35
  58. data/app/services/spree_cm_commissioner/vote_counters/snapshot_to_db.rb +113 -0
  59. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +1 -0
  60. data/app/services/spree_cm_commissioner/voting_leaderboards/calculate_score.rb +74 -0
  61. data/app/views/spree/admin/integrations/_form.html.erb +0 -12
  62. data/app/views/spree/admin/integrations/index.html.erb +1 -1
  63. data/config/initializers/spree_permitted_attributes.rb +1 -0
  64. data/config/locales/en.yml +0 -1
  65. data/config/locales/km.yml +0 -1
  66. data/config/routes.rb +1 -1
  67. data/db/migrate/20260518090920_add_unique_voter_count_to_voting_contestants.rb +5 -0
  68. data/db/migrate/20260518094322_create_cm_voting_session_stats.rb +17 -0
  69. data/db/migrate/20260520000001_add_scoring_model_to_cm_voting_sessions.rb +5 -0
  70. data/db/migrate/20260525042257_add_vote_number_to_cm_voting_contestants.rb +18 -0
  71. data/db/migrate/20260527062005_add_eliminated_at_to_cm_show_contestants.rb +5 -0
  72. data/lib/spree_cm_commissioner/test_helper/factories/integration_factory.rb +0 -11
  73. data/lib/spree_cm_commissioner/test_helper/factories/show_factory.rb +8 -0
  74. data/lib/spree_cm_commissioner/trip_result.rb +48 -21
  75. data/lib/spree_cm_commissioner/version.rb +1 -1
  76. data/spree_cm_commissioner.gemspec +1 -1
  77. metadata +17 -118
  78. data/app/controllers/spree/api/v2/storefront/transit/item_availabilities_controller.rb +0 -66
  79. data/app/jobs/spree_cm_commissioner/audit_event_job.rb +0 -29
  80. data/app/jobs/spree_cm_commissioner/cleanup_expired_access_tokens_job.rb +0 -9
  81. data/app/models/concerns/spree_cm_commissioner/audit_wrapper.rb +0 -139
  82. data/app/models/concerns/spree_cm_commissioner/integrations/inventory_sync_cachable.rb +0 -9
  83. data/app/models/concerns/spree_cm_commissioner/variant_metadata.rb +0 -24
  84. data/app/models/spree_cm_commissioner/audit_event.rb +0 -11
  85. data/app/models/spree_cm_commissioner/currency_rate.rb +0 -15
  86. data/app/models/spree_cm_commissioner/integrations/book_me_bus_v1.rb +0 -56
  87. data/app/models/spree_cm_commissioner/integrations/larryta.rb +0 -81
  88. data/app/models/spree_cm_commissioner/integrations/vireak_buntham.rb +0 -82
  89. data/app/serializables/spree_cm_commissioner/item_availability_sync.rb +0 -10
  90. data/app/serializers/spree_cm_commissioner/v2/storefront/item_availability_sync_serializer.rb +0 -10
  91. data/app/services/spree_cm_commissioner/audit_logger.rb +0 -59
  92. data/app/services/spree_cm_commissioner/cleanup_expired_access_tokens.rb +0 -52
  93. data/app/services/spree_cm_commissioner/currency_converter/create.rb +0 -27
  94. data/app/services/spree_cm_commissioner/currency_rates/manage.rb +0 -99
  95. data/app/services/spree_cm_commissioner/google_maps_geocoder.rb +0 -41
  96. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/external_client/client.rb +0 -261
  97. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/external_client/connection.rb +0 -147
  98. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/inventory/external_inventory_item_status.rb +0 -52
  99. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/inventory/external_inventory_items.rb +0 -91
  100. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/inventory/unstock_inventory.rb +0 -140
  101. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_inventory.rb +0 -52
  102. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_item_availability.rb +0 -249
  103. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_locations.rb +0 -103
  104. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_product.rb +0 -66
  105. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_route_stops.rb +0 -113
  106. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_routes.rb +0 -128
  107. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_seat_layout.rb +0 -342
  108. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_service_calendars.rb +0 -59
  109. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_trip_stop.rb +0 -179
  110. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_trips.rb +0 -597
  111. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_variant.rb +0 -58
  112. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/sync_vehicle_types.rb +0 -87
  113. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/polling/time_parser.rb +0 -19
  114. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/base.rb +0 -40
  115. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/branch.rb +0 -65
  116. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/direction.rb +0 -51
  117. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/inventory_item_status.rb +0 -148
  118. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/location.rb +0 -55
  119. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/operator.rb +0 -17
  120. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/reservation_cart.rb +0 -85
  121. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat.rb +0 -128
  122. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb +0 -363
  123. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/stop.rb +0 -84
  124. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/trip.rb +0 -199
  125. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/wallet_payment.rb +0 -40
  126. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/sync_manager.rb +0 -22
  127. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/sync_strategies/full_sync_strategy.rb +0 -117
  128. data/app/services/spree_cm_commissioner/integrations/book_me_bus_v1/sync_strategies/incremental_sync_strategy.rb +0 -64
  129. data/app/services/spree_cm_commissioner/integrations/larryta/external_client/client.rb +0 -344
  130. data/app/services/spree_cm_commissioner/integrations/larryta/external_client/connection.rb +0 -74
  131. data/app/services/spree_cm_commissioner/integrations/larryta/inventory/external_inventory_item_status.rb +0 -53
  132. data/app/services/spree_cm_commissioner/integrations/larryta/inventory/external_inventory_items.rb +0 -106
  133. data/app/services/spree_cm_commissioner/integrations/larryta/inventory/hold_seats.rb +0 -143
  134. data/app/services/spree_cm_commissioner/integrations/larryta/inventory/release_seats.rb +0 -90
  135. data/app/services/spree_cm_commissioner/integrations/larryta/inventory/unstock_inventory.rb +0 -113
  136. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_item_availability.rb +0 -261
  137. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_product.rb +0 -72
  138. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_routes.rb +0 -142
  139. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_seat_layout.rb +0 -255
  140. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_stock_item.rb +0 -55
  141. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_trip_stop.rb +0 -167
  142. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_trips.rb +0 -320
  143. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_variant.rb +0 -63
  144. data/app/services/spree_cm_commissioner/integrations/larryta/polling/sync_vehicle_type.rb +0 -79
  145. data/app/services/spree_cm_commissioner/integrations/larryta/resources/base.rb +0 -39
  146. data/app/services/spree_cm_commissioner/integrations/larryta/resources/booking.rb +0 -113
  147. data/app/services/spree_cm_commissioner/integrations/larryta/resources/booking_session.rb +0 -43
  148. data/app/services/spree_cm_commissioner/integrations/larryta/resources/booking_transaction.rb +0 -236
  149. data/app/services/spree_cm_commissioner/integrations/larryta/resources/direction.rb +0 -71
  150. data/app/services/spree_cm_commissioner/integrations/larryta/resources/passenger.rb +0 -48
  151. data/app/services/spree_cm_commissioner/integrations/larryta/resources/schedule.rb +0 -150
  152. data/app/services/spree_cm_commissioner/integrations/larryta/resources/seat.rb +0 -31
  153. data/app/services/spree_cm_commissioner/integrations/larryta/resources/seat_availability.rb +0 -49
  154. data/app/services/spree_cm_commissioner/integrations/larryta/resources/seat_layout.rb +0 -211
  155. data/app/services/spree_cm_commissioner/integrations/larryta/sync_manager.rb +0 -17
  156. data/app/services/spree_cm_commissioner/integrations/larryta/sync_strategies/full_sync_strategy.rb +0 -79
  157. data/app/services/spree_cm_commissioner/integrations/larryta/sync_strategies/incremental_sync_strategy.rb +0 -58
  158. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/external_client/client.rb +0 -206
  159. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/external_client/connection.rb +0 -59
  160. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/inventory/external_inventory_item_status.rb +0 -48
  161. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/inventory/external_inventory_items.rb +0 -97
  162. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/inventory/unstock_inventory.rb +0 -208
  163. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_item_availability.rb +0 -270
  164. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_locations.rb +0 -96
  165. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_nationality_pricing.rb +0 -76
  166. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_product.rb +0 -69
  167. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_routes.rb +0 -110
  168. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_seat_layout.rb +0 -207
  169. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_stock_item.rb +0 -43
  170. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_trip_stop.rb +0 -185
  171. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_trips.rb +0 -300
  172. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_variant.rb +0 -56
  173. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/polling/sync_vehicle_type.rb +0 -51
  174. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/base.rb +0 -32
  175. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/booking.rb +0 -48
  176. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/booking_transaction.rb +0 -46
  177. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/cell.rb +0 -53
  178. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/confirm_booking_request.rb +0 -43
  179. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/location.rb +0 -37
  180. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/schedule.rb +0 -138
  181. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/seat.rb +0 -48
  182. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/resources/seat_layout.rb +0 -79
  183. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/sync_manager.rb +0 -17
  184. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/sync_strategies/full_sync_strategy.rb +0 -87
  185. data/app/services/spree_cm_commissioner/integrations/vireak_buntham/sync_strategies/incremental_sync_strategy.rb +0 -53
  186. data/app/services/spree_cm_commissioner/inventory_items/generate_permanent_item.rb +0 -48
  187. data/app/services/spree_cm_commissioner/place_resolver.rb +0 -95
  188. data/app/views/spree/admin/integrations/_book_me_bus_v1_fields.html.erb +0 -47
  189. data/app/views/spree/admin/integrations/_larryta_fields.html.erb +0 -58
  190. data/app/views/spree/admin/integrations/_vireak_buntham_fields.html.erb +0 -75
  191. data/db/migrate/20260327143200_create_cm_audit_events.rb +0 -21
  192. data/db/migrate/20260410045815_create_cm_currency_rates.rb +0 -23
  193. data/db/migrate/20260411102139_add_metadata_to_cm_inventory_items.rb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8250d9a96dcceb058991c416ad4b91380fa42f5d43e301c366e74bfe9eb0e27b
4
- data.tar.gz: a8c9301047c15f6ef760bdda1cc9087ac4f7a3539cd6aa86b43a99ab97fc6f16
3
+ metadata.gz: ed6326825a04e2ef186e72511e895b9fbf8598858d7d8f8e4358c0dbc0bc6f7e
4
+ data.tar.gz: ee5cdc0fd119a84c4619596f5db5a6a2aef89b39e0be982f71612a68bd8bbd16
5
5
  SHA512:
6
- metadata.gz: 87bba18fe41a801abf62fc7a83c444452f5b3780b23edaa44bbf86b98271b06877bc8c52bddfc5761b5fdee5953226201c52556cfba30405c1e1f95af2067861
7
- data.tar.gz: 2a7fd81827d6be81291146d17f46ff54a61a59aa4194a552f89ccc59463dc93a4ccc742c0534fd5c18354136314b2e9db571e97b6e8822fff3bbc6c116f3114d
6
+ metadata.gz: 7975ae665f017e022b41297314d72e25ac872241e5e224f5581cea5a736ef7e4e8abee4a8fa71916b038661da894a116c15ceeb71c03e4259627e44fff11222f
7
+ data.tar.gz: 6fa46d5991c849243fdac985bed14ad86d88404adf5880d0e8000c48867f27e6f20c08973bbe41c293e200650ac7b5416a0e4fc0b628a5d1a9b722062101f8c9
data/.env.example CHANGED
@@ -34,6 +34,7 @@ DISTANCE_SIGNING_KEY=hei********************VY
34
34
 
35
35
  # Cache durations (in seconds) for different content types
36
36
  # See: app/controllers/concerns/spree_cm_commissioner/content_cachable.rb
37
+ CACHE_AUTO_INVALIDATION_DISABLED="" # Set to yes to disable CDN cache invalidation entirely (kill switch)
37
38
  CACHE_CDN_MAX_AGE=86400 # CDN/server-side cache duration for all responses
38
39
  CACHE_STATIC_MAX_AGE=86400 # Static content (countries, provinces, seat layouts, CMS pages) - 1 day
39
40
  CACHE_SEMI_STATIC_MAX_AGE=3600 # Semi-static content (menus, homepage backgrounds, routes) - 1 hour
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.8.1.pre.3)
37
+ spree_cm_commissioner (2.8.1.pre.pre.4)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -39,7 +39,6 @@ module Spree
39
39
  params[:date],
40
40
  params[:route_type],
41
41
  params[:vendor_id],
42
- params[:featured],
43
42
  params[:number_of_guests],
44
43
  resource_includes&.sort&.join(','),
45
44
  sparse_fields&.sort&.join(','),
@@ -0,0 +1,19 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class EliminatedContestantsController < ShowContestantsController
6
+ private
7
+
8
+ def scope
9
+ super.eliminated
10
+ end
11
+
12
+ def collection_serializer
13
+ Spree::V2::Tenant::ShowContestantSerializer
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -18,6 +18,7 @@ module Spree
18
18
  .where(show_id: current_show.id)
19
19
  .includes(
20
20
  :show_contestant_images,
21
+ :show_contestant_videos,
21
22
  :current_voting_session,
22
23
  :voting_contestants,
23
24
  assigned_show_person: :show_person_images,
@@ -0,0 +1,68 @@
1
+ # 🎉 ---[Event]---
2
+ #
3
+ # 📋 Event: {{event.name}}
4
+ #
5
+ # 👤 Organizer: {{vendor.name}}
6
+ #
7
+ # 🗓️ Start Date: {{from_date}}
8
+ # 🗓️ End Date: {{to_date}}
9
+ # 🔗 URL: ......
10
+ #
11
+ module SpreeCmCommissioner
12
+ class EventTelegramMessageFactory < TelegramMessageFactory
13
+ attr_reader :event
14
+
15
+ def initialize(event:)
16
+ @event = event
17
+
18
+ title = "✨ #{event.name} ✨"
19
+
20
+ super(title: title)
21
+ end
22
+
23
+ def body
24
+ [
25
+ event_name_line,
26
+ organizer_line,
27
+ [start_date_line, end_date_line].compact.join("\n"),
28
+ event_url_line
29
+ ].compact_blank.join("\n\n")
30
+ end
31
+
32
+ private
33
+
34
+ def event_name_line
35
+ "📋 Event: #{event.name}" if event.name.present?
36
+ end
37
+
38
+ def organizer_line
39
+ return if event.vendor&.name.blank?
40
+
41
+ "👤 Organizer: #{bold(event.vendor.name)}"
42
+ end
43
+
44
+ def start_date_line
45
+ return if event.from_date.blank?
46
+
47
+ "🗓️ Start Date: #{pretty_datetime(event.from_date)}"
48
+ end
49
+
50
+ def end_date_line
51
+ return if event.to_date.blank?
52
+
53
+ "🗓️ End Date: #{pretty_datetime(event.to_date)}"
54
+ end
55
+
56
+ def pretty_datetime(date)
57
+ return '' if date.blank?
58
+
59
+ date.strftime('%b %d, %Y · %H:%M')
60
+ end
61
+
62
+ def event_url_line
63
+ return if event.event_url.blank?
64
+
65
+ "🔗 URL: #{event.event_url}"
66
+ end
67
+ end
68
+ end
@@ -15,8 +15,8 @@ module SpreeCmCommissioner
15
15
  .joins(:inventory_items)
16
16
  .where(vendor_id: vendor_id)
17
17
  .where(inventory_items: { inventory_date: stay_dates })
18
- .where('CAST(spree_variants.public_metadata->\'cm_options\'->>\'number-of-adults\' AS INTEGER) +
19
- CAST(spree_variants.public_metadata->\'cm_options\'->>\'number-of-kids\' AS INTEGER) >= ?', number_of_guests
18
+ .where('CAST(public_metadata->\'cm_options\'->>\'number-of-adults\' AS INTEGER) +
19
+ CAST(public_metadata->\'cm_options\'->>\'number-of-kids\' AS INTEGER) >= ?', number_of_guests
20
20
  )
21
21
  .where('inventory_items.quantity_available > 0')
22
22
  .distinct
@@ -0,0 +1,10 @@
1
+ module SpreeCmCommissioner
2
+ class EventCreationTelegramAlertSenderJob < ApplicationUniqueJob
3
+ queue_as :telegram_bot
4
+
5
+ def perform(options = {})
6
+ event = Spree::Taxon.find(options[:event_id])
7
+ SpreeCmCommissioner::TelegramAlerts::EventCreation.call(event: event)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module SpreeCmCommissioner
2
+ module OauthAccessTokens
3
+ class CleanupExpiredJob < SpreeCmCommissioner::ApplicationJob
4
+ queue_as :default
5
+
6
+ def perform
7
+ SpreeCmCommissioner::OauthAccessTokens::CleanupExpired.new.call
8
+ end
9
+ end
10
+ end
11
+ end
@@ -7,6 +7,7 @@ module SpreeCmCommissioner
7
7
  preference :telegram_order_alert_chat_id, :string
8
8
  preference :telegram_order_request_alert_chat_id, :string
9
9
  preference :telegram_new_vendor_alert_chat_id, :string
10
+ preference :telegram_new_event_alert_chat_id, :string
10
11
  preference :assetlinks, :string, default: ''
11
12
  preference :apple_app_site_association, :string, default: ''
12
13
  end
@@ -2,7 +2,7 @@ module SpreeCmCommissioner
2
2
  module VehicleKind
3
3
  extend ActiveSupport::Concern
4
4
 
5
- VEHICLE_KINDS = %i[suv sedan minivan van sleeping_bus luxury_van air_bus bus ferry boat].freeze
5
+ VEHICLE_KINDS = %i[suv sedan minivan van sleeping_bus luxury_van air_bus bus ferry].freeze
6
6
 
7
7
  included do
8
8
  enum kind: VEHICLE_KINDS if table_exists? && column_names.include?('kind')
@@ -25,36 +25,5 @@ module SpreeCmCommissioner
25
25
  def unstock_external_inventory!(_order, _line_items)
26
26
  raise NotImplementedError, 'Subclasses must implement the unstock_external_inventory! method'
27
27
  end
28
-
29
- def sync_item_availability!(_options = {})
30
- raise NotImplementedError, 'Subclasses must implement the sync_item_availability! method'
31
- end
32
-
33
- def hold_inventory!(_order, _line_items)
34
- raise NotImplementedError, 'Subclasses must implement the hold_inventory! method'
35
- end
36
-
37
- # Integrations that manage external inventory reservations should override this to return true
38
- def supports_external_inventory_holding?
39
- false
40
- end
41
-
42
- # Integrations that support automatically releasing external inventory
43
- # after reservation expiration or order cancellation should override this to return true
44
- def supports_auto_release_inventory?
45
- false
46
- end
47
-
48
- def release_inventory!(_order, _line_items)
49
- raise NotImplementedError, 'Subclasses must implement the release_inventory! method'
50
- end
51
-
52
- def external_inventory_items(_order)
53
- raise NotImplementedError, 'Subclasses must implement the external_inventory_items method'
54
- end
55
-
56
- def external_inventory_item_status(_order, _options)
57
- raise NotImplementedError, 'Subclasses must implement the external_inventory_item_status method'
58
- end
59
28
  end
60
29
  end
@@ -5,7 +5,10 @@ class SpreeCmCommissioner::Integrations::StadiumXV1 < SpreeCmCommissioner::Integ
5
5
 
6
6
  # override
7
7
  def sync_manager
8
- SpreeCmCommissioner::Integrations::StadiumXV1::SyncManager.new(integration: self)
8
+ SpreeCmCommissioner::Integrations::StadiumXV1::SyncManager.new(
9
+ integration: self,
10
+ client: client
11
+ )
9
12
  end
10
13
 
11
14
  # override
@@ -15,6 +18,7 @@ class SpreeCmCommissioner::Integrations::StadiumXV1 < SpreeCmCommissioner::Integ
15
18
  order: order,
16
19
  line_items: line_items
17
20
  )
21
+
18
22
  raise SpreeCmCommissioner::Integrations::SyncError, result.error unless result.success?
19
23
  end
20
24
 
@@ -23,9 +27,11 @@ class SpreeCmCommissioner::Integrations::StadiumXV1 < SpreeCmCommissioner::Integ
23
27
  raise SpreeCmCommissioner::Integrations::SyncError, 'Ticket cannot be cancelled'
24
28
  end
25
29
 
26
- def sync_item_availability!(_options = {}); end
27
-
28
30
  def client
29
- @client ||= SpreeCmCommissioner::Integrations::StadiumXV1::ExternalClient::Client.new(integration: self)
31
+ SpreeCmCommissioner::Integrations::StadiumXV1::ExternalClient::Client.new(
32
+ public_key: public_key,
33
+ private_key: private_key,
34
+ base_url: base_url
35
+ )
30
36
  end
31
37
  end
@@ -1,15 +1,9 @@
1
1
  module SpreeCmCommissioner
2
2
  class InventoryItem < Base
3
3
  include SpreeCmCommissioner::ProductType
4
- include SpreeCmCommissioner::StoreMetadata
5
- include SpreeCmCommissioner::Integrations::IntegrationMappable
6
4
 
7
5
  MAX_DISPLAY_STOCK = 20
8
6
 
9
- store_public_metadata :last_synced_at, :datetime
10
- store_public_metadata :original_price, :integer
11
- store_public_metadata :currency, :string
12
-
13
7
  # Association
14
8
  belongs_to :variant, class_name: 'Spree::Variant', optional: false
15
9
 
@@ -29,8 +23,23 @@ module SpreeCmCommissioner
29
23
 
30
24
  before_save -> { self.product_type = variant.product_type }, if: -> { product_type.nil? }
31
25
 
32
- # Create maintaining task to purge product related caches
33
- after_commit { SpreeCmCommissioner::MaintenanceTasks::CacheInvalidation.pending.create_or_find_by(maintainable: variant.product) }
26
+ after_commit :schedule_product_cache_invalidation
27
+
28
+ # Only for ecommerce: the app uses product.in_stock? (derived from quantity_available) for product cards.
29
+ # Other types (e.g. accommodation, bus) have many inventory items (including daily-generated ones),
30
+ # so invalidating per item would flood the task queue.
31
+ #
32
+ # This is temporary until we have a more robust cache invalidation strategy in place.
33
+ def schedule_product_cache_invalidation
34
+ return unless ecommerce?
35
+ return unless saved_change_to_quantity_available?
36
+
37
+ # Only fires on in_stock status transition (0 ↔ N); non-zero to non-zero changes are skipped.
38
+ old_val, new_val = saved_change_to_quantity_available
39
+ return if old_val.to_i.positive? && new_val.to_i.positive?
40
+
41
+ SpreeCmCommissioner::MaintenanceTasks::CacheInvalidation.pending.create_or_find_by(maintainable: variant.product)
42
+ end
34
43
 
35
44
  def public_quantity_available
36
45
  [quantity_available, MAX_DISPLAY_STOCK].min
@@ -3,6 +3,8 @@ module SpreeCmCommissioner
3
3
  module MaintenanceTasks
4
4
  class CacheInvalidation < MaintenanceTask
5
5
  def maintain
6
+ return if ENV['CACHE_AUTO_INVALIDATION_DISABLED'] == 'yes'
7
+
6
8
  if maintainable.is_a?(SpreeCmCommissioner::HomepageBackground) || maintainable.is_a?(Spree::Menu)
7
9
  SpreeCmCommissioner::HomepageDataLoader.clear_cache
8
10
  end
@@ -7,6 +7,7 @@
7
7
  # `maintain` runs three steps in order:
8
8
  # 1. RebuildFromDb — overwrites Redis counters with DB totals (source of truth)
9
9
  # 2. AuditCounters — logs any remaining mismatches between Redis and DB
10
+ # 3. SnapshotToDb — writes final aggregates to cm_voting_contestants and cm_voting_session_stats
10
11
  #
11
12
  # maintainable: SpreeCmCommissioner::VotingSession
12
13
  #
@@ -19,6 +20,7 @@ module SpreeCmCommissioner
19
20
  ttl = rebuild_ttl
20
21
  SpreeCmCommissioner::VoteCounters::RebuildFromDb.call(voting_session_id: maintainable.id, ttl: ttl)
21
22
  SpreeCmCommissioner::VoteCounters::AuditCounters.call(voting_session_id: maintainable.id)
23
+ SpreeCmCommissioner::VoteCounters::SnapshotToDb.call(voting_session_id: maintainable.id)
22
24
  end
23
25
 
24
26
  # For closed sessions use the fixed 24h constant — closes_at is in the past
@@ -42,7 +42,6 @@ module SpreeCmCommissioner
42
42
  base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
43
43
  base.has_many :guest_card_classes, class_name: 'SpreeCmCommissioner::GuestCardClass', through: :variants
44
44
  base.has_many :product_completion_steps, class_name: 'SpreeCmCommissioner::ProductCompletionStep', through: :line_items
45
- base.has_many :audit_events, class_name: 'SpreeCmCommissioner::AuditEvent', as: :auditable
46
45
 
47
46
  base.delegate :customer, to: :user, allow_nil: true
48
47
 
@@ -1,7 +1,5 @@
1
1
  module SpreeCmCommissioner
2
2
  class Place < Base
3
- include SpreeCmCommissioner::Integrations::IntegrationMappable
4
-
5
3
  acts_as_nested_set
6
4
 
7
5
  validates :reference, presence: true, if: :validate_reference?
@@ -1,7 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  class Route < Base
3
3
  include SpreeCmCommissioner::RouteType
4
- include SpreeCmCommissioner::Integrations::IntegrationMappable
5
4
  include SpreeCmCommissioner::StoreMetadata
6
5
 
7
6
  belongs_to :vendor, class_name: 'Spree::Vendor', optional: false
@@ -1,7 +1,5 @@
1
1
  module SpreeCmCommissioner
2
2
  class SeatLayout < Base
3
- include SpreeCmCommissioner::Integrations::IntegrationMappable
4
-
5
3
  has_many :seat_sections, class_name: 'SpreeCmCommissioner::SeatSection', dependent: :destroy
6
4
 
7
5
  has_many :blocks, class_name: 'SpreeCmCommissioner::Block'
@@ -28,7 +28,9 @@ module SpreeCmCommissioner
28
28
  :max_paid_votes_per_session,
29
29
  :sms_vote_enabled,
30
30
  :sms_vote_cost_usd,
31
- :operator_vote_enabled
31
+ :operator_vote_enabled,
32
+ :votes_weight,
33
+ :voters_weight
32
34
 
33
35
  # voting_credit_scope determines how purchased vote credits are grouped (scoped).
34
36
  # Changing this after credits have been allocated will cause inconsistencies:
@@ -27,8 +27,20 @@ module SpreeCmCommissioner
27
27
  validates :name, presence: true
28
28
  validates :contestant_number, uniqueness: { scope: :show_id }, allow_nil: true
29
29
 
30
+ before_save :set_eliminated_at, if: :status_changed_to_eliminated?
31
+
30
32
  scope :ordered, -> { order(:position, :id) }
31
33
 
34
+ private
35
+
36
+ def status_changed_to_eliminated?
37
+ status_changed? && eliminated?
38
+ end
39
+
40
+ def set_eliminated_at
41
+ self.eliminated_at = Time.current
42
+ end
43
+
32
44
  self.whitelisted_ransackable_attributes = %w[name contestant_number status gender category origin]
33
45
  end
34
46
  end
@@ -6,9 +6,6 @@ module SpreeCmCommissioner
6
6
 
7
7
  base.after_commit :create_inventory_items, on: :create
8
8
  base.after_commit :adjust_inventory_items_async, on: :destroy
9
-
10
- # Create maintaining task to purge product related caches
11
- base.after_commit { SpreeCmCommissioner::MaintenanceTasks::CacheInvalidation.pending.create_or_find_by(maintainable: variant.product) }
12
9
  end
13
10
 
14
11
  def update_vendor_total_inventory
@@ -18,10 +15,6 @@ module SpreeCmCommissioner
18
15
  private
19
16
 
20
17
  def create_inventory_items
21
- # Skip automatic inventory generation when variant has manual_generate_inventory_items set to true
22
- # Use case: For variants where inventory items need to be manually created/managed (e.g., external integrations)
23
- return if variant.manual_generate_inventory_items?
24
-
25
18
  SpreeCmCommissioner::InventoryItems::GenerateInventoryItemsJob.perform_later(variant_id: variant.id)
26
19
  end
27
20
 
@@ -74,6 +74,7 @@ module SpreeCmCommissioner
74
74
  base.has_many :taxon_option_values, class_name: 'SpreeCmCommissioner::TaxonOptionValue'
75
75
 
76
76
  base.after_commit :send_transaction_email_to_organizers, on: :create
77
+ base.after_commit :send_event_creation_telegram_alert, on: :create
77
78
 
78
79
  base.has_many :taxon_places, class_name: 'SpreeCmCommissioner::TaxonPlace', dependent: :destroy
79
80
  base.has_many :places, through: :taxon_places
@@ -154,6 +155,12 @@ module SpreeCmCommissioner
154
155
  SpreeCmCommissioner::OrganizersTransactionalEmailNotifier.call(event_id: id)
155
156
  end
156
157
 
158
+ def send_event_creation_telegram_alert
159
+ return unless kind == 'event' && depth == 1
160
+
161
+ SpreeCmCommissioner::EventCreationTelegramAlertSenderJob.perform_later(event_id: id)
162
+ end
163
+
157
164
  def sync_event_dates_to_line_items
158
165
  return unless event? && depth == 1
159
166
 
@@ -2,7 +2,6 @@ module SpreeCmCommissioner
2
2
  class Trip < Base
3
3
  include SpreeCmCommissioner::StoreMetadata
4
4
  include SpreeCmCommissioner::RouteType
5
- include SpreeCmCommissioner::Integrations::IntegrationMappable
6
5
 
7
6
  attr_accessor :hours, :minutes, :seconds
8
7
 
@@ -26,7 +25,7 @@ module SpreeCmCommissioner
26
25
  after_commit :update_route_price_range, on: %i[create update]
27
26
 
28
27
  belongs_to :vendor, class_name: 'Spree::Vendor', inverse_of: :trips, optional: false
29
- belongs_to :product, class_name: 'Spree::Product', inverse_of: :trip, optional: true
28
+ belongs_to :product, class_name: 'Spree::Product', inverse_of: :trip, optional: false
30
29
 
31
30
  belongs_to :service_origin, class_name: 'Spree::Taxon', optional: true
32
31
 
@@ -1,7 +1,5 @@
1
1
  module SpreeCmCommissioner
2
2
  class TripStop < Base
3
- include SpreeCmCommissioner::Integrations::IntegrationMappable
4
-
5
3
  acts_as_list column: :sequence, scope: :trip_id
6
4
 
7
5
  belongs_to :trip, class_name: 'SpreeCmCommissioner::Trip', optional: false
@@ -6,7 +6,6 @@ module SpreeCmCommissioner
6
6
  base.include SpreeCmCommissioner::VariantOptionsConcern
7
7
  base.include SpreeCmCommissioner::KycBitwise
8
8
  base.include SpreeCmCommissioner::Integrations::IntegrationMappable
9
- base.include SpreeCmCommissioner::VariantMetadata
10
9
 
11
10
  base.after_commit :update_vendor_price
12
11
  base.validate :validate_option_types
@@ -1,7 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  class Vehicle < Base
3
3
  include SpreeCmCommissioner::VehicleKind
4
- include SpreeCmCommissioner::Integrations::IntegrationMappable
5
4
 
6
5
  belongs_to :vendor, class_name: 'Spree::Vendor'
7
6
  belongs_to :vehicle_type, class_name: 'SpreeCmCommissioner::VehicleType'
@@ -14,8 +13,6 @@ module SpreeCmCommissioner
14
13
  validates :name, presence: true
15
14
  validates :license_plate, uniqueness: true, allow_blank: true
16
15
 
17
- has_one :seat_layout, through: :vehicle_type
18
-
19
16
  self.whitelisted_ransackable_attributes = %w[name license_plate kind]
20
17
 
21
18
  def display_name
@@ -2,7 +2,6 @@ module SpreeCmCommissioner
2
2
  class VehicleType < Base
3
3
  include SpreeCmCommissioner::StoreMetadata
4
4
  include SpreeCmCommissioner::VehicleKind
5
- include SpreeCmCommissioner::Integrations::IntegrationMappable
6
5
 
7
6
  # This model has no seat_layout column (polymorphic association), so we store the preload_seat_layout_id ID in public_metadata.
8
7
  # This lets us check if a seat layout exists without triggering a database query.
@@ -30,7 +30,6 @@ module SpreeCmCommissioner
30
30
  base.has_many :nearby_places, -> { order(position: :asc) }, class_name: 'SpreeCmCommissioner::VendorPlace', dependent: :destroy
31
31
 
32
32
  base.has_many :stock_items, through: :variants, class_name: 'Spree::StockItem'
33
- base.has_many :currency_rates, class_name: 'SpreeCmCommissioner::CurrencyRate', dependent: :destroy
34
33
 
35
34
  base.has_many :taxon_vendors, class_name: 'SpreeCmCommissioner::TaxonVendor'
36
35
  base.has_many :taxons, through: :taxon_vendors
@@ -102,7 +101,6 @@ module SpreeCmCommissioner
102
101
  base.has_many :boarding_trip_stops, through: :trips, class_name: 'SpreeCmCommissioner::TripStop', source: :boarding_trip_stops
103
102
  base.has_many :drop_off_trip_stops, through: :trips, class_name: 'SpreeCmCommissioner::TripStop', source: :drop_off_trip_stops
104
103
  base.has_many :pricing_models, class_name: 'SpreeCmCommissioner::PricingModel', foreign_key: :vendor_id, dependent: :destroy
105
- base.has_many :orders, -> { distinct }, through: :variants, source: :orders
106
104
 
107
105
  base.has_many :agency_categories, -> { where(kind: :agency_category) }, class_name: 'Spree::Taxon', foreign_key: :vendor_id
108
106
 
@@ -245,21 +243,6 @@ module SpreeCmCommissioner
245
243
  end
246
244
 
247
245
  delegate :present?, to: :tenant, prefix: true
248
-
249
- # Returns the exchange rate between two currencies
250
- # If no direct rate exists, calculates the inverse rate from the reverse pair
251
- # Returns 1.0 for identical currencies, nil if no rate is found
252
- def exchange_rate(from_currency, to_currency)
253
- return 1.0 if from_currency == to_currency
254
-
255
- pair = currency_rates.by_pair(from_currency, to_currency).first
256
- return pair.rate if pair.present?
257
-
258
- reverse_pair = currency_rates.by_pair(to_currency, from_currency).first
259
- return (1.0 / reverse_pair.rate).round(6) if reverse_pair.present?
260
-
261
- nil
262
- end
263
246
  end
264
247
  end
265
248
 
@@ -1,7 +1,5 @@
1
1
  module SpreeCmCommissioner
2
2
  class VendorPlace < Base
3
- include SpreeCmCommissioner::Integrations::IntegrationMappable
4
-
5
3
  enum place_type: { venue: 0, branch: 1, stop: 2, location: 3 }
6
4
  acts_as_list scope: :vendor
7
5
 
@@ -20,6 +20,18 @@ module SpreeCmCommissioner
20
20
 
21
21
  validates :eliminated_via, presence: true, if: :eliminated?
22
22
 
23
+ # Uniqueness validation: vote_number must be unique per contestant per voting_session
24
+ # Scope: [show_contestant_id, voting_session_id]
25
+ #
26
+ # | contestant_id | session_id | vote_number | Status | Reason |
27
+ # |---------------|-----------|-------------|--------|---------------------------|
28
+ # | 1 | 1 | 1 | ✓ OK | First record |
29
+ # | 1 | 1 | 1 | ✗ FAIL | Duplicate in same scope |
30
+ # | 1 | 1 | 2 | ✓ OK | Can update/change number |
31
+ # | 2 | 1 | 1 | ✓ OK | Different contestant |
32
+ # | 1 | 2 | 1 | ✓ OK | Different session |
33
+ validates :vote_number, uniqueness: { scope: %i[show_contestant_id voting_session_id], allow_nil: true }
34
+
23
35
  delegate :name, :contestant_number, :category, :gender, to: :show_contestant, allow_nil: true
24
36
  delegate :can_vote?, to: :voting_session, allow_nil: true
25
37