spree_cm_commissioner 2.5.8 → 2.5.10
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/operator/guest_json_gzips_controller.rb +53 -0
- data/app/controllers/spree_cm_commissioner/orders_controller.rb +1 -1
- data/app/jobs/spree_cm_commissioner/export_job.rb +8 -0
- data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +5 -0
- data/app/models/spree_cm_commissioner/check_in_ability.rb +2 -0
- data/app/models/spree_cm_commissioner/export.rb +26 -10
- data/app/models/spree_cm_commissioner/exports/operator_guest_json_gzip.rb +37 -0
- data/app/models/spree_cm_commissioner/order_decorator.rb +14 -0
- data/app/models/spree_cm_commissioner/pricing_action.rb +21 -14
- data/app/models/spree_cm_commissioner/pricing_actions/create_line_item_adjustments.rb +14 -0
- data/app/models/spree_cm_commissioner/pricing_actions/create_route_adjustments.rb +70 -0
- data/app/models/spree_cm_commissioner/pricing_model.rb +39 -0
- data/app/models/spree_cm_commissioner/pricing_model_handler/order.rb +72 -0
- data/app/models/spree_cm_commissioner/pricing_model_route.rb +16 -0
- data/app/models/spree_cm_commissioner/route.rb +2 -0
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +2 -0
- data/app/queries/spree_cm_commissioner/check_in_sessions_metrics_query.rb +24 -0
- data/app/serializers/spree/v2/storefront/cart_serializer_decorator.rb +1 -0
- data/app/serializers/spree_cm_commissioner/v2/operator/export_serializer.rb +14 -0
- data/app/services/spree_cm_commissioner/cart/recalculate_decorator.rb +0 -4
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_matches.rb +11 -1
- data/app/services/spree_cm_commissioner/operator_guest_json_gzips/create.rb +40 -0
- data/app/services/spree_cm_commissioner/orders/jwt_token/generate.rb +1 -1
- data/app/services/spree_cm_commissioner/transit/legs_builder_service.rb +2 -1
- data/app/services/spree_cm_commissioner/transit_order/create.rb +14 -8
- data/app/views/blazer/queries/_preset.html.erb +2 -4
- data/config/initializers/spree_permitted_attributes.rb +1 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20260110073000_create_cm_pricing_model_routes.rb +37 -0
- data/db/migrate/20260128093305_add_exportable_to_cm_exports.rb +5 -0
- data/db/migrate/20260128093313_add_metadata_to_cm_exports.rb +11 -0
- data/db/migrate/20260129082338_remove_preferences_file_name_columns_from_cm_exports.rb +13 -0
- data/db/migrate/20260204092321_add_type_to_cm_exports.rb +11 -0
- data/db/migrate/20260204183545_add_term_accepted_at_to_spree_orders.rb +6 -0
- data/lib/spree_cm_commissioner/check_in_sessions_metric.rb +34 -0
- data/lib/spree_cm_commissioner/test_helper/factories/pricing_action_factory.rb +4 -0
- data/lib/spree_cm_commissioner/test_helper/factories/pricing_model_route_factory.rb +8 -0
- data/lib/spree_cm_commissioner/transit/leg.rb +4 -1
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +1 -0
- metadata +19 -4
- data/app/services/spree_cm_commissioner/line_items/apply_pricing_models.rb +0 -27
- data/app/services/spree_cm_commissioner/pricing_models/apply.rb +0 -43
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 673c4b3d46c1121063b406d0a7228e1f640467906b8c0960d9c76bc4553c7a59
|
|
4
|
+
data.tar.gz: 45b5352a4f194674bae8fb259d766057d9404d498539ff5ebae46f202534ba6c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a0209ab5b1a8b0b381cf33211265acad61b368a0cc09eed582d0b4d6264b9151dd522fcf3d7609b3c501e1a957fb16779bab58f717a93664219a6ed2a9781b7
|
|
7
|
+
data.tar.gz: 88b21257aba4536f9ffbc86d2c94a631440b772af6f7ac724e80f943152ed33ac0c6207f15e12af32b96a3530ad6ef819fc4e216e6ce003c0fefecd796d4fcde
|
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V2
|
|
4
|
+
module Operator
|
|
5
|
+
class GuestJsonGzipsController < ::Spree::Api::V2::ResourceController
|
|
6
|
+
before_action :require_spree_current_user
|
|
7
|
+
|
|
8
|
+
# POST /api/v2/operator/guest_json_gzips
|
|
9
|
+
# - taxon_id=1
|
|
10
|
+
# - resource_includes[]=[check_ins,check_ins.check_in_by]
|
|
11
|
+
# - force_create=true (optional, to bypass recent export check)
|
|
12
|
+
def create
|
|
13
|
+
spree_authorize! :create, SpreeCmCommissioner::Exports::OperatorGuestJsonGzip
|
|
14
|
+
|
|
15
|
+
exportable = Spree::Taxon.find(params[:taxon_id])
|
|
16
|
+
|
|
17
|
+
result = SpreeCmCommissioner::OperatorGuestJsonGzips::Create.call(
|
|
18
|
+
exportable: exportable,
|
|
19
|
+
resource_includes: params[:resource_includes] || [],
|
|
20
|
+
force_create: params[:force_create] == 'true'
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
if result.success?
|
|
24
|
+
status = result.value.created_at < 1.minute.ago ? 200 : 201
|
|
25
|
+
@export = result.value
|
|
26
|
+
render_serialized_payload(status) { serialize_resource(@export) }
|
|
27
|
+
else
|
|
28
|
+
render_error_payload(result.error)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# override
|
|
33
|
+
def scope
|
|
34
|
+
SpreeCmCommissioner::Exports::OperatorGuestJsonGzip.where(
|
|
35
|
+
exportable_type: 'Spree::Taxon',
|
|
36
|
+
exportable_id: params[:taxon_id]
|
|
37
|
+
).order(created_at: :desc)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# override
|
|
41
|
+
def collection_serializer
|
|
42
|
+
SpreeCmCommissioner::V2::Operator::ExportSerializer
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# override
|
|
46
|
+
def resource_serializer
|
|
47
|
+
SpreeCmCommissioner::V2::Operator::ExportSerializer
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -7,7 +7,7 @@ module SpreeCmCommissioner
|
|
|
7
7
|
@order = if params[:id].match?(/^R\d{9,}-([A-Za-z0-9_\-]+)$/)
|
|
8
8
|
Spree::Order.search_by_qr_data!(params[:id])
|
|
9
9
|
else
|
|
10
|
-
SpreeCmCommissioner::Orders::
|
|
10
|
+
SpreeCmCommissioner::Orders::JwtToken::Verify.call(token: params[:t]).value[:order]
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
@product_type = @order.products.first&.product_type || 'accommodation'
|
|
@@ -53,6 +53,7 @@ module SpreeCmCommissioner
|
|
|
53
53
|
|
|
54
54
|
def direction = private_metadata['direction']
|
|
55
55
|
def trip_id = private_metadata['trip_id']&.to_i
|
|
56
|
+
def connected_trip_id = private_metadata['connected_trip_id']
|
|
56
57
|
def boarding_trip_stop_id = private_metadata['boarding_trip_stop_id']&.to_i
|
|
57
58
|
def drop_off_trip_stop_id = private_metadata['drop_off_trip_stop_id']&.to_i
|
|
58
59
|
|
|
@@ -99,6 +100,10 @@ module SpreeCmCommissioner
|
|
|
99
100
|
set_private_metadata_value('trip_id', value)
|
|
100
101
|
end
|
|
101
102
|
|
|
103
|
+
def connected_trip_id=(value)
|
|
104
|
+
set_private_metadata_value('connected_trip_id', value)
|
|
105
|
+
end
|
|
106
|
+
|
|
102
107
|
def boarding_trip_stop_id=(value)
|
|
103
108
|
set_private_metadata_value('boarding_trip_stop_id', value)
|
|
104
109
|
end
|
|
@@ -5,9 +5,11 @@ module SpreeCmCommissioner
|
|
|
5
5
|
def initialize(user)
|
|
6
6
|
if user.has_spree_role?('operator')
|
|
7
7
|
can :manage, CheckIn
|
|
8
|
+
can :create, Export
|
|
8
9
|
elsif user.has_spree_role?('organizer')
|
|
9
10
|
can :manage, CheckIn
|
|
10
11
|
can :manage, Guest
|
|
12
|
+
can :create, Export
|
|
11
13
|
else
|
|
12
14
|
cannot :manage, CheckIn
|
|
13
15
|
end
|
|
@@ -1,26 +1,42 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
class Export < Base
|
|
3
|
-
|
|
3
|
+
self.inheritance_column = :export_type
|
|
4
|
+
|
|
5
|
+
include SpreeCmCommissioner::StoreMetadata
|
|
6
|
+
include ::Rails.application.routes.url_helpers
|
|
7
|
+
|
|
8
|
+
belongs_to :exportable, polymorphic: true
|
|
9
|
+
|
|
4
10
|
has_one_attached :exported_file
|
|
5
11
|
|
|
12
|
+
before_validation :set_uuid
|
|
13
|
+
|
|
14
|
+
after_create :enqueue_export
|
|
15
|
+
|
|
6
16
|
enum status: { :queue => 0, :progress => 1, :done => 2, :failed => 3 }
|
|
7
17
|
|
|
8
|
-
def
|
|
9
|
-
|
|
18
|
+
def set_uuid
|
|
19
|
+
self.uuid = SecureRandom.uuid
|
|
10
20
|
end
|
|
11
21
|
|
|
12
|
-
def
|
|
13
|
-
|
|
22
|
+
def exported_file_name
|
|
23
|
+
return nil if exported_file.blank?
|
|
24
|
+
|
|
25
|
+
exported_file.filename.to_s
|
|
14
26
|
end
|
|
15
27
|
|
|
16
|
-
def
|
|
17
|
-
|
|
28
|
+
def exported_file_url
|
|
29
|
+
return nil if exported_file.blank?
|
|
30
|
+
|
|
31
|
+
cdn_image_url(exported_file)
|
|
18
32
|
end
|
|
19
33
|
|
|
20
|
-
def
|
|
21
|
-
|
|
34
|
+
def enqueue_export
|
|
35
|
+
SpreeCmCommissioner::ExportJob.perform_later(export_id: id)
|
|
22
36
|
end
|
|
23
37
|
|
|
24
|
-
def
|
|
38
|
+
def export
|
|
39
|
+
raise NotImplementedError, 'Subclasses must implement the export method'
|
|
40
|
+
end
|
|
25
41
|
end
|
|
26
42
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Exports
|
|
3
|
+
class OperatorGuestJsonGzip < ::SpreeCmCommissioner::Export
|
|
4
|
+
# eg. ['check_ins', 'check_ins.check_in_by', 'line_item', 'line_item.order']
|
|
5
|
+
store_public_metadata :resource_includes, :array
|
|
6
|
+
store_public_metadata :guests_count, :integer
|
|
7
|
+
|
|
8
|
+
# override
|
|
9
|
+
def export
|
|
10
|
+
update(status: :progress)
|
|
11
|
+
|
|
12
|
+
guests = SpreeCmCommissioner::GuestSearcherQuery.new(event_id: exportable_id).call
|
|
13
|
+
hash = SpreeCmCommissioner::V2::Operator::GuestSerializer.new(
|
|
14
|
+
guests,
|
|
15
|
+
{ include: resource_includes }
|
|
16
|
+
).serializable_hash
|
|
17
|
+
|
|
18
|
+
file_name = "exports_operator_guest_#{id}.json.gz"
|
|
19
|
+
json_gzip = ActiveSupport::Gzip.compress(JSON.generate(hash))
|
|
20
|
+
|
|
21
|
+
exported_file.attach(
|
|
22
|
+
io: StringIO.new(json_gzip),
|
|
23
|
+
filename: file_name,
|
|
24
|
+
content_type: 'application/gzip'
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
update(
|
|
28
|
+
guests_count: guests.size,
|
|
29
|
+
status: :done
|
|
30
|
+
)
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
CmAppLogger.error(label: "#{self.class.name}#export", data: { export_id: id, error: e.message, backtrace: e.backtrace })
|
|
33
|
+
update(status: :failed)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -264,6 +264,20 @@ module SpreeCmCommissioner
|
|
|
264
264
|
tenant&.formatted_url.presence || ENV.fetch('DEFAULT_URL_HOST')
|
|
265
265
|
end
|
|
266
266
|
|
|
267
|
+
# Returns arrays of connected line_item IDs grouped by connected_trip_id.
|
|
268
|
+
# Example: [[1,2,3], [4,5], [6]]
|
|
269
|
+
#
|
|
270
|
+
# Line items with the same connected_trip_id are grouped together.
|
|
271
|
+
# Line items without a group_id are returned as singletons.
|
|
272
|
+
def connected_line_item_ids(direction: nil)
|
|
273
|
+
scoped = line_items
|
|
274
|
+
scoped = scoped.select { |li| li.direction == direction } if direction.present?
|
|
275
|
+
|
|
276
|
+
scoped.group_by { |li| li.connected_trip_id || li.id }
|
|
277
|
+
.values
|
|
278
|
+
.map { |group| group.map(&:id).sort }
|
|
279
|
+
end
|
|
280
|
+
|
|
267
281
|
private
|
|
268
282
|
|
|
269
283
|
def unstock_inventory_in_redis!
|
|
@@ -1,27 +1,34 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
class PricingAction < Base
|
|
3
|
-
|
|
3
|
+
include Spree::CalculatedAdjustments
|
|
4
|
+
include Spree::AdjustmentSource
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
accepts_nested_attributes_for :calculator
|
|
6
|
+
has_many :adjustments, as: :source, class_name: 'Spree::Adjustment'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
return if pricing_rule_group.pricing_rules.blank?
|
|
8
|
+
belongs_to :pricing_rule_group, class_name: 'SpreeCmCommissioner::PricingRuleGroup'
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
delegate :pricing_rules, to: :pricing_rule_group
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
mandatory: true
|
|
20
|
-
)
|
|
12
|
+
def perform(_options = {})
|
|
13
|
+
raise NotImplementedError, "#{self.class}#perform must be implemented"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def compute_amount(adjustable)
|
|
17
|
+
calculator&.compute(adjustable) || 0
|
|
21
18
|
end
|
|
22
19
|
|
|
23
20
|
def self.available_calculator_types
|
|
24
21
|
SpreeCmCommissioner::Calculators.constants.map(&:to_s)
|
|
25
22
|
end
|
|
23
|
+
|
|
24
|
+
protected
|
|
25
|
+
|
|
26
|
+
def label
|
|
27
|
+
pricing_rule_group.name
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def order_currency(order)
|
|
31
|
+
order&.currency || Spree::Config[:currency]
|
|
32
|
+
end
|
|
26
33
|
end
|
|
27
34
|
end
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
module PricingActions
|
|
3
3
|
class CreateLineItemAdjustments < SpreeCmCommissioner::PricingAction
|
|
4
|
+
def perform(options = {})
|
|
5
|
+
order = options[:order]
|
|
6
|
+
line_items = options[:line_items] || []
|
|
7
|
+
|
|
8
|
+
return if line_items.blank?
|
|
9
|
+
|
|
10
|
+
line_items.each do |line_item|
|
|
11
|
+
create_unique_adjustment(order, line_item)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def compute_amount(line_item)
|
|
16
|
+
compute(line_item)
|
|
17
|
+
end
|
|
4
18
|
end
|
|
5
19
|
end
|
|
6
20
|
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module PricingActions
|
|
3
|
+
class CreateRouteAdjustments < SpreeCmCommissioner::PricingAction
|
|
4
|
+
def perform(options = {})
|
|
5
|
+
order = options[:order]
|
|
6
|
+
line_items = options[:line_items] || []
|
|
7
|
+
|
|
8
|
+
return if pricing_rules.blank?
|
|
9
|
+
return if line_items.blank?
|
|
10
|
+
|
|
11
|
+
eligible_guests = collect_unique_eligible_guests(line_items)
|
|
12
|
+
return if eligible_guests.empty?
|
|
13
|
+
|
|
14
|
+
total_amount = compute_total_amount(order, eligible_guests)
|
|
15
|
+
return if total_amount.zero?
|
|
16
|
+
|
|
17
|
+
create_route_adjustment(order, total_amount)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def collect_unique_eligible_guests(line_items)
|
|
23
|
+
seen = {}
|
|
24
|
+
|
|
25
|
+
line_items.each_with_object([]) do |line_item, result|
|
|
26
|
+
line_item.guests.select { |guest| guest_eligible?(guest) }.each_with_index do |guest, index|
|
|
27
|
+
key = guest.saved_guest_id.present? ? [guest.saved_guest_id, index] : guest.id
|
|
28
|
+
next if seen[key]
|
|
29
|
+
|
|
30
|
+
seen[key] = true
|
|
31
|
+
result << guest
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def guest_eligible?(guest)
|
|
37
|
+
pricing_rules.all? do |rule|
|
|
38
|
+
!rule.respond_to?(:guest_eligible?) || rule.guest_eligible?(guest)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def compute_total_amount(order, guests)
|
|
43
|
+
guests.sum { |guest| compute_per_guest_amount(order, guest) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def compute_per_guest_amount(order, guest)
|
|
47
|
+
item = build_per_guest_item(order, guest)
|
|
48
|
+
compute_amount(item)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def build_per_guest_item(order, guest)
|
|
52
|
+
Struct.new(:amount, :currency, :quantity).new(
|
|
53
|
+
guest.line_item.amount_per_guest,
|
|
54
|
+
order_currency(order),
|
|
55
|
+
1
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def create_route_adjustment(order, amount)
|
|
60
|
+
adjustments.create!(
|
|
61
|
+
adjustable: order,
|
|
62
|
+
amount: amount,
|
|
63
|
+
order: order,
|
|
64
|
+
label: label,
|
|
65
|
+
mandatory: true
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -6,6 +6,8 @@ module SpreeCmCommissioner
|
|
|
6
6
|
|
|
7
7
|
has_many :pricing_model_variants, class_name: 'SpreeCmCommissioner::PricingModelVariant', dependent: :destroy
|
|
8
8
|
has_many :variants, through: :pricing_model_variants, class_name: 'Spree::Variant'
|
|
9
|
+
has_many :pricing_model_routes, class_name: 'SpreeCmCommissioner::PricingModelRoute', dependent: :destroy
|
|
10
|
+
has_many :routes, through: :pricing_model_routes, class_name: 'SpreeCmCommissioner::Route'
|
|
9
11
|
has_many :pricing_rule_groups, class_name: 'SpreeCmCommissioner::PricingRuleGroup', dependent: :destroy
|
|
10
12
|
has_many :pricing_rules, through: :pricing_rule_groups, class_name: 'SpreeCmCommissioner::PricingRule'
|
|
11
13
|
|
|
@@ -14,5 +16,42 @@ module SpreeCmCommissioner
|
|
|
14
16
|
validates :name, presence: true, uniqueness: { scope: :vendor_id }
|
|
15
17
|
|
|
16
18
|
enum status: { draft: 0, active: 1, archived: 2 }
|
|
19
|
+
|
|
20
|
+
# Activates pricing model for an order (similar to Spree::Promotion#activate)
|
|
21
|
+
def activate(order:, line_items:)
|
|
22
|
+
pricing_rule_groups.each do |group|
|
|
23
|
+
activate_group(group, order, line_items)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def activate_group(group, order, line_items)
|
|
30
|
+
eligible_rules = group.pricing_rules.select { |r| any_line_item_eligible?(r, line_items) }
|
|
31
|
+
|
|
32
|
+
return if eligible_rules.empty?
|
|
33
|
+
|
|
34
|
+
if group_eligible?(group, eligible_rules)
|
|
35
|
+
|
|
36
|
+
group.pricing_action&.perform(order: order, line_items: line_items)
|
|
37
|
+
else
|
|
38
|
+
Rails.logger.info("PricingRuleGroup #{group.id} not eligible for order #{order.id}")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def any_line_item_eligible?(rule, line_items)
|
|
43
|
+
line_items.any? { |li| rule.eligible?(li) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def group_eligible?(group, eligible_rules)
|
|
47
|
+
case group.match_type
|
|
48
|
+
when 'all'
|
|
49
|
+
eligible_rules.size == group.pricing_rules.size
|
|
50
|
+
when 'any'
|
|
51
|
+
eligible_rules.any?
|
|
52
|
+
else
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
17
56
|
end
|
|
18
57
|
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module PricingModelHandler
|
|
3
|
+
# Handles pricing model activation for orders
|
|
4
|
+
class Order
|
|
5
|
+
attr_reader :order
|
|
6
|
+
|
|
7
|
+
def initialize(order)
|
|
8
|
+
@order = order
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def activate
|
|
12
|
+
return unless order&.persisted?
|
|
13
|
+
|
|
14
|
+
order.adjustments.pricing_action.delete_all
|
|
15
|
+
|
|
16
|
+
order.connected_line_item_ids.each do |group_ids|
|
|
17
|
+
line_items_in_group = order.line_items.where(id: group_ids)
|
|
18
|
+
activate_for_line_items(line_items_in_group)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def activate_for_line_items(line_items)
|
|
25
|
+
return if line_items.blank?
|
|
26
|
+
|
|
27
|
+
pricing_models = find_pricing_models(line_items).compact
|
|
28
|
+
return if pricing_models.blank?
|
|
29
|
+
|
|
30
|
+
pricing_models.each do |pricing_model|
|
|
31
|
+
pricing_model.activate(order: order, line_items: line_items)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def find_pricing_models(line_items)
|
|
36
|
+
route_pricing_models(line_items) + variant_pricing_models(line_items)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def route_pricing_models(line_items)
|
|
40
|
+
transit_line_items = line_items.select { |li| li.trip_id.present? }
|
|
41
|
+
return [] if transit_line_items.blank?
|
|
42
|
+
|
|
43
|
+
origin_place_id, destination_place_id = determine_origin_destination(transit_line_items)
|
|
44
|
+
|
|
45
|
+
SpreeCmCommissioner::PricingModelRoute
|
|
46
|
+
.active
|
|
47
|
+
.for_origin_destination(origin_place_id, destination_place_id)
|
|
48
|
+
.includes(:pricing_model)
|
|
49
|
+
.map(&:pricing_model)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def variant_pricing_models(line_items)
|
|
53
|
+
line_items.flat_map { |li| li.variant&.pricing_models&.active&.to_a || [] }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def determine_origin_destination(line_items)
|
|
57
|
+
if line_items.size > 1
|
|
58
|
+
first_line_item = line_items.min_by(&:id)
|
|
59
|
+
last_line_item = line_items.max_by(&:id)
|
|
60
|
+
|
|
61
|
+
first_trip = SpreeCmCommissioner::Trip.find(first_line_item.trip_id)
|
|
62
|
+
last_trip = SpreeCmCommissioner::Trip.find(last_line_item.trip_id)
|
|
63
|
+
|
|
64
|
+
[first_trip.origin_place_id, last_trip.destination_place_id]
|
|
65
|
+
else
|
|
66
|
+
trip = SpreeCmCommissioner::Trip.find(line_items.first.trip_id)
|
|
67
|
+
[trip.origin_place_id, trip.destination_place_id]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class PricingModelRoute < Base
|
|
3
|
+
belongs_to :route, class_name: 'SpreeCmCommissioner::Route'
|
|
4
|
+
belongs_to :pricing_model, class_name: 'SpreeCmCommissioner::PricingModel'
|
|
5
|
+
belongs_to :origin_place, class_name: 'SpreeCmCommissioner::Place'
|
|
6
|
+
belongs_to :destination_place, class_name: 'SpreeCmCommissioner::Place'
|
|
7
|
+
|
|
8
|
+
scope :for_origin_destination, lambda { |origin_place_id, destination_place_id|
|
|
9
|
+
where(origin_place_id: origin_place_id, destination_place_id: destination_place_id)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
scope :active, lambda {
|
|
13
|
+
joins(:pricing_model).where(pricing_model: { status: :active })
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -14,6 +14,8 @@ module SpreeCmCommissioner
|
|
|
14
14
|
has_many :route_photos, class_name: 'SpreeCmCommissioner::RoutePhoto', as: :viewable, dependent: :destroy
|
|
15
15
|
|
|
16
16
|
has_many :trips, inverse_of: :route
|
|
17
|
+
has_many :pricing_model_routes, class_name: 'SpreeCmCommissioner::PricingModelRoute', dependent: :destroy
|
|
18
|
+
has_many :pricing_models, through: :pricing_model_routes, class_name: 'SpreeCmCommissioner::PricingModel'
|
|
17
19
|
|
|
18
20
|
validates :route_name, presence: true
|
|
19
21
|
|
|
@@ -41,6 +41,8 @@ module SpreeCmCommissioner
|
|
|
41
41
|
base.has_many :visible_classifications, -> { where(visible: true).order(:position) }, class_name: 'Spree::Classification'
|
|
42
42
|
base.has_many :visible_products, through: :visible_classifications, class_name: 'Spree::Product', source: :product
|
|
43
43
|
|
|
44
|
+
base.has_many :exports, -> { order(created_at: :desc) }, class_name: 'SpreeCmCommissioner::Export', as: :exportable
|
|
45
|
+
|
|
44
46
|
base.belongs_to :vendor, class_name: 'Spree::Vendor'
|
|
45
47
|
|
|
46
48
|
base.validates_associated :category_icon
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class CheckInSessionsMetricsQuery
|
|
3
|
+
def initialize(event:, session:)
|
|
4
|
+
@event = event
|
|
5
|
+
@session = session
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
guests = @session.check_in_rules.any? ? eligible_guests_for_session : @event.guests
|
|
10
|
+
guests_count = guests.count
|
|
11
|
+
check_ins_count = guests.left_joins(:check_in).where.not(cm_check_ins: { id: nil })
|
|
12
|
+
.where(cm_check_ins: { check_in_session_id: [@session.id, nil] })
|
|
13
|
+
.distinct.count(:id)
|
|
14
|
+
|
|
15
|
+
CheckInSessionsMetric.new(check_ins_count: check_ins_count, guests_count: guests_count)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def eligible_guests_for_session
|
|
21
|
+
@event.guests.where('cm_guests.public_metadata @> ?::jsonb', { eligible_check_in_session_ids: [@session.id] }.to_json)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -24,10 +24,6 @@ module SpreeCmCommissioner
|
|
|
24
24
|
else
|
|
25
25
|
order.ensure_updated_shipments
|
|
26
26
|
end
|
|
27
|
-
# SPREE: Original Spree::Cart::Recalculate code ends here
|
|
28
|
-
|
|
29
|
-
# CUSTOM: Apply pricing models (intercity taxi, line item pricing) to the line item
|
|
30
|
-
SpreeCmCommissioner::LineItems::ApplyPricingModels.call(order: order, line_item: line_item)
|
|
31
27
|
|
|
32
28
|
# SPREE: Original Spree::Cart::Recalculate code continues here
|
|
33
29
|
::Spree::PromotionHandler::Cart.new(order, line_item).activate
|
|
@@ -36,6 +36,8 @@ class SpreeCmCommissioner::Integrations::StadiumXV1
|
|
|
36
36
|
|
|
37
37
|
match_mapping = Spree::Taxon.find_or_initialize_integration_mapping(integration_id: @integration.id, external_id: external_match._id)
|
|
38
38
|
match_taxon = match_mapping.internal
|
|
39
|
+
match_name = "#{external_match.home_name} vs #{external_match.away_name}"
|
|
40
|
+
match_permalink = generate_match_permalink(match_name)
|
|
39
41
|
|
|
40
42
|
# Track match sync and create event taxon directly under events/
|
|
41
43
|
@sync_result.track(:match, match_taxon) do |tracker|
|
|
@@ -43,7 +45,8 @@ class SpreeCmCommissioner::Integrations::StadiumXV1
|
|
|
43
45
|
vendor: @integration.vendor,
|
|
44
46
|
parent: events_root_taxon,
|
|
45
47
|
taxonomy: events_taxonomy,
|
|
46
|
-
name:
|
|
48
|
+
name: match_name,
|
|
49
|
+
permalink: match_permalink,
|
|
47
50
|
kind: :event,
|
|
48
51
|
from_date: external_match.match_datetime,
|
|
49
52
|
to_date: external_match.match_datetime + 120.minutes,
|
|
@@ -108,6 +111,13 @@ class SpreeCmCommissioner::Integrations::StadiumXV1
|
|
|
108
111
|
def events_taxonomy
|
|
109
112
|
@events_taxonomy ||= Spree::Taxonomy.events
|
|
110
113
|
end
|
|
114
|
+
|
|
115
|
+
def generate_match_permalink(match_name)
|
|
116
|
+
loop do
|
|
117
|
+
base_permalink = "#{events_root_taxon.permalink}/#{match_name.to_s.parameterize}-#{SecureRandom.hex(4)}"
|
|
118
|
+
break base_permalink unless Spree::Taxon.exists?(permalink: base_permalink)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
111
121
|
end
|
|
112
122
|
end
|
|
113
123
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SpreeCmCommissioner
|
|
4
|
+
module OperatorGuestJsonGzips
|
|
5
|
+
class Create
|
|
6
|
+
prepend ::Spree::ServiceModule::Base
|
|
7
|
+
|
|
8
|
+
def call(exportable:, resource_includes: [], force_create: false)
|
|
9
|
+
unless force_create
|
|
10
|
+
recent_export = find_recent_export(exportable)
|
|
11
|
+
return success(recent_export) if recent_export
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
export = build_export(exportable, resource_includes)
|
|
15
|
+
if export.save
|
|
16
|
+
success(export)
|
|
17
|
+
else
|
|
18
|
+
failure(export, export.errors.full_messages.to_sentence)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def find_recent_export(exportable)
|
|
25
|
+
SpreeCmCommissioner::Exports::OperatorGuestJsonGzip
|
|
26
|
+
.where(exportable: exportable)
|
|
27
|
+
.where('created_at > ?', 2.hours.ago)
|
|
28
|
+
.order(created_at: :desc)
|
|
29
|
+
.first
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def build_export(exportable, resource_includes)
|
|
33
|
+
SpreeCmCommissioner::Exports::OperatorGuestJsonGzip.new(
|
|
34
|
+
exportable: exportable,
|
|
35
|
+
resource_includes: resource_includes
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -5,7 +5,7 @@ module SpreeCmCommissioner
|
|
|
5
5
|
|
|
6
6
|
def call(order:)
|
|
7
7
|
nonce = generate_nonce
|
|
8
|
-
token = "#{order.number}?
|
|
8
|
+
token = "#{order.number}?t=#{nonce}-#{generate_qr_jwt(order: order, nonce: nonce)}"
|
|
9
9
|
|
|
10
10
|
success(token: token)
|
|
11
11
|
end
|
|
@@ -13,6 +13,7 @@ module SpreeCmCommissioner
|
|
|
13
13
|
SpreeCmCommissioner::Transit::Leg.new(
|
|
14
14
|
direction: direction,
|
|
15
15
|
trip_id: leg['trip_id'].to_i,
|
|
16
|
+
main_trip_id: leg['main_trip_id']&.to_i,
|
|
16
17
|
boarding_trip_stop_id: leg['boarding_trip_stop_id'].to_i,
|
|
17
18
|
drop_off_trip_stop_id: leg['drop_off_trip_stop_id'].to_i,
|
|
18
19
|
seat_selections: Array(leg['seat_selections']).map do |seat|
|
|
@@ -35,7 +36,7 @@ module SpreeCmCommissioner
|
|
|
35
36
|
else
|
|
36
37
|
legs_params.map do |leg|
|
|
37
38
|
leg.permit(
|
|
38
|
-
:trip_id, :boarding_trip_stop_id, :drop_off_trip_stop_id,
|
|
39
|
+
:trip_id, :main_trip_id, :boarding_trip_stop_id, :drop_off_trip_stop_id,
|
|
39
40
|
seat_selections: [:variant_id, :quantity, { block_ids: [] }]
|
|
40
41
|
)
|
|
41
42
|
end
|
|
@@ -53,8 +53,11 @@ module SpreeCmCommissioner
|
|
|
53
53
|
all_line_items = []
|
|
54
54
|
current_leg_date = initial_date
|
|
55
55
|
|
|
56
|
+
# Use main_trip_id for connected trips (when legs have multiple trips)
|
|
57
|
+
connected_trip_id = legs.size > 1 ? legs.first.main_trip_id&.to_s : nil
|
|
58
|
+
|
|
56
59
|
legs.each do |leg|
|
|
57
|
-
leg_line_items = build_line_items_for!(leg, order, current_leg_date)
|
|
60
|
+
leg_line_items = build_line_items_for!(leg, order, current_leg_date, connected_trip_id)
|
|
58
61
|
leg_line_items = insert_saved_guests_per_line_items_leg(leg_line_items)
|
|
59
62
|
|
|
60
63
|
all_line_items.concat(leg_line_items)
|
|
@@ -64,7 +67,7 @@ module SpreeCmCommissioner
|
|
|
64
67
|
all_line_items
|
|
65
68
|
end
|
|
66
69
|
|
|
67
|
-
def build_line_items_for!(leg, order, date)
|
|
70
|
+
def build_line_items_for!(leg, order, date, connected_trip_id = nil)
|
|
68
71
|
trip = SpreeCmCommissioner::Trip.find(leg.trip_id)
|
|
69
72
|
trip_stops = trip.trip_stops.where(id: [leg.boarding_trip_stop_id, leg.drop_off_trip_stop_id]).index_by(&:id)
|
|
70
73
|
|
|
@@ -75,18 +78,21 @@ module SpreeCmCommissioner
|
|
|
75
78
|
)
|
|
76
79
|
|
|
77
80
|
leg.seat_selections.group_by(&:variant_id).map do |variant_id, seat_selections|
|
|
81
|
+
metadata = {
|
|
82
|
+
direction: leg.direction,
|
|
83
|
+
trip_id: leg.trip_id.to_s,
|
|
84
|
+
boarding_trip_stop_id: leg.boarding_trip_stop_id.to_s,
|
|
85
|
+
drop_off_trip_stop_id: leg.drop_off_trip_stop_id.to_s
|
|
86
|
+
}
|
|
87
|
+
metadata[:connected_trip_id] = connected_trip_id if connected_trip_id.present?
|
|
88
|
+
|
|
78
89
|
line_item = order.line_items.new(
|
|
79
90
|
product_type: :transit,
|
|
80
91
|
from_date: from_date,
|
|
81
92
|
to_date: to_date,
|
|
82
93
|
variant_id: variant_id,
|
|
83
94
|
quantity: seat_selections.sum(&:quantity),
|
|
84
|
-
private_metadata:
|
|
85
|
-
direction: leg.direction,
|
|
86
|
-
trip_id: leg.trip_id.to_s,
|
|
87
|
-
boarding_trip_stop_id: leg.boarding_trip_stop_id.to_s,
|
|
88
|
-
drop_off_trip_stop_id: leg.drop_off_trip_stop_id.to_s
|
|
89
|
-
}
|
|
95
|
+
private_metadata: metadata
|
|
90
96
|
)
|
|
91
97
|
|
|
92
98
|
build_guests_for!(line_item, seat_selections)
|
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
<%= f.label :preset, Spree.t(:preset) %>
|
|
5
5
|
</div>
|
|
6
6
|
<small style="margin-bottom: 6px; display: inline-block;">
|
|
7
|
-
|
|
7
|
+
Preset reports are generated automatically for all new organizers and vendors once created.
|
|
8
8
|
</small>
|
|
9
|
-
<% end %>
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
<% end %>
|
data/config/routes.rb
CHANGED
|
@@ -703,6 +703,7 @@ Spree::Core::Engine.add_routes do
|
|
|
703
703
|
resources :event_qrs, only: [:show]
|
|
704
704
|
resources :recalculate_tickets, only: [:create]
|
|
705
705
|
resources :check_in_sessions, only: %i[index]
|
|
706
|
+
resources :guest_json_gzips, only: %i[index show create]
|
|
706
707
|
|
|
707
708
|
resources :taxons, only: %i[show] do
|
|
708
709
|
resource :event_ticket_aggregators, only: %i[show]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Migration to create cm_route_pricing_models table
|
|
4
|
+
# This table links pricing models to routes with specific origin/destination pairs
|
|
5
|
+
#
|
|
6
|
+
# Example: A route PP → KP → KPC → SR can have different pricing models for each O-D pair:
|
|
7
|
+
# - PP → SR: $1 extra charge
|
|
8
|
+
# - PP → KP: $2 extra charge
|
|
9
|
+
# - KP → KPC: $3 extra charge
|
|
10
|
+
# - KPC → SR: $4 extra charge
|
|
11
|
+
#
|
|
12
|
+
# When a user books PP → SR, only the PP → SR pricing model ($1) applies,
|
|
13
|
+
# not the sum of all segment charges
|
|
14
|
+
|
|
15
|
+
class CreateCmPricingModelRoutes < ActiveRecord::Migration[7.0]
|
|
16
|
+
def change
|
|
17
|
+
create_table :cm_pricing_model_routes, if_not_exists: true do |t|
|
|
18
|
+
t.references :route, null: false, foreign_key: { to_table: :cm_routes }
|
|
19
|
+
t.references :pricing_model, null: false, foreign_key: { to_table: :cm_pricing_models }
|
|
20
|
+
t.references :origin_place, null: false, foreign_key: { to_table: :cm_places }
|
|
21
|
+
t.references :destination_place, null: false, foreign_key: { to_table: :cm_places }
|
|
22
|
+
|
|
23
|
+
t.timestamps
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Ensure unique combination of route + pricing_model + origin + destination
|
|
27
|
+
add_index :cm_pricing_model_routes,
|
|
28
|
+
%i[route_id pricing_model_id origin_place_id destination_place_id],
|
|
29
|
+
unique: true,
|
|
30
|
+
name: 'idx_pricing_model_routes_unique'
|
|
31
|
+
|
|
32
|
+
# Index for efficient lookup by route and origin/destination
|
|
33
|
+
add_index :cm_pricing_model_routes,
|
|
34
|
+
%i[route_id origin_place_id destination_place_id],
|
|
35
|
+
name: 'idx_pricing_model_routes_on_route_origin_dest'
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class AddMetadataToCmExports < ActiveRecord::Migration[7.0]
|
|
2
|
+
def up
|
|
3
|
+
add_column :cm_exports, :public_metadata, :jsonb, default: '{}', if_not_exists: true
|
|
4
|
+
add_column :cm_exports, :private_metadata, :jsonb, default: '{}', if_not_exists: true
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def down
|
|
8
|
+
remove_column :cm_exports, :public_metadata, if_exists: true
|
|
9
|
+
remove_column :cm_exports, :private_metadata, if_exists: true
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class RemovePreferencesFileNameColumnsFromCmExports < ActiveRecord::Migration[7.0]
|
|
2
|
+
def up
|
|
3
|
+
remove_column :cm_exports, :preferences, if_exists: true
|
|
4
|
+
remove_column :cm_exports, :file_name, if_exists: true
|
|
5
|
+
remove_column :cm_exports, :file_path, if_exists: true
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def down
|
|
9
|
+
add_column :cm_exports, :preferences, :text, if_not_exists: true
|
|
10
|
+
add_column :cm_exports, :file_name, :string, if_not_exists: true
|
|
11
|
+
add_column :cm_exports, :file_path, :string, if_not_exists: true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class AddTypeToCmExports < ActiveRecord::Migration[7.0]
|
|
2
|
+
def up
|
|
3
|
+
add_column :cm_exports, :type, :string, if_not_exists: true
|
|
4
|
+
remove_column :cm_exports, :export_type, if_exists: true
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def down
|
|
8
|
+
add_column :cm_exports, :export_type, :string, if_not_exists: true
|
|
9
|
+
remove_column :cm_exports, :type, if_exists: true
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class CheckInSessionsMetric
|
|
3
|
+
attr_reader :check_ins_count, :guests_count, :percent, :other_value
|
|
4
|
+
|
|
5
|
+
def initialize(check_ins_count:, guests_count:)
|
|
6
|
+
@check_ins_count = check_ins_count
|
|
7
|
+
@guests_count = guests_count
|
|
8
|
+
@percent = calculate_attendance_percent
|
|
9
|
+
@other_value = 100 - @percent
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_h
|
|
13
|
+
{
|
|
14
|
+
check_ins_count: check_ins_count,
|
|
15
|
+
guests_count: guests_count,
|
|
16
|
+
no_show: no_show,
|
|
17
|
+
percent: percent,
|
|
18
|
+
other_value: other_value
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def no_show
|
|
23
|
+
guests_count - check_ins_count
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def calculate_attendance_percent
|
|
29
|
+
return 0 if guests_count.zero?
|
|
30
|
+
|
|
31
|
+
((check_ins_count.to_f / guests_count) * 100).round(2)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -6,4 +6,8 @@ FactoryBot.define do
|
|
|
6
6
|
factory :pricing_action_guest_adjustments, class: 'SpreeCmCommissioner::PricingActions::CreateGuestAdjustments' do
|
|
7
7
|
association :pricing_rule_group, factory: :pricing_rule_group
|
|
8
8
|
end
|
|
9
|
+
|
|
10
|
+
factory :pricing_action_route_adjustment, class: 'SpreeCmCommissioner::PricingActions::CreateRouteAdjustments' do
|
|
11
|
+
association :pricing_rule_group, factory: :pricing_rule_group
|
|
12
|
+
end
|
|
9
13
|
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
FactoryBot.define do
|
|
2
|
+
factory :cm_pricing_model_route, class: 'SpreeCmCommissioner::PricingModelRoute' do
|
|
3
|
+
association :pricing_model, factory: :cm_pricing_model
|
|
4
|
+
association :route, factory: :cm_route
|
|
5
|
+
association :origin_place, factory: :cm_place
|
|
6
|
+
association :destination_place, factory: :cm_place
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
module SpreeCmCommissioner::Transit
|
|
2
2
|
class Leg
|
|
3
|
-
attr_accessor :direction, :trip_id, :boarding_trip_stop_id, :drop_off_trip_stop_id, :seat_selections
|
|
3
|
+
attr_accessor :direction, :trip_id, :main_trip_id, :boarding_trip_stop_id, :drop_off_trip_stop_id, :seat_selections
|
|
4
4
|
|
|
5
5
|
def initialize(options = {})
|
|
6
6
|
@direction = options[:direction]
|
|
7
7
|
@trip_id = options[:trip_id]
|
|
8
|
+
@main_trip_id = options[:main_trip_id]
|
|
8
9
|
@boarding_trip_stop_id = options[:boarding_trip_stop_id]
|
|
9
10
|
@drop_off_trip_stop_id = options[:drop_off_trip_stop_id]
|
|
10
11
|
@seat_selections = options[:seat_selections] || []
|
|
@@ -14,6 +15,7 @@ module SpreeCmCommissioner::Transit
|
|
|
14
15
|
new(
|
|
15
16
|
direction: hash[:direction], # outbound / inbound
|
|
16
17
|
trip_id: hash[:trip_id],
|
|
18
|
+
main_trip_id: hash[:main_trip_id],
|
|
17
19
|
boarding_trip_stop_id: hash[:boarding_trip_stop_id],
|
|
18
20
|
drop_off_trip_stop_id: hash[:drop_off_trip_stop_id],
|
|
19
21
|
seat_selections: (hash[:seat_selections] || []).map { |seat_selection| SeatSelection.from_hash(seat_selection) }
|
|
@@ -28,6 +30,7 @@ module SpreeCmCommissioner::Transit
|
|
|
28
30
|
{
|
|
29
31
|
direction: @direction,
|
|
30
32
|
trip_id: @trip_id,
|
|
33
|
+
main_trip_id: @main_trip_id,
|
|
31
34
|
boarding_trip_stop_id: @boarding_trip_stop_id,
|
|
32
35
|
drop_off_trip_stop_id: @drop_off_trip_stop_id,
|
|
33
36
|
seat_selections: @seat_selections.map(&:to_h)
|
|
@@ -30,6 +30,7 @@ require 'spree_cm_commissioner/transit/trip_stop_form'
|
|
|
30
30
|
require 'spree_cm_commissioner/transit/service_calendar_form'
|
|
31
31
|
require 'spree_cm_commissioner/intercity_taxi/map_place'
|
|
32
32
|
require 'spree_cm_commissioner/distance'
|
|
33
|
+
require 'spree_cm_commissioner/check_in_sessions_metric'
|
|
33
34
|
|
|
34
35
|
require 'activerecord_multi_tenant'
|
|
35
36
|
require 'google/cloud/recaptcha_enterprise'
|
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.5.
|
|
4
|
+
version: 2.5.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- You
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: spree
|
|
@@ -910,6 +910,7 @@ files:
|
|
|
910
910
|
- app/controllers/spree/api/v2/operator/event_charts_controller.rb
|
|
911
911
|
- app/controllers/spree/api/v2/operator/event_qrs_controller.rb
|
|
912
912
|
- app/controllers/spree/api/v2/operator/event_ticket_aggregators_controller.rb
|
|
913
|
+
- app/controllers/spree/api/v2/operator/guest_json_gzips_controller.rb
|
|
913
914
|
- app/controllers/spree/api/v2/operator/guests_controller.rb
|
|
914
915
|
- app/controllers/spree/api/v2/operator/line_items_controller.rb
|
|
915
916
|
- app/controllers/spree/api/v2/operator/pie_chart_event_aggregators_controller.rb
|
|
@@ -1319,6 +1320,7 @@ files:
|
|
|
1319
1320
|
- app/jobs/spree_cm_commissioner/ensure_correct_product_type_job.rb
|
|
1320
1321
|
- app/jobs/spree_cm_commissioner/ensure_event_for_product_line_item_guests_job.rb
|
|
1321
1322
|
- app/jobs/spree_cm_commissioner/ensure_event_id_for_guests_job.rb
|
|
1323
|
+
- app/jobs/spree_cm_commissioner/export_job.rb
|
|
1322
1324
|
- app/jobs/spree_cm_commissioner/firebase_email_fetcher_job.rb
|
|
1323
1325
|
- app/jobs/spree_cm_commissioner/guests/preload_check_in_session_ids_job.rb
|
|
1324
1326
|
- app/jobs/spree_cm_commissioner/import_order_job.rb
|
|
@@ -1444,6 +1446,7 @@ files:
|
|
|
1444
1446
|
- app/models/spree_cm_commissioner/dynamic_field_option.rb
|
|
1445
1447
|
- app/models/spree_cm_commissioner/event_ticket_google_wallet.rb
|
|
1446
1448
|
- app/models/spree_cm_commissioner/export.rb
|
|
1449
|
+
- app/models/spree_cm_commissioner/exports/operator_guest_json_gzip.rb
|
|
1447
1450
|
- app/models/spree_cm_commissioner/feature_image.rb
|
|
1448
1451
|
- app/models/spree_cm_commissioner/front_image.rb
|
|
1449
1452
|
- app/models/spree_cm_commissioner/google_wallet.rb
|
|
@@ -1515,7 +1518,10 @@ files:
|
|
|
1515
1518
|
- app/models/spree_cm_commissioner/pricing_action.rb
|
|
1516
1519
|
- app/models/spree_cm_commissioner/pricing_actions/create_guest_adjustments.rb
|
|
1517
1520
|
- app/models/spree_cm_commissioner/pricing_actions/create_line_item_adjustments.rb
|
|
1521
|
+
- app/models/spree_cm_commissioner/pricing_actions/create_route_adjustments.rb
|
|
1518
1522
|
- app/models/spree_cm_commissioner/pricing_model.rb
|
|
1523
|
+
- app/models/spree_cm_commissioner/pricing_model_handler/order.rb
|
|
1524
|
+
- app/models/spree_cm_commissioner/pricing_model_route.rb
|
|
1519
1525
|
- app/models/spree_cm_commissioner/pricing_model_variant.rb
|
|
1520
1526
|
- app/models/spree_cm_commissioner/pricing_rule.rb
|
|
1521
1527
|
- app/models/spree_cm_commissioner/pricing_rule_group.rb
|
|
@@ -1776,6 +1782,7 @@ files:
|
|
|
1776
1782
|
- app/overrides/spree/layouts/admin/map_head.html.erb.deface
|
|
1777
1783
|
- app/presenters/spree/variants/visible_options_presenter.rb
|
|
1778
1784
|
- app/queries/spree_cm_commissioner/accommodation_query.rb
|
|
1785
|
+
- app/queries/spree_cm_commissioner/check_in_sessions_metrics_query.rb
|
|
1779
1786
|
- app/queries/spree_cm_commissioner/dashboard_crew_event_query.rb
|
|
1780
1787
|
- app/queries/spree_cm_commissioner/event_chart_queries.rb
|
|
1781
1788
|
- app/queries/spree_cm_commissioner/event_ticket_aggregator_query.rb
|
|
@@ -1912,6 +1919,7 @@ files:
|
|
|
1912
1919
|
- app/serializers/spree_cm_commissioner/v2/operator/dashboard_crew_event_serializer.rb
|
|
1913
1920
|
- app/serializers/spree_cm_commissioner/v2/operator/event_qr_serializer.rb
|
|
1914
1921
|
- app/serializers/spree_cm_commissioner/v2/operator/event_ticket_aggregator_serializer.rb
|
|
1922
|
+
- app/serializers/spree_cm_commissioner/v2/operator/export_serializer.rb
|
|
1915
1923
|
- app/serializers/spree_cm_commissioner/v2/operator/guest_serializer.rb
|
|
1916
1924
|
- app/serializers/spree_cm_commissioner/v2/operator/line_item_serializer.rb
|
|
1917
1925
|
- app/serializers/spree_cm_commissioner/v2/operator/order_serializer.rb
|
|
@@ -2043,9 +2051,9 @@ files:
|
|
|
2043
2051
|
- app/services/spree_cm_commissioner/intercity_taxi_order/calculate_distance.rb
|
|
2044
2052
|
- app/services/spree_cm_commissioner/intercity_taxi_order/create.rb
|
|
2045
2053
|
- app/services/spree_cm_commissioner/intercity_taxi_order/update.rb
|
|
2046
|
-
- app/services/spree_cm_commissioner/line_items/apply_pricing_models.rb
|
|
2047
2054
|
- app/services/spree_cm_commissioner/line_items/sync_event_date.rb
|
|
2048
2055
|
- app/services/spree_cm_commissioner/metafields/product_metadata_service.rb
|
|
2056
|
+
- app/services/spree_cm_commissioner/operator_guest_json_gzips/create.rb
|
|
2049
2057
|
- app/services/spree_cm_commissioner/order_params_checker.rb
|
|
2050
2058
|
- app/services/spree_cm_commissioner/orders/bulk_archive_inactive_orders.rb
|
|
2051
2059
|
- app/services/spree_cm_commissioner/orders/daily_archive_inactive_orders.rb
|
|
@@ -2056,7 +2064,6 @@ files:
|
|
|
2056
2064
|
- app/services/spree_cm_commissioner/organizer/export_invite_guest_csv_service.rb
|
|
2057
2065
|
- app/services/spree_cm_commissioner/payment_method_type_mapper.rb
|
|
2058
2066
|
- app/services/spree_cm_commissioner/penalty_calculator.rb
|
|
2059
|
-
- app/services/spree_cm_commissioner/pricing_models/apply.rb
|
|
2060
2067
|
- app/services/spree_cm_commissioner/pricing_models/create_with_rule_groups.rb
|
|
2061
2068
|
- app/services/spree_cm_commissioner/pricing_models/update_with_rule_groups.rb
|
|
2062
2069
|
- app/services/spree_cm_commissioner/pricing_rules/build_params.rb
|
|
@@ -2998,9 +3005,15 @@ files:
|
|
|
2998
3005
|
- db/migrate/20260105072450_migrate_cm_trip_stops_to_support_trip_connection.rb
|
|
2999
3006
|
- db/migrate/20260106093359_add_contact_phone_to_cm_vendor_places.rb
|
|
3000
3007
|
- db/migrate/20260108101406_add_allow_booking_to_cm_trips.rb
|
|
3008
|
+
- db/migrate/20260110073000_create_cm_pricing_model_routes.rb
|
|
3001
3009
|
- db/migrate/20260121024645_add_nationality_group_to_cm_guests.rb
|
|
3002
3010
|
- db/migrate/20260126110528_seed_user_initial_usernames.rb
|
|
3003
3011
|
- db/migrate/20260128043540_add_counter_cache_to_spree_users.rb
|
|
3012
|
+
- db/migrate/20260128093305_add_exportable_to_cm_exports.rb
|
|
3013
|
+
- db/migrate/20260128093313_add_metadata_to_cm_exports.rb
|
|
3014
|
+
- db/migrate/20260129082338_remove_preferences_file_name_columns_from_cm_exports.rb
|
|
3015
|
+
- db/migrate/20260204092321_add_type_to_cm_exports.rb
|
|
3016
|
+
- db/migrate/20260204183545_add_term_accepted_at_to_spree_orders.rb
|
|
3004
3017
|
- docker-compose.yml
|
|
3005
3018
|
- docs/api/scoped-access-token-endpoints.md
|
|
3006
3019
|
- docs/option_types/attr_types.md
|
|
@@ -3025,6 +3038,7 @@ files:
|
|
|
3025
3038
|
- lib/spree_cm_commissioner.rb
|
|
3026
3039
|
- lib/spree_cm_commissioner/cached_inventory_item.rb
|
|
3027
3040
|
- lib/spree_cm_commissioner/calendar_event.rb
|
|
3041
|
+
- lib/spree_cm_commissioner/check_in_sessions_metric.rb
|
|
3028
3042
|
- lib/spree_cm_commissioner/distance.rb
|
|
3029
3043
|
- lib/spree_cm_commissioner/engine.rb
|
|
3030
3044
|
- lib/spree_cm_commissioner/factories.rb
|
|
@@ -3081,6 +3095,7 @@ files:
|
|
|
3081
3095
|
- lib/spree_cm_commissioner/test_helper/factories/place_factory.rb
|
|
3082
3096
|
- lib/spree_cm_commissioner/test_helper/factories/pricing_action_factory.rb
|
|
3083
3097
|
- lib/spree_cm_commissioner/test_helper/factories/pricing_model_factory.rb
|
|
3098
|
+
- lib/spree_cm_commissioner/test_helper/factories/pricing_model_route_factory.rb
|
|
3084
3099
|
- lib/spree_cm_commissioner/test_helper/factories/pricing_model_variant_factory.rb
|
|
3085
3100
|
- lib/spree_cm_commissioner/test_helper/factories/pricing_rule_factory.rb
|
|
3086
3101
|
- lib/spree_cm_commissioner/test_helper/factories/pricing_rule_group_factory.rb
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
module SpreeCmCommissioner
|
|
2
|
-
module LineItems
|
|
3
|
-
class ApplyPricingModels
|
|
4
|
-
prepend ::Spree::ServiceModule::Base
|
|
5
|
-
|
|
6
|
-
def call(order:, line_item:)
|
|
7
|
-
return success(nil) if line_item.blank?
|
|
8
|
-
|
|
9
|
-
return success(line_item) unless order&.persisted?
|
|
10
|
-
return success(line_item) if line_item.variant.blank?
|
|
11
|
-
|
|
12
|
-
active_pricing_models = line_item.variant.pricing_models.active
|
|
13
|
-
return success(line_item) unless active_pricing_models.exists?
|
|
14
|
-
|
|
15
|
-
line_item.adjustments.pricing_action.delete_all
|
|
16
|
-
|
|
17
|
-
active_pricing_models.each do |pricing_model|
|
|
18
|
-
SpreeCmCommissioner::PricingModels::Apply.new(
|
|
19
|
-
line_item: line_item,
|
|
20
|
-
pricing_model: pricing_model
|
|
21
|
-
).call
|
|
22
|
-
end
|
|
23
|
-
success(line_item)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
module SpreeCmCommissioner
|
|
2
|
-
module PricingModels
|
|
3
|
-
class Apply
|
|
4
|
-
def initialize(line_item:, pricing_model:)
|
|
5
|
-
@line_item = line_item
|
|
6
|
-
@pricing_model = pricing_model
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def call
|
|
10
|
-
pricing_model.pricing_rule_groups.each do |group|
|
|
11
|
-
apply_group(group, line_item)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
attr_reader :line_item, :pricing_model
|
|
18
|
-
|
|
19
|
-
def apply_group(group, line_item)
|
|
20
|
-
eligible_rules = group.pricing_rules.select { |r| r.eligible?(line_item) }
|
|
21
|
-
|
|
22
|
-
return if eligible_rules.empty?
|
|
23
|
-
|
|
24
|
-
if group_eligible?(group, eligible_rules)
|
|
25
|
-
group.pricing_action&.perform(line_item)
|
|
26
|
-
else
|
|
27
|
-
Rails.logger.info("Group #{group.id} not eligible for line_item #{line_item.id}")
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def group_eligible?(group, eligible_rules)
|
|
32
|
-
case group.match_type
|
|
33
|
-
when 'all'
|
|
34
|
-
eligible_rules.size == group.pricing_rules.size
|
|
35
|
-
when 'any'
|
|
36
|
-
eligible_rules.any?
|
|
37
|
-
else
|
|
38
|
-
false
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|