spree_cm_commissioner 2.5.1.pre.pre1 → 2.5.1.pre.pre2
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/admin/guests_controller.rb +5 -5
- data/app/controllers/spree/api/chatrace/check_ins_controller.rb +6 -4
- data/app/controllers/spree/api/chatrace/guests_controller.rb +5 -18
- data/app/controllers/spree/api/v2/operator/check_in_bulks_controller.rb +6 -5
- data/app/controllers/spree/api/v2/operator/check_in_sessions_controller.rb +32 -0
- data/app/controllers/spree/api/v2/operator/check_ins_controller.rb +5 -5
- data/app/controllers/spree/api/v2/operator/event_qrs_controller.rb +2 -0
- data/app/controllers/spree/api/v2/storefront/popular_route_places_controller.rb +1 -1
- data/app/controllers/spree/api/v2/storefront/self_check_in_controller.rb +7 -7
- data/app/controllers/spree/api/v2/storefront/transit/draft_orders_controller.rb +4 -4
- data/app/controllers/spree/api/v2/tenant/popular_route_places_controller.rb +60 -0
- data/app/controllers/spree/api/v2/tenant/routes_controller.rb +50 -0
- data/app/controllers/spree/api/v2/tenant/transit/draft_orders_controller.rb +46 -0
- data/app/controllers/spree/events/guests_controller.rb +9 -10
- data/app/controllers/spree/transit/trips_controller.rb +3 -3
- data/app/finders/spree_cm_commissioner/places/find_with_route.rb +12 -12
- data/app/finders/spree_cm_commissioner/route_metrics/find_popular.rb +44 -0
- data/app/finders/spree_cm_commissioner/routes/find.rb +94 -0
- data/app/finders/spree_cm_commissioner/routes/find_popular.rb +20 -35
- data/app/interactors/spree_cm_commissioner/event_qr_generator.rb +2 -1
- data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +11 -4
- data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +10 -1
- data/app/interactors/spree_cm_commissioner/trip_clone_creator.rb +4 -3
- data/app/interactors/spree_cm_commissioner/trip_stops_creator.rb +2 -2
- data/app/jobs/spree_cm_commissioner/guests/preload_check_in_session_ids_job.rb +10 -0
- data/app/jobs/spree_cm_commissioner/route_metrics/decrease_trip_count_job.rb +10 -0
- data/app/jobs/spree_cm_commissioner/route_metrics/increase_fulfilled_order_count_job.rb +10 -0
- data/app/jobs/spree_cm_commissioner/route_metrics/increase_order_count_job.rb +10 -0
- data/app/jobs/spree_cm_commissioner/route_metrics/increase_trip_count_job.rb +10 -0
- data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +2 -2
- data/app/models/concerns/spree_cm_commissioner/route_order_countable.rb +2 -2
- data/app/models/spree_cm_commissioner/check_in.rb +34 -7
- data/app/models/spree_cm_commissioner/check_in_session.rb +8 -3
- data/app/models/spree_cm_commissioner/guest.rb +60 -28
- data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +2 -2
- data/app/models/spree_cm_commissioner/place.rb +5 -8
- data/app/models/spree_cm_commissioner/pricing_actions/create_guest_adjustments.rb +52 -0
- data/app/models/spree_cm_commissioner/pricing_actions/create_line_item_adjustments.rb +6 -0
- data/app/models/spree_cm_commissioner/pricing_rule.rb +4 -0
- data/app/models/spree_cm_commissioner/pricing_rules/age_group.rb +45 -0
- data/app/models/spree_cm_commissioner/pricing_rules/nationality.rb +21 -2
- data/app/models/spree_cm_commissioner/pricing_rules/nationality_group.rb +41 -0
- data/app/models/spree_cm_commissioner/product_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/route.rb +46 -5
- data/app/models/spree_cm_commissioner/route_metric.rb +21 -0
- data/app/models/spree_cm_commissioner/route_photo.rb +12 -0
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/trip.rb +8 -33
- data/app/models/spree_cm_commissioner/trip_stop.rb +16 -2
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +3 -1
- data/app/queries/spree_cm_commissioner/trip_query.rb +2 -2
- data/app/serializers/spree/v2/tenant/transit_cart_serializer.rb +11 -0
- data/app/serializers/spree_cm_commissioner/v2/operator/check_in_serializer.rb +1 -2
- data/app/serializers/spree_cm_commissioner/v2/operator/check_in_session_serializer.rb +9 -0
- data/app/serializers/spree_cm_commissioner/v2/operator/guest_serializer.rb +1 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +2 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/route_serializer.rb +3 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/transit_line_item_serializer.rb +17 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_stop_serializer.rb +1 -1
- data/app/services/spree_cm_commissioner/check_ins/create_bulk.rb +65 -0
- data/app/services/spree_cm_commissioner/check_ins/destroy_bulk.rb +54 -0
- data/app/services/spree_cm_commissioner/guests/preload_check_in_session_ids.rb +22 -0
- data/app/services/spree_cm_commissioner/pricing_models/create_with_rule_groups.rb +56 -0
- data/app/services/spree_cm_commissioner/pricing_models/update_with_rule_groups.rb +69 -0
- data/app/services/spree_cm_commissioner/pricing_rules/build_params.rb +16 -7
- data/app/services/spree_cm_commissioner/route_metrics/decrease_trip_count.rb +31 -0
- data/app/services/spree_cm_commissioner/{routes/increment_fulfilled_order_count.rb → route_metrics/increase_fulfilled_order_count.rb} +3 -3
- data/app/services/spree_cm_commissioner/{routes/increment_order_count.rb → route_metrics/increase_order_count.rb} +3 -3
- data/app/services/spree_cm_commissioner/route_metrics/increase_trip_count.rb +31 -0
- data/app/services/spree_cm_commissioner/{routes/base_update_order_metrics.rb → route_metrics/update_route_metrics.rb} +11 -16
- data/app/services/spree_cm_commissioner/routes/create.rb +51 -0
- data/app/services/spree_cm_commissioner/routes/update.rb +25 -0
- data/app/{interactors/spree_cm_commissioner/transit/draft_order_creator.rb → services/spree_cm_commissioner/transit_order/create.rb} +13 -16
- data/app/services/spree_cm_commissioner/trips/create_single_leg.rb +123 -0
- data/app/services/spree_cm_commissioner/trips/service_calendars/create_or_update.rb +54 -0
- data/app/services/spree_cm_commissioner/trips/update_single_leg.rb +88 -0
- data/app/services/spree_cm_commissioner/trips/variants/create.rb +103 -0
- data/app/views/spree/transit/trip_stops/index.html.erb +4 -2
- data/app/views/spree_cm_commissioner/guest_mailer/send_ticket_to_guest.html.erb +0 -1
- data/config/initializers/spree_permitted_attributes.rb +11 -0
- data/config/locales/en.yml +2 -0
- data/config/locales/km.yml +2 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20251224033103_migrate_cm_routes_to_cm_route_metrics.rb +17 -0
- data/db/migrate/20251224033910_migrate_cm_vendor_routes_to_cm_routes.rb +30 -0
- data/db/migrate/20251225100000_add_age_group_to_cm_guests.rb +6 -0
- data/db/migrate/20260105024742_add_type_to_cm_pricing_actions.rb +11 -0
- data/db/migrate/20260105072450_migrate_cm_trip_stops_to_support_trip_connection.rb +12 -0
- data/db/migrate/20260108101406_add_allow_booking_to_cm_trips.rb +5 -0
- data/db/migrate/20260121024645_add_nationality_group_to_cm_guests.rb +5 -0
- data/docs/pricing_model/age_group.md +40 -0
- data/docs/pricing_model/nationality_group.md +35 -0
- data/lib/spree_cm_commissioner/test_helper/factories/check_in_factory.rb +3 -1
- data/lib/spree_cm_commissioner/test_helper/factories/check_in_session_factory.rb +26 -0
- data/lib/spree_cm_commissioner/test_helper/factories/guest_factory.rb +4 -0
- data/lib/spree_cm_commissioner/test_helper/factories/pricing_action_factory.rb +4 -0
- data/lib/spree_cm_commissioner/test_helper/factories/pricing_rule_factory.rb +45 -1
- data/lib/spree_cm_commissioner/test_helper/factories/route_factory.rb +7 -6
- data/lib/spree_cm_commissioner/test_helper/factories/route_metric_factory.rb +12 -0
- data/lib/spree_cm_commissioner/test_helper/factories/route_photo_factory.rb +5 -0
- data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +4 -1
- data/lib/spree_cm_commissioner/test_helper/factories/trip_stop_factory.rb +3 -1
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +2 -0
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +22 -0
- data/lib/spree_cm_commissioner/transit/route_stop.rb +61 -0
- data/lib/spree_cm_commissioner/transit/route_stop_collection.rb +175 -0
- data/lib/spree_cm_commissioner/transit/trip_form.rb +81 -0
- data/lib/spree_cm_commissioner/transit/trip_stop_form.rb +61 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +4 -0
- metadata +54 -20
- data/app/interactors/spree_cm_commissioner/check_in_bulk_creator.rb +0 -71
- data/app/interactors/spree_cm_commissioner/check_in_destroyer.rb +0 -43
- data/app/jobs/spree_cm_commissioner/transit/route_fulfilled_order_count_incrementer_job.rb +0 -10
- data/app/jobs/spree_cm_commissioner/transit/route_order_count_incrementer_job.rb +0 -10
- data/app/jobs/spree_cm_commissioner/transit/route_previous_trip_count_decrementer_job.rb +0 -13
- data/app/jobs/spree_cm_commissioner/transit/route_trip_count_decrementer_job.rb +0 -10
- data/app/jobs/spree_cm_commissioner/transit/route_trip_count_incrementer_job.rb +0 -10
- data/app/models/concerns/spree_cm_commissioner/route_trip_count_callbacks.rb +0 -48
- data/app/models/spree_cm_commissioner/trip_connection.rb +0 -36
- data/app/models/spree_cm_commissioner/vendor_route.rb +0 -9
- data/app/services/spree_cm_commissioner/routes/decrement_previous_trip_count.rb +0 -30
- data/app/services/spree_cm_commissioner/routes/decrement_trip_count.rb +0 -33
- data/app/services/spree_cm_commissioner/routes/increment_trip_count.rb +0 -33
- data/lib/spree_cm_commissioner/test_helper/factories/trip_connection_factory.rb +0 -6
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module PricingModels
|
|
3
|
+
class CreateWithRuleGroups
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(vendor:, params:, route: nil, origin_place_id: nil, destination_place_id: nil)
|
|
7
|
+
pricing_model = vendor.pricing_models.new(model_params(params))
|
|
8
|
+
|
|
9
|
+
ApplicationRecord.transaction do
|
|
10
|
+
pricing_model.save!
|
|
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?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
success(pricing_model)
|
|
16
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
17
|
+
failure(pricing_model, e.message)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def model_params(params)
|
|
23
|
+
{
|
|
24
|
+
name: params[:name],
|
|
25
|
+
description: params[:description],
|
|
26
|
+
status: params[:status] || 'draft',
|
|
27
|
+
variant_ids: params[:variant_ids] || []
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def build_rule_groups(pricing_model, rule_groups_params)
|
|
32
|
+
return if rule_groups_params.blank?
|
|
33
|
+
|
|
34
|
+
rule_groups_params.each do |template_key, group_params|
|
|
35
|
+
next if group_params.blank?
|
|
36
|
+
|
|
37
|
+
PricingRules::Create.call(
|
|
38
|
+
pricing_model: pricing_model,
|
|
39
|
+
params: group_params.merge(template_key: template_key)
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def create_route_assignment(pricing_model, route, origin_place_id, destination_place_id)
|
|
45
|
+
return unless origin_place_id.present? && destination_place_id.present?
|
|
46
|
+
|
|
47
|
+
PricingModelRoute.create!(
|
|
48
|
+
route: route,
|
|
49
|
+
pricing_model: pricing_model,
|
|
50
|
+
origin_place_id: origin_place_id,
|
|
51
|
+
destination_place_id: destination_place_id
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module PricingModels
|
|
3
|
+
class UpdateWithRuleGroups
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(pricing_model:, params:, route: nil, origin_place_id: nil, destination_place_id: nil)
|
|
7
|
+
ApplicationRecord.transaction do
|
|
8
|
+
pricing_model.update!(model_params(params))
|
|
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?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
success(pricing_model)
|
|
14
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
15
|
+
failure(pricing_model, e.message)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def model_params(params)
|
|
21
|
+
{
|
|
22
|
+
name: params[:name],
|
|
23
|
+
description: params[:description],
|
|
24
|
+
status: params[:status],
|
|
25
|
+
variant_ids: params[:variant_ids] || []
|
|
26
|
+
}.compact
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def sync_rule_groups(pricing_model, rule_groups_params)
|
|
30
|
+
return if rule_groups_params.nil?
|
|
31
|
+
|
|
32
|
+
keep_ids = []
|
|
33
|
+
|
|
34
|
+
rule_groups_params.each do |template_key, group_params|
|
|
35
|
+
next if group_params.blank?
|
|
36
|
+
|
|
37
|
+
if group_params[:id].present?
|
|
38
|
+
group = pricing_model.pricing_rule_groups.find(group_params[:id])
|
|
39
|
+
PricingRules::Update.call(
|
|
40
|
+
pricing_rule_group: group,
|
|
41
|
+
params: group_params.merge(template_key: template_key)
|
|
42
|
+
)
|
|
43
|
+
keep_ids << group.id
|
|
44
|
+
else
|
|
45
|
+
new_group = PricingRules::Create.call(
|
|
46
|
+
pricing_model: pricing_model,
|
|
47
|
+
params: group_params.merge(template_key: template_key)
|
|
48
|
+
)
|
|
49
|
+
keep_ids << new_group.id if new_group.persisted?
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
pricing_model.pricing_rule_groups.where.not(id: keep_ids).destroy_all
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def update_route_assignment(pricing_model, route, origin_place_id, destination_place_id)
|
|
56
|
+
return unless origin_place_id.present? && destination_place_id.present?
|
|
57
|
+
|
|
58
|
+
route_assignment = PricingModelRoute.find_or_initialize_by(
|
|
59
|
+
route: route,
|
|
60
|
+
pricing_model: pricing_model
|
|
61
|
+
)
|
|
62
|
+
route_assignment.update!(
|
|
63
|
+
origin_place_id: origin_place_id,
|
|
64
|
+
destination_place_id: destination_place_id
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -5,14 +5,16 @@ module SpreeCmCommissioner
|
|
|
5
5
|
|
|
6
6
|
def permitted_group_params(params)
|
|
7
7
|
group_params = params[:spree_cm_commissioner_pricing_rule_group] || params
|
|
8
|
+
template_key = group_params[:template_key] || params[:template_key]
|
|
9
|
+
template = PRICING_RULE_GROUP_TEMPLATES[template_key.to_sym] if template_key
|
|
8
10
|
|
|
9
11
|
{
|
|
10
|
-
name: group_params[:name],
|
|
11
|
-
status: group_params[:status],
|
|
12
|
-
template_key:
|
|
13
|
-
match_type: group_params[:match_type],
|
|
12
|
+
name: template&.dig(:name) || group_params[:name],
|
|
13
|
+
status: group_params[:status] || 'active',
|
|
14
|
+
template_key: template_key,
|
|
15
|
+
match_type: group_params[:match_type] || 'any',
|
|
14
16
|
pricing_rules_attributes: build_rules_attributes(params[:pricing_rules]),
|
|
15
|
-
pricing_action_attributes: build_action_attributes(params[:pricing_action])
|
|
17
|
+
pricing_action_attributes: build_action_attributes(params[:pricing_action], template)
|
|
16
18
|
}
|
|
17
19
|
end
|
|
18
20
|
|
|
@@ -29,14 +31,21 @@ module SpreeCmCommissioner
|
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
def build_action_attributes(action_data)
|
|
34
|
+
def build_action_attributes(action_data, template = nil)
|
|
33
35
|
return nil unless action_data&.dig(:calculator)
|
|
34
36
|
|
|
35
37
|
calc_data = action_data[:calculator]
|
|
36
38
|
calculator = calc_data[:type].safe_constantize&.new
|
|
39
|
+
|
|
37
40
|
set_preferences(calculator, calc_data[:preferences]) if calculator
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
action_type = action_data[:type] || template&.dig(:action, :type)
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
id: action_data[:id],
|
|
46
|
+
type: action_type,
|
|
47
|
+
calculator: calculator
|
|
48
|
+
}
|
|
40
49
|
end
|
|
41
50
|
|
|
42
51
|
def set_preferences(calculator, preferences)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class DecreaseTripCount
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(trip:)
|
|
7
|
+
return failure(nil, 'Trip not found') unless trip
|
|
8
|
+
|
|
9
|
+
route_metric = find_or_create_route_metric(trip)
|
|
10
|
+
|
|
11
|
+
route_metric.with_lock do
|
|
12
|
+
route_metric.update!(trip_count: [route_metric.trip_count - 1, 0].max)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
success(trip: trip)
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
failure(nil, e.message)
|
|
18
|
+
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
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
|
-
module
|
|
3
|
-
class
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class IncreaseFulfilledOrderCount
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
6
|
def call(order:)
|
|
7
7
|
return failure(nil, 'Order not found') unless order
|
|
8
8
|
|
|
9
|
-
SpreeCmCommissioner::
|
|
9
|
+
SpreeCmCommissioner::RouteMetrics::UpdateRouteMetrics
|
|
10
10
|
.call(order: order, attribute: :fulfilled_order_count)
|
|
11
11
|
|
|
12
12
|
success(order: order)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
|
-
module
|
|
3
|
-
class
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class IncreaseOrderCount
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
6
|
def call(order:)
|
|
7
7
|
return failure(nil, 'Order not found') unless order
|
|
8
8
|
|
|
9
|
-
SpreeCmCommissioner::
|
|
9
|
+
SpreeCmCommissioner::RouteMetrics::UpdateRouteMetrics
|
|
10
10
|
.new(order: order, attribute: :order_count)
|
|
11
11
|
.call
|
|
12
12
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class IncreaseTripCount
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(trip:)
|
|
7
|
+
return failure(nil, 'Trip not found') unless trip
|
|
8
|
+
|
|
9
|
+
route_metric = find_or_create_route_metric(trip)
|
|
10
|
+
|
|
11
|
+
route_metric.with_lock do
|
|
12
|
+
route_metric.update!(trip_count: route_metric.trip_count + 1)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
success(trip: trip)
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
failure(nil, e.message)
|
|
18
|
+
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
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
|
-
module
|
|
3
|
-
class
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class UpdateRouteMetrics
|
|
4
4
|
attr_reader :order, :attribute
|
|
5
5
|
|
|
6
6
|
SUPPORTED_ATTRIBUTES = %i[order_count fulfilled_order_count].freeze
|
|
@@ -31,26 +31,21 @@ module SpreeCmCommissioner
|
|
|
31
31
|
trip = product&.trip
|
|
32
32
|
return unless trip
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
route_metric = find_or_create_route_metric_for_trip(trip)
|
|
35
|
+
increment_route_by(route_metric, line_item.quantity)
|
|
36
|
+
|
|
37
|
+
route = trip.route
|
|
38
|
+
increment_route_by(route, line_item.quantity) if route
|
|
37
39
|
end
|
|
38
40
|
|
|
39
|
-
def
|
|
40
|
-
SpreeCmCommissioner::
|
|
41
|
+
def find_or_create_route_metric_for_trip(trip)
|
|
42
|
+
SpreeCmCommissioner::RouteMetric.find_or_create_by(
|
|
41
43
|
origin_place_id: trip.origin_place_id,
|
|
42
|
-
destination_place_id: trip.destination_place_id
|
|
44
|
+
destination_place_id: trip.destination_place_id,
|
|
45
|
+
route_type: trip.route_type
|
|
43
46
|
)
|
|
44
47
|
end
|
|
45
48
|
|
|
46
|
-
def ensure_trip_route(trip, route)
|
|
47
|
-
trip_route_id = trip.respond_to?(:route_id) ? trip.route_id : nil
|
|
48
|
-
|
|
49
|
-
return unless trip.respond_to?(:update_column) && trip_route_id != route.id
|
|
50
|
-
|
|
51
|
-
trip.update_column(:route_id, route.id) # rubocop:disable Rails/SkipsModelValidations
|
|
52
|
-
end
|
|
53
|
-
|
|
54
49
|
def increment_route_by(route, qty)
|
|
55
50
|
route.with_lock do
|
|
56
51
|
current_value = route.public_send(attribute) || 0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Routes
|
|
3
|
+
class Create
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
# @param vendor [Spree::Vendor]
|
|
7
|
+
# @param route_params [Hash]
|
|
8
|
+
# @param route_stops [SpreeCmCommissioner::Transit::RouteStopCollection]
|
|
9
|
+
def call(vendor:, route_params:, route_stops:)
|
|
10
|
+
# vendor_id, tenant_id, origin_place_id, destination_place_id are excluded and set automatically.
|
|
11
|
+
attrs = ::Spree::PermittedAttributes.route_attributes
|
|
12
|
+
.index_with { |attr_key| route_params[attr_key] }
|
|
13
|
+
.except(:vendor_id, :tenant_id, :route_stops, :origin_place_id, :destination_place_id)
|
|
14
|
+
.compact
|
|
15
|
+
|
|
16
|
+
return failure(nil, 'Route stops are required') if route_stops.length < 2
|
|
17
|
+
|
|
18
|
+
origin_place = find_place_for(route_stops, route_stops.first)
|
|
19
|
+
destination_place = find_place_for(route_stops, route_stops.last)
|
|
20
|
+
|
|
21
|
+
return failure(nil, 'Origin or destination place could not be determined') if origin_place.nil? || destination_place.nil?
|
|
22
|
+
return failure(nil, 'Route with origin & destination already exists') if vendor.routes.exists?(
|
|
23
|
+
origin_place_id: origin_place.id,
|
|
24
|
+
destination_place_id: destination_place.id
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
attrs = attrs.merge(
|
|
28
|
+
tenant_id: vendor.tenant_id,
|
|
29
|
+
route_name: attrs[:route_name] || "#{origin_place.name} -> #{destination_place.name}",
|
|
30
|
+
origin_place_id: origin_place.id,
|
|
31
|
+
destination_place_id: destination_place.id,
|
|
32
|
+
route_stops: route_stops
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
route = vendor.routes.new(attrs)
|
|
36
|
+
if route.save
|
|
37
|
+
success(route: route)
|
|
38
|
+
else
|
|
39
|
+
failure(route.errors)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def find_place_for(route_stops, route_stop)
|
|
44
|
+
return nil if route_stop.nil?
|
|
45
|
+
|
|
46
|
+
@locations ||= SpreeCmCommissioner::VendorPlace.where(id: route_stops.map(&:location_id).uniq).index_by(&:id)
|
|
47
|
+
@locations[route_stop.location_id]&.place
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Routes
|
|
3
|
+
class Update
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(vendor:, route:, route_params:)
|
|
7
|
+
# vendor_id, tenant_id, origin_place_id, destination_place_id are excluded and set automatically.
|
|
8
|
+
# route_stops is not updateable.
|
|
9
|
+
attrs = ::Spree::PermittedAttributes.route_attributes
|
|
10
|
+
.index_with { |attr_key| route_params[attr_key] }
|
|
11
|
+
.except(:vendor_id, :tenant_id, :route_stops, :origin_place_id, :destination_place_id)
|
|
12
|
+
.compact
|
|
13
|
+
|
|
14
|
+
route = vendor.routes.find_by(id: route.id)
|
|
15
|
+
return failure(nil, :route_not_found) if route.nil?
|
|
16
|
+
|
|
17
|
+
if route.update(attrs)
|
|
18
|
+
success(route: route)
|
|
19
|
+
else
|
|
20
|
+
failure(route.errors)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SpreeCmCommissioner::TransitOrder::Create creates a new order for a entire journey, including outbound and (if present) inbound directions.
|
|
2
2
|
#
|
|
3
3
|
# Attributes:
|
|
4
4
|
# - outbound_date: [Date] The date of outbound transit
|
|
@@ -12,25 +12,22 @@
|
|
|
12
12
|
#
|
|
13
13
|
# Note: inbound_legs and inbound_date are optional; the order may represent a one-way (outbound only) journey.
|
|
14
14
|
module SpreeCmCommissioner
|
|
15
|
-
module
|
|
16
|
-
class
|
|
17
|
-
|
|
18
|
-
:inbound_date,
|
|
19
|
-
:outbound_legs,
|
|
20
|
-
:inbound_legs,
|
|
21
|
-
:user, to: :context
|
|
15
|
+
module TransitOrder
|
|
16
|
+
class Create
|
|
17
|
+
prepend ::Spree::ServiceModule::Base
|
|
22
18
|
|
|
23
|
-
def call
|
|
24
|
-
return
|
|
19
|
+
def call(outbound_date:, inbound_date:, outbound_legs:, inbound_legs: [], user: nil)
|
|
20
|
+
return failure(nil, 'Outbound legs are missing') if outbound_legs.blank?
|
|
25
21
|
|
|
26
22
|
begin
|
|
27
|
-
|
|
23
|
+
order = create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user)
|
|
24
|
+
success(order: order)
|
|
28
25
|
rescue StandardError => e
|
|
29
|
-
|
|
26
|
+
failure(nil, e.message)
|
|
30
27
|
end
|
|
31
28
|
end
|
|
32
29
|
|
|
33
|
-
def create_order!
|
|
30
|
+
def create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user)
|
|
34
31
|
order = Spree::Order.new(state: 'cart', use_billing: true, user: user)
|
|
35
32
|
|
|
36
33
|
outbound_line_items = build_line_items_for_legs!(order: order, legs: outbound_legs, initial_date: outbound_date)
|
|
@@ -112,10 +109,10 @@ module SpreeCmCommissioner
|
|
|
112
109
|
|
|
113
110
|
def insert_saved_guests_per_line_items_leg(line_items)
|
|
114
111
|
line_items.flat_map(&:guests).each_with_index do |guest, index|
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
@saved_guests ||= []
|
|
113
|
+
@saved_guests << SpreeCmCommissioner::SavedGuest.new if @saved_guests[index].blank?
|
|
117
114
|
|
|
118
|
-
guest.saved_guest =
|
|
115
|
+
guest.saved_guest = @saved_guests[index]
|
|
119
116
|
end
|
|
120
117
|
|
|
121
118
|
line_items
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Trips
|
|
3
|
+
# Service class responsible for creating a single-leg trip in the booking system.
|
|
4
|
+
# Orchestrates the creation of product variant, trip record, stops, calendar, and inventory.
|
|
5
|
+
class CreateSingleLeg
|
|
6
|
+
prepend Spree::ServiceModule::Base
|
|
7
|
+
|
|
8
|
+
# Main service method that validates the trip form and orchestrates creation.
|
|
9
|
+
# Creates variant, trip, calendar, and inventory within a database transaction.
|
|
10
|
+
# Returns success with created objects or failure with error message on exceptions.
|
|
11
|
+
def call(vendor:, trip_form:)
|
|
12
|
+
return failure(nil, trip_form.errors.full_messages.to_sentence) unless trip_form.valid_data?
|
|
13
|
+
|
|
14
|
+
ApplicationRecord.transaction do
|
|
15
|
+
variant = create_variant!(vendor, trip_form)
|
|
16
|
+
trip = create_trip!(vendor, trip_form, variant)
|
|
17
|
+
calendar = setup_calendar!(variant.product, trip_form.service_calendar)
|
|
18
|
+
generate_inventory!(variant)
|
|
19
|
+
|
|
20
|
+
success(trip: trip, variant: variant, calendar: calendar)
|
|
21
|
+
rescue StandardError => e
|
|
22
|
+
CmAppLogger.error(
|
|
23
|
+
label: 'SpreeCmCommissioner::Trips::CreateSingleLeg#call',
|
|
24
|
+
data: {
|
|
25
|
+
error_class: e.class.name,
|
|
26
|
+
error_message: e.message
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
failure(nil, e.message)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
# Creates a product variant for the trip using the vehicle type's seat capacity.
|
|
36
|
+
def create_variant!(vendor, trip_form)
|
|
37
|
+
first_stop = trip_form.trip_stops.first
|
|
38
|
+
vehicle_type = SpreeCmCommissioner::VehicleType.find(first_stop.vehicle_type_id)
|
|
39
|
+
capacity = vehicle_type.number_of_seats
|
|
40
|
+
|
|
41
|
+
result = SpreeCmCommissioner::Trips::Variants::Create.call(
|
|
42
|
+
vendor: vendor,
|
|
43
|
+
trip_form: trip_form,
|
|
44
|
+
price: trip_form.price || 0.0,
|
|
45
|
+
capacity: capacity
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
raise StandardError, result.error unless result.success?
|
|
49
|
+
|
|
50
|
+
result.value[:variant]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Creates the main trip record with details extracted from the trip form.
|
|
54
|
+
# Associates the trip with vendor, product, vehicle, route, and time.
|
|
55
|
+
def create_trip!(vendor, trip_form, variant)
|
|
56
|
+
first_stop = trip_form.trip_stops.first
|
|
57
|
+
last_stop = trip_form.trip_stops.last
|
|
58
|
+
|
|
59
|
+
locations = vendor.locations.where(id: trip_form.trip_stops.map(&:location_id)).index_by(&:id)
|
|
60
|
+
stops = vendor.stops.where(id: trip_form.trip_stops.map(&:stop_id)).index_by(&:id)
|
|
61
|
+
|
|
62
|
+
trip = vendor.trips.create!(
|
|
63
|
+
product: variant.product,
|
|
64
|
+
vehicle_type: SpreeCmCommissioner::VehicleType.find_by(id: first_stop.vehicle_type_id),
|
|
65
|
+
vehicle: SpreeCmCommissioner::Vehicle.find_by(id: first_stop.vehicle_id),
|
|
66
|
+
origin_place: locations[first_stop.location_id].place,
|
|
67
|
+
destination_place: locations[last_stop.location_id].place,
|
|
68
|
+
route: vendor.routes.find(trip_form.route_id),
|
|
69
|
+
departure_time: first_stop.departure_time,
|
|
70
|
+
duration: trip_form.total_duration_seconds,
|
|
71
|
+
allow_booking: trip_form.allow_booking,
|
|
72
|
+
allow_seat_selection: trip_form.allow_seat_selection,
|
|
73
|
+
route_type: trip_form.route_type || vendor.routes.find(trip_form.route_id)&.route_type
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
create_trip_stops(trip, trip_form, locations, stops)
|
|
77
|
+
trip
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Creates individual trip stops based on the trip form stops.
|
|
81
|
+
# Each stop includes arrival/departure times and boarding/drop-off permissions.
|
|
82
|
+
def create_trip_stops(trip, trip_form, locations, stops)
|
|
83
|
+
previous_departure = nil
|
|
84
|
+
|
|
85
|
+
trip_form.trip_stops.each do |ts|
|
|
86
|
+
arrival_time = previous_departure || ts.departure_time
|
|
87
|
+
|
|
88
|
+
trip.trip_stops.create!(
|
|
89
|
+
stop_place: stops[ts.stop_id].place,
|
|
90
|
+
location_place: locations[ts.location_id].place,
|
|
91
|
+
allow_boarding: ts.allow_boarding?,
|
|
92
|
+
allow_drop_off: ts.allow_drop_off,
|
|
93
|
+
arrival_time: arrival_time,
|
|
94
|
+
departure_time: ts.departure_time
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
previous_departure = ts.departure_time
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Sets up the service calendar for the trip, defining operational dates, weekdays, and exceptions.
|
|
102
|
+
def setup_calendar!(product, calendar_form)
|
|
103
|
+
res = SpreeCmCommissioner::Trips::ServiceCalendars::CreateOrUpdate.call(
|
|
104
|
+
calendarable: product,
|
|
105
|
+
name: calendar_form.name,
|
|
106
|
+
start_date: calendar_form.start_date,
|
|
107
|
+
end_date: calendar_form.end_date,
|
|
108
|
+
weekdays: calendar_form.weekdays,
|
|
109
|
+
exception_rules: calendar_form.exception_rules || []
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
raise StandardError, res.error unless res.success?
|
|
113
|
+
|
|
114
|
+
res.value[:calendar]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Triggers asynchronous generation of permanent inventory items for the variant.
|
|
118
|
+
def generate_inventory!(variant)
|
|
119
|
+
SpreeCmCommissioner::Stock::PermanentInventoryItemsGeneratorJob.perform_later(variant_ids: [variant[:id]])
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Trips
|
|
3
|
+
module ServiceCalendars
|
|
4
|
+
# Service to create or update a service calendar for a calendarable entity.
|
|
5
|
+
class CreateOrUpdate
|
|
6
|
+
prepend ::Spree::ServiceModule::Base
|
|
7
|
+
|
|
8
|
+
def call(calendarable:, name:, start_date:, end_date:, weekdays:, exception_rules: []) # rubocop:disable Metrics/ParameterLists
|
|
9
|
+
return failure(nil, 'calendarable must be present') if calendarable.blank?
|
|
10
|
+
return failure(nil, 'name must be present') if name.blank?
|
|
11
|
+
return failure(nil, 'start_date must be present') if start_date.blank?
|
|
12
|
+
return failure(nil, 'end_date must be present') if end_date.blank?
|
|
13
|
+
return failure(nil, 'weekdays must be present') if weekdays.blank?
|
|
14
|
+
|
|
15
|
+
ApplicationRecord.transaction do
|
|
16
|
+
calendar = create_or_update_calendar(calendarable, name, start_date, end_date, weekdays, exception_rules)
|
|
17
|
+
success(calendar: calendar)
|
|
18
|
+
end
|
|
19
|
+
rescue StandardError => e
|
|
20
|
+
CmAppLogger.error(
|
|
21
|
+
label: 'SpreeCmCommissioner::Trips::ServiceCalendars::CreateOrUpdate#call',
|
|
22
|
+
data: {
|
|
23
|
+
error_class: e.class.name,
|
|
24
|
+
error_message: e.message
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
failure(nil, 'Failed to create service calendar')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# Create or update calendar
|
|
33
|
+
def create_or_update_calendar(calendarable, name, start_date, end_date, weekdays, exception_rules) # rubocop:disable Metrics/ParameterLists
|
|
34
|
+
calendar = calendarable.service_calendar || calendarable.build_service_calendar
|
|
35
|
+
|
|
36
|
+
calendar.assign_attributes(
|
|
37
|
+
name: name,
|
|
38
|
+
start_date: start_date,
|
|
39
|
+
end_date: end_date,
|
|
40
|
+
exception_rules: exception_rules
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Set weekday attributes
|
|
44
|
+
weekdays.each do |day, enabled|
|
|
45
|
+
calendar.send("#{day}=", enabled)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
calendar.save!
|
|
49
|
+
calendar
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|