spree_cm_commissioner 2.8.2 → 2.8.3.pre.pre1
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 +4 -4
- data/Gemfile.lock +1 -1
- data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +6 -3
- data/app/factory/spree_cm_commissioner/order_telegram_message_factory.rb +31 -17
- data/app/factory/spree_cm_commissioner/telegram_message_factory.rb +6 -0
- data/app/interactors/spree_cm_commissioner/invalidate_cache_request.rb +5 -1
- data/app/jobs/spree_cm_commissioner/invalidate_cache_request_job.rb +4 -1
- data/app/jobs/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_job.rb +4 -2
- data/app/jobs/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_on_hold_job.rb +4 -2
- data/app/jobs/spree_cm_commissioner/route_metrics/decrease_trip_count_job.rb +8 -2
- data/app/jobs/spree_cm_commissioner/route_metrics/increase_trip_count_job.rb +5 -2
- data/app/models/spree_cm_commissioner/order_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/trip.rb +10 -2
- data/app/queries/spree_cm_commissioner/multi_leg_trips_query.rb +22 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/amenity_serializer.rb +3 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_query_result_serializer.rb +1 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_result_serializer.rb +1 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_vehicle_type_serializer.rb +6 -3
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_vendor_serializer.rb +6 -2
- data/app/services/spree_cm_commissioner/inventory_holds/acquire.rb +3 -0
- data/app/services/spree_cm_commissioner/inventory_holds/convert.rb +7 -2
- data/app/services/spree_cm_commissioner/inventory_holds/release.rb +7 -2
- data/app/services/spree_cm_commissioner/inventory_items/bulk_adjust_quantities.rb +36 -4
- data/app/services/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_on_hold.rb +39 -4
- data/app/services/spree_cm_commissioner/inventory_items/bulk_generate_permanent_items.rb +4 -6
- data/app/services/spree_cm_commissioner/oauth_access_tokens/cleanup_expired.rb +13 -7
- data/app/services/spree_cm_commissioner/redis_stock/base.rb +2 -1
- data/app/services/spree_cm_commissioner/route_metrics/decrease_trip_count.rb +3 -15
- data/app/services/spree_cm_commissioner/route_metrics/increase_trip_count.rb +7 -15
- data/app/services/spree_cm_commissioner/transit_order/create.rb +8 -2
- data/app/views/spree/admin/line_items/_form.html.erb +2 -3
- data/lib/spree_cm_commissioner/trip_query_result.rb +25 -1
- data/lib/spree_cm_commissioner/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6113b7370f204cdd539916ac0e1881763beec50c577ba5973160f10941015f99
|
|
4
|
+
data.tar.gz: 356ebf217c53946872067544869cec5695e063df4092ae8b05d3c5e6a5dbef4e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d99e1e40d83080a9487bc6929fedb7f3f0e2e847635fde43f5b96479e0f19386e17357e0bb798dae74f3302429e166d851a0247ab5b0c1a49bb62e38fc83a29f
|
|
7
|
+
data.tar.gz: 1560f7edd9efb1eb30351da6a44081f4eee124be109351d835631b0b1f82db176de3a8d4cdfa1112d1f2c96be55f7268dfa6a2c5ec617864146ecea5cd5d1c8b
|
data/Gemfile.lock
CHANGED
|
@@ -64,8 +64,7 @@ module Spree
|
|
|
64
64
|
'trips.vendor',
|
|
65
65
|
'trips.vendor.logo',
|
|
66
66
|
'trips.vehicle_type',
|
|
67
|
-
'trips.vehicle_type.vehicle_photos'
|
|
68
|
-
'trips.amenities'
|
|
67
|
+
'trips.vehicle_type.vehicle_photos'
|
|
69
68
|
]
|
|
70
69
|
end
|
|
71
70
|
|
|
@@ -99,7 +98,11 @@ module Spree
|
|
|
99
98
|
|
|
100
99
|
# override
|
|
101
100
|
def serializer_params
|
|
102
|
-
|
|
101
|
+
super.merge(
|
|
102
|
+
exclude_vendor_kind_option_types: true,
|
|
103
|
+
exclude_vendor_kind_option_values: true,
|
|
104
|
+
exclude_vehicle_type_amenities: true
|
|
105
|
+
)
|
|
103
106
|
end
|
|
104
107
|
|
|
105
108
|
# override
|
|
@@ -48,7 +48,7 @@ module SpreeCmCommissioner
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
def line_item_content(line_item)
|
|
51
|
-
return
|
|
51
|
+
return transit_line_item_content(line_item) if line_item.transit?
|
|
52
52
|
|
|
53
53
|
text = []
|
|
54
54
|
|
|
@@ -64,8 +64,8 @@ module SpreeCmCommissioner
|
|
|
64
64
|
def pretty_date_for(line_item)
|
|
65
65
|
return nil unless line_item.date_present?
|
|
66
66
|
|
|
67
|
-
from_date =
|
|
68
|
-
to_date =
|
|
67
|
+
from_date = pretty_datetime(line_item.from_date)
|
|
68
|
+
to_date = pretty_datetime(line_item.to_date)
|
|
69
69
|
|
|
70
70
|
if from_date == to_date
|
|
71
71
|
"🗓️ #{from_date}"
|
|
@@ -84,7 +84,7 @@ module SpreeCmCommissioner
|
|
|
84
84
|
text << "Email: #{inline_code(order.email)}" if order.email.present?
|
|
85
85
|
text << "Delivery Address: #{formatted_shipping_address.presence || 'N/A'}" if order.delivery_required?
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
append_transit_footer(text) if transit_order?
|
|
88
88
|
|
|
89
89
|
if show_details_link && order.guests.any?
|
|
90
90
|
text << ''
|
|
@@ -132,12 +132,12 @@ module SpreeCmCommissioner
|
|
|
132
132
|
|
|
133
133
|
private
|
|
134
134
|
|
|
135
|
-
def
|
|
136
|
-
|
|
135
|
+
def transit_order?
|
|
136
|
+
selected_line_items.any?(&:transit?)
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
def intercity_taxi_order?
|
|
140
|
-
selected_line_items.any? { |li|
|
|
140
|
+
selected_line_items.any? { |li| trip_for(li)&.intercity_taxi? }
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
def trip_for(line_item)
|
|
@@ -147,10 +147,10 @@ module SpreeCmCommissioner
|
|
|
147
147
|
@trip_cache[line_item.trip_id] ||= SpreeCmCommissioner::Trip.find_by(id: line_item.trip_id)
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
def
|
|
150
|
+
def transit_line_item_content(line_item)
|
|
151
151
|
text = []
|
|
152
|
-
route_text =
|
|
153
|
-
departure_text =
|
|
152
|
+
route_text = transit_route_text(line_item)
|
|
153
|
+
departure_text = transit_departure_text(line_item)
|
|
154
154
|
text << bold('🚗 Trip Details')
|
|
155
155
|
text << "Route: #{route_text}" if route_text.present?
|
|
156
156
|
text << "Passengers: #{line_item.passenger_count || line_item.quantity}"
|
|
@@ -159,7 +159,7 @@ module SpreeCmCommissioner
|
|
|
159
159
|
text.compact.join("\n")
|
|
160
160
|
end
|
|
161
161
|
|
|
162
|
-
def
|
|
162
|
+
def transit_route_text(line_item)
|
|
163
163
|
trip = trip_for(line_item)
|
|
164
164
|
return line_item.product.name if trip.blank?
|
|
165
165
|
|
|
@@ -171,21 +171,35 @@ module SpreeCmCommissioner
|
|
|
171
171
|
vehicle.present? ? "#{parts} (#{vehicle})" : parts
|
|
172
172
|
end
|
|
173
173
|
|
|
174
|
-
def
|
|
174
|
+
def transit_departure_text(line_item)
|
|
175
175
|
return nil unless line_item.date_present?
|
|
176
176
|
|
|
177
177
|
line_item.from_date.strftime('%b %d, %Y · %H:%M')
|
|
178
178
|
end
|
|
179
179
|
|
|
180
180
|
def nationality_text
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
grouped = order.saved_guests.group_by { |sg| sg.nationality_group&.humanize }
|
|
182
|
+
grouped.delete(nil)
|
|
183
|
+
return nil if grouped.empty?
|
|
183
184
|
|
|
184
|
-
|
|
185
|
+
grouped.map { |nationality_group, guests| customer_type_summary(nationality_group, guests) }.join(', ')
|
|
185
186
|
end
|
|
186
187
|
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
# e.g. "Local (Adult x1, Child x1)". age_group is NOT NULL, so it is always present.
|
|
189
|
+
def customer_type_summary(nationality_group, guests)
|
|
190
|
+
age_breakdown = guests
|
|
191
|
+
.group_by { |sg| sg.age_group.humanize }
|
|
192
|
+
.map { |age_group, age_guests| "#{age_group} x#{age_guests.count}" }
|
|
193
|
+
.join(', ')
|
|
194
|
+
|
|
195
|
+
"#{nationality_group} (#{age_breakdown})"
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def append_transit_footer(text)
|
|
199
|
+
nationality = nationality_text
|
|
200
|
+
text << "Nationality: #{nationality}" if nationality.present?
|
|
201
|
+
|
|
202
|
+
return unless intercity_taxi_order?
|
|
189
203
|
|
|
190
204
|
pickup = selected_line_items.filter_map(&:pickup_map_place).first
|
|
191
205
|
dropoff = selected_line_items.filter_map(&:dropoff_map_place).first
|
|
@@ -19,13 +19,17 @@ module SpreeCmCommissioner
|
|
|
19
19
|
context.response = client.create_invalidation(
|
|
20
20
|
distribution_id: ENV.fetch('ASSETS_SYNC_CF_DIST_ID'),
|
|
21
21
|
invalidation_batch: {
|
|
22
|
-
|
|
22
|
+
# Must be globally unique per distribution,
|
|
23
|
+
# Time.now.to_i collides when multiple jobs fire in the same second.
|
|
24
|
+
caller_reference: SecureRandom.uuid,
|
|
23
25
|
paths: {
|
|
24
26
|
quantity: patterns.size,
|
|
25
27
|
items: patterns
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
)
|
|
31
|
+
rescue Aws::CloudFront::Errors::TooManyInvalidationsInProgress => e
|
|
32
|
+
context.fail!(message: "Too many invalidations in progress: #{e}")
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
end
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
class InvalidateCacheRequestJob < ApplicationUniqueJob
|
|
3
|
+
queue_as :cache_invalidation
|
|
4
|
+
|
|
3
5
|
def perform(options = {})
|
|
4
|
-
SpreeCmCommissioner::InvalidateCacheRequest.call(patterns: options[:patterns])
|
|
6
|
+
result = SpreeCmCommissioner::InvalidateCacheRequest.call(patterns: options[:patterns])
|
|
7
|
+
raise result.error if result.failure?
|
|
5
8
|
end
|
|
6
9
|
end
|
|
7
10
|
end
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
module InventoryItems
|
|
3
3
|
class BulkAdjustQuantitiesJob < ApplicationUniqueJob
|
|
4
|
-
# :line_item_ids, :inventory_id_and_quantities
|
|
4
|
+
# :line_item_ids, :inventory_id_and_quantities, :caller_source
|
|
5
5
|
#
|
|
6
6
|
# :line_item_ids is included for unique job key generation to prevent duplicate jobs,
|
|
7
7
|
# though it's not used in the perform method implementation.
|
|
8
|
+
# :caller_source is a string like "ClassName#method" identifying who enqueued the job.
|
|
8
9
|
def perform(options = {})
|
|
9
10
|
SpreeCmCommissioner::InventoryItems::BulkAdjustQuantities.call!(
|
|
10
|
-
inventory_id_and_quantities: options[:inventory_id_and_quantities]
|
|
11
|
+
inventory_id_and_quantities: options[:inventory_id_and_quantities],
|
|
12
|
+
caller_source: options[:caller_source]
|
|
11
13
|
)
|
|
12
14
|
end
|
|
13
15
|
end
|
|
@@ -3,16 +3,18 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class BulkAdjustQuantitiesOnHoldJob < ApplicationUniqueJob
|
|
4
4
|
queue_as :default
|
|
5
5
|
|
|
6
|
-
# :order_id, :inventory_id_and_quantities
|
|
6
|
+
# :order_id, :inventory_id_and_quantities, :caller_source
|
|
7
7
|
#
|
|
8
8
|
# :order_id is included for unique job key generation to prevent duplicate jobs,
|
|
9
9
|
# though it's not used in the perform method implementation.
|
|
10
|
+
# :caller_source is a string like "ClassName#method" identifying who enqueued the job.
|
|
10
11
|
def perform(options = {})
|
|
11
12
|
raise ArgumentError, 'order_id is required' if options[:order_id].blank?
|
|
12
13
|
raise ArgumentError, 'inventory_id_and_quantities is required' if options[:inventory_id_and_quantities].blank?
|
|
13
14
|
|
|
14
15
|
SpreeCmCommissioner::InventoryItems::BulkAdjustQuantitiesOnHold.call(
|
|
15
|
-
inventory_id_and_quantities: options[:inventory_id_and_quantities]
|
|
16
|
+
inventory_id_and_quantities: options[:inventory_id_and_quantities],
|
|
17
|
+
caller_source: options[:caller_source]
|
|
16
18
|
)
|
|
17
19
|
end
|
|
18
20
|
end
|
|
@@ -2,8 +2,14 @@ module SpreeCmCommissioner
|
|
|
2
2
|
module RouteMetrics
|
|
3
3
|
class DecreaseTripCountJob < ApplicationUniqueJob
|
|
4
4
|
def perform(options = {})
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
route_metric = SpreeCmCommissioner::RouteMetric.find_by(
|
|
6
|
+
origin_place_id: options[:origin_place_id],
|
|
7
|
+
destination_place_id: options[:destination_place_id],
|
|
8
|
+
route_type: options[:route_type]
|
|
9
|
+
)
|
|
10
|
+
return if route_metric.nil?
|
|
11
|
+
|
|
12
|
+
SpreeCmCommissioner::RouteMetrics::DecreaseTripCount.call(route_metric: route_metric)
|
|
7
13
|
end
|
|
8
14
|
end
|
|
9
15
|
end
|
|
@@ -2,8 +2,11 @@ module SpreeCmCommissioner
|
|
|
2
2
|
module RouteMetrics
|
|
3
3
|
class IncreaseTripCountJob < ApplicationUniqueJob
|
|
4
4
|
def perform(options = {})
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
SpreeCmCommissioner::RouteMetrics::IncreaseTripCount.call(
|
|
6
|
+
origin_place_id: options[:origin_place_id],
|
|
7
|
+
destination_place_id: options[:destination_place_id],
|
|
8
|
+
route_type: options[:route_type]
|
|
9
|
+
)
|
|
7
10
|
end
|
|
8
11
|
end
|
|
9
12
|
end
|
|
@@ -34,6 +34,7 @@ module SpreeCmCommissioner
|
|
|
34
34
|
base.has_many :guests, through: :line_items, class_name: 'SpreeCmCommissioner::Guest'
|
|
35
35
|
|
|
36
36
|
base.has_many :saved_guests,
|
|
37
|
+
-> { reorder(nil).distinct },
|
|
37
38
|
through: :guests,
|
|
38
39
|
source: :saved_guest,
|
|
39
40
|
class_name: 'SpreeCmCommissioner::SavedGuest'
|
|
@@ -162,11 +162,19 @@ module SpreeCmCommissioner
|
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
def increment_route_metric_trip_count
|
|
165
|
-
SpreeCmCommissioner::RouteMetrics::IncreaseTripCountJob.perform_later(
|
|
165
|
+
SpreeCmCommissioner::RouteMetrics::IncreaseTripCountJob.perform_later(
|
|
166
|
+
origin_place_id: origin_place_id,
|
|
167
|
+
destination_place_id: destination_place_id,
|
|
168
|
+
route_type: route_type
|
|
169
|
+
)
|
|
166
170
|
end
|
|
167
171
|
|
|
168
172
|
def decrement_route_metric_trip_count
|
|
169
|
-
SpreeCmCommissioner::RouteMetrics::DecreaseTripCountJob.perform_later(
|
|
173
|
+
SpreeCmCommissioner::RouteMetrics::DecreaseTripCountJob.perform_later(
|
|
174
|
+
origin_place_id: origin_place_id,
|
|
175
|
+
destination_place_id: destination_place_id,
|
|
176
|
+
route_type: route_type
|
|
177
|
+
)
|
|
170
178
|
end
|
|
171
179
|
|
|
172
180
|
def update_route_price_range
|
|
@@ -56,6 +56,8 @@ module SpreeCmCommissioner
|
|
|
56
56
|
return [] if trip_legs.empty?
|
|
57
57
|
|
|
58
58
|
legs_by_parent = group_legs(trip_legs: trip_legs)
|
|
59
|
+
legs_by_parent = filter_complete_parents(legs_by_parent)
|
|
60
|
+
return [] if legs_by_parent.empty?
|
|
59
61
|
|
|
60
62
|
leg_ids = legs_by_parent.values.flatten.uniq
|
|
61
63
|
legs_by_id = preload_leg_trips(leg_ids: leg_ids)
|
|
@@ -159,6 +161,26 @@ module SpreeCmCommissioner
|
|
|
159
161
|
.having('SUM(cm_inventory_items.quantity_available) >= ?', number_of_guests)
|
|
160
162
|
end
|
|
161
163
|
|
|
164
|
+
# Discards parent trips whose found-leg count doesn't match their total leg count.
|
|
165
|
+
# This handles the case where one leg lacks sufficient inventory — the parent would
|
|
166
|
+
# otherwise be returned with only the legs that passed the HAVING filter, producing
|
|
167
|
+
# a partial (incorrect) multi-leg result.
|
|
168
|
+
#
|
|
169
|
+
# @return [Hash] { parent_trip_id => [leg_ids] } with incomplete parents removed
|
|
170
|
+
def filter_complete_parents(legs_by_parent)
|
|
171
|
+
parent_ids = legs_by_parent.keys
|
|
172
|
+
total_leg_counts = SpreeCmCommissioner::TripStop
|
|
173
|
+
.where(trip_id: parent_ids)
|
|
174
|
+
.where.not(board_to_trip_id: nil)
|
|
175
|
+
.group(:trip_id)
|
|
176
|
+
.count('DISTINCT board_to_trip_id')
|
|
177
|
+
|
|
178
|
+
legs_by_parent.select do |parent_id, leg_ids|
|
|
179
|
+
total = total_leg_counts[parent_id].to_i
|
|
180
|
+
total.positive? && leg_ids.size == total
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
162
184
|
# @return [Hash] { parent_trip_id => [leg_ids] }
|
|
163
185
|
def group_legs(trip_legs:)
|
|
164
186
|
trip_legs.group_by(&:parent_trip_id).transform_values { |r| r.map(&:leg_id).uniq }
|
|
@@ -3,12 +3,15 @@ module SpreeCmCommissioner
|
|
|
3
3
|
module Storefront
|
|
4
4
|
class AmenitySerializer < BaseSerializer
|
|
5
5
|
set_type :amenity
|
|
6
|
+
|
|
6
7
|
attributes :name, :presentation
|
|
7
8
|
attribute :display_icon do |option_value|
|
|
8
9
|
::ActionController::Base.helpers.image_url(option_value.display_icon)
|
|
9
10
|
rescue StandardError
|
|
10
11
|
nil
|
|
11
12
|
end
|
|
13
|
+
|
|
14
|
+
has_one :option_type, serializer: ::Spree::V2::Storefront::OptionTypeSerializer
|
|
12
15
|
end
|
|
13
16
|
end
|
|
14
17
|
end
|
|
@@ -4,7 +4,7 @@ module SpreeCmCommissioner
|
|
|
4
4
|
class TripQueryResultSerializer < BaseSerializer
|
|
5
5
|
set_type :trip_query_result
|
|
6
6
|
|
|
7
|
-
attributes :quantity_available, :max_capacity
|
|
7
|
+
attributes :quantity_available, :max_capacity, :price, :compare_at_price, :currency, :display_price, :display_compare_at_price
|
|
8
8
|
|
|
9
9
|
attribute :direct, &:direct?
|
|
10
10
|
has_many :trips, serializer: ::SpreeCmCommissioner::V2::Storefront::TripResultSerializer
|
|
@@ -24,9 +24,9 @@ module SpreeCmCommissioner
|
|
|
24
24
|
|
|
25
25
|
attribute :duration_in_hms, &:duration_in_hms
|
|
26
26
|
attribute :arrival_time, &:arrival_time
|
|
27
|
+
|
|
27
28
|
belongs_to :vendor, serializer: ::SpreeCmCommissioner::V2::Storefront::TripVendorSerializer
|
|
28
29
|
belongs_to :vehicle_type, serializer: ::SpreeCmCommissioner::V2::Storefront::TripVehicleTypeSerializer
|
|
29
|
-
has_many :amenities, serializer: ::SpreeCmCommissioner::V2::Storefront::AmenitySerializer
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -5,9 +5,12 @@ module SpreeCmCommissioner
|
|
|
5
5
|
attributes :id, :name, :kind, :number_of_seats
|
|
6
6
|
|
|
7
7
|
has_many :vehicle_photos, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
|
|
8
|
-
|
|
9
|
-
has_many :option_types, serializer: ::Spree::V2::Storefront::OptionTypeSerializer
|
|
10
|
-
|
|
8
|
+
|
|
9
|
+
has_many :option_types, serializer: ::Spree::V2::Storefront::OptionTypeSerializer
|
|
10
|
+
|
|
11
|
+
# Included by default. Excluded ONLY when param is explicitly true or "true".
|
|
12
|
+
has_many :amenities, serializer: ::SpreeCmCommissioner::V2::Storefront::AmenitySerializer,
|
|
13
|
+
if: proc { |_, params| !params || params[:exclude_vehicle_type_amenities].to_s != 'true' }
|
|
11
14
|
end
|
|
12
15
|
end
|
|
13
16
|
end
|
|
@@ -8,8 +8,12 @@ module SpreeCmCommissioner
|
|
|
8
8
|
|
|
9
9
|
has_one :logo, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
has_many :
|
|
11
|
+
# Included by default. Excluded ONLY when param is explicitly true or "true".
|
|
12
|
+
has_many :vendor_kind_option_types, serializer: ::Spree::V2::Storefront::OptionTypeSerializer,
|
|
13
|
+
if: proc { |_, params| !params || params[:exclude_vendor_kind_option_types].to_s != 'true' }
|
|
14
|
+
|
|
15
|
+
has_many :vendor_kind_option_values, serializer: ::Spree::V2::Storefront::OptionValueSerializer,
|
|
16
|
+
if: proc { |_, params| !params || params[:exclude_vendor_kind_option_values].to_s != 'true' }
|
|
13
17
|
end
|
|
14
18
|
end
|
|
15
19
|
end
|
|
@@ -144,8 +144,11 @@ module SpreeCmCommissioner
|
|
|
144
144
|
end
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
+
return if inventory_id_and_quantities.blank?
|
|
148
|
+
|
|
147
149
|
SpreeCmCommissioner::InventoryItems::BulkAdjustQuantitiesOnHoldJob.perform_later(
|
|
148
150
|
order_id: order.id,
|
|
151
|
+
caller_source: "#{self.class.name}#enqueue_sync_inventory_on_hold",
|
|
149
152
|
inventory_id_and_quantities: inventory_id_and_quantities
|
|
150
153
|
)
|
|
151
154
|
end
|
|
@@ -36,7 +36,8 @@ module SpreeCmCommissioner
|
|
|
36
36
|
order.line_items.each do |li|
|
|
37
37
|
next unless li.should_hold_inventory?
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
# Skip .active scope: holds on past-dated items must also be cleared (e.g. delayed conversion after trip date).
|
|
40
|
+
li.inventory_items.each do |item|
|
|
40
41
|
keys << item.redis_hold_key
|
|
41
42
|
quantities << li.quantity
|
|
42
43
|
inventory_items << item
|
|
@@ -68,7 +69,8 @@ module SpreeCmCommissioner
|
|
|
68
69
|
inventory_id_and_quantities = order.line_items.flat_map do |line_item|
|
|
69
70
|
next [] unless line_item.should_hold_inventory?
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
# Skip .active scope for the same reason as clear_hold_redis!.
|
|
73
|
+
line_item.inventory_items.map do |inventory_item|
|
|
72
74
|
{
|
|
73
75
|
inventory_id: inventory_item.id,
|
|
74
76
|
quantity: -line_item.quantity
|
|
@@ -76,8 +78,11 @@ module SpreeCmCommissioner
|
|
|
76
78
|
end
|
|
77
79
|
end
|
|
78
80
|
|
|
81
|
+
return if inventory_id_and_quantities.blank?
|
|
82
|
+
|
|
79
83
|
SpreeCmCommissioner::InventoryItems::BulkAdjustQuantitiesOnHoldJob.perform_later(
|
|
80
84
|
order_id: order.id,
|
|
85
|
+
caller_source: "#{self.class.name}#enqueue_sync_inventory_on_hold",
|
|
81
86
|
inventory_id_and_quantities: inventory_id_and_quantities
|
|
82
87
|
)
|
|
83
88
|
end
|
|
@@ -64,7 +64,8 @@ module SpreeCmCommissioner
|
|
|
64
64
|
order.line_items.includes(:variant).find_each do |li|
|
|
65
65
|
next unless li.should_hold_inventory?
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
# Skip .active scope: holds on past-dated items must also be released (e.g. delayed job fires after trip date).
|
|
68
|
+
li.inventory_items.each do |item|
|
|
68
69
|
keys << item.redis_hold_key
|
|
69
70
|
quantities << li.quantity
|
|
70
71
|
inventory_items << item
|
|
@@ -82,7 +83,8 @@ module SpreeCmCommissioner
|
|
|
82
83
|
inventory_id_and_quantities = order.line_items.flat_map do |line_item|
|
|
83
84
|
next [] unless line_item.should_hold_inventory?
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
# Skip .active scope for the same reason as hold_keys_and_quantities.
|
|
87
|
+
line_item.inventory_items.map do |inventory_item|
|
|
86
88
|
{
|
|
87
89
|
inventory_id: inventory_item.id,
|
|
88
90
|
quantity: -line_item.quantity
|
|
@@ -90,8 +92,11 @@ module SpreeCmCommissioner
|
|
|
90
92
|
end
|
|
91
93
|
end
|
|
92
94
|
|
|
95
|
+
return if inventory_id_and_quantities.blank?
|
|
96
|
+
|
|
93
97
|
SpreeCmCommissioner::InventoryItems::BulkAdjustQuantitiesOnHoldJob.perform_later(
|
|
94
98
|
order_id: order.id,
|
|
99
|
+
caller_source: "#{self.class.name}#enqueue_sync_inventory_on_hold",
|
|
95
100
|
inventory_id_and_quantities: inventory_id_and_quantities
|
|
96
101
|
)
|
|
97
102
|
end
|
|
@@ -4,12 +4,17 @@ module SpreeCmCommissioner
|
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
extend SpreeCmCommissioner::ServiceModuleThrowable
|
|
6
6
|
|
|
7
|
-
def call(inventory_id_and_quantities:)
|
|
7
|
+
def call(inventory_id_and_quantities:, caller_source: nil)
|
|
8
|
+
CmAppLogger.log(
|
|
9
|
+
label: "#{self.class.name}#call started",
|
|
10
|
+
data: { caller_source: caller_source, inventory_id_and_quantities: inventory_id_and_quantities }
|
|
11
|
+
)
|
|
12
|
+
|
|
8
13
|
ActiveRecord::Base.transaction do
|
|
9
14
|
inventory_items(inventory_id_and_quantities).each do |inventory_item|
|
|
10
15
|
quantity = inventory_id_and_quantities.select { |item| item[:inventory_id] == inventory_item.id }
|
|
11
16
|
.sum { |item| item[:quantity] }
|
|
12
|
-
adjust_quantity_available(inventory_item, quantity)
|
|
17
|
+
adjust_quantity_available(inventory_item, quantity, caller_source)
|
|
13
18
|
end
|
|
14
19
|
end
|
|
15
20
|
|
|
@@ -18,7 +23,7 @@ module SpreeCmCommissioner
|
|
|
18
23
|
|
|
19
24
|
private
|
|
20
25
|
|
|
21
|
-
def adjust_quantity_available(inventory_item, quantity)
|
|
26
|
+
def adjust_quantity_available(inventory_item, quantity, caller_source)
|
|
22
27
|
# IMPORTANT: Apply the quantity change directly without defensive clamping.
|
|
23
28
|
# The model validation will catch any attempts to go negative, surfacing bugs
|
|
24
29
|
# in upstream Redis deduction logic.
|
|
@@ -28,8 +33,35 @@ module SpreeCmCommissioner
|
|
|
28
33
|
# 2. lock_version (Optimistic): Catches race conditions if row is modified between
|
|
29
34
|
# SELECT and UPDATE (e.g., admin adjusts stock while job runs)
|
|
30
35
|
inventory_item.with_lock do
|
|
31
|
-
|
|
36
|
+
before = inventory_item.quantity_available
|
|
37
|
+
after = before + quantity
|
|
38
|
+
|
|
39
|
+
CmAppLogger.log(
|
|
40
|
+
label: "#{self.class.name}#adjust_quantity_available",
|
|
41
|
+
data: {
|
|
42
|
+
caller_source: caller_source,
|
|
43
|
+
inventory_item_id: inventory_item.id,
|
|
44
|
+
quantity_available_before: before,
|
|
45
|
+
delta: quantity,
|
|
46
|
+
quantity_available_after: after
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
inventory_item.update!(quantity_available: after)
|
|
32
51
|
end
|
|
52
|
+
rescue ActiveRecord::RecordInvalid
|
|
53
|
+
CmAppLogger.error(
|
|
54
|
+
label: "#{self.class.name}#adjust_quantity_available failed",
|
|
55
|
+
data: {
|
|
56
|
+
caller_source: caller_source,
|
|
57
|
+
inventory_item_id: inventory_item.id,
|
|
58
|
+
quantity_available_current: inventory_item.quantity_available,
|
|
59
|
+
delta: quantity,
|
|
60
|
+
would_result_in: inventory_item.quantity_available + quantity,
|
|
61
|
+
errors: inventory_item.errors.full_messages
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
raise
|
|
33
65
|
end
|
|
34
66
|
|
|
35
67
|
def inventory_items(inventory_id_and_quantities)
|
|
@@ -4,11 +4,19 @@ module SpreeCmCommissioner
|
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
extend SpreeCmCommissioner::ServiceModuleThrowable
|
|
6
6
|
|
|
7
|
-
def call(inventory_id_and_quantities:)
|
|
7
|
+
def call(inventory_id_and_quantities:, caller_source: nil)
|
|
8
|
+
CmAppLogger.log(
|
|
9
|
+
label: "#{self.class.name}#call started",
|
|
10
|
+
data: {
|
|
11
|
+
caller_source: caller_source,
|
|
12
|
+
inventory_id_and_quantities: inventory_id_and_quantities
|
|
13
|
+
}
|
|
14
|
+
)
|
|
15
|
+
|
|
8
16
|
ActiveRecord::Base.transaction do
|
|
9
17
|
inventory_items(inventory_id_and_quantities).each do |inventory_item|
|
|
10
18
|
quantity = inventory_id_and_quantities.find { |item| item[:inventory_id] == inventory_item.id }&.dig(:quantity) || 0
|
|
11
|
-
adjust_quantity_on_hold(inventory_item, quantity)
|
|
19
|
+
adjust_quantity_on_hold(inventory_item, quantity, caller_source)
|
|
12
20
|
end
|
|
13
21
|
end
|
|
14
22
|
|
|
@@ -17,7 +25,7 @@ module SpreeCmCommissioner
|
|
|
17
25
|
|
|
18
26
|
private
|
|
19
27
|
|
|
20
|
-
def adjust_quantity_on_hold(inventory_item, quantity)
|
|
28
|
+
def adjust_quantity_on_hold(inventory_item, quantity, caller_source)
|
|
21
29
|
# IMPORTANT: Apply the quantity change directly without defensive clamping.
|
|
22
30
|
# The model validation will catch any attempts to go negative, surfacing bugs
|
|
23
31
|
# in upstream Redis deduction logic.
|
|
@@ -27,8 +35,35 @@ module SpreeCmCommissioner
|
|
|
27
35
|
# 2. lock_version (Optimistic): Catches race conditions if row is modified between
|
|
28
36
|
# SELECT and UPDATE (e.g., admin adjusts stock while job runs)
|
|
29
37
|
inventory_item.with_lock do
|
|
30
|
-
|
|
38
|
+
before = inventory_item.quantity_on_hold
|
|
39
|
+
after = before + quantity
|
|
40
|
+
|
|
41
|
+
CmAppLogger.log(
|
|
42
|
+
label: "#{self.class.name}#adjust_quantity_on_hold",
|
|
43
|
+
data: {
|
|
44
|
+
caller_source: caller_source,
|
|
45
|
+
inventory_item_id: inventory_item.id,
|
|
46
|
+
quantity_on_hold_before: before,
|
|
47
|
+
delta: quantity,
|
|
48
|
+
quantity_on_hold_after: after
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
inventory_item.update!(quantity_on_hold: after)
|
|
31
53
|
end
|
|
54
|
+
rescue ActiveRecord::RecordInvalid
|
|
55
|
+
CmAppLogger.error(
|
|
56
|
+
label: "#{self.class.name}#adjust_quantity_on_hold failed",
|
|
57
|
+
data: {
|
|
58
|
+
caller_source: caller_source,
|
|
59
|
+
inventory_item_id: inventory_item.id,
|
|
60
|
+
quantity_on_hold_current: inventory_item.quantity_on_hold,
|
|
61
|
+
delta: quantity,
|
|
62
|
+
would_result_in: inventory_item.quantity_on_hold + quantity,
|
|
63
|
+
errors: inventory_item.errors.full_messages
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
raise
|
|
32
67
|
end
|
|
33
68
|
|
|
34
69
|
def inventory_items(inventory_id_and_quantities)
|
|
@@ -32,8 +32,6 @@ module SpreeCmCommissioner
|
|
|
32
32
|
|
|
33
33
|
def generate_inventory_items_for_variant(variant, count_on_hand)
|
|
34
34
|
inventory_dates_for(variant).each do |inventory_date|
|
|
35
|
-
next if inventory_exist?(variant, inventory_date)
|
|
36
|
-
|
|
37
35
|
create_inventory_item(variant, inventory_date, count_on_hand)
|
|
38
36
|
end
|
|
39
37
|
end
|
|
@@ -52,17 +50,17 @@ module SpreeCmCommissioner
|
|
|
52
50
|
end
|
|
53
51
|
end
|
|
54
52
|
|
|
55
|
-
def inventory_exist?(variant, inventory_date)
|
|
56
|
-
variant.inventory_items.exists?(inventory_date: inventory_date)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
53
|
def create_inventory_item(variant, inventory_date, count_on_hand)
|
|
54
|
+
return if variant.inventory_items.exists?(inventory_date: inventory_date)
|
|
55
|
+
|
|
60
56
|
variant.inventory_items.create!(
|
|
61
57
|
inventory_date: inventory_date,
|
|
62
58
|
quantity_available: count_on_hand,
|
|
63
59
|
max_capacity: count_on_hand,
|
|
64
60
|
product_type: variant.product_type
|
|
65
61
|
)
|
|
62
|
+
rescue ActiveRecord::RecordNotUnique
|
|
63
|
+
# concurrent worker won the race; record already exists
|
|
66
64
|
end
|
|
67
65
|
|
|
68
66
|
# Returns a hash: { variant_id => total_on_hand, ... }
|
|
@@ -3,22 +3,28 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class CleanupExpired
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
|
-
BATCH_SIZE =
|
|
6
|
+
BATCH_SIZE = 500
|
|
7
|
+
|
|
8
|
+
# The access tokens set by doorkeeper to expire in 1 day (cm-market-server/config/initializers/doorkeeper.rb),
|
|
9
|
+
# so we set the threshold to 90 days to make sure all expired tokens are cleaned up.
|
|
7
10
|
EXPIRATION_THRESHOLD_DAYS = 90
|
|
8
11
|
|
|
9
12
|
def call
|
|
10
|
-
|
|
13
|
+
cutoff_time = EXPIRATION_THRESHOLD_DAYS.days.ago
|
|
11
14
|
total_deleted = 0
|
|
12
15
|
|
|
16
|
+
# oauth_access_tokens is a standalone table with no foreign keys or associations
|
|
17
|
+
# pointing to it (checked cm-market-server/db/schema.rb), so it is safe to use
|
|
18
|
+
# delete_all here for faster bulk cleanup.
|
|
13
19
|
Spree::OauthAccessToken
|
|
14
|
-
.where('
|
|
20
|
+
.where('created_at < ?', cutoff_time)
|
|
15
21
|
.in_batches(of: BATCH_SIZE) do |relation|
|
|
16
22
|
deleted_count = relation.delete_all
|
|
17
23
|
total_deleted += deleted_count
|
|
18
24
|
end
|
|
19
25
|
|
|
20
|
-
log_cleanup_result(total_deleted,
|
|
21
|
-
success(total_deleted: total_deleted,
|
|
26
|
+
log_cleanup_result(total_deleted, cutoff_time)
|
|
27
|
+
success(total_deleted: total_deleted, cutoff_time: cutoff_time, batch_size: BATCH_SIZE, expiration_threshold_days: EXPIRATION_THRESHOLD_DAYS)
|
|
22
28
|
rescue StandardError => e
|
|
23
29
|
log_error(e)
|
|
24
30
|
failure(nil, e.message)
|
|
@@ -26,12 +32,12 @@ module SpreeCmCommissioner
|
|
|
26
32
|
|
|
27
33
|
private
|
|
28
34
|
|
|
29
|
-
def log_cleanup_result(total_deleted,
|
|
35
|
+
def log_cleanup_result(total_deleted, cutoff_time)
|
|
30
36
|
CmAppLogger.log(
|
|
31
37
|
label: 'SpreeCmCommissioner::OauthAccessTokens::CleanupExpired completed',
|
|
32
38
|
data: {
|
|
33
39
|
total_deleted: total_deleted,
|
|
34
|
-
|
|
40
|
+
cutoff_time: cutoff_time,
|
|
35
41
|
batch_size: BATCH_SIZE,
|
|
36
42
|
expiration_threshold_days: EXPIRATION_THRESHOLD_DAYS
|
|
37
43
|
}
|
|
@@ -31,7 +31,8 @@ module SpreeCmCommissioner
|
|
|
31
31
|
def schedule_sync_inventory(inventory_id_and_quantities)
|
|
32
32
|
SpreeCmCommissioner::InventoryItems::BulkAdjustQuantitiesJob.perform_later(
|
|
33
33
|
inventory_id_and_quantities: inventory_id_and_quantities,
|
|
34
|
-
line_item_ids: @line_item_ids
|
|
34
|
+
line_item_ids: @line_item_ids,
|
|
35
|
+
caller_source: "#{self.class.name}#schedule_sync_inventory"
|
|
35
36
|
)
|
|
36
37
|
end
|
|
37
38
|
end
|
|
@@ -3,29 +3,17 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class DecreaseTripCount
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
|
-
def call(
|
|
7
|
-
return failure(nil, '
|
|
8
|
-
|
|
9
|
-
route_metric = find_or_create_route_metric(trip)
|
|
6
|
+
def call(route_metric:)
|
|
7
|
+
return failure(nil, 'Route metric not found') unless route_metric
|
|
10
8
|
|
|
11
9
|
route_metric.with_lock do
|
|
12
10
|
route_metric.update!(trip_count: [route_metric.trip_count - 1, 0].max)
|
|
13
11
|
end
|
|
14
12
|
|
|
15
|
-
success(
|
|
13
|
+
success(route_metric: route_metric)
|
|
16
14
|
rescue StandardError => e
|
|
17
15
|
failure(nil, e.message)
|
|
18
16
|
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def find_or_create_route_metric(trip)
|
|
23
|
-
SpreeCmCommissioner::RouteMetric.find_or_create_by!(
|
|
24
|
-
origin_place_id: trip.origin_place_id,
|
|
25
|
-
destination_place_id: trip.destination_place_id,
|
|
26
|
-
route_type: trip.route_type
|
|
27
|
-
)
|
|
28
|
-
end
|
|
29
17
|
end
|
|
30
18
|
end
|
|
31
19
|
end
|
|
@@ -3,29 +3,21 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class IncreaseTripCount
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
|
-
def call(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
def call(origin_place_id:, destination_place_id:, route_type:)
|
|
7
|
+
route_metric = SpreeCmCommissioner::RouteMetric.find_or_create_by!(
|
|
8
|
+
origin_place_id: origin_place_id,
|
|
9
|
+
destination_place_id: destination_place_id,
|
|
10
|
+
route_type: route_type
|
|
11
|
+
)
|
|
10
12
|
|
|
11
13
|
route_metric.with_lock do
|
|
12
14
|
route_metric.update!(trip_count: route_metric.trip_count + 1)
|
|
13
15
|
end
|
|
14
16
|
|
|
15
|
-
success(
|
|
17
|
+
success(route_metric: route_metric)
|
|
16
18
|
rescue StandardError => e
|
|
17
19
|
failure(nil, e.message)
|
|
18
20
|
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def find_or_create_route_metric(trip)
|
|
23
|
-
SpreeCmCommissioner::RouteMetric.find_or_create_by!(
|
|
24
|
-
origin_place_id: trip.origin_place_id,
|
|
25
|
-
destination_place_id: trip.destination_place_id,
|
|
26
|
-
route_type: trip.route_type
|
|
27
|
-
)
|
|
28
|
-
end
|
|
29
21
|
end
|
|
30
22
|
end
|
|
31
23
|
end
|
|
@@ -49,9 +49,15 @@ module SpreeCmCommissioner
|
|
|
49
49
|
order.preload_main_trip_ids = (outbound_legs.map(&:main_trip_id) + inbound_legs.map(&:main_trip_id)).flatten.compact.uniq
|
|
50
50
|
order.order_options = order_options if order_options.present?
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
ActiveRecord::Base.transaction do
|
|
53
|
+
raise StandardError, order.errors.full_messages.to_sentence unless order.save
|
|
54
|
+
|
|
55
|
+
order.update_with_updater!
|
|
56
|
+
|
|
57
|
+
# Move the order from 'cart' to 'address' & hold the selected seats.
|
|
58
|
+
order.next!
|
|
59
|
+
end
|
|
53
60
|
|
|
54
|
-
order.update_with_updater!
|
|
55
61
|
order
|
|
56
62
|
end
|
|
57
63
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<div data-hook="admin_line_item_form_date">
|
|
13
13
|
<%= f.field_container :from_date do %>
|
|
14
14
|
<%= f.label :from_date, raw(Spree.t(:from_date) + required_span_tag) %>
|
|
15
|
-
<%= f.text_field :from_date, class: 'form-control datePickerFrom mb-2', 'data-alt-input': true, 'data-enable-time': true, value:
|
|
15
|
+
<%= f.text_field :from_date, class: 'form-control datePickerFrom mb-2', 'data-alt-input': true, 'data-enable-time': true, value: @line_item.from_date&.in_time_zone&.strftime('%Y-%m-%d %H:%M') %>
|
|
16
16
|
<%= f.error_message_on :from_date %>
|
|
17
17
|
<% end %>
|
|
18
18
|
</div>
|
|
@@ -20,11 +20,10 @@
|
|
|
20
20
|
<div data-hook="admin_line_item_to_date">
|
|
21
21
|
<%= f.field_container :to_date do %>
|
|
22
22
|
<%= f.label :to_date, raw(Spree.t(:to_date) + required_span_tag) %>
|
|
23
|
-
<%= f.text_field :to_date, class: 'form-control datePickerTo', 'data-alt-input': true, 'data-enable-time': true, value: @line_item.to_date, 'data-min-date': @line_item.from_date %>
|
|
23
|
+
<%= f.text_field :to_date, class: 'form-control datePickerTo', 'data-alt-input': true, 'data-enable-time': true, value: @line_item.to_date&.in_time_zone&.strftime('%Y-%m-%d %H:%M'), 'data-min-date': @line_item.from_date&.in_time_zone&.strftime('%Y-%m-%d %H:%M') %>
|
|
24
24
|
<%= f.error_message_on :to_date %>
|
|
25
25
|
<% end %>
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
28
28
|
</div>
|
|
29
29
|
</div>
|
|
30
|
-
|
|
@@ -50,10 +50,34 @@ module SpreeCmCommissioner
|
|
|
50
50
|
@trips.map(&:max_capacity).compact.min
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def
|
|
53
|
+
def price
|
|
54
54
|
@trips.map(&:price).compact.sum
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
# alias total_price to price for backward compatibility.
|
|
58
|
+
alias total_price price
|
|
59
|
+
|
|
60
|
+
def compare_at_price
|
|
61
|
+
values = @trips.map(&:compare_at_price).compact
|
|
62
|
+
values.empty? ? nil : values.sum
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def currency
|
|
66
|
+
@trips.first&.currency
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def display_price
|
|
70
|
+
return nil if price.nil? || currency.nil?
|
|
71
|
+
|
|
72
|
+
Spree::Money.new(price, currency: currency).to_s
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def display_compare_at_price
|
|
76
|
+
return nil if compare_at_price.nil? || currency.nil?
|
|
77
|
+
|
|
78
|
+
Spree::Money.new(compare_at_price, currency: currency).to_s
|
|
79
|
+
end
|
|
80
|
+
|
|
57
81
|
def total_open_return_price
|
|
58
82
|
return total_price unless direct?
|
|
59
83
|
|
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.
|
|
4
|
+
version: 2.8.3.pre.pre1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- You
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: spree
|
|
@@ -3370,9 +3370,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
3370
3370
|
version: '2.7'
|
|
3371
3371
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
3372
3372
|
requirements:
|
|
3373
|
-
- - "
|
|
3373
|
+
- - ">"
|
|
3374
3374
|
- !ruby/object:Gem::Version
|
|
3375
|
-
version:
|
|
3375
|
+
version: 1.3.1
|
|
3376
3376
|
requirements:
|
|
3377
3377
|
- none
|
|
3378
3378
|
rubygems_version: 3.4.1
|