spree_cm_commissioner 2.0.3.pre.pre6 → 2.0.3.pre.pre.pre7
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/.github/workflows/test_and_build_gem.yml +2 -16
- data/.gitignore +1 -2
- data/Gemfile.lock +4 -39
- data/Rakefile +4 -33
- data/app/assets/stylesheets/spree_cm_commissioner/backend/calendar.scss +11 -8
- data/app/controllers/concerns/spree_cm_commissioner/transit/taxon_bitwise.rb +44 -0
- data/app/controllers/spree/admin/stock_managements_controller.rb +1 -63
- data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +31 -14
- data/app/controllers/spree/api/v2/storefront/dynamic_fields_controller.rb +42 -0
- data/app/controllers/spree/api/v2/storefront/guests_controller.rb +2 -0
- data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +2 -2
- data/app/finders/spree_cm_commissioner/line_items/find_by_variant_decorator.rb +20 -0
- data/app/interactors/spree_cm_commissioner/create_vendor.rb +11 -1
- data/app/jobs/spree_cm_commissioner/application_job.rb +0 -20
- data/app/jobs/spree_cm_commissioner/application_unique_job.rb +0 -20
- data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +15 -18
- data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +15 -29
- data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +12 -2
- data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +0 -39
- data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +3 -1
- data/app/models/concerns/spree_cm_commissioner/product_type.rb +0 -10
- data/app/models/concerns/spree_cm_commissioner/route_type.rb +1 -1
- data/app/models/spree_cm_commissioner/address_decorator.rb +2 -36
- data/app/models/spree_cm_commissioner/branch.rb +12 -0
- data/app/models/spree_cm_commissioner/guest.rb +85 -71
- data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +37 -27
- data/app/models/spree_cm_commissioner/line_item_decorator.rb +78 -47
- data/app/models/spree_cm_commissioner/line_item_seat.rb +10 -0
- data/app/models/spree_cm_commissioner/notification_taxon.rb +1 -1
- data/app/models/spree_cm_commissioner/option_type_decorator.rb +11 -1
- data/app/models/spree_cm_commissioner/option_value_vehicle_type.rb +8 -0
- data/app/models/spree_cm_commissioner/order/address_book_decorator.rb +12 -30
- data/app/models/spree_cm_commissioner/order_decorator.rb +1 -38
- data/app/models/spree_cm_commissioner/place.rb +4 -3
- data/app/models/spree_cm_commissioner/product_decorator.rb +6 -10
- data/app/models/spree_cm_commissioner/service_calendar.rb +2 -0
- data/app/models/spree_cm_commissioner/state_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/stock/availability_checker.rb +25 -26
- data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +1 -2
- data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
- data/app/models/spree_cm_commissioner/stock_item_decorator.rb +0 -17
- data/app/models/spree_cm_commissioner/stop.rb +23 -0
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +6 -0
- data/app/models/spree_cm_commissioner/trip.rb +10 -19
- data/app/models/spree_cm_commissioner/trip_connection.rb +5 -5
- data/app/models/spree_cm_commissioner/trip_stop.rb +21 -10
- data/app/models/spree_cm_commissioner/user_decorator.rb +1 -1
- data/app/models/spree_cm_commissioner/variant_decorator.rb +47 -37
- data/app/models/spree_cm_commissioner/variant_options.rb +23 -0
- data/app/models/spree_cm_commissioner/vehicle.rb +16 -11
- data/app/models/spree_cm_commissioner/vehicle_seat.rb +11 -0
- data/app/models/spree_cm_commissioner/vehicle_type.rb +76 -0
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +14 -14
- data/app/models/spree_cm_commissioner/vendor_place.rb +3 -13
- data/app/models/spree_cm_commissioner/vendor_stop.rb +10 -0
- data/app/queries/spree_cm_commissioner/trip_query.rb +131 -110
- data/app/queries/spree_cm_commissioner/trip_search_query.rb +76 -0
- data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +45 -0
- data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +55 -0
- data/app/queries/spree_cm_commissioner/vendor_stop_place_query.rb +54 -0
- data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +0 -3
- data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
- data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +0 -2
- data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +0 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +1 -3
- data/app/services/spree_cm_commissioner/vehicle_option_value_creator.rb +11 -0
- data/app/views/spree/admin/stock_managements/_variant_stock_items.html.erb +2 -7
- data/app/views/spree/admin/stock_managements/index.html.erb +6 -55
- data/config/initializers/spree_permitted_attributes.rb +0 -5
- data/config/routes.rb +3 -24
- data/db/migrate/20240202080634_update_counter_cache_of_vehicle_type.rb +1 -3
- data/db/migrate/20250812121745_add_data_fill_stage_phase_to_cm_guests.rb +5 -0
- data/docker-compose.yml +1 -1
- data/lib/cm_app_logger.rb +4 -11
- data/lib/generators/spree_cm_commissioner/install/install_generator.rb +11 -14
- data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_dashboard/spree_cm_commissioner → spree_cm_commissioner}/utilities.js +0 -4
- data/lib/spree_cm_commissioner/calendar_event.rb +1 -11
- data/lib/spree_cm_commissioner/test_helper/factories/branch_factory.rb +12 -0
- data/lib/spree_cm_commissioner/test_helper/factories/departure_time_option_type_factory.rb +8 -0
- data/lib/spree_cm_commissioner/test_helper/factories/duration_option_type_factory.rb +8 -0
- data/lib/spree_cm_commissioner/test_helper/factories/guest_factory.rb +0 -10
- data/lib/spree_cm_commissioner/test_helper/factories/homepage_section_relatable_factory.rb +1 -1
- data/lib/spree_cm_commissioner/test_helper/factories/line_item_factory.rb +1 -1
- data/lib/spree_cm_commissioner/test_helper/factories/line_item_seat_factory.rb +7 -0
- data/lib/spree_cm_commissioner/test_helper/factories/option_type_factory.rb +30 -6
- data/lib/spree_cm_commissioner/test_helper/factories/order_factory.rb +36 -0
- data/lib/spree_cm_commissioner/test_helper/factories/product_factory.rb +34 -18
- data/lib/spree_cm_commissioner/test_helper/factories/stock_location_factory.rb +2 -2
- data/lib/spree_cm_commissioner/test_helper/factories/stop_factory.rb +14 -0
- data/lib/spree_cm_commissioner/test_helper/factories/transit_place_factory.rb +8 -0
- data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +3 -11
- data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +19 -41
- data/lib/spree_cm_commissioner/test_helper/factories/vehicle_factory.rb +1 -1
- data/lib/spree_cm_commissioner/test_helper/factories/vehicle_option_type_factory.rb +8 -0
- data/lib/spree_cm_commissioner/test_helper/factories/vehicle_type_factory.rb +96 -0
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -6
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +1 -13
- data/lib/spree_cm_commissioner/trip_query_result.rb +0 -50
- data/lib/spree_cm_commissioner/trip_result.rb +10 -19
- data/lib/spree_cm_commissioner/trip_seat_layout_result.rb +11 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +1 -37
- data/spree_cm_commissioner.gemspec +0 -7
- metadata +28 -163
- data/app/controllers/spree/admin/inventory_items_controller.rb +0 -83
- data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +0 -42
- data/app/controllers/spree/api/v2/storefront/trip_places_controller.rb +0 -29
- data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +0 -62
- data/app/finders/spree_cm_commissioner/accommodations/find.rb +0 -37
- data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +0 -32
- data/app/interactors/spree_cm_commissioner/ensure_correct_product_type.rb +0 -40
- data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +0 -25
- data/app/interactors/spree_cm_commissioner/stock/inventory_item_resetter.rb +0 -44
- data/app/interactors/spree_cm_commissioner/stock/inventory_items_adjuster.rb +0 -13
- data/app/interactors/spree_cm_commissioner/stock/inventory_items_generator.rb +0 -15
- data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +0 -75
- data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +0 -32
- data/app/interactors/spree_cm_commissioner/taxi_trip_creator.rb +0 -66
- data/app/interactors/spree_cm_commissioner/transit/draft_order_creator.rb +0 -132
- data/app/interactors/spree_cm_commissioner/variant_block_updater.rb +0 -62
- data/app/interactors/spree_cm_commissioner/vehicle_updater.rb +0 -41
- data/app/jobs/spree_cm_commissioner/ensure_correct_product_type_job.rb +0 -7
- data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +0 -7
- data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +0 -11
- data/app/jobs/spree_cm_commissioner/stock/inventory_items_generator_job.rb +0 -11
- data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +0 -9
- data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +0 -89
- data/app/models/concerns/spree_cm_commissioner/order_seatable.rb +0 -44
- data/app/models/concerns/spree_cm_commissioner/vehicle_type.rb +0 -11
- data/app/models/spree_cm_commissioner/block.rb +0 -43
- data/app/models/spree_cm_commissioner/inventory.rb +0 -11
- data/app/models/spree_cm_commissioner/inventory_item.rb +0 -69
- data/app/models/spree_cm_commissioner/price_decorator.rb +0 -9
- data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +0 -41
- data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +0 -126
- data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +0 -36
- data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +0 -25
- data/app/models/spree_cm_commissioner/reserved_block.rb +0 -30
- data/app/models/spree_cm_commissioner/saved_guest.rb +0 -15
- data/app/models/spree_cm_commissioner/seat_layout.rb +0 -20
- data/app/models/spree_cm_commissioner/seat_section.rb +0 -16
- data/app/models/spree_cm_commissioner/seats/blocks_canceler.rb +0 -30
- data/app/models/spree_cm_commissioner/seats/blocks_holder.rb +0 -53
- data/app/models/spree_cm_commissioner/seats/blocks_reserver.rb +0 -49
- data/app/models/spree_cm_commissioner/seats/errors/blocks_are_on_hold_by_other_guest.rb +0 -4
- data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_other_guest.rb +0 -4
- data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_same_guest.rb +0 -4
- data/app/models/spree_cm_commissioner/seats/errors/unable_to_save_reserved_block_record.rb +0 -4
- data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +0 -44
- data/app/models/spree_cm_commissioner/variant_block.rb +0 -17
- data/app/request_schemas/spree_cm_commissioner/trip_search_request_schema.rb +0 -20
- data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +0 -19
- data/app/serializers/spree/v2/storefront/amenity_serializer.rb +0 -15
- data/app/serializers/spree/v2/storefront/trip_place_serializer.rb +0 -10
- data/app/serializers/spree/v2/storefront/trip_query_result_serializer.rb +0 -14
- data/app/serializers/spree/v2/storefront/trip_result_serializer.rb +0 -17
- data/app/serializers/spree/v2/storefront/trip_vehicle_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/trip_vendor_serializer.rb +0 -13
- data/app/views/spree/admin/inventory_items/show.html.erb +0 -72
- data/app/views/spree/admin/stock_managements/calendar.html.erb +0 -56
- data/config/initializers/paper_trail.rb +0 -1
- data/db/migrate/20250122000000_move_route_type_from_vehicles_to_trips.rb +0 -7
- data/db/migrate/20250304293518_create_cm_inventory_items.rb +0 -21
- data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +0 -5
- data/db/migrate/20250502025848_add_index_to_spree_products.rb +0 -5
- data/db/migrate/20250502030001_add_product_type_to_spree_variants.rb +0 -5
- data/db/migrate/20250502030002_add_product_type_to_spree_line_items.rb +0 -5
- data/db/migrate/20250603035256_add_inventory_item_to_spree_prices.rb +0 -7
- data/db/migrate/20250619073724_drop_table_cm_line_item_seats.rb +0 -5
- data/db/migrate/20250619073812_drop_table_cm_vehicle_seats.rb +0 -5
- data/db/migrate/20250619073844_drop_table_cm_vehicle_types.rb +0 -9
- data/db/migrate/20250619073957_drop_table_cm_option_value_vehicle_types.rb +0 -5
- data/db/migrate/20250619082354_remove_unnecessary_fields_from_cm_places.rb +0 -9
- data/db/migrate/20250619082736_remove_route_type_from_spree_products.rb +0 -5
- data/db/migrate/20250619083055_remove_unnecessary_fields_from_spree_taxons.rb +0 -5
- data/db/migrate/20250620083055_remove_variant_id_from_cm_trips.rb +0 -5
- data/db/migrate/20250620090000_update_cm_trip_connections_to_use_cm_trips.rb +0 -6
- data/db/migrate/20250620090001_create_cm_seat_layouts.rb +0 -17
- data/db/migrate/20250620090002_create_cm_seat_sections.rb +0 -18
- data/db/migrate/20250620090003_create_cm_blocks.rb +0 -18
- data/db/migrate/20250624091005_create_cm_reserved_blocks.rb +0 -29
- data/db/migrate/20250626083642_create_cm_variant_blocks.rb +0 -24
- data/db/migrate/20250627023314_add_block_id_to_cm_guests.rb +0 -13
- data/db/migrate/20250716022821_add_location_reference_to_cm_vendor_places.rb +0 -5
- data/db/migrate/20250716031743_drop_table_cm_vendor_stops.rb +0 -5
- data/db/migrate/20250717023824_add_vendor_reference_to_cm_trips.rb +0 -5
- data/db/migrate/20250717041414_add_location_place_reference_to_cm_trip_stops.rb +0 -5
- data/db/migrate/20250717042539_rename_cm_trip_stops_stop_id_column_to_stop_place_id.rb +0 -7
- data/db/migrate/20250717042707_rename_cm_trips_origin_and_destination_to_origin_place_and_destination_place.rb +0 -11
- data/db/migrate/20250721080738_add_vehicle_type_to_cm_vehicles.rb +0 -7
- data/db/migrate/20250725092713_add_block_type_to_cm_blocks.rb +0 -5
- data/db/migrate/20250731062816_add_departure_time_and_arrival_time_to_trip_stop.rb +0 -6
- data/db/migrate/20250807033035_create_spree_cm_commissioner_saved_guests.rb +0 -23
- data/db/migrate/20250808054835_add_saved_guest_reference_to_cm_blocks.rb +0 -5
- data/lib/spree_cm_commissioner/cached_inventory_item.rb +0 -23
- data/lib/spree_cm_commissioner/test_helper/factories/block_factory.rb +0 -16
- data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +0 -9
- data/lib/spree_cm_commissioner/test_helper/factories/reserved_block_factory.rb +0 -27
- data/lib/spree_cm_commissioner/test_helper/factories/seat_layout_factory.rb +0 -11
- data/lib/spree_cm_commissioner/test_helper/factories/seat_section_factory.rb +0 -16
- data/lib/spree_cm_commissioner/test_helper/factories/trip_connection_factory.rb +0 -6
- data/lib/spree_cm_commissioner/test_helper/factories/trip_stop_factory.rb +0 -13
- data/lib/spree_cm_commissioner/test_helper/factories/variant_block_factory.rb +0 -7
- data/lib/spree_cm_commissioner/transit/leg.rb +0 -37
- data/lib/spree_cm_commissioner/transit/seat_selection.rb +0 -27
- data/lib/tasks/create_default_non_permanent_inventory_items.rake +0 -16
- data/lib/tasks/ensure_correct_product_type.rake +0 -7
- data/lib/tasks/generate_inventory_items.rake +0 -7
@@ -1,132 +0,0 @@
|
|
1
|
-
# DraftOrderCreator creates a new order for a entire journey, including outbound and (if present) inbound directions.
|
2
|
-
#
|
3
|
-
# Attributes:
|
4
|
-
# - outbound_date: [Date] The date of outbound transit
|
5
|
-
# - inbound_date: [Date] The date of inbound transit
|
6
|
-
# - outbound_legs: [Array<SpreeCmCommissioner::Transit::Leg>] Outbound transit legs (one for direct, multiple for connecting)
|
7
|
-
# - inbound_legs: [Array<SpreeCmCommissioner::Transit::Leg>] Inbound transit legs (one for direct, multiple for connecting)
|
8
|
-
# - user: [User] The user for whom the order is being created
|
9
|
-
#
|
10
|
-
# Each line item is built with precise from_date and to_date based on legs and trip stop times.
|
11
|
-
# Each line item has guests built corresponding to seat selection blocks.
|
12
|
-
#
|
13
|
-
# Note: inbound_legs and inbound_date are optional; the order may represent a one-way (outbound only) journey.
|
14
|
-
module SpreeCmCommissioner
|
15
|
-
module Transit
|
16
|
-
class DraftOrderCreator < BaseInteractor
|
17
|
-
delegate :outbound_date,
|
18
|
-
:inbound_date,
|
19
|
-
:outbound_legs,
|
20
|
-
:inbound_legs,
|
21
|
-
:user, to: :context
|
22
|
-
|
23
|
-
def call
|
24
|
-
return context.fail!(message: 'Outbound legs are missing') if outbound_legs.blank?
|
25
|
-
|
26
|
-
begin
|
27
|
-
context.order = create_order!
|
28
|
-
rescue StandardError => e
|
29
|
-
context.fail!(message: e.message)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def create_order!
|
34
|
-
order = Spree::Order.new(state: 'cart', use_billing: true, user: user)
|
35
|
-
|
36
|
-
outbound_line_items = build_line_items_for_legs!(order: order, legs: outbound_legs, initial_date: outbound_date)
|
37
|
-
inbound_line_items = inbound_legs.blank? ? [] : build_line_items_for_legs!(order: order, legs: inbound_legs, initial_date: inbound_date)
|
38
|
-
|
39
|
-
outbound_qty = outbound_line_items.sum(&:quantity)
|
40
|
-
inbound_qty = inbound_line_items.sum(&:quantity)
|
41
|
-
|
42
|
-
raise StandardError, 'Outbound & inbound line item quantities do not match' if inbound_line_items.any? && outbound_qty != inbound_qty
|
43
|
-
raise StandardError, order.errors.full_messages.to_sentence unless order.save
|
44
|
-
|
45
|
-
order
|
46
|
-
end
|
47
|
-
|
48
|
-
# Build line items for each leg, using the previous leg's to_date as the next leg's date,
|
49
|
-
# or the initial date for the first leg.
|
50
|
-
def build_line_items_for_legs!(order:, legs:, initial_date:)
|
51
|
-
all_line_items = []
|
52
|
-
current_leg_date = initial_date
|
53
|
-
|
54
|
-
legs.each do |leg|
|
55
|
-
leg_line_items = build_line_items_for!(leg, order, current_leg_date)
|
56
|
-
leg_line_items = insert_saved_guests_per_line_items_leg(leg_line_items)
|
57
|
-
|
58
|
-
all_line_items.concat(leg_line_items)
|
59
|
-
current_leg_date = leg_line_items.last.to_date.to_date if leg_line_items.any?
|
60
|
-
end
|
61
|
-
|
62
|
-
all_line_items
|
63
|
-
end
|
64
|
-
|
65
|
-
def build_line_items_for!(leg, order, date)
|
66
|
-
trip = SpreeCmCommissioner::Trip.find(leg.trip_id)
|
67
|
-
trip_stops = trip.trip_stops.where(id: [leg.boarding_trip_stop_id, leg.drop_off_trip_stop_id]).index_by(&:id)
|
68
|
-
|
69
|
-
from_date, to_date = calculate_line_item_duration!(
|
70
|
-
date: date,
|
71
|
-
departure_time: trip_stops[leg.boarding_trip_stop_id].departure_time,
|
72
|
-
arrival_time: trip_stops[leg.drop_off_trip_stop_id].arrival_time
|
73
|
-
)
|
74
|
-
|
75
|
-
leg.seat_selections.group_by(&:variant_id).map do |variant_id, seat_selections|
|
76
|
-
line_item = order.line_items.new(
|
77
|
-
product_type: :transit,
|
78
|
-
from_date: from_date,
|
79
|
-
to_date: to_date,
|
80
|
-
variant_id: variant_id,
|
81
|
-
quantity: seat_selections.sum(&:quantity),
|
82
|
-
private_metadata: {
|
83
|
-
direction: leg.direction,
|
84
|
-
trip_id: leg.trip_id.to_s,
|
85
|
-
boarding_trip_stop_id: leg.boarding_trip_stop_id.to_s,
|
86
|
-
drop_off_trip_stop_id: leg.drop_off_trip_stop_id.to_s
|
87
|
-
}
|
88
|
-
)
|
89
|
-
|
90
|
-
build_guests_for!(line_item, seat_selections)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def build_guests_for!(line_item, seat_selections)
|
95
|
-
block_ids = seat_selections.flat_map(&:block_ids)
|
96
|
-
|
97
|
-
if block_ids.any? && block_ids.size != line_item.quantity
|
98
|
-
raise StandardError, "Number of blocks (#{block_ids.size}) does not match quantity (#{line_item.quantity})"
|
99
|
-
end
|
100
|
-
|
101
|
-
Array.new(line_item.quantity) do |index|
|
102
|
-
line_item.guests.new(block_id: block_ids[index])
|
103
|
-
end
|
104
|
-
|
105
|
-
line_item
|
106
|
-
end
|
107
|
-
|
108
|
-
def insert_saved_guests_per_line_items_leg(line_items)
|
109
|
-
line_items.flat_map(&:guests).each_with_index do |guest, index|
|
110
|
-
context.saved_guests ||= []
|
111
|
-
context.saved_guests << SpreeCmCommissioner::SavedGuest.new if context.saved_guests[index].blank?
|
112
|
-
|
113
|
-
guest.saved_guest = context.saved_guests[index]
|
114
|
-
end
|
115
|
-
|
116
|
-
line_items
|
117
|
-
end
|
118
|
-
|
119
|
-
def calculate_line_item_duration!(date:, departure_time:, arrival_time:)
|
120
|
-
raise StandardError, 'Departure or arrival time in trip stop is missing' if departure_time.blank? || arrival_time.blank?
|
121
|
-
raise StandardError, 'Arrival time cannot be before departure time' if arrival_time < departure_time
|
122
|
-
|
123
|
-
trip_duration_in_seconds = arrival_time - departure_time
|
124
|
-
|
125
|
-
from_date = date.to_datetime.change(hour: departure_time.hour, min: departure_time.min, sec: departure_time.sec)
|
126
|
-
to_date = from_date + trip_duration_in_seconds.seconds
|
127
|
-
|
128
|
-
[from_date, to_date]
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
class VariantBlockUpdater < BaseInteractor
|
3
|
-
delegate :variant, :data, :stock_location, :current_store, to: :context
|
4
|
-
|
5
|
-
def call
|
6
|
-
block_ids = data[:block_ids] || []
|
7
|
-
|
8
|
-
ActiveRecord::Base.transaction do
|
9
|
-
update_variant_block!(block_ids, variant)
|
10
|
-
update_stock_item!(variant)
|
11
|
-
end
|
12
|
-
|
13
|
-
context.message = 'Update variant blocks successfully'
|
14
|
-
rescue StandardError => e
|
15
|
-
context.fail!(message: "Update variant blocks Failed: #{e.message}")
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def update_variant_block!(block_ids, variant)
|
21
|
-
variant.variant_blocks.where.not(block_id: block_ids).destroy_all
|
22
|
-
|
23
|
-
block_ids.each do |block_id|
|
24
|
-
next unless SpreeCmCommissioner::Block.exists?(id: block_id) # Skip invalid block_ids
|
25
|
-
|
26
|
-
block = SpreeCmCommissioner::VariantBlock.find_by(
|
27
|
-
block_id: block_id,
|
28
|
-
trip_id: variant.product.trip.id,
|
29
|
-
variant_id: variant.id
|
30
|
-
)
|
31
|
-
|
32
|
-
next unless block.nil?
|
33
|
-
|
34
|
-
SpreeCmCommissioner::VariantBlock.create!(
|
35
|
-
block_id: block_id,
|
36
|
-
trip_id: variant.product.trip.id,
|
37
|
-
variant_id: variant.id
|
38
|
-
)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def update_stock_item!(variant)
|
43
|
-
stock_items = variant.stock_items
|
44
|
-
|
45
|
-
context.fail!(message: 'Variant has more than one stock item. Please report to admin.') if stock_items.count > 1
|
46
|
-
|
47
|
-
stock_item = stock_items.first || variant.stock_items.create!(stock_location: stock_location)
|
48
|
-
quantity_difference = variant.variant_blocks.count - stock_item.count_on_hand
|
49
|
-
|
50
|
-
resource = SpreeCmCommissioner::Stock::StockMovementCreator.call(
|
51
|
-
variant_id: variant.id,
|
52
|
-
stock_location_id: stock_location.id,
|
53
|
-
current_store: current_store,
|
54
|
-
stock_movement_params: { quantity: quantity_difference }
|
55
|
-
)
|
56
|
-
|
57
|
-
return if resource.success?
|
58
|
-
|
59
|
-
context.fail!(message: "Stock update failed: #{resource.errors}")
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
class VehicleUpdater < BaseInteractor
|
3
|
-
def call
|
4
|
-
vehicle = context.vehicle
|
5
|
-
data = context.data
|
6
|
-
|
7
|
-
option_value_ids = data[:option_value_ids] || []
|
8
|
-
option_type_ids = data[:option_type_ids] || []
|
9
|
-
|
10
|
-
ActiveRecord::Base.transaction do
|
11
|
-
update_vehicle!(vehicle, data[:vehicle_attributes])
|
12
|
-
update_amenities!(vehicle, option_value_ids, option_type_ids)
|
13
|
-
end
|
14
|
-
|
15
|
-
context.message = I18n.t('views.transit.vehicles.update_success')
|
16
|
-
rescue StandardError => e
|
17
|
-
context.fail!(message: "Failed to update vehicle: #{e.message}")
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def update_vehicle!(vehicle, attributes)
|
23
|
-
return if vehicle.update(attributes.slice(:code, :license_plate, :allow_seat_selection, :vehicle_type, :number_of_seats))
|
24
|
-
|
25
|
-
raise vehicle.errors.full_messages.to_sentence
|
26
|
-
end
|
27
|
-
|
28
|
-
def update_amenities!(vehicle, option_value_ids, option_type_ids)
|
29
|
-
vehicle.option_value_vehicles.where.not(option_value_id: option_value_ids).destroy_all
|
30
|
-
vehicle.vehicle_option_types.where.not(option_type_id: option_type_ids).destroy_all
|
31
|
-
|
32
|
-
option_value_ids.each do |option_value_id|
|
33
|
-
vehicle.option_value_vehicles.find_or_create_by(option_value_id: option_value_id)
|
34
|
-
end
|
35
|
-
|
36
|
-
option_type_ids.each do |option_type_id|
|
37
|
-
vehicle.vehicle_option_types.find_or_create_by(option_type_id: option_type_id)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
module Stock
|
3
|
-
class InventoryItemsAdjusterJob < ApplicationUniqueJob
|
4
|
-
def perform(variant_id:, quantity:)
|
5
|
-
variant = Spree::Variant.find(variant_id)
|
6
|
-
|
7
|
-
SpreeCmCommissioner::Stock::InventoryItemsAdjuster.call(variant: variant, quantity: quantity)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
module Stock
|
3
|
-
class InventoryItemsGeneratorJob < ApplicationUniqueJob
|
4
|
-
def perform(variant_id:)
|
5
|
-
variant = Spree::Variant.find(variant_id)
|
6
|
-
|
7
|
-
SpreeCmCommissioner::Stock::InventoryItemsGenerator.call(variant: variant)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
# This concern allow line item to have trip-related metadata.
|
2
|
-
#
|
3
|
-
# Metadata structure:
|
4
|
-
# {
|
5
|
-
# 'direction': 'outbound' or 'inbound',
|
6
|
-
# 'trip_id': 123,
|
7
|
-
# 'boarding_trip_stop_id': 456,
|
8
|
-
# 'drop_off_trip_stop_id': 789
|
9
|
-
# }
|
10
|
-
#
|
11
|
-
# Direction:
|
12
|
-
# - "outbound": The trip is moving away from the origin (e.g., A → B → C → D).
|
13
|
-
# This term is more flexible than "departure" and applies to both direct and connected trips.
|
14
|
-
# - "inbound": The trip is returning toward the origin (e.g., D → C → B → A).
|
15
|
-
# This term is more flexible than "return" and applies to both direct and connected trips.
|
16
|
-
module SpreeCmCommissioner
|
17
|
-
module LineItemTransitable
|
18
|
-
extend ActiveSupport::Concern
|
19
|
-
|
20
|
-
DIRECTION = %w[outbound inbound].freeze
|
21
|
-
|
22
|
-
TripKey = Struct.new(:trip_id, :direction, :boarding_trip_stop_id, :drop_off_trip_stop_id)
|
23
|
-
|
24
|
-
included do
|
25
|
-
validates :direction, inclusion: { in: DIRECTION }, allow_nil: true
|
26
|
-
validates :trip_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
27
|
-
validates :boarding_trip_stop_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
28
|
-
validates :drop_off_trip_stop_id, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
29
|
-
|
30
|
-
# Groups LineItems by trip fields. Some fields can be null,
|
31
|
-
# so use it with caution. Output:
|
32
|
-
# {
|
33
|
-
# $<TripKey:> => [<LineItem id:1>]
|
34
|
-
# $<TripKey:> => [<LineItem id:2>]
|
35
|
-
# $<TripKey:> => [<LineItem id:3>, <LineItem id:4>]
|
36
|
-
# }
|
37
|
-
def self.group_by_trip_key
|
38
|
-
all.group_by do |line_item|
|
39
|
-
TripKey.new(
|
40
|
-
line_item.trip_id,
|
41
|
-
line_item.direction,
|
42
|
-
line_item.boarding_trip_stop_id,
|
43
|
-
line_item.drop_off_trip_stop_id
|
44
|
-
)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def outbound? = direction == 'outbound'
|
50
|
-
def inbound? = direction == 'inbound'
|
51
|
-
|
52
|
-
def direction = private_metadata['direction']
|
53
|
-
def trip_id = private_metadata['trip_id']&.to_i
|
54
|
-
def boarding_trip_stop_id = private_metadata['boarding_trip_stop_id']&.to_i
|
55
|
-
def drop_off_trip_stop_id = private_metadata['drop_off_trip_stop_id']&.to_i
|
56
|
-
|
57
|
-
def direction=(value)
|
58
|
-
if value.nil?
|
59
|
-
private_metadata.delete('direction')
|
60
|
-
else
|
61
|
-
private_metadata['direction'] = value.to_s
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def trip_id=(value)
|
66
|
-
if value.nil?
|
67
|
-
private_metadata.delete('trip_id')
|
68
|
-
else
|
69
|
-
private_metadata['trip_id'] = value.to_s
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def boarding_trip_stop_id=(value)
|
74
|
-
if value.nil?
|
75
|
-
private_metadata.delete('boarding_trip_stop_id')
|
76
|
-
else
|
77
|
-
private_metadata['boarding_trip_stop_id'] = value.to_s
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def drop_off_trip_stop_id=(value)
|
82
|
-
if value.nil?
|
83
|
-
private_metadata.delete('drop_off_trip_stop_id')
|
84
|
-
else
|
85
|
-
private_metadata['drop_off_trip_stop_id'] = value.to_s
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
module OrderSeatable
|
3
|
-
def should_manage_blocks?
|
4
|
-
preload_block_ids.any?
|
5
|
-
end
|
6
|
-
|
7
|
-
def hold_blocks!
|
8
|
-
return unless should_manage_blocks?
|
9
|
-
|
10
|
-
CmAppLogger.log(label: "#{self.class.name}#hold_blocks!", data: { order_id: id }) do
|
11
|
-
SpreeCmCommissioner::Seats::BlocksHolder.new(line_item_ids: line_item_ids, hold_by: user).hold_blocks!
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def cancel_blocks!
|
16
|
-
return unless should_manage_blocks?
|
17
|
-
|
18
|
-
CmAppLogger.log(label: "#{self.class.name}#cancel_blocks!", data: { order_id: id }) do
|
19
|
-
SpreeCmCommissioner::Seats::BlocksCanceler.new(order_id: id, cancel_by: user).cancel_blocks!
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def reserve_blocks!
|
24
|
-
return unless should_manage_blocks?
|
25
|
-
|
26
|
-
CmAppLogger.log(label: "#{self.class.name}#reserve_blocks!", data: { order_id: id }) do
|
27
|
-
SpreeCmCommissioner::Seats::BlocksReserver.new(line_item_ids: line_item_ids, reserve_by: user).reserve_blocks!
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Calling `.block_ids` directly can cause many slow database queries (N+1 problem)
|
32
|
-
# every time `.should_manage_blocks?` or `.preload_block_ids` runs.
|
33
|
-
# To avoid this, we store a precomputed list of block IDs in `private_metadata`.
|
34
|
-
# This list is updated whenever a guest’s block is saved or destroy.
|
35
|
-
def preload_block_ids=(preload_block_ids = [])
|
36
|
-
self.private_metadata ||= {}
|
37
|
-
self.private_metadata['preload_block_ids'] = preload_block_ids
|
38
|
-
end
|
39
|
-
|
40
|
-
def preload_block_ids
|
41
|
-
self.private_metadata&.fetch('preload_block_ids', []) || []
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
module VehicleType
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
VEHICLE_TYPES = %i[suv sedan minivan van sleeping_bus luxury_van air_bus].freeze
|
6
|
-
|
7
|
-
included do
|
8
|
-
enum vehicle_type: VEHICLE_TYPES if table_exists? && column_names.include?('vehicle_type')
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
class Block < Base
|
3
|
-
enum block_type: {
|
4
|
-
seat: 1,
|
5
|
-
sleeping_seat: 2,
|
6
|
-
driver: 3,
|
7
|
-
bathroom: 4,
|
8
|
-
other: 0
|
9
|
-
}
|
10
|
-
|
11
|
-
belongs_to :seat_section, class_name: 'SpreeCmCommissioner::SeatSection', optional: true
|
12
|
-
belongs_to :seat_layout, class_name: 'SpreeCmCommissioner::SeatLayout', optional: false
|
13
|
-
|
14
|
-
validates :label, presence: true, if: :label_required?
|
15
|
-
|
16
|
-
has_many :variant_blocks, class_name: 'SpreeCmCommissioner::VariantBlock', dependent: :destroy
|
17
|
-
has_many :variants, class_name: 'Spree::Variant', through: :variant_blocks
|
18
|
-
|
19
|
-
validates :width, presence: true, numericality: { greater_than: 0 }
|
20
|
-
validates :height, presence: true, numericality: { greater_than: 0 }
|
21
|
-
validates :x, presence: true, numericality: true
|
22
|
-
validates :y, presence: true, numericality: true
|
23
|
-
validates :rotation, presence: true, numericality: { greater_than_or_equal_to: -360, less_than_or_equal_to: 360 }
|
24
|
-
|
25
|
-
before_validation :assign_layout_from_section, if: -> { seat_layout.nil? && seat_section.present? }
|
26
|
-
|
27
|
-
def label_required?
|
28
|
-
seatable? || block_type.to_s == 'other'
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.seatable?(block_type)
|
32
|
-
block_type.to_s.in?(%w[sleeping_seat seat])
|
33
|
-
end
|
34
|
-
|
35
|
-
def seatable?
|
36
|
-
self.class.seatable?(block_type)
|
37
|
-
end
|
38
|
-
|
39
|
-
def assign_layout_from_section
|
40
|
-
self.seat_layout = seat_section.seat_layout
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
class Inventory
|
3
|
-
include ActiveModel::Model
|
4
|
-
|
5
|
-
attr_accessor :variant_id, :inventory_date, :quantity_available, :max_capacity, :product_type
|
6
|
-
|
7
|
-
validates :variant_id, presence: true
|
8
|
-
validates :quantity_available, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, allow_nil: true
|
9
|
-
validates :max_capacity, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, allow_nil: true
|
10
|
-
end
|
11
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
class InventoryItem < Base
|
3
|
-
include SpreeCmCommissioner::ProductType
|
4
|
-
|
5
|
-
# Association
|
6
|
-
belongs_to :variant, class_name: 'Spree::Variant', optional: false
|
7
|
-
has_many :prices, class_name: 'Spree::Price', inverse_of: :inventory_item
|
8
|
-
|
9
|
-
# Validation
|
10
|
-
validates :quantity_available, numericality: { greater_than_or_equal_to: 0 }
|
11
|
-
validates :max_capacity, numericality: { greater_than_or_equal_to: 0 } # Originally inventory of each variant.
|
12
|
-
validates :inventory_date, presence: true, if: :permanent_stock?
|
13
|
-
validates :variant_id, uniqueness: { scope: :inventory_date, message: -> (object, _data) { "The variant is taken on #{object.inventory_date}" } }
|
14
|
-
|
15
|
-
# Scope
|
16
|
-
scope :active, -> { where(inventory_date: nil).or(where('inventory_date >= ?', Time.zone.today)) }
|
17
|
-
|
18
|
-
before_save -> { self.product_type = variant.product_type }, if: -> { product_type.nil? }
|
19
|
-
|
20
|
-
# This method is only used when admin update stock
|
21
|
-
def adjust_quantity!(quantity)
|
22
|
-
with_lock do
|
23
|
-
self.max_capacity = [max_capacity + quantity, 0].max
|
24
|
-
self.quantity_available = [quantity_available + quantity, 0].max
|
25
|
-
save!
|
26
|
-
|
27
|
-
# When user has been searched or booked a product, it has cached the quantity in redis,
|
28
|
-
# So we need to update redis cache if inventory key has been created in redis
|
29
|
-
adjust_quantity_in_redis(quantity)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def redis_key
|
34
|
-
"inventory:#{id}"
|
35
|
-
end
|
36
|
-
|
37
|
-
def adjust_quantity_in_redis(quantity)
|
38
|
-
SpreeCmCommissioner.redis_pool.with do |redis|
|
39
|
-
cached_quantity_available = redis.get(redis_key)
|
40
|
-
# ignore if redis doesn't exist
|
41
|
-
return if cached_quantity_available.nil? # rubocop:disable Lint/NonLocalExitFromIterator
|
42
|
-
|
43
|
-
script = <<~LUA
|
44
|
-
local key = KEYS[1]
|
45
|
-
local increment = tonumber(ARGV[1])
|
46
|
-
local current = tonumber(redis.call('GET', key) or 0)
|
47
|
-
local new_value = current + increment
|
48
|
-
if new_value < 0 then
|
49
|
-
new_value = 0
|
50
|
-
end
|
51
|
-
redis.call('SET', key, new_value)
|
52
|
-
return new_value
|
53
|
-
LUA
|
54
|
-
|
55
|
-
redis.eval(script, keys: [redis_key], argv: [quantity])
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def active?
|
60
|
-
inventory_date.nil? || inventory_date >= Time.zone.today
|
61
|
-
end
|
62
|
-
|
63
|
-
def redis_expired_in
|
64
|
-
expired_in = 31_536_000 # 1 year for normal stock
|
65
|
-
expired_in = Time.parse(inventory_date.to_s).end_of_day.to_i - Time.zone.now.to_i if inventory_date.present?
|
66
|
-
[expired_in, 0].max
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,9 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
module PriceDecorator
|
3
|
-
def self.prepended(base)
|
4
|
-
base.belongs_to :inventory_item, class_name: 'SpreeCmCommissioner::InventoryItem', inverse_of: :prices, optional: true
|
5
|
-
end
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
Spree::Price.prepend(SpreeCmCommissioner::PriceDecorator) unless Spree::Price.included_modules.include?(SpreeCmCommissioner::PriceDecorator)
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module SpreeCmCommissioner
|
2
|
-
module RedisStock
|
3
|
-
class CachedInventoryItemsBuilder
|
4
|
-
attr_reader :inventory_items
|
5
|
-
|
6
|
-
def initialize(inventory_items)
|
7
|
-
@inventory_items = inventory_items
|
8
|
-
end
|
9
|
-
|
10
|
-
# output: [ CachedInventoryItem(...), CachedInventoryItem(...) ]
|
11
|
-
def call
|
12
|
-
keys = inventory_items.map { |item| "inventory:#{item.id}" }
|
13
|
-
return [] unless keys.any?
|
14
|
-
|
15
|
-
counts = SpreeCmCommissioner.redis_pool.with { |redis| redis.mget(*keys) }
|
16
|
-
inventory_items.map.with_index do |inventory_item, i|
|
17
|
-
::SpreeCmCommissioner::CachedInventoryItem.new(
|
18
|
-
inventory_key: keys[i],
|
19
|
-
active: inventory_item.active?,
|
20
|
-
quantity_available: cache_inventory(keys[i], inventory_item, counts[i]),
|
21
|
-
inventory_item_id: inventory_item.id,
|
22
|
-
variant_id: inventory_item.variant_id
|
23
|
-
)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def cache_inventory(key, inventory_item, count_in_redis)
|
30
|
-
return count_in_redis.to_i if count_in_redis.present?
|
31
|
-
return inventory_item.quantity_available unless inventory_item.active?
|
32
|
-
|
33
|
-
SpreeCmCommissioner.redis_pool.with do |redis|
|
34
|
-
redis.set(key, inventory_item.quantity_available, ex: inventory_item.redis_expired_in)
|
35
|
-
end
|
36
|
-
|
37
|
-
inventory_item.quantity_available
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|