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,88 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Trips
|
|
3
|
+
# Service class responsible for updating an existing single-leg trip.
|
|
4
|
+
# Handles updates to trip, product, variant, stops, and calendar in the booking system.
|
|
5
|
+
class UpdateSingleLeg
|
|
6
|
+
prepend Spree::ServiceModule::Base
|
|
7
|
+
|
|
8
|
+
# Main service method that orchestrates trip updates within a database transaction.
|
|
9
|
+
# Updates trip/product, variant if price provided, stops, and calendar conditionally.
|
|
10
|
+
# Returns success with updated objects or failure with error message.
|
|
11
|
+
def call(trip:, trip_form:)
|
|
12
|
+
ApplicationRecord.transaction do
|
|
13
|
+
update_trip_and_product(trip, trip_form)
|
|
14
|
+
update_variant(trip, trip_form) if trip_form.price.present?
|
|
15
|
+
update_trip_stops(trip, trip_form)
|
|
16
|
+
calendar = update_calendar(trip.product, trip_form.service_calendar) if trip_form.service_calendar.present?
|
|
17
|
+
|
|
18
|
+
success(trip: trip, variant: trip.product.variants.first, calendar: calendar)
|
|
19
|
+
rescue StandardError => e
|
|
20
|
+
CmAppLogger.error(
|
|
21
|
+
label: 'SpreeCmCommissioner::Trips::UpdateSingleLeg#call',
|
|
22
|
+
data: {
|
|
23
|
+
error_class: e.class.name,
|
|
24
|
+
error_message: e.message
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
failure(nil, 'Failed to update trip')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# Updates the trip record and associated product with attributes from the form.
|
|
34
|
+
def update_trip_and_product(trip, trip_form)
|
|
35
|
+
trip.update!(trip_attrs(trip_form))
|
|
36
|
+
trip.product.update!(product_attrs(trip_form))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Updates the variant's price if a new price is provided in the form.
|
|
40
|
+
def update_variant(trip, trip_form)
|
|
41
|
+
variant = trip.product.variants.where.not(id: trip.product.master.id).first
|
|
42
|
+
return unless variant
|
|
43
|
+
|
|
44
|
+
variant.update!(price: trip_form.price)
|
|
45
|
+
trip.product.update!(price: trip_form.price)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Iterates through stops and applies updates only if attributes are present.
|
|
49
|
+
def update_trip_stops(trip, trip_form)
|
|
50
|
+
trip.trip_stops.each_with_index do |stop, idx|
|
|
51
|
+
ts_form = trip_form.trip_stops[idx]
|
|
52
|
+
next unless ts_form
|
|
53
|
+
|
|
54
|
+
updates = {
|
|
55
|
+
allow_boarding: ts_form.allow_boarding?,
|
|
56
|
+
allow_drop_off: ts_form.allow_drop_off
|
|
57
|
+
}.compact
|
|
58
|
+
|
|
59
|
+
stop.update!(updates) if updates.any?
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Updates or creates the service calendar for the product using calendar form data.
|
|
64
|
+
def update_calendar(product, calendar_form)
|
|
65
|
+
result = SpreeCmCommissioner::Trips::ServiceCalendars::CreateOrUpdate.call(
|
|
66
|
+
calendarable: product,
|
|
67
|
+
name: calendar_form.name,
|
|
68
|
+
start_date: calendar_form.start_date,
|
|
69
|
+
end_date: calendar_form.end_date,
|
|
70
|
+
weekdays: calendar_form.weekdays,
|
|
71
|
+
exception_rules: calendar_form.exception_rules || []
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
raise result.error unless result.success?
|
|
75
|
+
|
|
76
|
+
result.value[:calendar]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def trip_attrs(form)
|
|
80
|
+
{ allow_booking: form.allow_booking, allow_seat_selection: form.allow_seat_selection }.compact
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def product_attrs(form)
|
|
84
|
+
{ name: form.name, short_name: form.short_name }.compact
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Trips
|
|
3
|
+
module Variants
|
|
4
|
+
# Service class responsible for creating product and variant for a trip.
|
|
5
|
+
# Handles validations, product creation with options, variant pricing, and stock setup.
|
|
6
|
+
class Create
|
|
7
|
+
prepend ::Spree::ServiceModule::Base
|
|
8
|
+
|
|
9
|
+
# Main method that validates inputs and creates product, options, variant, and stock in transaction.
|
|
10
|
+
# Returns success with product and variant or failure with error message.
|
|
11
|
+
def call(vendor:, trip_form:, price:, capacity:)
|
|
12
|
+
return failure(nil, 'vendor must be present') if vendor.blank?
|
|
13
|
+
return failure(nil, 'trip_form must be present') if trip_form.blank?
|
|
14
|
+
return failure(nil, 'price must be present') if price.blank?
|
|
15
|
+
return failure(nil, 'capacity must be present') if capacity.blank?
|
|
16
|
+
return failure(nil, 'capacity must be greater than 0') if capacity <= 0
|
|
17
|
+
|
|
18
|
+
ApplicationRecord.transaction do
|
|
19
|
+
product = create_product!(vendor, trip_form)
|
|
20
|
+
option_values = setup_option_values!(product)
|
|
21
|
+
variant = create_variant!(product, price, option_values)
|
|
22
|
+
|
|
23
|
+
create_stock_item!(variant, capacity)
|
|
24
|
+
|
|
25
|
+
success(product: product, variant: variant)
|
|
26
|
+
end
|
|
27
|
+
rescue StandardError => e
|
|
28
|
+
CmAppLogger.error(
|
|
29
|
+
label: 'SpreeCmCommissioner::Trips::Variants::Create#call',
|
|
30
|
+
data: {
|
|
31
|
+
error_class: e.class.name,
|
|
32
|
+
error_message: e.message
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
failure(nil, e.message)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# Creates a transit product with name based on stops, assigns vendor, type, and options.
|
|
41
|
+
# Includes seat-type option type and default store association.
|
|
42
|
+
def create_product!(vendor, trip_form)
|
|
43
|
+
vendor_stops = stops(vendor, trip_form)
|
|
44
|
+
first_stop = vendor_stops[trip_form.trip_stops.first.stop_id].place
|
|
45
|
+
last_stop = vendor_stops[trip_form.trip_stops.last.stop_id].place
|
|
46
|
+
|
|
47
|
+
Spree::Product.create!(
|
|
48
|
+
name: trip_form.name.presence || "#{first_stop.name} - #{last_stop.name}",
|
|
49
|
+
short_name: trip_form.short_name,
|
|
50
|
+
vendor: vendor,
|
|
51
|
+
product_type: 'transit',
|
|
52
|
+
status: 'active',
|
|
53
|
+
available_on: Time.current,
|
|
54
|
+
price: trip_form.price,
|
|
55
|
+
shipping_category: Spree::ShippingCategory.find_or_create_by!(name: 'Default'),
|
|
56
|
+
option_types: [Spree::OptionType.find_by(name: 'seat-type')].compact,
|
|
57
|
+
stores: [Spree::Store.default].compact
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Retrieves and indexes stops from the vendor for the trip form's stop IDs.
|
|
62
|
+
def stops(vendor, trip_form)
|
|
63
|
+
vendor.stops.where(id: trip_form.trip_stops.map(&:stop_id)).index_by(&:id)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Sets up or finds the seat-type option type and creates normal option value.
|
|
67
|
+
# Associates the option type with the product if not already present.
|
|
68
|
+
def setup_option_values!(product)
|
|
69
|
+
option_type = Spree::OptionType.find_or_create_by!(
|
|
70
|
+
name: 'seat-type',
|
|
71
|
+
presentation: 'Seat Type'
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
product.option_types << option_type unless product.option_types.include?(option_type)
|
|
75
|
+
|
|
76
|
+
option_value = option_type.option_values.find_or_create_by_name!(option_type, 'Normal')
|
|
77
|
+
|
|
78
|
+
[option_value]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Creates a product variant with the given price and associated option values.
|
|
82
|
+
# Saves the variant to the database.
|
|
83
|
+
def create_variant!(product, price, option_values)
|
|
84
|
+
variant = product.variants.new(price: price)
|
|
85
|
+
variant.option_values = option_values
|
|
86
|
+
variant.save!
|
|
87
|
+
variant
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Creates a stock item for the variant with the specified capacity.
|
|
91
|
+
# Uses stock movement creator to initialize inventory.
|
|
92
|
+
def create_stock_item!(variant, capacity)
|
|
93
|
+
result = SpreeCmCommissioner::Stock::StockMovementCreator.call(
|
|
94
|
+
variant_id: variant.id,
|
|
95
|
+
current_store: variant.product.stores.first,
|
|
96
|
+
stock_movement_params: { quantity: capacity }
|
|
97
|
+
)
|
|
98
|
+
result.stock_item
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
<tr data-hook="option_header">
|
|
10
10
|
<th class="no-border handel-head"></th>
|
|
11
11
|
<th><%= Spree.t(:name) %></th>
|
|
12
|
-
<th><%= Spree.t(:
|
|
12
|
+
<th><%= Spree.t(:allow_boarding) %></th>
|
|
13
|
+
<th><%= Spree.t(:allow_drop_off) %></th>
|
|
13
14
|
<th><%= Spree.t(:sequence) %></th>
|
|
14
15
|
<th><%= Spree.t(:created_at) %></th>
|
|
15
16
|
</tr>
|
|
@@ -21,7 +22,8 @@
|
|
|
21
22
|
<%= svg_icon name: "grip-vertical.svg", width: '18', height: '18' %>
|
|
22
23
|
</td>
|
|
23
24
|
<td><%= stop.stop_name %></td>
|
|
24
|
-
<td> <%= stop.
|
|
25
|
+
<td> <%= stop.allow_boarding ? 'Yes' : 'No' %></td>
|
|
26
|
+
<td> <%= stop.allow_drop_off ? 'Yes' : 'No' %></td>
|
|
25
27
|
<td> <%= stop.sequence %></td>
|
|
26
28
|
<td> <%= stop.created_at.to_date %></td>
|
|
27
29
|
</tr>
|
|
@@ -151,7 +151,6 @@
|
|
|
151
151
|
<% @trip.trip_stops.order(:sequence).each do |stop| %>
|
|
152
152
|
<tr>
|
|
153
153
|
<td>
|
|
154
|
-
<span class="stop-type <%= stop.stop_type %>"><%= stop.stop_type.to_s.titleize %></span>
|
|
155
154
|
<div class="stop-name"><strong><%= stop.stop_name %></strong></div>
|
|
156
155
|
<% if stop.respond_to?(:location_place) && stop.location_place.present? %>
|
|
157
156
|
<% if stop.location_place.respond_to?(:address) && stop.location_place.address.present? %>
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
module PermittedAttributes
|
|
3
|
+
ATTRIBUTES << :route_attributes unless ATTRIBUTES.include?(:route_attributes)
|
|
4
|
+
mattr_reader :route_attributes
|
|
5
|
+
|
|
3
6
|
@@vendor_attributes << :logo
|
|
4
7
|
|
|
5
8
|
# Permitted all guest attributes for now as permitting only some guest attributes is not working by design
|
|
@@ -85,5 +88,13 @@ module Spree
|
|
|
85
88
|
originator_type
|
|
86
89
|
originator_id
|
|
87
90
|
]
|
|
91
|
+
|
|
92
|
+
@@route_attributes = %i[
|
|
93
|
+
route_name
|
|
94
|
+
short_name
|
|
95
|
+
vendor_id
|
|
96
|
+
route_type
|
|
97
|
+
route_stops
|
|
98
|
+
]
|
|
88
99
|
end
|
|
89
100
|
end
|
data/config/locales/en.yml
CHANGED
|
@@ -480,6 +480,8 @@ en:
|
|
|
480
480
|
success: "Guest uncheck-in in successfully"
|
|
481
481
|
check_in:
|
|
482
482
|
already_checked_in: "Guest has already checked in for this session"
|
|
483
|
+
check_in_session_required: "Check-in session required"
|
|
484
|
+
check_in_session_is_not_allowed_or_invalid: "Check-in session is not allowed or invalid for this guest/ticket"
|
|
483
485
|
|
|
484
486
|
activerecord:
|
|
485
487
|
attributes:
|
data/config/locales/km.yml
CHANGED
|
@@ -24,6 +24,8 @@ km:
|
|
|
24
24
|
success: "Guest uncheck-in in successfully"
|
|
25
25
|
check-in:
|
|
26
26
|
already_checked_in: "ភ្ញៀវបានចូលរួចហើយ"
|
|
27
|
+
check_in_session_required: "ត្រូវតែមានវគ្គចុះឈ្មោះចូល"
|
|
28
|
+
check_in_session_is_not_allowed_or_invalid: "វគ្គចុះឈ្មោះនេះមិនត្រឹមត្រូវ សម្រាប់ភ្ញៀវ ឬសំបុត្រនេះទេ"
|
|
27
29
|
|
|
28
30
|
sms:
|
|
29
31
|
to:
|
data/config/routes.rb
CHANGED
|
@@ -560,6 +560,12 @@ Spree::Core::Engine.add_routes do
|
|
|
560
560
|
resources :trip_places, only: :index
|
|
561
561
|
resources :trip_search, only: [:index]
|
|
562
562
|
resources :trips, only: %i[show]
|
|
563
|
+
resources :popular_route_places, only: [:index]
|
|
564
|
+
resources :routes, only: [:index]
|
|
565
|
+
|
|
566
|
+
namespace :transit do
|
|
567
|
+
resources :draft_orders, only: %i[create]
|
|
568
|
+
end
|
|
563
569
|
|
|
564
570
|
namespace :intercity_taxi do
|
|
565
571
|
resource :draft_orders, only: %i[create update]
|
|
@@ -721,6 +727,8 @@ Spree::Core::Engine.add_routes do
|
|
|
721
727
|
resources :dashboard_crew_events, only: %i[index]
|
|
722
728
|
resources :event_qrs, only: [:show]
|
|
723
729
|
resources :recalculate_tickets, only: [:create]
|
|
730
|
+
resources :check_in_sessions, only: %i[index]
|
|
731
|
+
|
|
724
732
|
resources :taxons, only: %i[show] do
|
|
725
733
|
resource :event_ticket_aggregators, only: %i[show]
|
|
726
734
|
resource :pie_chart_event_aggregators, only: %i[show]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class MigrateCmRoutesToCmRouteMetrics < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
# 1. Rename cm_routes which we use to track order, trip count to cm_route_metrics instead.
|
|
4
|
+
remove_index :cm_routes, [:origin_place_id, :destination_place_id] if index_exists?(:cm_routes, [:origin_place_id, :destination_place_id])
|
|
5
|
+
rename_table :cm_routes, :cm_route_metrics unless table_exists?(:cm_route_metrics)
|
|
6
|
+
add_column :cm_route_metrics, :route_type, :integer, default: 0, null: false unless column_exists?(:cm_route_metrics, :route_type)
|
|
7
|
+
|
|
8
|
+
# 2. Drop the old index before renaming table to avoid index name length issues & re-add the index with a shorter name
|
|
9
|
+
unless index_exists?(:cm_route_metrics, [:route_type, :origin_place_id, :destination_place_id], name: 'index_cm_route_metrics_on_origin_dest')
|
|
10
|
+
add_index :cm_route_metrics, [:route_type, :origin_place_id, :destination_place_id], unique: true, name: 'index_cm_route_metrics_on_origin_dest'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# 3. Remove old route_id column from trips.
|
|
14
|
+
# it has route_metrics value, and trip don't need to have association with metric directly.
|
|
15
|
+
remove_column :cm_trips, :route_id if column_exists?(:cm_trips, :route_id)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class MigrateCmVendorRoutesToCmRoutes < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
# 1. Remove cm_vendor_routes and add cm_routes instead for routes that associated with vendor.
|
|
4
|
+
drop_table :cm_vendor_routes, if_exists: true
|
|
5
|
+
create_table :cm_routes, if_not_exists: true do |t|
|
|
6
|
+
t.string :route_name
|
|
7
|
+
t.string :short_name
|
|
8
|
+
t.integer :order_count
|
|
9
|
+
t.integer :fulfilled_order_count
|
|
10
|
+
t.integer :route_type
|
|
11
|
+
t.jsonb :route_stops, default: "[]"
|
|
12
|
+
t.references :vendor, foreign_key: { to_table: :spree_vendors }, null: false
|
|
13
|
+
t.references :tenant, foreign_key: { to_table: :cm_tenants }, null: true
|
|
14
|
+
|
|
15
|
+
t.references :origin_place, foreign_key: { to_table: :cm_places }, null: false
|
|
16
|
+
t.references :destination_place, foreign_key: { to_table: :cm_places }, null: false
|
|
17
|
+
|
|
18
|
+
t.integer :lock_version, default: 0, null: false
|
|
19
|
+
t.timestamps
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# 2. Add indexes for popular_routes association (vendor_id + order by fulfilled_order_count, order_count)
|
|
23
|
+
add_index :cm_routes, [:vendor_id, :route_type, :fulfilled_order_count, :order_count],
|
|
24
|
+
order: { fulfilled_order_count: :desc, order_count: :desc },
|
|
25
|
+
name: 'index_cm_routes_on_vendor_id_route_type_and_popular' unless index_exists?(:cm_routes, [:vendor_id, :route_type, :fulfilled_order_count, :order_count])
|
|
26
|
+
|
|
27
|
+
# 3. Add new route reference to cm_trips
|
|
28
|
+
add_reference :cm_trips, :route, foreign_key: { to_table: :cm_routes }, null: true unless column_exists?(:cm_trips, :route_id)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class AddTypeToCmPricingActions < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
add_column :cm_pricing_actions,
|
|
4
|
+
:type,
|
|
5
|
+
:string,
|
|
6
|
+
default: 'SpreeCmCommissioner::PricingActions::CreateLineItemAdjustments',
|
|
7
|
+
if_not_exists: true
|
|
8
|
+
|
|
9
|
+
add_index :cm_pricing_actions, :type, if_not_exists: true
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class MigrateCmTripStopsToSupportTripConnection < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
# 1. Replace stop_type with allow_boarding & allow_drop_off instead, it is more flexible.
|
|
4
|
+
# Useful for middle stops where both boarding & drop off can be allowed or both can be disallowed.
|
|
5
|
+
remove_column :cm_trip_stops, :stop_type if column_exists?(:cm_trip_stops, :stop_type)
|
|
6
|
+
add_column :cm_trip_stops, :allow_boarding, :boolean unless column_exists?(:cm_trip_stops, :allow_boarding)
|
|
7
|
+
add_column :cm_trip_stops, :allow_drop_off, :boolean unless column_exists?(:cm_trip_stops, :allow_drop_off)
|
|
8
|
+
|
|
9
|
+
# 2. Add references to link trip stops to trips for boarding, this will enable trip connections. Where current trip is main trip.
|
|
10
|
+
add_reference :cm_trip_stops, :board_to_trip, foreign_key: { to_table: :cm_trips }, null: true unless column_exists?(:cm_trip_stops, :board_to_trip_id)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
## 📌 Summary
|
|
2
|
+
|
|
3
|
+
Add **age-based pricing rules** for **discounts or surcharges** based on guest age groups
|
|
4
|
+
Supports both **line-item** and **per-guest** adjustments.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ⚙️ How It Works
|
|
9
|
+
|
|
10
|
+
### 👶 Children Discount (Per-Guest)
|
|
11
|
+
|
|
12
|
+
- **Rule:** `all` + `['child']`
|
|
13
|
+
- **Adjustment:** $1 per child
|
|
14
|
+
- **Guests:** 3 children ($6 each)
|
|
15
|
+
- **Calculation:** 3 × $6 = $18 → $3 total discount
|
|
16
|
+
- **Total:** **$15**
|
|
17
|
+
|
|
18
|
+
### 👧 Children Surcharge (Per-Guest)
|
|
19
|
+
|
|
20
|
+
- **Rule:** `any` + `['child']`
|
|
21
|
+
- **Adjustment:** $0.50 per child
|
|
22
|
+
- **Guests:** 2 children ($6 each)
|
|
23
|
+
- **Calculation:** 2 × $6 = $12 → $1 total surcharge
|
|
24
|
+
- **Total:** **$13**
|
|
25
|
+
|
|
26
|
+
### 🧑 Adult Discount (Line-Item)
|
|
27
|
+
|
|
28
|
+
- **Rule:** `any` + `['adult']`
|
|
29
|
+
- **Adjustment:** $1 discount
|
|
30
|
+
- **Guests:** 2 adults, 2 children ($6 each)
|
|
31
|
+
- **Calculation:** 4 × $6 = $24 → $1 discount
|
|
32
|
+
- **Total:** **$23**
|
|
33
|
+
|
|
34
|
+
### 🧔 Adult Surcharge (Line-Item)
|
|
35
|
+
|
|
36
|
+
- **Rule:** `none` + `['adult']`
|
|
37
|
+
- **Adjustment:** $0.50 surcharge
|
|
38
|
+
- **Guests:** 3 teenagers ($6 each)
|
|
39
|
+
- **Calculation:** 3 × $6 = $18 → $0.50 surcharge
|
|
40
|
+
- **Total:** **$18.50**
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
## 📌 Summary
|
|
2
|
+
Add **nationality-based pricing rules** for **discounts or surcharges** based on guest nationality groups.
|
|
3
|
+
Supports both **line-item** and **per-guest** adjustments.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ⚙️ How It Works
|
|
8
|
+
|
|
9
|
+
### Local Discount (Per-Guest)
|
|
10
|
+
- **Rule:** `any` + `['local']`
|
|
11
|
+
- **Adjustment:** $1 per local
|
|
12
|
+
- **Guests:** 2 locals ($6 each)
|
|
13
|
+
- **Calculation:** 2 × $6 = $12 → $2 total discount
|
|
14
|
+
- **Total:** **$10**
|
|
15
|
+
|
|
16
|
+
### Local Discount (Line-Item)
|
|
17
|
+
- **Rule:** `any` + `['local']`
|
|
18
|
+
- **Adjustment:** $1 discount
|
|
19
|
+
- **Guests:** 2 locals, 1 foreigner ($6 each)
|
|
20
|
+
- **Calculation:** 3 × $6 = $18 → $1 discount
|
|
21
|
+
- **Total:** **$17**
|
|
22
|
+
|
|
23
|
+
### 🌍 Foreigner Surcharge (Per-Guest)
|
|
24
|
+
- **Rule:** `any` + `['foreigner']`
|
|
25
|
+
- **Adjustment:** $2 per foreigner
|
|
26
|
+
- **Guests:** 1 local, 2 foreigners ($6 each)
|
|
27
|
+
- **Calculation:** 2 × $2 = $4 total surcharge
|
|
28
|
+
- **Total:** **$20**
|
|
29
|
+
|
|
30
|
+
### 🌍 Foreigner Surcharge (Line-Item)
|
|
31
|
+
- **Rule:** `none` + `['foreigner']`
|
|
32
|
+
- **Adjustment:** $0.50 surcharge
|
|
33
|
+
- **Guests:** 3 locals ($6 each)
|
|
34
|
+
- **Calculation:** 3 × $6 = $18 → $0.50 surcharge
|
|
35
|
+
- **Total:** **$18.50**
|
|
@@ -2,8 +2,10 @@ FactoryBot.define do
|
|
|
2
2
|
factory :cm_check_in, class: SpreeCmCommissioner::CheckIn do
|
|
3
3
|
confirmed_at { DateTime.current }
|
|
4
4
|
check_in_type { "pre_check_in" }
|
|
5
|
-
|
|
5
|
+
association :guest, factory: :cm_guest
|
|
6
6
|
check_in_method { "manual" }
|
|
7
|
+
check_in_by { create(:user) }
|
|
8
|
+
checkinable { create(:cm_taxon_event) }
|
|
7
9
|
verification_state { "submitted" }
|
|
8
10
|
end
|
|
9
11
|
end
|
|
@@ -7,5 +7,31 @@ FactoryBot.define do
|
|
|
7
7
|
start_time { 1.hour.from_now }
|
|
8
8
|
end_time { 2.hours.from_now }
|
|
9
9
|
association :event, factory: :cm_taxon_event
|
|
10
|
+
|
|
11
|
+
transient do
|
|
12
|
+
products { nil }
|
|
13
|
+
variants { nil }
|
|
14
|
+
option_values { nil }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
after(:build) do |check_in_session, evaluator|
|
|
18
|
+
if evaluator.products.present?
|
|
19
|
+
evaluator.products.each do |product|
|
|
20
|
+
check_in_session.check_in_rules.build(ruleable: product)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if evaluator.variants.present?
|
|
25
|
+
evaluator.variants.each do |variant|
|
|
26
|
+
check_in_session.check_in_rules.build(ruleable: variant)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if evaluator.option_values.present?
|
|
31
|
+
evaluator.option_values.each do |option_value|
|
|
32
|
+
check_in_session.check_in_rules.build(ruleable: option_value)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
10
36
|
end
|
|
11
37
|
end
|
|
@@ -7,6 +7,8 @@ FactoryBot.define do
|
|
|
7
7
|
gender { 1 }
|
|
8
8
|
dob { '1986-03-28' }
|
|
9
9
|
token { SecureRandom.hex(32) }
|
|
10
|
+
public_metadata { {} }
|
|
11
|
+
private_metadata { {} }
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
factory :cm_guest, class: SpreeCmCommissioner::Guest do
|
|
@@ -16,5 +18,7 @@ FactoryBot.define do
|
|
|
16
18
|
gender { 1 }
|
|
17
19
|
dob { '1986-03-28' }
|
|
18
20
|
token { SecureRandom.hex(32) }
|
|
21
|
+
public_metadata { {} }
|
|
22
|
+
private_metadata { {} }
|
|
19
23
|
end
|
|
20
24
|
end
|
|
@@ -2,4 +2,8 @@ FactoryBot.define do
|
|
|
2
2
|
factory :pricing_action, class: 'SpreeCmCommissioner::PricingAction' do
|
|
3
3
|
association :pricing_rule_group, factory: :pricing_rule_group
|
|
4
4
|
end
|
|
5
|
+
|
|
6
|
+
factory :pricing_action_guest_adjustments, class: 'SpreeCmCommissioner::PricingActions::CreateGuestAdjustments' do
|
|
7
|
+
association :pricing_rule_group, factory: :pricing_rule_group
|
|
8
|
+
end
|
|
5
9
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
FactoryBot.define do
|
|
2
2
|
factory :pricing_rule_nationality, class: 'SpreeCmCommissioner::PricingRules::Nationality' do
|
|
3
3
|
association :pricing_rule_group, factory: :pricing_rule_group
|
|
4
|
-
rule_type { '
|
|
4
|
+
rule_type { 'any' }
|
|
5
5
|
nationalities { ["Cambodian"] }
|
|
6
6
|
end
|
|
7
7
|
|
|
@@ -14,4 +14,48 @@ FactoryBot.define do
|
|
|
14
14
|
association :pricing_rule_group, factory: :pricing_rule_group
|
|
15
15
|
min_distance { 5 }
|
|
16
16
|
end
|
|
17
|
+
|
|
18
|
+
factory :pricing_rule_age_group, class: 'SpreeCmCommissioner::PricingRules::AgeGroup' do
|
|
19
|
+
association :pricing_rule_group, factory: :pricing_rule_group
|
|
20
|
+
rule_type { 'any' }
|
|
21
|
+
age_groups { ['adult'] }
|
|
22
|
+
|
|
23
|
+
trait :all_match do
|
|
24
|
+
rule_type { 'all' }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
trait :none_match do
|
|
28
|
+
rule_type { 'none' }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
trait :children do
|
|
32
|
+
age_groups { ['child'] }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
trait :adults do
|
|
36
|
+
age_groups { ['adult'] }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
factory :pricing_rule_nationality_group, class: 'SpreeCmCommissioner::PricingRules::NationalityGroup' do
|
|
41
|
+
association :pricing_rule_group, factory: :pricing_rule_group
|
|
42
|
+
rule_type { 'any' }
|
|
43
|
+
nationality_groups { ['local'] }
|
|
44
|
+
|
|
45
|
+
trait :all_match do
|
|
46
|
+
rule_type { 'all' }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
trait :none_match do
|
|
50
|
+
rule_type { 'none' }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
trait :locals do
|
|
54
|
+
nationality_groups { ['local'] }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
trait :foreigners do
|
|
58
|
+
nationality_groups { ['foreigner'] }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
17
61
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
FactoryBot.define do
|
|
2
|
-
factory :cm_route, class:
|
|
2
|
+
factory :cm_route, class: SpreeCmCommissioner::Route do
|
|
3
|
+
association :vendor, factory: :vendor
|
|
4
|
+
association :tenant, factory: :cm_tenant
|
|
5
|
+
association :origin_place, factory: :cm_place
|
|
6
|
+
association :destination_place, factory: :cm_place
|
|
7
|
+
|
|
3
8
|
sequence(:route_name) { |n| "Route #{n}" }
|
|
4
|
-
|
|
5
|
-
destination_place_id { create(:cm_place).id }
|
|
6
|
-
trip_count { 0 }
|
|
7
|
-
order_count { 0 }
|
|
8
|
-
fulfilled_order_count { 0 }
|
|
9
|
+
sequence(:short_name) { |n| "R#{n}" }
|
|
9
10
|
end
|
|
10
11
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
FactoryBot.define do
|
|
2
|
+
factory :cm_route_metric, class: SpreeCmCommissioner::RouteMetric do
|
|
3
|
+
association :origin_place, factory: :cm_place
|
|
4
|
+
association :destination_place, factory: :cm_place
|
|
5
|
+
|
|
6
|
+
route_name { "#{origin_place.name} - #{destination_place.name}" }
|
|
7
|
+
route_type { :bus }
|
|
8
|
+
trip_count { 0 }
|
|
9
|
+
order_count { 0 }
|
|
10
|
+
fulfilled_order_count { 0 }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -11,7 +11,10 @@ FactoryBot.define do
|
|
|
11
11
|
association :vehicle, factory: :cm_vehicle
|
|
12
12
|
association :origin_place, factory: :cm_place
|
|
13
13
|
association :destination_place, factory: :cm_place
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
# Don't create route by default to avoid uniqueness conflicts
|
|
16
|
+
# Tests that need these should create them explicitly
|
|
17
|
+
route { nil }
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
factory :cm_trip_with_seat_counts, parent: :cm_trip do
|
|
@@ -4,7 +4,9 @@ FactoryBot.define do
|
|
|
4
4
|
association :stop_place, factory: :cm_place
|
|
5
5
|
association :location_place, factory: :cm_place
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
allow_boarding { true }
|
|
8
|
+
allow_drop_off { true }
|
|
9
|
+
|
|
8
10
|
stop_name { stop_place.name }
|
|
9
11
|
|
|
10
12
|
arrival_time { Time.current }
|