spree_cm_commissioner 2.5.16.pre.pre8 → 2.5.16.pre.pre9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/app/controllers/spree/api/v2/organizer/invite_guests_controller.rb +91 -0
- data/app/controllers/spree/api/v2/storefront/saved_guests_controller.rb +77 -0
- data/app/helpers/spree_cm_commissioner/transit/trip_helper.rb +0 -28
- data/app/interactors/spree_cm_commissioner/create_vendor.rb +2 -0
- data/app/models/spree_cm_commissioner/trip.rb +0 -2
- data/app/models/spree_cm_commissioner/user_decorator.rb +1 -0
- data/app/queries/spree_cm_commissioner/trip_query.rb +128 -28
- data/app/serializers/spree/v2/organizer/invite_guest_serializer.rb +13 -0
- data/app/services/spree_cm_commissioner/transit_order/create.rb +6 -48
- data/app/services/spree_cm_commissioner/trips/create_single_leg.rb +1 -2
- data/app/services/spree_cm_commissioner/trips/search.rb +8 -12
- data/config/routes.rb +2 -0
- data/lib/spree_cm_commissioner/transit/service_calendar_form.rb +0 -19
- data/lib/spree_cm_commissioner/trip_query_result.rb +6 -30
- data/lib/spree_cm_commissioner/trip_result.rb +0 -55
- data/lib/spree_cm_commissioner/version.rb +1 -1
- metadata +5 -7
- data/app/queries/spree_cm_commissioner/multi_leg_trips_query.rb +0 -292
- data/app/queries/spree_cm_commissioner/single_leg_trips_query.rb +0 -91
- data/app/services/spree_cm_commissioner/trips/create_multi_leg.rb +0 -542
- data/app/services/spree_cm_commissioner/trips/preload_inventory.rb +0 -80
- data/db/migrate/20260226105108_add_trip_type_to_cm_trip.rb +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2046dd747c4cf51ac0d7e234515660e7245e55327647299bf7f132bf4aae78e8
|
|
4
|
+
data.tar.gz: fd9229c34306586e999a0fbaab5e2a8e90b57ceed353eba6fe6b3e6230105eb1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8472c56f7159e01aea47fbb5add8613d6f9b0158c95de0bca11c149fd7e8c15e2d8e67fa69b3bd97ccef545c7e94a4d580bd2f4e604d54ca6914948c62a3c6bd
|
|
7
|
+
data.tar.gz: 3d78511c0dd9b9d21c9bf26c044fe304d88f246f243ce7a81101bc9ea42172cc9127ba6db150f7e4923060fb3e0d6c1140b1d35076c56b8b1e9838e2fabe3ab4
|
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V2
|
|
4
|
+
module Organizer
|
|
5
|
+
class InviteGuestsController < ::Spree::Api::V2::Organizer::BaseController
|
|
6
|
+
before_action :load_invite_guest_by_token, only: :show
|
|
7
|
+
before_action :load_invite_guest, :assign_line_item_data, only: :update
|
|
8
|
+
|
|
9
|
+
def show
|
|
10
|
+
render_serialized_payload { serialize_resource(@invite_guest) }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def update
|
|
14
|
+
return render_error(:revoked) if @invite_guest.revoked?
|
|
15
|
+
return render_error(:closed) if @invite_guest.expired?
|
|
16
|
+
return render_error(:fully_claimed) if @invite_guest.fully_claimed?
|
|
17
|
+
|
|
18
|
+
guest = @line_item.guests.new(guest_params)
|
|
19
|
+
guest.event_id = @invite_guest.event_id
|
|
20
|
+
|
|
21
|
+
if guest.save
|
|
22
|
+
@invite_guest.update(claimed_status: :claimed) if @line_item.guests.count == @invite_guest.quantity
|
|
23
|
+
send_guest_claimed_invitation_telegram_alert_to_vendor(guest) if guest.event.vendor.preferred_telegram_chat_id.present?
|
|
24
|
+
|
|
25
|
+
render json: SpreeCmCommissioner::V2::Storefront::GuestSerializer.new(guest.reload).serializable_hash
|
|
26
|
+
else
|
|
27
|
+
render_error_payload(guest.errors.full_messages.to_sentence)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def send_guest_claimed_invitation_telegram_alert_to_vendor(guest)
|
|
34
|
+
title = '📣 --- [NEW GUEST CLAIMED INVITATION] ---' # Style/StringLiterals
|
|
35
|
+
chat_id = guest.event.vendor.preferred_telegram_chat_id
|
|
36
|
+
return if chat_id.blank?
|
|
37
|
+
|
|
38
|
+
factory = SpreeCmCommissioner::InviteGuestClaimedTelegramMessageFactory.new(
|
|
39
|
+
title: title,
|
|
40
|
+
order: @invite_guest.order,
|
|
41
|
+
guest: guest,
|
|
42
|
+
vendor: guest.event.vendor
|
|
43
|
+
)
|
|
44
|
+
SpreeCmCommissioner::TelegramNotificationSenderJob.perform_later(
|
|
45
|
+
chat_id: chat_id,
|
|
46
|
+
message: factory.message,
|
|
47
|
+
parse_mode: factory.parse_mode
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def load_invite_guest_by_token
|
|
52
|
+
@invite_guest = SpreeCmCommissioner::InviteGuest.find_by(token: params[:id])
|
|
53
|
+
rescue ActiveRecord::RecordNotFound
|
|
54
|
+
render_error_payload(I18n.t('invite.url_not_found'))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def load_invite_guest
|
|
58
|
+
@invite_guest = SpreeCmCommissioner::InviteGuest.find(params[:id])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def assign_line_item_data
|
|
62
|
+
@line_item = @invite_guest.order.line_items.first
|
|
63
|
+
@guests = @line_item.guests
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def render_error(message)
|
|
67
|
+
render json: { errors: message }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def guest_params
|
|
71
|
+
params.require(:invite_guest).permit(
|
|
72
|
+
:first_name,
|
|
73
|
+
:last_name,
|
|
74
|
+
:dob,
|
|
75
|
+
:gender,
|
|
76
|
+
:age,
|
|
77
|
+
:emergency_contact,
|
|
78
|
+
:phone_number,
|
|
79
|
+
:address,
|
|
80
|
+
:other_organization
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def resource_serializer
|
|
85
|
+
::Spree::V2::Organizer::InviteGuestSerializer
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V2
|
|
4
|
+
module Storefront
|
|
5
|
+
class SavedGuestsController < ::Spree::Api::V2::ResourceController
|
|
6
|
+
before_action :require_spree_current_user
|
|
7
|
+
before_action :load_saved_guest, only: %i[show update destroy]
|
|
8
|
+
|
|
9
|
+
def collection
|
|
10
|
+
spree_current_user.saved_guests.order(created_at: :desc)
|
|
11
|
+
.page(params[:page])
|
|
12
|
+
.per(params[:per_page])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
saved_guest = spree_current_user.saved_guests.new(saved_guest_params)
|
|
17
|
+
|
|
18
|
+
if saved_guest.save
|
|
19
|
+
render_serialized_payload(201) { serialize_resource(saved_guest) }
|
|
20
|
+
else
|
|
21
|
+
render_error_payload(saved_guest.errors.full_messages.to_sentence, 422)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def update
|
|
26
|
+
if @saved_guest.update(saved_guest_params)
|
|
27
|
+
render_serialized_payload { serialize_resource(@saved_guest) }
|
|
28
|
+
else
|
|
29
|
+
render_error_payload(@saved_guest.errors.full_messages.to_sentence, 400)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def destroy
|
|
34
|
+
@saved_guest.destroy
|
|
35
|
+
head :no_content
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def model_class
|
|
41
|
+
SpreeCmCommissioner::SavedGuest
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def collection_serializer
|
|
45
|
+
resource_serializer
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def resource_serializer
|
|
49
|
+
SpreeCmCommissioner::V2::Storefront::SavedGuestSerializer
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def load_saved_guest
|
|
53
|
+
@saved_guest = spree_current_user.saved_guests.find(params[:id])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def saved_guest_params
|
|
57
|
+
params.require(:saved_guest).permit(
|
|
58
|
+
:first_name,
|
|
59
|
+
:last_name,
|
|
60
|
+
:dob,
|
|
61
|
+
:age,
|
|
62
|
+
:gender,
|
|
63
|
+
:email,
|
|
64
|
+
:country_code,
|
|
65
|
+
:phone_number,
|
|
66
|
+
:intel_phone_number,
|
|
67
|
+
:nationality_id,
|
|
68
|
+
:occupation_id,
|
|
69
|
+
:nationality_group,
|
|
70
|
+
:age_group
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -7,34 +7,6 @@ module SpreeCmCommissioner
|
|
|
7
7
|
formatted_time = Time.zone.parse(time.to_s)
|
|
8
8
|
timezone ? formatted_time.in_time_zone(timezone) : formatted_time
|
|
9
9
|
end
|
|
10
|
-
|
|
11
|
-
# Helper to parse date strings or return date objects
|
|
12
|
-
def parse_date(date_obj)
|
|
13
|
-
return date_obj if date_obj.is_a?(Date)
|
|
14
|
-
|
|
15
|
-
Date.parse(date_obj.to_s)
|
|
16
|
-
rescue ArgumentError
|
|
17
|
-
nil
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def normalize_date(value)
|
|
21
|
-
if value.respond_to?(:to_date) && value.to_date == Time.zone.now.to_date
|
|
22
|
-
Time.zone.now
|
|
23
|
-
else
|
|
24
|
-
Time.zone.parse(value.to_s)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def minutes_since_midnight(value)
|
|
29
|
-
case value
|
|
30
|
-
when Time, ActiveSupport::TimeWithZone
|
|
31
|
-
(value.hour * 60) + value.min
|
|
32
|
-
else
|
|
33
|
-
str = value.to_s.strip
|
|
34
|
-
h, m = str.split(':', 2).map(&:to_i)
|
|
35
|
-
(h * 60) + (m || 0)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
10
|
end
|
|
39
11
|
end
|
|
40
12
|
end
|
|
@@ -5,8 +5,6 @@ module SpreeCmCommissioner
|
|
|
5
5
|
|
|
6
6
|
attr_accessor :hours, :minutes, :seconds
|
|
7
7
|
|
|
8
|
-
enum trip_type: { direct: 0, multi_leg: 1 }
|
|
9
|
-
|
|
10
8
|
# This model has no seat_layout column (polymorphic association), so we store the preload_seat_layout_id ID in public_metadata.
|
|
11
9
|
# This lets us check if a seat layout exists without triggering a database query.
|
|
12
10
|
# The ID is automatically updated whenever the seat_layout is saved.
|
|
@@ -24,6 +24,7 @@ module SpreeCmCommissioner
|
|
|
24
24
|
base.has_many :user_events, class_name: 'SpreeCmCommissioner::UserEvent'
|
|
25
25
|
base.has_many :events, through: :user_events, class_name: 'Spree::Taxon', source: 'taxon'
|
|
26
26
|
base.has_many :guests, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
|
|
27
|
+
base.has_many :saved_guests, class_name: 'SpreeCmCommissioner::SavedGuest', dependent: :nullify
|
|
27
28
|
|
|
28
29
|
base.has_many :google_user_identity_providers,
|
|
29
30
|
-> { where(identity_type: :google) },
|
|
@@ -16,39 +16,139 @@ module SpreeCmCommissioner
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def call
|
|
19
|
-
return Kaminari.paginate_array([])
|
|
19
|
+
return Kaminari.paginate_array([]) if date.to_date < Date.current
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
paginated_relation = direct_trips
|
|
22
|
+
return Kaminari.paginate_array([]) if paginated_relation.empty?
|
|
23
|
+
|
|
24
|
+
unique_trips = paginated_relation.uniq(&:id)
|
|
25
|
+
results_array = unique_trips.map do |trip|
|
|
26
|
+
result = build_trip_result(trip)
|
|
27
|
+
SpreeCmCommissioner::TripQueryResult.new([result])
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Kaminari.paginate_array(
|
|
31
|
+
results_array,
|
|
32
|
+
total_count: unique_trips.size,
|
|
33
|
+
limit: unique_trips.size,
|
|
34
|
+
offset: paginated_relation.offset_value
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def direct_trips
|
|
39
|
+
result = trip_scope
|
|
40
|
+
result = result.where({ vendor_id: vendor_id }.compact) if vendor_id.present?
|
|
41
|
+
result = result.where(route_type: route_type) if route_type.present?
|
|
42
|
+
result = result.where(spree_vendors: { tenant_id: tenant_id }) if tenant_id.present?
|
|
43
|
+
paginate(result)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def product_inventory_totals
|
|
47
|
+
Spree::Product
|
|
48
|
+
.select(
|
|
49
|
+
'spree_products.id AS product_id,
|
|
50
|
+
SUM(cm_inventory_items.max_capacity) AS max_capacity,
|
|
51
|
+
SUM(cm_inventory_items.quantity_available) AS quantity_available'
|
|
52
|
+
)
|
|
53
|
+
.joins(variants: :inventory_items)
|
|
54
|
+
.where('cm_inventory_items.inventory_date = ? AND cm_inventory_items.quantity_available >= ?', @date.to_date, @number_of_guests)
|
|
55
|
+
.group('spree_products.id')
|
|
24
56
|
end
|
|
25
57
|
|
|
26
58
|
private
|
|
27
59
|
|
|
28
|
-
def
|
|
29
|
-
SpreeCmCommissioner::
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
def trip_scope
|
|
61
|
+
scope = SpreeCmCommissioner::Trip
|
|
62
|
+
.select(<<~SQL.squish)
|
|
63
|
+
cm_trips.*,
|
|
64
|
+
boarding.departure_time AS boarding_departure_time,
|
|
65
|
+
boarding.stop_place_id AS boarding_stop_id, boarding.stop_name AS boarding_stop_name,
|
|
66
|
+
drop_off.stop_name AS drop_off_stop_name, drop_off.stop_place_id AS drop_off_stop_id,
|
|
67
|
+
drop_off.arrival_time AS drop_off_arrival_time,
|
|
68
|
+
COALESCE(iv.quantity_available, 0) AS quantity_available,
|
|
69
|
+
COALESCE(iv.max_capacity, 0) AS max_capacity,
|
|
70
|
+
origin_places.name AS origin_place_name, dest_places.name AS destination_place_name,
|
|
71
|
+
prices.amount AS amount, prices.compare_at_amount AS compare_at_amount,
|
|
72
|
+
prices.currency AS currency
|
|
73
|
+
SQL
|
|
74
|
+
.includes(vendor: :logo, vehicle_type: :option_values, route: {}, open_dated_product: %i[trip variants])
|
|
75
|
+
|
|
76
|
+
scope = scope.joins(:vendor) if tenant_id.present?
|
|
77
|
+
|
|
78
|
+
scope
|
|
79
|
+
.joins(<<~SQL.squish)
|
|
80
|
+
INNER JOIN cm_trip_stops AS boarding ON boarding.trip_id = cm_trips.id AND boarding.allow_boarding = true
|
|
81
|
+
INNER JOIN cm_trip_stops AS drop_off ON drop_off.trip_id = cm_trips.id AND drop_off.allow_drop_off = true
|
|
82
|
+
INNER JOIN cm_places AS origin_places ON origin_places.id = cm_trips.origin_place_id
|
|
83
|
+
INNER JOIN cm_places AS dest_places ON dest_places.id = cm_trips.destination_place_id
|
|
84
|
+
INNER JOIN spree_variants AS master ON master.product_id = cm_trips.product_id AND master.is_master = true
|
|
85
|
+
INNER JOIN spree_prices AS prices ON prices.variant_id = master.id AND prices.deleted_at IS NULL
|
|
86
|
+
SQL
|
|
87
|
+
.where('(boarding.location_place_id = ? OR boarding.stop_place_id = ? OR cm_trips.origin_place_id = ?)
|
|
88
|
+
AND (drop_off.location_place_id = ? OR drop_off.stop_place_id = ? OR cm_trips.destination_place_id = ?)',
|
|
89
|
+
origin_id, origin_id, origin_id, destination_id, destination_id, destination_id
|
|
90
|
+
)
|
|
91
|
+
.joins("INNER JOIN (#{inventory_sql.to_sql}) iv ON cm_trips.product_id = iv.product_id")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def paginate(result)
|
|
95
|
+
@per_page.to_i.positive? ? result.page(@page).per(@per_page) : result.page(@page)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def inventory_sql
|
|
99
|
+
@inventory_sql ||= product_inventory_totals
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def build_trip_result(trip)
|
|
103
|
+
vehicle_type = trip&.vehicle_type
|
|
104
|
+
vendor = trip&.vendor
|
|
105
|
+
trip_result_options = {
|
|
106
|
+
id: trip&.id,
|
|
107
|
+
departure_time: trip&.departure_time,
|
|
108
|
+
duration: trip&.duration,
|
|
109
|
+
distance: trip&.distance,
|
|
110
|
+
allow_seat_selection: trip&.allow_seat_selection,
|
|
111
|
+
route_type: trip&.route_type,
|
|
112
|
+
origin_place: {
|
|
113
|
+
id: trip&.origin_place_id,
|
|
114
|
+
name: trip&.origin_place_name
|
|
115
|
+
},
|
|
116
|
+
destination_place: {
|
|
117
|
+
id: trip&.destination_place_id,
|
|
118
|
+
name: trip&.destination_place_name
|
|
119
|
+
},
|
|
120
|
+
vehicle_type_id: trip&.vehicle_type_id,
|
|
121
|
+
vehicle_type: vehicle_type,
|
|
122
|
+
vendor_id: trip&.vendor_id,
|
|
123
|
+
vendor: vendor,
|
|
124
|
+
product_id: trip&.product_id,
|
|
125
|
+
price: trip&.amount,
|
|
126
|
+
currency: trip&.currency,
|
|
127
|
+
compare_at_amount: trip&.compare_at_amount,
|
|
128
|
+
boarding: build_boarding_info(trip),
|
|
129
|
+
drop_off: build_drop_off_info(trip),
|
|
130
|
+
quantity_available: trip&.quantity_available,
|
|
131
|
+
max_capacity: trip&.max_capacity,
|
|
132
|
+
amenities: (trip.vehicle_type&.option_values || []),
|
|
133
|
+
open_dated_product: trip&.open_dated_product
|
|
134
|
+
}
|
|
135
|
+
SpreeCmCommissioner::TripResult.new(trip_result_options)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def build_boarding_info(trip)
|
|
139
|
+
{
|
|
140
|
+
stop_id: trip&.boarding_stop_id,
|
|
141
|
+
stop_name: trip&.boarding_stop_name,
|
|
142
|
+
departure_time: trip&.boarding_departure_time
|
|
143
|
+
}
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def build_drop_off_info(trip)
|
|
147
|
+
{
|
|
148
|
+
stop_id: trip&.drop_off_stop_id,
|
|
149
|
+
stop_name: trip&.drop_off_stop_name,
|
|
150
|
+
arrival_time: trip&.drop_off_arrival_time
|
|
151
|
+
}
|
|
52
152
|
end
|
|
53
153
|
end
|
|
54
154
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module V2
|
|
3
|
+
module Organizer
|
|
4
|
+
class InviteGuestSerializer < BaseSerializer
|
|
5
|
+
attributes :email, :quantity, :token, :invite_type, :claimed_status, :issued_to, :expiration_date,
|
|
6
|
+
:email_send_at, :created_at, :updated_at, :remark
|
|
7
|
+
belongs_to :variant, serializer: SpreeCmCommissioner::V2::Storefront::EventVariantSerializer
|
|
8
|
+
belongs_to :order, serializer: Spree::V2::Storefront::OrderSerializer
|
|
9
|
+
belongs_to :event, serializer: Spree::V2::Storefront::TaxonSerializer
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -54,61 +54,24 @@ module SpreeCmCommissioner
|
|
|
54
54
|
|
|
55
55
|
# Build line items for each leg, using the previous leg's to_date as the next leg's date,
|
|
56
56
|
# or the initial date for the first leg.
|
|
57
|
-
# Automatically detects if a leg crosses into the next day based on departure/arrival times.
|
|
58
57
|
def build_line_items_for_legs!(order:, legs:, initial_date:)
|
|
59
58
|
all_line_items = []
|
|
60
59
|
current_leg_date = initial_date
|
|
61
|
-
previous_arrival_time = nil
|
|
62
60
|
|
|
63
61
|
# Use main_trip_id for connected trips (when legs have multiple trips)
|
|
64
62
|
connected_trip_id = legs.size > 1 ? legs.first.main_trip_id&.to_s : nil
|
|
65
63
|
|
|
66
64
|
legs.each do |leg|
|
|
67
|
-
|
|
68
|
-
leg_date = calculate_leg_date(leg, current_leg_date, previous_arrival_time)
|
|
69
|
-
|
|
70
|
-
leg_line_items = build_line_items_for!(leg, order, leg_date, connected_trip_id)
|
|
65
|
+
leg_line_items = build_line_items_for!(leg, order, current_leg_date, connected_trip_id)
|
|
71
66
|
leg_line_items = insert_saved_guests_per_line_items_leg(leg_line_items)
|
|
72
67
|
|
|
73
68
|
all_line_items.concat(leg_line_items)
|
|
74
|
-
|
|
75
|
-
# Store the arrival time and date for the next leg's calculation
|
|
76
|
-
if leg_line_items.any?
|
|
77
|
-
previous_arrival_time = extract_leg_arrival_time(leg)
|
|
78
|
-
current_leg_date = leg_line_items.last.to_date.to_date
|
|
79
|
-
end
|
|
69
|
+
current_leg_date = leg_line_items.last.to_date.to_date if leg_line_items.any?
|
|
80
70
|
end
|
|
81
71
|
|
|
82
72
|
all_line_items
|
|
83
73
|
end
|
|
84
74
|
|
|
85
|
-
# Calculate the date for a leg by checking if its departure time suggests it's on a later day
|
|
86
|
-
def calculate_leg_date(leg, current_leg_date, previous_arrival_time)
|
|
87
|
-
return current_leg_date if previous_arrival_time.nil?
|
|
88
|
-
|
|
89
|
-
trip = SpreeCmCommissioner::Trip.find(leg.trip_id)
|
|
90
|
-
boarding_stop_id = leg.boarding_trip_stop_id.presence || trip.trip_stops.first&.id
|
|
91
|
-
boarding_stop = trip.trip_stops.find(boarding_stop_id)
|
|
92
|
-
|
|
93
|
-
departure_time = boarding_stop&.departure_time
|
|
94
|
-
return current_leg_date if departure_time.nil?
|
|
95
|
-
|
|
96
|
-
# If next leg's departure time is less than previous leg's arrival time,
|
|
97
|
-
# it indicates crossing into the next day
|
|
98
|
-
if departure_time < previous_arrival_time
|
|
99
|
-
current_leg_date + 1.day
|
|
100
|
-
else
|
|
101
|
-
current_leg_date
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# Extract the arrival time from the last line item for comparison with the next leg
|
|
106
|
-
def extract_leg_arrival_time(leg)
|
|
107
|
-
trip = SpreeCmCommissioner::Trip.find(leg.trip_id)
|
|
108
|
-
drop_off_stop_id = leg.drop_off_trip_stop_id.presence || trip.trip_stops.last&.id
|
|
109
|
-
trip.trip_stops.find(drop_off_stop_id)&.arrival_time
|
|
110
|
-
end
|
|
111
|
-
|
|
112
75
|
def build_line_items_for!(leg, order, date, connected_trip_id = nil)
|
|
113
76
|
trip = SpreeCmCommissioner::Trip.find(leg.trip_id)
|
|
114
77
|
from_date, to_date = resolve_leg_dates(trip, leg, date)
|
|
@@ -140,14 +103,12 @@ module SpreeCmCommissioner
|
|
|
140
103
|
def resolve_leg_dates(trip, leg, date)
|
|
141
104
|
return open_dated_leg_dates(trip, leg, date) if trip.open_dated?
|
|
142
105
|
|
|
143
|
-
|
|
144
|
-
drop_off_stop_id = leg.drop_off_trip_stop_id.presence || trip.trip_stops.last&.id
|
|
106
|
+
trip_stops = trip.trip_stops.where(id: [leg.boarding_trip_stop_id, leg.drop_off_trip_stop_id]).index_by(&:id)
|
|
145
107
|
|
|
146
|
-
trip_stops = trip.trip_stops.where(id: [boarding_stop_id, drop_off_stop_id]).index_by(&:id)
|
|
147
108
|
calculate_line_item_duration!(
|
|
148
109
|
date: date,
|
|
149
|
-
departure_time: trip_stops[
|
|
150
|
-
arrival_time: trip_stops[
|
|
110
|
+
departure_time: trip_stops[leg.boarding_trip_stop_id]&.departure_time,
|
|
111
|
+
arrival_time: trip_stops[leg.drop_off_trip_stop_id]&.arrival_time
|
|
151
112
|
)
|
|
152
113
|
end
|
|
153
114
|
|
|
@@ -185,13 +146,10 @@ module SpreeCmCommissioner
|
|
|
185
146
|
|
|
186
147
|
def calculate_line_item_duration!(date:, departure_time:, arrival_time:)
|
|
187
148
|
raise StandardError, 'Departure or arrival time in trip stop is missing' if departure_time.blank? || arrival_time.blank?
|
|
149
|
+
raise StandardError, 'Arrival time cannot be before departure time' if arrival_time < departure_time
|
|
188
150
|
|
|
189
151
|
trip_duration_in_seconds = arrival_time - departure_time
|
|
190
152
|
|
|
191
|
-
# If trip_duration_in_seconds is negative, the trip crosses midnight (e.g., 22:00 -> 01:00)
|
|
192
|
-
# Add 24 hours to get the correct duration and ensure to_date falls on the next day
|
|
193
|
-
trip_duration_in_seconds += 24 * 3600 if trip_duration_in_seconds.negative?
|
|
194
|
-
|
|
195
153
|
# The input `date` is in local time (e.g., 10-10-2022).
|
|
196
154
|
# Combine it with the departure_time in Rails default timezone so that
|
|
197
155
|
# the resulting from_date stays on the intended local calendar day when stored in UTC.
|
|
@@ -66,11 +66,10 @@ module SpreeCmCommissioner
|
|
|
66
66
|
|
|
67
67
|
route = vendor.routes.find(trip_form.route_id)
|
|
68
68
|
|
|
69
|
-
locations = vendor.locations.
|
|
69
|
+
locations = vendor.locations.where(id: trip_form.trip_stops.map(&:location_id)).index_by(&:id)
|
|
70
70
|
|
|
71
71
|
# vendor_places are either stops or branches
|
|
72
72
|
vendor_places = SpreeCmCommissioner::VendorPlace
|
|
73
|
-
.includes(:place)
|
|
74
73
|
.where(id: trip_form.trip_stops.map(&:stop_id), vendor: vendor)
|
|
75
74
|
.index_by(&:id)
|
|
76
75
|
|
|
@@ -16,16 +16,14 @@ module SpreeCmCommissioner
|
|
|
16
16
|
cache_key = cache_key(params, vendor)
|
|
17
17
|
|
|
18
18
|
results = Rails.cache.fetch(cache_key, expires_in: SEARCH_CACHE_TTL) do
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
route_type = intercity_taxi?(params) ? 'intercity_taxi' : nil
|
|
21
20
|
trips = SpreeCmCommissioner::TripQuery.new(
|
|
22
21
|
origin_id: origin_id(params),
|
|
23
22
|
destination_id: destination_id(params),
|
|
24
23
|
date: search_date(params).to_date,
|
|
25
|
-
route_type: route_type
|
|
24
|
+
route_type: route_type,
|
|
26
25
|
vendor_id: vendor.id,
|
|
27
|
-
number_of_guests: params[:number_of_guests]
|
|
28
|
-
params: query_params
|
|
26
|
+
number_of_guests: params[:number_of_guests] || 1
|
|
29
27
|
).call
|
|
30
28
|
|
|
31
29
|
trips
|
|
@@ -42,13 +40,11 @@ module SpreeCmCommissioner
|
|
|
42
40
|
params[:origin].present? && params[:destination].present? && params[:outbound_date].present?
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
def origin_id(params)
|
|
46
|
-
def destination_id(params)
|
|
47
|
-
def search_date(params)
|
|
48
|
-
def outbound?(params)
|
|
49
|
-
def intercity_taxi?(params)
|
|
50
|
-
def route_type(params) = (intercity_taxi?(params) ? 'intercity_taxi' : params[:route_type] || nil)
|
|
51
|
-
def include_multi_leg?(params) = params[:include_multi_leg].to_s == 'true'
|
|
43
|
+
def origin_id(params) = outbound?(params) ? params[:origin] : params[:destination]
|
|
44
|
+
def destination_id(params) = outbound?(params) ? params[:destination] : params[:origin]
|
|
45
|
+
def search_date(params) = outbound?(params) ? params[:outbound_date] : params[:inbound_date]
|
|
46
|
+
def outbound?(params) = params[:direction] == 'outbound' || params[:direction].blank?
|
|
47
|
+
def intercity_taxi?(params) = params[:service_type] == 'intercity_taxi'
|
|
52
48
|
|
|
53
49
|
def cache_key(params, vendor)
|
|
54
50
|
[
|
data/config/routes.rb
CHANGED
|
@@ -473,6 +473,7 @@ Spree::Core::Engine.add_routes do
|
|
|
473
473
|
resources :images
|
|
474
474
|
resource :s3_signed_urls
|
|
475
475
|
resources :invites
|
|
476
|
+
resources :invite_guests, only: %i[show update]
|
|
476
477
|
resources :invite_crews, only: %i[show update]
|
|
477
478
|
end
|
|
478
479
|
|
|
@@ -627,6 +628,7 @@ Spree::Core::Engine.add_routes do
|
|
|
627
628
|
end
|
|
628
629
|
end
|
|
629
630
|
|
|
631
|
+
resources :saved_guests
|
|
630
632
|
resource :s3_signed_urls
|
|
631
633
|
resources :google_wallet_object_tokens
|
|
632
634
|
resources :provinces, only: %i[index]
|
|
@@ -22,25 +22,6 @@ module SpreeCmCommissioner::Transit
|
|
|
22
22
|
@exception_rules ||= []
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
# Create form from ServiceCalendar ActiveRecord object
|
|
26
|
-
def self.from_service_calendar(calendar)
|
|
27
|
-
return new if calendar.blank?
|
|
28
|
-
|
|
29
|
-
new(
|
|
30
|
-
name: calendar.name,
|
|
31
|
-
start_date: calendar.start_date,
|
|
32
|
-
end_date: calendar.end_date,
|
|
33
|
-
monday: calendar.monday,
|
|
34
|
-
tuesday: calendar.tuesday,
|
|
35
|
-
wednesday: calendar.wednesday,
|
|
36
|
-
thursday: calendar.thursday,
|
|
37
|
-
friday: calendar.friday,
|
|
38
|
-
saturday: calendar.saturday,
|
|
39
|
-
sunday: calendar.sunday,
|
|
40
|
-
exception_rules: calendar.exception_rules || []
|
|
41
|
-
)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
25
|
def weekdays
|
|
45
26
|
{
|
|
46
27
|
'monday' => monday,
|