spree_cm_commissioner 2.9.1.pre.pre3 → 2.9.1.pre.pre4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84c27f4187a23acbe9422e5b33cba6cca077dee5fe7a5e879acd3a5d06ee20c9
4
- data.tar.gz: e46311b9f88d5a32ddb2272506e99dc1aee786acf800163a833134d942705bc1
3
+ metadata.gz: ebefceb78297eb71b4dcb417b47de1c9440786f17942f341aa5cff394558b2aa
4
+ data.tar.gz: 4fae27019658db8352dd7001445b331355d7b20f321b079c211e4e87889789eb
5
5
  SHA512:
6
- metadata.gz: f679ac4607b2c7a6b01d6151605cd7339ff57ad721bb18708cff888362b4c19bb9b7f9847016b3e1f93fd0ce31a74635eb6635de83f6764b89873fc44aeb8d2e
7
- data.tar.gz: 0705c2ddb0b22a1bd2581645cfe18f2488b7aaf827ba90873130c782ac253fd95a50aa9795f982b863fc401744eb8654bc4c225caebec1af08965bab8144c72f
6
+ metadata.gz: ed1b54c40e5288bc4e04e467c978b531f80b49985e387e4ed5a65908dd9b8152fe024fd4dcfdadba2f279b385fc8250588b3cd674125abf4a4ddd4d0306560b1
7
+ data.tar.gz: 283fa4cceb6e50ef28eba6e0eb4ecbdba5ca2984a377009934d057606840ce101db088d4f766c8d37b623bff61fe5b030867c99540ea00e33ed3067c20a4c243
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.9.1.pre.pre3)
37
+ spree_cm_commissioner (2.9.1.pre.pre4)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -1,10 +1,18 @@
1
1
  module SpreeCmCommissioner
2
+ # A pricing-model assignment. A row is either:
3
+ # - route-scoped: trip_id NULL, keyed by route + O-D (unchanged legacy behaviour), or
4
+ # - trip-scoped: trip_id set, keyed by that specific trip + its own O-D (overrides route pricing
5
+ # for that trip only).
2
6
  class PricingModelRoute < Base
3
7
  belongs_to :route, class_name: 'SpreeCmCommissioner::Route'
8
+ belongs_to :trip, class_name: 'SpreeCmCommissioner::Trip', optional: true
4
9
  belongs_to :pricing_model, class_name: 'SpreeCmCommissioner::PricingModel'
5
10
  belongs_to :origin_place, class_name: 'SpreeCmCommissioner::Place'
6
11
  belongs_to :destination_place, class_name: 'SpreeCmCommissioner::Place'
7
12
 
13
+ scope :route_scoped, -> { where(trip_id: nil) }
14
+ scope :trip_scoped, -> { where.not(trip_id: nil) }
15
+
8
16
  scope :for_origin_destination, lambda { |origin_place_id, destination_place_id|
9
17
  where(origin_place_id: origin_place_id, destination_place_id: destination_place_id)
10
18
  }
@@ -52,6 +52,9 @@ module SpreeCmCommissioner
52
52
  has_many :trip_blazer_queries, as: :queryable, class_name: 'SpreeCmCommissioner::BlazerQueryable'
53
53
  has_many :blazer_queries, through: :trip_blazer_queries, source: :blazer_query, class_name: 'Blazer::Query'
54
54
 
55
+ has_many :pricing_model_routes, class_name: 'SpreeCmCommissioner::PricingModelRoute', dependent: :destroy
56
+ has_many :pricing_models, through: :pricing_model_routes, class_name: 'SpreeCmCommissioner::PricingModel'
57
+
55
58
  has_many :trip_stops, class_name: 'SpreeCmCommissioner::TripStop', dependent: :destroy
56
59
  has_many :boarding_trip_stops, -> { boarding.order('departure_time ASC NULLS LAST, id ASC') }, class_name: 'SpreeCmCommissioner::TripStop'
57
60
  has_many :drop_off_trip_stops, -> { drop_off.order('arrival_time ASC NULLS LAST') }, class_name: 'SpreeCmCommissioner::TripStop'
@@ -3,13 +3,13 @@ module SpreeCmCommissioner
3
3
  class CreateWithRuleGroups
4
4
  prepend ::Spree::ServiceModule::Base
5
5
 
6
- def call(vendor:, params:, route: nil, origin_place_id: nil, destination_place_id: nil)
6
+ def call(vendor:, params:, route: nil, trip: nil, origin_place_id: nil, destination_place_id: nil) # rubocop:disable Metrics/ParameterLists
7
7
  pricing_model = vendor.pricing_models.new(model_params(params))
8
8
 
9
9
  ApplicationRecord.transaction do
10
10
  pricing_model.save!
11
11
  build_rule_groups(pricing_model, params[:rule_groups])
12
- create_route_assignment(pricing_model, route, origin_place_id, destination_place_id) if route.present?
12
+ create_route_assignment(pricing_model, route, trip, origin_place_id, destination_place_id) if route.present?
13
13
  end
14
14
 
15
15
  success(pricing_model)
@@ -41,11 +41,17 @@ module SpreeCmCommissioner
41
41
  end
42
42
  end
43
43
 
44
- def create_route_assignment(pricing_model, route, origin_place_id, destination_place_id)
44
+ # A row is trip-scoped when a trip is given (overrides route pricing for that trip);
45
+ # otherwise route-scoped (unchanged legacy behaviour). Trip-scoped rows take their O-D from
46
+ # the trip so they match the trip's own journey at resolution time.
47
+ def create_route_assignment(pricing_model, route, trip, origin_place_id, destination_place_id)
48
+ origin_place_id = trip.origin_place_id if trip.present?
49
+ destination_place_id = trip.destination_place_id if trip.present?
45
50
  return unless origin_place_id.present? && destination_place_id.present?
46
51
 
47
52
  PricingModelRoute.create!(
48
53
  route: route,
54
+ trip: trip,
49
55
  pricing_model: pricing_model,
50
56
  origin_place_id: origin_place_id,
51
57
  destination_place_id: destination_place_id
@@ -39,29 +39,72 @@ module SpreeCmCommissioner
39
39
  end
40
40
 
41
41
  def find_pricing_models(group_contexts)
42
- route_pricing_models(group_contexts) + variant_pricing_models(group_contexts)
42
+ transit_pricing_models(group_contexts) + variant_pricing_models(group_contexts)
43
43
  end
44
44
 
45
- def route_pricing_models(group_contexts)
45
+ # Trip-level pricing overrides route-level pricing for the same journey; route pricing
46
+ # is the fallback when the trip (or connected journey's parent trip) has none assigned.
47
+ def transit_pricing_models(group_contexts)
46
48
  transit_contexts = group_contexts.select { |ctx| ctx.trip_id.present? }
47
49
  return [] if transit_contexts.blank?
48
50
 
49
51
  origin_place_id, destination_place_id = determine_origin_destination(transit_contexts)
50
52
  return [] if origin_place_id.blank? || destination_place_id.blank?
51
53
 
52
- vendor_ids = transit_contexts.map { |ctx| variant_vendor_id(ctx.variant_id) }.compact.uniq
54
+ vendor_ids = transit_vendor_ids(transit_contexts)
53
55
  return [] if vendor_ids.blank?
54
56
 
55
- route_ids = trip_route_ids(transit_contexts)
57
+ trip_level_pricing_models(
58
+ trip_ids: trip_candidate_ids(transit_contexts),
59
+ origin_place_id: origin_place_id,
60
+ destination_place_id: destination_place_id,
61
+ vendor_ids: vendor_ids
62
+ ).presence || route_level_pricing_models(
63
+ route_ids: trip_route_ids(transit_contexts),
64
+ origin_place_id: origin_place_id,
65
+ destination_place_id: destination_place_id,
66
+ vendor_ids: vendor_ids
67
+ )
68
+ end
69
+
70
+ def trip_level_pricing_models(trip_ids:, origin_place_id:, destination_place_id:, vendor_ids:)
71
+ return [] if trip_ids.empty?
56
72
 
57
73
  scope = SpreeCmCommissioner::PricingModelRoute
58
74
  .active
75
+ .trip_scoped
76
+ .where(trip_id: trip_ids)
59
77
  .for_origin_destination(origin_place_id, destination_place_id)
60
- .includes(:pricing_model)
61
78
 
79
+ pricing_models_for(scope, vendor_ids)
80
+ end
81
+
82
+ def route_level_pricing_models(route_ids:, origin_place_id:, destination_place_id:, vendor_ids:)
83
+ scope = SpreeCmCommissioner::PricingModelRoute
84
+ .active
85
+ .route_scoped
86
+ .for_origin_destination(origin_place_id, destination_place_id)
62
87
  scope = scope.where(route_id: route_ids) if route_ids.any?
63
88
 
64
- scope.map(&:pricing_model).select { |pm| vendor_ids.include?(pm.vendor_id) }
89
+ pricing_models_for(scope, vendor_ids)
90
+ end
91
+
92
+ # Resolves a PricingModelRoute scope into its pricing models, restricted to vendors
93
+ # actually present among the line items being priced.
94
+ def pricing_models_for(scope, vendor_ids)
95
+ scope.includes(:pricing_model).map(&:pricing_model).select { |pm| vendor_ids.include?(pm.vendor_id) }
96
+ end
97
+
98
+ # A booking's legs can each have their own trip-level price, and a connected journey
99
+ # (multiple legs sharing connected_trip_id) can also have its own price on the shared
100
+ # parent trip. This returns every trip id worth checking for either case.
101
+ def trip_candidate_ids(transit_contexts)
102
+ connected_trip_id = Integer(transit_contexts.first&.connected_trip_id.to_s, exception: false)
103
+ (transit_contexts.map(&:trip_id) + [connected_trip_id]).compact.uniq
104
+ end
105
+
106
+ def transit_vendor_ids(transit_contexts)
107
+ transit_contexts.map { |ctx| variant_vendor_id(ctx.variant_id) }.compact.uniq
65
108
  end
66
109
 
67
110
  def variant_pricing_models(group_contexts)
@@ -3,11 +3,11 @@ module SpreeCmCommissioner
3
3
  class UpdateWithRuleGroups
4
4
  prepend ::Spree::ServiceModule::Base
5
5
 
6
- def call(pricing_model:, params:, route: nil, origin_place_id: nil, destination_place_id: nil)
6
+ def call(pricing_model:, params:, route: nil, trip: nil, origin_place_id: nil, destination_place_id: nil) # rubocop:disable Metrics/ParameterLists
7
7
  ApplicationRecord.transaction do
8
8
  pricing_model.update!(model_params(params))
9
9
  sync_rule_groups(pricing_model, params[:rule_groups])
10
- update_route_assignment(pricing_model, route, origin_place_id, destination_place_id) if route.present?
10
+ update_route_assignment(pricing_model, route, trip, origin_place_id, destination_place_id) if route.present?
11
11
  end
12
12
 
13
13
  success(pricing_model)
@@ -47,14 +47,17 @@ module SpreeCmCommissioner
47
47
  end
48
48
  end
49
49
 
50
- def update_route_assignment(pricing_model, route, origin_place_id, destination_place_id)
50
+ # Each pricing model created via this flow has a single assignment row; update it in place so
51
+ # the assigned trip (and O-D) can be changed on edit. Trip-scoped rows take O-D from the trip.
52
+ def update_route_assignment(pricing_model, route, trip, origin_place_id, destination_place_id)
53
+ origin_place_id = trip.origin_place_id if trip.present?
54
+ destination_place_id = trip.destination_place_id if trip.present?
51
55
  return unless origin_place_id.present? && destination_place_id.present?
52
56
 
53
- route_assignment = PricingModelRoute.find_or_initialize_by(
54
- route: route,
55
- pricing_model: pricing_model
56
- )
57
+ route_assignment = PricingModelRoute.find_or_initialize_by(pricing_model: pricing_model)
57
58
  route_assignment.update!(
59
+ route: route,
60
+ trip: trip,
58
61
  origin_place_id: origin_place_id,
59
62
  destination_place_id: destination_place_id
60
63
  )
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ class AddTripToCmPricingModelRoutes < ActiveRecord::Migration[7.0]
3
+ def change
4
+ add_reference :cm_pricing_model_routes, :trip, null: true,
5
+ foreign_key: { to_table: :cm_trips }, index: true
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ FactoryBot.define do
2
+ # A trip-scoped PricingModelRoute row — overrides route pricing for one specific trip.
3
+ # origin/destination default to the trip's own O-D (mirrors how trip pricing is resolved).
4
+ factory :cm_pricing_model_trip, class: 'SpreeCmCommissioner::PricingModelRoute' do
5
+ association :pricing_model, factory: :cm_pricing_model
6
+ association :trip, factory: :cm_trip
7
+ route { trip.route || create(:cm_route, origin_place: trip.origin_place, destination_place: trip.destination_place) }
8
+ origin_place { trip.origin_place }
9
+ destination_place { trip.destination_place }
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '2.9.1.pre.pre3'.freeze
2
+ VERSION = '2.9.1.pre.pre4'.freeze
3
3
 
4
4
  module_function
5
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_cm_commissioner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.1.pre.pre3
4
+ version: 2.9.1.pre.pre4
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
@@ -3410,6 +3410,7 @@ files:
3410
3410
  - db/migrate/20260623082233_create_cm_claims.rb
3411
3411
  - db/migrate/20260624175658_add_unique_index_to_cm_claims.rb
3412
3412
  - db/migrate/20260629000001_add_term_of_use_to_spree_vendors.rb
3413
+ - db/migrate/20260630000001_add_trip_to_cm_pricing_model_routes.rb
3413
3414
  - db/migrate/20260701000001_add_device_info_to_cm_waiting_room_sessions.rb
3414
3415
  - db/migrate/20260703065239_add_position_to_cm_voting_contestants.rb
3415
3416
  - docker-compose.yml
@@ -3510,6 +3511,7 @@ files:
3510
3511
  - lib/spree_cm_commissioner/test_helper/factories/pricing_action_factory.rb
3511
3512
  - lib/spree_cm_commissioner/test_helper/factories/pricing_model_factory.rb
3512
3513
  - lib/spree_cm_commissioner/test_helper/factories/pricing_model_route_factory.rb
3514
+ - lib/spree_cm_commissioner/test_helper/factories/pricing_model_trip_factory.rb
3513
3515
  - lib/spree_cm_commissioner/test_helper/factories/pricing_model_variant_factory.rb
3514
3516
  - lib/spree_cm_commissioner/test_helper/factories/pricing_rule_factory.rb
3515
3517
  - lib/spree_cm_commissioner/test_helper/factories/pricing_rule_group_factory.rb