spree_cm_commissioner 2.8.1.pre.pre.4 → 2.8.2.pre.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/controllers/spree/api/v2/tenant/show_elimination_sessions_controller.rb +57 -0
  4. data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +8 -0
  5. data/app/models/concerns/spree_cm_commissioner/service_origin.rb +22 -0
  6. data/app/models/spree_cm_commissioner/route.rb +6 -1
  7. data/app/models/spree_cm_commissioner/show_contestant.rb +2 -9
  8. data/app/models/spree_cm_commissioner/trip.rb +5 -0
  9. data/app/models/spree_cm_commissioner/voting_contestant.rb +1 -1
  10. data/app/models/spree_cm_commissioner/voting_session.rb +4 -1
  11. data/app/serializers/spree/v2/tenant/voting_contestant_serializer.rb +5 -1
  12. data/app/serializers/spree/v2/tenant/voting_session_serializer.rb +4 -1
  13. data/app/services/spree_cm_commissioner/pricing_models/preview.rb +15 -6
  14. data/app/services/spree_cm_commissioner/routes/create.rb +0 -5
  15. data/app/services/spree_cm_commissioner/trips/create_multi_leg.rb +5 -16
  16. data/app/services/spree_cm_commissioner/trips/create_single_leg.rb +0 -1
  17. data/app/services/spree_cm_commissioner/vote_counters/per_contestant_counter.rb +2 -0
  18. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +2 -1
  19. data/app/services/spree_cm_commissioner/voting_sessions/finalize.rb +66 -0
  20. data/config/locales/en.yml +2 -0
  21. data/config/locales/km.yml +4 -0
  22. data/config/routes.rb +1 -1
  23. data/db/migrate/20260527035430_add_confirmed_rank_to_cm_voting_contestants.rb +5 -0
  24. data/lib/spree_cm_commissioner/test_helper/factories/show_factory.rb +16 -0
  25. data/lib/spree_cm_commissioner/version.rb +1 -1
  26. metadata +6 -3
  27. data/app/controllers/spree/api/v2/tenant/eliminated_contestants_controller.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed6326825a04e2ef186e72511e895b9fbf8598858d7d8f8e4358c0dbc0bc6f7e
4
- data.tar.gz: ee5cdc0fd119a84c4619596f5db5a6a2aef89b39e0be982f71612a68bd8bbd16
3
+ metadata.gz: 595e82de2ef3a0ab170476a3ad96ab5d25d3d501916fa7b740d4d3d50f11193f
4
+ data.tar.gz: fb43eb4f67c1dc65ea1833f90f51624595122a6555c5099ac153a6abf20a1d3b
5
5
  SHA512:
6
- metadata.gz: 7975ae665f017e022b41297314d72e25ac872241e5e224f5581cea5a736ef7e4e8abee4a8fa71916b038661da894a116c15ceeb71c03e4259627e44fff11222f
7
- data.tar.gz: 6fa46d5991c849243fdac985bed14ad86d88404adf5880d0e8000c48867f27e6f20c08973bbe41c293e200650ac7b5416a0e4fc0b628a5d1a9b722062101f8c9
6
+ metadata.gz: a63ca4741ece801cadde290f28f810bcc7143a320201af0d1a074b2a9ae380b7307807d06eac856d01d062eb27b149efaf9e70e87c6853008d2bf667d852d3d1
7
+ data.tar.gz: d6cbf032196337ad97649cc72a4f2d1a7a0426224498cd0e2df492e4251a67ed00a7876e9719a66296b8ff9f168be7fa4c991e91a7d318f71eeab08802ae377f
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.pre.4)
37
+ spree_cm_commissioner (2.8.2.pre.pre.1)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -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
@@ -23,6 +23,8 @@ module SpreeCmCommissioner
23
23
  TripKey = Struct.new(:trip_id, :direction, :boarding_trip_stop_id, :drop_off_trip_stop_id)
24
24
 
25
25
  included do
26
+ include SpreeCmCommissioner::ServiceOrigin
27
+
26
28
  validates :direction, inclusion: { in: DIRECTION }, allow_nil: true
27
29
  validates :trip_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
28
30
  validates :service_origin_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
@@ -125,6 +127,12 @@ module SpreeCmCommissioner
125
127
 
126
128
  private
127
129
 
130
+ def resolve_service_origin_id
131
+ return nil if trip_id.blank?
132
+
133
+ SpreeCmCommissioner::Trip.find_by(id: trip_id)&.service_origin_id
134
+ end
135
+
128
136
  def validate_trip_stops_for_scheduled_trips
129
137
  return if trip_id.blank? || trip_id.zero?
130
138
 
@@ -0,0 +1,22 @@
1
+ module SpreeCmCommissioner
2
+ # Defaults service_origin (nationality) from parent associations during validation (on create).
3
+ # Vendor → Route → Trip → LineItem.
4
+ # Pricing rules use this to determine local vs foreigner rates.
5
+ module ServiceOrigin
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_validation :assign_service_origin_id, on: :create
10
+ end
11
+
12
+ private
13
+
14
+ def assign_service_origin_id
15
+ self.service_origin_id ||= resolve_service_origin_id
16
+ end
17
+
18
+ def resolve_service_origin_id
19
+ nil
20
+ end
21
+ end
22
+ end
@@ -2,8 +2,9 @@ module SpreeCmCommissioner
2
2
  class Route < Base
3
3
  include SpreeCmCommissioner::RouteType
4
4
  include SpreeCmCommissioner::StoreMetadata
5
+ include SpreeCmCommissioner::ServiceOrigin
5
6
 
6
- belongs_to :vendor, class_name: 'Spree::Vendor', optional: false
7
+ belongs_to :vendor, class_name: 'Spree::Vendor', inverse_of: :routes, optional: false
7
8
  belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant', optional: true
8
9
 
9
10
  belongs_to :service_origin, class_name: 'Spree::Taxon', optional: true
@@ -66,6 +67,10 @@ module SpreeCmCommissioner
66
67
 
67
68
  private
68
69
 
70
+ def resolve_service_origin_id
71
+ vendor&.service_origin_id
72
+ end
73
+
69
74
  def validate_route_stops
70
75
  return if route_stops.valid?
71
76
 
@@ -27,17 +27,10 @@ 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
-
32
30
  scope :ordered, -> { order(:position, :id) }
33
31
 
34
- private
35
-
36
- def status_changed_to_eliminated?
37
- status_changed? && eliminated?
38
- end
39
-
40
- def set_eliminated_at
32
+ def eliminate
33
+ self.status = :eliminated
41
34
  self.eliminated_at = Time.current
42
35
  end
43
36
 
@@ -2,6 +2,7 @@ module SpreeCmCommissioner
2
2
  class Trip < Base
3
3
  include SpreeCmCommissioner::StoreMetadata
4
4
  include SpreeCmCommissioner::RouteType
5
+ include SpreeCmCommissioner::ServiceOrigin
5
6
 
6
7
  attr_accessor :hours, :minutes, :seconds
7
8
 
@@ -133,6 +134,10 @@ module SpreeCmCommissioner
133
134
 
134
135
  private
135
136
 
137
+ def resolve_service_origin_id
138
+ route&.service_origin_id || vendor&.service_origin_id
139
+ end
140
+
136
141
  def duplicate_seat_layout_from_vehicle
137
142
  # Duplicate the vehicle's seat layout into this trip. Copies nested
138
143
  # seat sections and blocks while excluding identifying columns and
@@ -32,7 +32,7 @@ module SpreeCmCommissioner
32
32
  # | 1 | 2 | 1 | ✓ OK | Different session |
33
33
  validates :vote_number, uniqueness: { scope: %i[show_contestant_id voting_session_id], allow_nil: true }
34
34
 
35
- delegate :name, :contestant_number, :category, :gender, to: :show_contestant, allow_nil: true
35
+ delegate :name, :contestant_number, :category, :gender, :eliminated_at, to: :show_contestant, allow_nil: true
36
36
  delegate :can_vote?, to: :voting_session, allow_nil: true
37
37
 
38
38
  def special_rule_type=(value)
@@ -8,6 +8,9 @@ module SpreeCmCommissioner
8
8
 
9
9
  has_many :voting_credits, class_name: 'SpreeCmCommissioner::VotingCredit', as: :votable, dependent: :destroy
10
10
  has_many :voting_contestants, class_name: 'SpreeCmCommissioner::VotingContestant', dependent: :destroy
11
+ has_many :eliminated_voting_contestants, lambda {
12
+ where(eliminated: true)
13
+ }, class_name: 'SpreeCmCommissioner::VotingContestant', foreign_key: 'voting_session_id'
11
14
  has_many :show_contestants, through: :voting_contestants
12
15
  has_many :contestants, through: :show, source: :show_contestants
13
16
  has_many :votes, class_name: 'SpreeCmCommissioner::Vote', dependent: :destroy
@@ -15,7 +18,7 @@ module SpreeCmCommissioner
15
18
 
16
19
  acts_as_list scope: :episode
17
20
 
18
- enum status: { disabled: 0, enabled: 1, closed: 2 }
21
+ enum status: { disabled: 0, enabled: 1, closed: 2, finalized: 3 }
19
22
  enum scoring_model: { manual: 0, geometric: 1, harmonic: 2, weighted_sum: 3, arithmetic: 4 }
20
23
 
21
24
  self.whitelisted_ransackable_attributes = %w[name status]
@@ -4,12 +4,16 @@ module Spree
4
4
  class VotingContestantSerializer < BaseSerializer
5
5
  set_type :voting_contestant
6
6
 
7
- attributes :show_contestant_id, :name, :contestant_number, :vote_number, :category, :gender
7
+ attributes :show_id, :show_contestant_id, :name, :contestant_number, :vote_number, :category, :gender,
8
+ :vote_count, :eliminated, :eliminated_via, :eliminated_at, :advanced_to_type, :advanced_to_id, :special_rules,
9
+ :created_at, :updated_at, :advanced_from_type, :advanced_from_id, :unique_voter_count, :preferences
8
10
 
9
11
  attribute :voting_session_id, &:voting_session_id
10
12
 
11
13
  attribute :can_vote, &:can_vote?
12
14
 
15
+ belongs_to :voting_session, serializer: ::Spree::V2::Tenant::VotingSessionSerializer
16
+
13
17
  has_many :show_contestant_images, serializer: ::Spree::V2::Tenant::AssetSerializer
14
18
  has_many :show_contestant_videos, serializer: ::Spree::V2::Tenant::VideoSerializer
15
19
  end
@@ -2,13 +2,16 @@ module Spree
2
2
  module V2
3
3
  module Tenant
4
4
  class VotingSessionSerializer < BaseSerializer
5
- attributes :opens_at, :closes_at, :status, :live_stream_enabled, :live_stream_thumbnail, :live_stream_title, :live_stream_description
5
+ attributes :name, :opens_at, :closes_at, :status, :live_stream_enabled, :live_stream_thumbnail, :live_stream_title, :live_stream_description,
6
+ :created_at
6
7
 
7
8
  attribute :live_stream_url, &:embedded_live_stream_url
8
9
  attribute :can_vote, &:can_vote?
9
10
 
10
11
  belongs_to :episode, serializer: Spree::V2::Tenant::ShowEpisodeSerializer
11
12
  belongs_to :show, serializer: Spree::V2::Tenant::ShowSerializer
13
+
14
+ has_many :eliminated_voting_contestants, serializer: ::Spree::V2::Tenant::VotingContestantSerializer
12
15
  end
13
16
  end
14
17
  end
@@ -52,12 +52,16 @@ module SpreeCmCommissioner
52
52
  vendor_ids = transit_contexts.map { |ctx| variant_vendor_id(ctx.variant_id) }.compact.uniq
53
53
  return [] if vendor_ids.blank?
54
54
 
55
- SpreeCmCommissioner::PricingModelRoute
56
- .active
57
- .for_origin_destination(origin_place_id, destination_place_id)
58
- .includes(:pricing_model)
59
- .map(&:pricing_model)
60
- .select { |pm| vendor_ids.include?(pm.vendor_id) }
55
+ route_ids = trip_route_ids(transit_contexts)
56
+
57
+ scope = SpreeCmCommissioner::PricingModelRoute
58
+ .active
59
+ .for_origin_destination(origin_place_id, destination_place_id)
60
+ .includes(:pricing_model)
61
+
62
+ scope = scope.where(route_id: route_ids) if route_ids.any?
63
+
64
+ scope.map(&:pricing_model).select { |pm| vendor_ids.include?(pm.vendor_id) }
61
65
  end
62
66
 
63
67
  def variant_pricing_models(group_contexts)
@@ -83,6 +87,11 @@ module SpreeCmCommissioner
83
87
  end
84
88
  end
85
89
 
90
+ def trip_route_ids(transit_contexts)
91
+ trip_ids = transit_contexts.map(&:trip_id).compact.uniq
92
+ SpreeCmCommissioner::Trip.where(id: trip_ids).where.not(route_id: nil).distinct.pluck(:route_id)
93
+ end
94
+
86
95
  def variant_vendor_id(variant_id)
87
96
  return nil if variant_id.blank?
88
97
 
@@ -19,15 +19,10 @@ module SpreeCmCommissioner
19
19
  destination_place = find_place_for(route_stops, route_stops.last)
20
20
 
21
21
  return failure(nil, 'Origin or destination place could not be determined') if origin_place.nil? || destination_place.nil?
22
- return failure(nil, 'Route with origin & destination already exists') if vendor.routes.exists?(
23
- origin_place_id: origin_place.id,
24
- destination_place_id: destination_place.id
25
- )
26
22
 
27
23
  attrs = attrs.merge(
28
24
  tenant_id: vendor.tenant_id,
29
25
  route_name: attrs[:route_name] || "#{origin_place.name} -> #{destination_place.name}",
30
- service_origin_id: vendor.service_origin_id,
31
26
  origin_place_id: origin_place.id,
32
27
  destination_place_id: destination_place.id,
33
28
  route_stops: route_stops
@@ -43,7 +43,7 @@ module SpreeCmCommissioner
43
43
  leg_trips_by_branch_id = find_all_leg_trips(vendor: @vendor, trip_stop_forms: @branch_stops)
44
44
 
45
45
  ApplicationRecord.transaction do
46
- @parent_route = load_parent_route!(vendor: @vendor, locations: @locations, branch_stops: @branch_stops, trip_form: @trip_form)
46
+ @parent_route = load_parent_route!(vendor: @vendor, trip_form: @trip_form)
47
47
 
48
48
  # Collect offset_days from input (relative: layover days at each branch)
49
49
  # Will be stored in parent_trip metadata for reference
@@ -128,21 +128,11 @@ module SpreeCmCommissioner
128
128
  .index_by(&:id)
129
129
  end
130
130
 
131
- # Find parent route by route_id or origin/destination places and route_type
131
+ # Find parent route by route_id
132
132
  #
133
133
  # @return [Route] Route from origin to destination place
134
- def load_parent_route!(vendor:, locations:, branch_stops:, trip_form:)
135
- return vendor.routes.find(trip_form.route_id) if trip_form.route_id.present?
136
-
137
- origin_place_id = locations[branch_stops.first.location_id.to_i]&.place_id
138
- destination_place_id = locations[branch_stops.last.location_id.to_i]&.place_id
139
- route_type = trip_form.route_type.presence || 'bus'
140
-
141
- vendor.routes.find_by(
142
- origin_place_id: origin_place_id,
143
- destination_place_id: destination_place_id,
144
- route_type: route_type
145
- ) or raise StandardError, "Route not found for #{origin_place_id} → #{destination_place_id}"
134
+ def load_parent_route!(vendor:, trip_form:)
135
+ vendor.routes.find(trip_form.route_id)
146
136
  end
147
137
 
148
138
  # Find leg trips and map by stop ID (skip final destination)
@@ -199,8 +189,7 @@ module SpreeCmCommissioner
199
189
  allow_booking: true,
200
190
  trip_type: :multi_leg,
201
191
  allow_seat_selection: false,
202
- route_type: route_type,
203
- service_origin_id: @parent_route.service_origin_id || @vendor.service_origin_id
192
+ route_type: route_type
204
193
  )
205
194
 
206
195
  # Store relative offset_days (layover days) as metadata
@@ -80,7 +80,6 @@ module SpreeCmCommissioner
80
80
  vehicle: SpreeCmCommissioner::Vehicle.find_by(id: first_stop.vehicle_id),
81
81
  origin_place_id: locations[first_stop.location_id.to_i].place_id,
82
82
  destination_place_id: locations[last_stop.location_id.to_i].place_id,
83
- service_origin_id: route.service_origin_id || vendor.service_origin_id,
84
83
  route: route,
85
84
  departure_time: first_stop.departure_time,
86
85
  duration: trip_form.total_duration_seconds,
@@ -39,6 +39,8 @@ module SpreeCmCommissioner
39
39
  unique_voters: session_unique_voter_count,
40
40
  unique_voters_per_contestant: contestant_unique_voter_counts(ids)
41
41
  )
42
+ rescue StandardError => e
43
+ failure(nil, e.message)
42
44
  end
43
45
 
44
46
  private
@@ -51,7 +51,8 @@ module SpreeCmCommissioner
51
51
  return unless attributes.key?(:eliminated)
52
52
  return unless attributes[:eliminated]
53
53
 
54
- voting_contestant.show_contestant.update!(status: :eliminated)
54
+ voting_contestant.show_contestant.eliminate
55
+ voting_contestant.show_contestant.save!
55
56
  end
56
57
 
57
58
  # Normalizes raw params into a safe attributes hash.
@@ -0,0 +1,66 @@
1
+ module SpreeCmCommissioner
2
+ module VotingSessions
3
+ class Finalize
4
+ prepend ::Spree::ServiceModule::Base
5
+
6
+ def call(voting_session:)
7
+ ApplicationRecord.transaction do
8
+ validate_confirmed_ranks!(voting_session)
9
+ advance_confirmed_winners(voting_session) if next_session?(voting_session)
10
+ voting_session.update!(status: :finalized)
11
+ success(voting_session: voting_session)
12
+ end
13
+ rescue StandardError => e
14
+ failure(nil, e.message)
15
+ end
16
+
17
+ private
18
+
19
+ def validate_confirmed_ranks!(voting_session)
20
+ if next_session?(voting_session)
21
+ raise I18n.t('voting.errors.no_winners_confirmed') if voting_session.voting_contestants.where.not(confirmed_rank: nil).none?
22
+ else
23
+ unranked = voting_session.voting_contestants.where(eliminated: false, confirmed_rank: nil)
24
+ raise I18n.t('voting.errors.all_contestants_must_be_ranked') if unranked.any?
25
+ end
26
+ end
27
+
28
+ # Re-syncs advancement on every call — handles first finalize and re-finalize.
29
+ # Contestants without a confirmed_rank get their advanced_to cleared.
30
+ def advance_confirmed_winners(voting_session)
31
+ next_session = resolve_next_session(voting_session)
32
+
33
+ # Reset soft eliminations from previous finalize so re-finalize can re-evaluate them.
34
+ # rubocop:disable Rails/SkipsModelValidations
35
+ voting_session.voting_contestants
36
+ .where(eliminated: true, eliminated_via: :public_vote)
37
+ .update_all(eliminated: false, eliminated_via: nil)
38
+ # rubocop:enable Rails/SkipsModelValidations
39
+
40
+ voting_session.voting_contestants.reload.each do |voting_contestant|
41
+ if voting_contestant.confirmed_rank.present?
42
+ SpreeCmCommissioner::VotingContestants::Advancer.call(
43
+ voting_contestant: voting_contestant,
44
+ attributes: { advanced_to: next_session }
45
+ )
46
+ else
47
+ SpreeCmCommissioner::VotingContestants::Advancer.call(
48
+ voting_contestant: voting_contestant,
49
+ attributes: { eliminated: true, eliminated_via: :public_vote, advanced_to_type: nil, advanced_to_id: nil }
50
+ )
51
+ end
52
+ end
53
+ end
54
+
55
+ def next_session?(voting_session)
56
+ resolve_next_session(voting_session).present?
57
+ end
58
+
59
+ def resolve_next_session(voting_session)
60
+ return @resolved_next_session if defined?(@resolved_next_session)
61
+
62
+ @resolved_next_session = voting_session.next_in_episode || voting_session.episode.next_episode_first_session
63
+ end
64
+ end
65
+ end
66
+ end
@@ -767,4 +767,6 @@ en:
767
767
  rate_limit_ip: "Too many votes from your network. Please try again shortly."
768
768
  device_account_limit: "This device has been used by too many accounts."
769
769
  vpn_blocked: "Voting is not allowed from VPN or proxy connections."
770
+ no_winners_confirmed: "No winners confirmed"
771
+ all_contestants_must_be_ranked: "All non-eliminated contestants must be ranked"
770
772
 
@@ -605,4 +605,8 @@ km:
605
605
  token_missing: "សញ្ញាណផ្ទៀងផ្ទាត់គឺបាត់"
606
606
  verification_failed: "ការផ្ទៀងផ្ទាត់បានបរាជ័យ"
607
607
  service_unavailable: "សេវាកម្មពេលនេះមិនមានការផ្ទៀងផ្ទាត់"
608
+ voting:
609
+ errors:
610
+ no_winners_confirmed: "មិនមានអ្នកឈ្នះត្រូវបានបញ្ជាក់"
611
+ all_contestants_must_be_ranked: "អ្នកចូលរួមទាំងអស់ដែលមិនត្រូវបានលុបចោលត្រូវតែមានចំណាត់ថ្នាក់"
608
612
 
data/config/routes.rb CHANGED
@@ -592,7 +592,7 @@ Spree::Core::Engine.add_routes do
592
592
  resources :assignments, controller: :show_person_assignments, only: %i[index]
593
593
  end
594
594
  resources :contestants, controller: :show_contestants, only: %i[show]
595
- resources :eliminated_contestants, controller: :eliminated_contestants, only: %i[index]
595
+ resources :elimination_sessions, controller: :show_elimination_sessions, only: %i[index]
596
596
  resources :free_vote_claims, only: :create
597
597
  end
598
598
 
@@ -0,0 +1,5 @@
1
+ class AddConfirmedRankToCmVotingContestants < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :cm_voting_contestants, :confirmed_rank, :integer, if_not_exists: true
4
+ end
5
+ end
@@ -100,5 +100,21 @@ FactoryBot.define do
100
100
  show_contestant { create(:cm_show_contestant, show: show) }
101
101
  voting_session { create(:cm_voting_session, episode: create(:cm_show_episode, event: show), show: show, vendor: show.vendor) }
102
102
  show_id { show.id }
103
+ eliminated { false }
104
+
105
+ trait :eliminated do
106
+ eliminated { true }
107
+ eliminated_via { :public_vote }
108
+ end
109
+
110
+ trait :eliminated_by_judges do
111
+ eliminated { true }
112
+ eliminated_via { :judges_deadlock }
113
+ end
114
+
115
+ trait :eliminated_by_coach do
116
+ eliminated { true }
117
+ eliminated_via { :coach_decision }
118
+ end
103
119
  end
104
120
  end
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '2.8.1.pre.pre.4'.freeze
2
+ VERSION = '2.8.2.pre.pre.1'.freeze
3
3
 
4
4
  module_function
5
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_cm_commissioner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.1.pre.pre.4
4
+ version: 2.8.2.pre.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-27 00:00:00.000000000 Z
11
+ date: 2026-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -1044,7 +1044,6 @@ files:
1044
1044
  - app/controllers/spree/api/v2/tenant/cms_pages_controller.rb
1045
1045
  - app/controllers/spree/api/v2/tenant/customer_notifications_controller.rb
1046
1046
  - app/controllers/spree/api/v2/tenant/dynamic_field_options_controller.rb
1047
- - app/controllers/spree/api/v2/tenant/eliminated_contestants_controller.rb
1048
1047
  - app/controllers/spree/api/v2/tenant/free_vote_claims_controller.rb
1049
1048
  - app/controllers/spree/api/v2/tenant/guests_controller.rb
1050
1049
  - app/controllers/spree/api/v2/tenant/homepage_sections_controller.rb
@@ -1069,6 +1068,7 @@ files:
1069
1068
  - app/controllers/spree/api/v2/tenant/routes_controller.rb
1070
1069
  - app/controllers/spree/api/v2/tenant/s3_signed_urls_controller.rb
1071
1070
  - app/controllers/spree/api/v2/tenant/show_contestants_controller.rb
1071
+ - app/controllers/spree/api/v2/tenant/show_elimination_sessions_controller.rb
1072
1072
  - app/controllers/spree/api/v2/tenant/show_people_controller.rb
1073
1073
  - app/controllers/spree/api/v2/tenant/show_person_assignments_controller.rb
1074
1074
  - app/controllers/spree/api/v2/tenant/shows_controller.rb
@@ -1442,6 +1442,7 @@ files:
1442
1442
  - app/models/concerns/spree_cm_commissioner/route_order_countable.rb
1443
1443
  - app/models/concerns/spree_cm_commissioner/route_type.rb
1444
1444
  - app/models/concerns/spree_cm_commissioner/service_calendar_type.rb
1445
+ - app/models/concerns/spree_cm_commissioner/service_origin.rb
1445
1446
  - app/models/concerns/spree_cm_commissioner/service_recommendations.rb
1446
1447
  - app/models/concerns/spree_cm_commissioner/service_type.rb
1447
1448
  - app/models/concerns/spree_cm_commissioner/store_metadata.rb
@@ -2285,6 +2286,7 @@ files:
2285
2286
  - app/services/spree_cm_commissioner/voting_credits/credit_calculator.rb
2286
2287
  - app/services/spree_cm_commissioner/voting_credits/de_allocate.rb
2287
2288
  - app/services/spree_cm_commissioner/voting_leaderboards/calculate_score.rb
2289
+ - app/services/spree_cm_commissioner/voting_sessions/finalize.rb
2288
2290
  - app/services/spree_cm_commissioner/waiting_room_system_metadata_fetcher.rb
2289
2291
  - app/services/spree_cm_commissioner/waiting_room_system_metadata_setter.rb
2290
2292
  - app/services/spree_cm_commissioner/webhooks/subscribers/handle_request_decorator.rb
@@ -3271,6 +3273,7 @@ files:
3271
3273
  - db/migrate/20260520000001_add_scoring_model_to_cm_voting_sessions.rb
3272
3274
  - db/migrate/20260520000001_optimize_cm_votes_indexes.rb
3273
3275
  - db/migrate/20260525042257_add_vote_number_to_cm_voting_contestants.rb
3276
+ - db/migrate/20260527035430_add_confirmed_rank_to_cm_voting_contestants.rb
3274
3277
  - db/migrate/20260527062005_add_eliminated_at_to_cm_show_contestants.rb
3275
3278
  - docker-compose.yml
3276
3279
  - docs/api/scoped-access-token-endpoints.md
@@ -1,19 +0,0 @@
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