spree_cm_commissioner 2.5.1.pre.pre3 → 2.5.1.pre.pre4
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 -2
- data/Gemfile.lock +1 -1
- data/app/controllers/spree/api/v2/storefront/popular_route_places_controller.rb +2 -2
- 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/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 +19 -35
- 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/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/place.rb +5 -8
- data/app/models/spree_cm_commissioner/product_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/route.rb +45 -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/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/storefront/route_metric_serializer.rb +13 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/route_serializer.rb +2 -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/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/routes.rb +6 -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/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/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 +37 -17
- 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,10 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class IncreaseTripCountJob < ApplicationUniqueJob
|
|
4
|
+
def perform(options = {})
|
|
5
|
+
trip = SpreeCmCommissioner::Trip.find(options[:trip_id])
|
|
6
|
+
SpreeCmCommissioner::RouteMetrics::IncreaseTripCount.call(trip: trip)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
module Stock
|
|
3
3
|
class PermanentInventoryItemsGeneratorJob < ApplicationUniqueJob
|
|
4
|
-
def perform
|
|
5
|
-
SpreeCmCommissioner::Stock::PermanentInventoryItemsGenerator.call
|
|
4
|
+
def perform(options = {})
|
|
5
|
+
SpreeCmCommissioner::Stock::PermanentInventoryItemsGenerator.call(options)
|
|
6
6
|
end
|
|
7
7
|
end
|
|
8
8
|
end
|
|
@@ -7,13 +7,13 @@ module SpreeCmCommissioner
|
|
|
7
7
|
def increment_route_fulfilled_order_count
|
|
8
8
|
return unless has_trip_ids?
|
|
9
9
|
|
|
10
|
-
SpreeCmCommissioner::
|
|
10
|
+
SpreeCmCommissioner::RouteMetrics::IncreaseFulfilledOrderCountJob.perform_later(order_id: id)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def increment_route_order_count
|
|
14
14
|
return unless has_trip_ids?
|
|
15
15
|
|
|
16
|
-
SpreeCmCommissioner::
|
|
16
|
+
SpreeCmCommissioner::RouteMetrics::IncreaseOrderCountJob.perform_later(order_id: id)
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -21,15 +21,12 @@ module SpreeCmCommissioner
|
|
|
21
21
|
has_many :taxon_places, class_name: 'SpreeCmCommissioner::TaxonPlace', dependent: :destroy
|
|
22
22
|
has_many :taxons, through: :taxon_places
|
|
23
23
|
|
|
24
|
-
has_many :
|
|
25
|
-
has_many :
|
|
24
|
+
has_many :route_metrics_as_origin, class_name: 'SpreeCmCommissioner::RouteMetric', foreign_key: :origin_place_id
|
|
25
|
+
has_many :route_metrics_as_destination, class_name: 'SpreeCmCommissioner::RouteMetric', foreign_key: :destination_place_id
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# Scopes for route-based filtering
|
|
31
|
-
scope :with_routes_as_origin, -> { joins(:routes_as_origin).distinct }
|
|
32
|
-
scope :with_routes_as_destination, -> { joins(:routes_as_destination).distinct }
|
|
27
|
+
# Scopes for route metric filtering
|
|
28
|
+
scope :with_route_metrics_as_origin, -> { joins(:route_metrics_as_origin).distinct }
|
|
29
|
+
scope :with_route_metrics_as_destination, -> { joins(:route_metrics_as_destination).distinct }
|
|
33
30
|
|
|
34
31
|
def self.ransackable_attributes(auth_object = nil)
|
|
35
32
|
super & %w[name code]
|
|
@@ -48,6 +48,7 @@ module SpreeCmCommissioner
|
|
|
48
48
|
base.accepts_nested_attributes_for :product_places, allow_destroy: true
|
|
49
49
|
|
|
50
50
|
base.has_one :trip, class_name: 'SpreeCmCommissioner::Trip', dependent: :destroy
|
|
51
|
+
base.has_one :service_calendar, as: :calendarable, class_name: 'SpreeCmCommissioner::ServiceCalendar', dependent: :destroy
|
|
51
52
|
|
|
52
53
|
base.belongs_to :event, class_name: 'Spree::Taxon', optional: true
|
|
53
54
|
|
|
@@ -1,12 +1,52 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
class Route < Base
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
include SpreeCmCommissioner::RouteType
|
|
4
|
+
|
|
5
|
+
belongs_to :vendor, class_name: 'Spree::Vendor', optional: false
|
|
6
|
+
belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant', optional: true
|
|
7
|
+
|
|
8
|
+
belongs_to :origin_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
|
9
|
+
belongs_to :destination_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
|
10
|
+
|
|
11
|
+
has_one :primary_photo, -> { order(position: :asc) }, class_name: 'SpreeCmCommissioner::RoutePhoto',
|
|
12
|
+
as: :viewable,
|
|
13
|
+
dependent: :destroy
|
|
14
|
+
has_many :route_photos, class_name: 'SpreeCmCommissioner::RoutePhoto', as: :viewable, dependent: :destroy
|
|
15
|
+
|
|
5
16
|
has_many :trips, inverse_of: :route
|
|
6
17
|
|
|
7
|
-
|
|
8
|
-
|
|
18
|
+
validates :route_name, presence: true
|
|
19
|
+
|
|
20
|
+
validate :validate_route_stops
|
|
21
|
+
|
|
22
|
+
delegate :multi_leg?, to: :route_stops
|
|
23
|
+
|
|
24
|
+
def self.ransackable_attributes(_auth_object = nil)
|
|
25
|
+
%w[route_type short_name route_name]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def route_stops
|
|
29
|
+
Transit::RouteStopCollection.from_hash(read_attribute(:route_stops))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def route_stops=(value)
|
|
33
|
+
if value.is_a?(Transit::RouteStopCollection)
|
|
34
|
+
@route_stops = value
|
|
35
|
+
self[:route_stops] = value.to_h
|
|
36
|
+
elsif value.is_a?(Array)
|
|
37
|
+
@route_stops = Transit::RouteStopCollection.from_hash(value)
|
|
38
|
+
self[:route_stops] = @route_stops.to_h
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError, 'route_stops must be an Array or RouteStopCollection'
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def validate_route_stops
|
|
47
|
+
return if route_stops.valid?
|
|
9
48
|
|
|
10
|
-
|
|
49
|
+
route_stops.errors.each { |error| errors.add(:route_stops, error) }
|
|
50
|
+
end
|
|
11
51
|
end
|
|
12
52
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class RouteMetric < Base
|
|
3
|
+
include SpreeCmCommissioner::RouteType
|
|
4
|
+
|
|
5
|
+
belongs_to :origin_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
|
6
|
+
belongs_to :destination_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
|
7
|
+
|
|
8
|
+
validates :route_type, presence: true
|
|
9
|
+
validates :route_type, uniqueness: { scope: %i[origin_place_id destination_place_id] }
|
|
10
|
+
|
|
11
|
+
validate :origin_and_destination_cannot_be_the_same
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def origin_and_destination_cannot_be_the_same
|
|
16
|
+
return unless origin_place_id == destination_place_id
|
|
17
|
+
|
|
18
|
+
errors.add(:base, 'Origin and destination cannot be the same')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -2,7 +2,6 @@ module SpreeCmCommissioner
|
|
|
2
2
|
class Trip < Base
|
|
3
3
|
include SpreeCmCommissioner::StoreMetadata
|
|
4
4
|
include SpreeCmCommissioner::RouteType
|
|
5
|
-
include SpreeCmCommissioner::RouteTripCountCallbacks
|
|
6
5
|
|
|
7
6
|
attr_accessor :hours, :minutes, :seconds
|
|
8
7
|
|
|
@@ -15,7 +14,9 @@ module SpreeCmCommissioner
|
|
|
15
14
|
|
|
16
15
|
# before create, duplicate seat layout from vehicle_type if present
|
|
17
16
|
before_validation :duplicate_seat_layout_from_vehicle, if: -> { seat_layout.nil? && vehicle_type&.seat_layout.present? }
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
after_create :increment_route_metric_trip_count
|
|
19
|
+
before_destroy :decrement_route_metric_trip_count
|
|
19
20
|
|
|
20
21
|
belongs_to :vendor, class_name: 'Spree::Vendor', inverse_of: :trips, optional: false
|
|
21
22
|
belongs_to :product, class_name: 'Spree::Product', inverse_of: :trip, optional: false
|
|
@@ -26,7 +27,7 @@ module SpreeCmCommissioner
|
|
|
26
27
|
|
|
27
28
|
belongs_to :origin_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
|
28
29
|
belongs_to :destination_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
|
29
|
-
belongs_to :route, inverse_of: :trips
|
|
30
|
+
belongs_to :route, class_name: 'SpreeCmCommissioner::Route', inverse_of: :trips, optional: true
|
|
30
31
|
|
|
31
32
|
has_many :trip_blazer_queries, as: :queryable, class_name: 'SpreeCmCommissioner::BlazerQueryable'
|
|
32
33
|
has_many :blazer_queries, through: :trip_blazer_queries, source: :blazer_query, class_name: 'Blazer::Query'
|
|
@@ -48,10 +49,6 @@ module SpreeCmCommissioner
|
|
|
48
49
|
self.whitelisted_ransackable_associations = %w[product vehicle vehicle_type]
|
|
49
50
|
self.whitelisted_ransackable_attributes = %w[origin_place_id destination_place_id]
|
|
50
51
|
|
|
51
|
-
def changed_route_attributes?
|
|
52
|
-
origin_place_id_changed? || destination_place_id_changed? || vendor_id_changed?
|
|
53
|
-
end
|
|
54
|
-
|
|
55
52
|
def convert_duration_to_seconds
|
|
56
53
|
return if hours.blank? && minutes.blank? && seconds.blank?
|
|
57
54
|
|
|
@@ -104,34 +101,12 @@ module SpreeCmCommissioner
|
|
|
104
101
|
)
|
|
105
102
|
end
|
|
106
103
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
# Returns true if any of the route context attributes will change on save.
|
|
110
|
-
will_save_change_to_route_id? ||
|
|
111
|
-
will_save_change_to_origin_place_id? ||
|
|
112
|
-
will_save_change_to_destination_place_id? ||
|
|
113
|
-
will_save_change_to_vendor_id?
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def changed_route_context?
|
|
117
|
-
saved_change_to_route_id? ||
|
|
118
|
-
saved_change_to_origin_place_id? ||
|
|
119
|
-
saved_change_to_destination_place_id? ||
|
|
120
|
-
saved_change_to_vendor_id?
|
|
104
|
+
def increment_route_metric_trip_count
|
|
105
|
+
SpreeCmCommissioner::RouteMetrics::IncreaseTripCountJob.perform_later(trip_id: id)
|
|
121
106
|
end
|
|
122
107
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
# product when the route is new/blank.
|
|
126
|
-
def assign_route_and_vendor_route
|
|
127
|
-
route = SpreeCmCommissioner::Route.find_or_create_by!(
|
|
128
|
-
origin_place_id: origin_place_id,
|
|
129
|
-
destination_place_id: destination_place_id
|
|
130
|
-
)
|
|
131
|
-
route.route_name = product.name if route.route_name.blank?
|
|
132
|
-
route.save! if route.changed?
|
|
133
|
-
|
|
134
|
-
self.route_id = route.id
|
|
108
|
+
def decrement_route_metric_trip_count
|
|
109
|
+
SpreeCmCommissioner::RouteMetrics::DecreaseTripCountJob.perform_later(trip_id: id)
|
|
135
110
|
end
|
|
136
111
|
end
|
|
137
112
|
end
|
|
@@ -1,25 +1,39 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
class TripStop < Base
|
|
3
3
|
acts_as_list column: :sequence, scope: :trip_id
|
|
4
|
-
enum :stop_type, { boarding: 0, drop_off: 1 }
|
|
5
4
|
|
|
6
5
|
belongs_to :trip, class_name: 'SpreeCmCommissioner::Trip', optional: false
|
|
7
6
|
belongs_to :stop_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
|
8
7
|
belongs_to :location_place, class_name: 'SpreeCmCommissioner::Place', optional: false
|
|
9
8
|
|
|
9
|
+
belongs_to :board_to_trip, class_name: 'SpreeCmCommissioner::Trip', optional: true
|
|
10
|
+
|
|
10
11
|
before_validation :set_stop_name
|
|
12
|
+
|
|
11
13
|
validates :stop_place_id, uniqueness: { scope: :trip_id }
|
|
14
|
+
validate :boarding_trip_requires_allow_boarding
|
|
15
|
+
|
|
16
|
+
scope :boarding, -> { where(allow_boarding: true) }
|
|
17
|
+
scope :drop_off, -> { where(allow_drop_off: true) }
|
|
12
18
|
|
|
13
19
|
def set_stop_name
|
|
14
20
|
self.stop_name = stop_place.name if stop_place.present?
|
|
15
21
|
end
|
|
16
22
|
|
|
17
23
|
def self.ransackable_attributes(_auth_object = nil)
|
|
18
|
-
%w[stop_name
|
|
24
|
+
%w[stop_name allow_boarding allow_drop_off]
|
|
19
25
|
end
|
|
20
26
|
|
|
21
27
|
def self.ransackable_associations(_auth_object = nil)
|
|
22
28
|
['stop_place']
|
|
23
29
|
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def boarding_trip_requires_allow_boarding
|
|
34
|
+
return unless board_to_trip_id.present? && !allow_boarding?
|
|
35
|
+
|
|
36
|
+
errors.add(:board_to_trip, 'requires allow_boarding to be true')
|
|
37
|
+
end
|
|
24
38
|
end
|
|
25
39
|
end
|
|
@@ -82,7 +82,9 @@ module SpreeCmCommissioner
|
|
|
82
82
|
base.has_many :subscriptions, through: :customers, class_name: 'SpreeCmCommissioner::Subscription'
|
|
83
83
|
base.has_many :subscription_orders, through: :subscriptions, class_name: 'Spree::Order', source: :orders
|
|
84
84
|
base.has_many :promotion_categories, class_name: 'Spree::PromotionCategory', foreign_key: :vendor_id, dependent: :destroy
|
|
85
|
-
base.has_many :
|
|
85
|
+
base.has_many :routes, class_name: 'SpreeCmCommissioner::Route', dependent: :destroy
|
|
86
|
+
base.has_many :popular_routes, -> { order(fulfilled_order_count: :desc, order_count: :desc) },
|
|
87
|
+
class_name: 'SpreeCmCommissioner::Route'
|
|
86
88
|
|
|
87
89
|
base.has_many :homepage_section_relatables,
|
|
88
90
|
as: :relatable,
|
|
@@ -77,8 +77,8 @@ module SpreeCmCommissioner
|
|
|
77
77
|
|
|
78
78
|
scope
|
|
79
79
|
.joins(<<~SQL.squish)
|
|
80
|
-
INNER JOIN cm_trip_stops AS boarding ON boarding.trip_id = cm_trips.id AND boarding.
|
|
81
|
-
INNER JOIN cm_trip_stops AS drop_off ON drop_off.trip_id = cm_trips.id AND drop_off.
|
|
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
82
|
INNER JOIN cm_places AS origin_places ON origin_places.id = cm_trips.origin_place_id
|
|
83
83
|
INNER JOIN cm_places AS dest_places ON dest_places.id = cm_trips.destination_place_id
|
|
84
84
|
INNER JOIN spree_variants AS master ON master.product_id = cm_trips.product_id AND master.is_master = true
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module V2
|
|
3
|
+
module Storefront
|
|
4
|
+
class RouteMetricSerializer < BaseSerializer
|
|
5
|
+
set_type :route
|
|
6
|
+
attributes :route_name
|
|
7
|
+
|
|
8
|
+
has_one :origin_place, serializer: ::Spree::V2::Storefront::PlaceSerializer
|
|
9
|
+
has_one :destination_place, serializer: ::Spree::V2::Storefront::PlaceSerializer
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -2,8 +2,9 @@ module SpreeCmCommissioner
|
|
|
2
2
|
module V2
|
|
3
3
|
module Storefront
|
|
4
4
|
class RouteSerializer < BaseSerializer
|
|
5
|
-
attributes :route_name
|
|
5
|
+
attributes :route_name, :route_type, :short_name
|
|
6
6
|
|
|
7
|
+
has_many :route_photos, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
|
|
7
8
|
has_one :origin_place, serializer: ::Spree::V2::Storefront::PlaceSerializer
|
|
8
9
|
has_one :destination_place, serializer: ::Spree::V2::Storefront::PlaceSerializer
|
|
9
10
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module V2
|
|
3
|
+
module Storefront
|
|
4
|
+
class TransitLineItemSerializer < BaseSerializer
|
|
5
|
+
# Nested-only API shape
|
|
6
|
+
attributes :from_date,
|
|
7
|
+
:to_date,
|
|
8
|
+
:trip_id,
|
|
9
|
+
:direction,
|
|
10
|
+
:boarding_trip_stop_id,
|
|
11
|
+
:drop_off_trip_stop_id
|
|
12
|
+
|
|
13
|
+
cache_options store: nil
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -2,7 +2,7 @@ module SpreeCmCommissioner
|
|
|
2
2
|
module V2
|
|
3
3
|
module Storefront
|
|
4
4
|
class TripStopSerializer < BaseSerializer
|
|
5
|
-
attributes :id, :
|
|
5
|
+
attributes :id, :allow_boarding, :allow_drop_off, :stop_name, :arrival_time, :departure_time
|
|
6
6
|
|
|
7
7
|
has_one :stop_place, serializer: ::SpreeCmCommissioner::V2::Storefront::TripPlaceSerializer
|
|
8
8
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class DecreaseTripCount
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(trip:)
|
|
7
|
+
return failure(nil, 'Trip not found') unless trip
|
|
8
|
+
|
|
9
|
+
route_metric = find_or_create_route_metric(trip)
|
|
10
|
+
|
|
11
|
+
route_metric.with_lock do
|
|
12
|
+
route_metric.update!(trip_count: [route_metric.trip_count - 1, 0].max)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
success(trip: trip)
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
failure(nil, e.message)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def find_or_create_route_metric(trip)
|
|
23
|
+
SpreeCmCommissioner::RouteMetric.find_or_create_by!(
|
|
24
|
+
origin_place_id: trip.origin_place_id,
|
|
25
|
+
destination_place_id: trip.destination_place_id,
|
|
26
|
+
route_type: trip.route_type
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
|
-
module
|
|
3
|
-
class
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class IncreaseFulfilledOrderCount
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
6
|
def call(order:)
|
|
7
7
|
return failure(nil, 'Order not found') unless order
|
|
8
8
|
|
|
9
|
-
SpreeCmCommissioner::
|
|
9
|
+
SpreeCmCommissioner::RouteMetrics::UpdateRouteMetrics
|
|
10
10
|
.call(order: order, attribute: :fulfilled_order_count)
|
|
11
11
|
|
|
12
12
|
success(order: order)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
|
-
module
|
|
3
|
-
class
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class IncreaseOrderCount
|
|
4
4
|
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
6
|
def call(order:)
|
|
7
7
|
return failure(nil, 'Order not found') unless order
|
|
8
8
|
|
|
9
|
-
SpreeCmCommissioner::
|
|
9
|
+
SpreeCmCommissioner::RouteMetrics::UpdateRouteMetrics
|
|
10
10
|
.new(order: order, attribute: :order_count)
|
|
11
11
|
.call
|
|
12
12
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class IncreaseTripCount
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(trip:)
|
|
7
|
+
return failure(nil, 'Trip not found') unless trip
|
|
8
|
+
|
|
9
|
+
route_metric = find_or_create_route_metric(trip)
|
|
10
|
+
|
|
11
|
+
route_metric.with_lock do
|
|
12
|
+
route_metric.update!(trip_count: route_metric.trip_count + 1)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
success(trip: trip)
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
failure(nil, e.message)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def find_or_create_route_metric(trip)
|
|
23
|
+
SpreeCmCommissioner::RouteMetric.find_or_create_by!(
|
|
24
|
+
origin_place_id: trip.origin_place_id,
|
|
25
|
+
destination_place_id: trip.destination_place_id,
|
|
26
|
+
route_type: trip.route_type
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
|
-
module
|
|
3
|
-
class
|
|
2
|
+
module RouteMetrics
|
|
3
|
+
class UpdateRouteMetrics
|
|
4
4
|
attr_reader :order, :attribute
|
|
5
5
|
|
|
6
6
|
SUPPORTED_ATTRIBUTES = %i[order_count fulfilled_order_count].freeze
|
|
@@ -31,26 +31,21 @@ module SpreeCmCommissioner
|
|
|
31
31
|
trip = product&.trip
|
|
32
32
|
return unless trip
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
route_metric = find_or_create_route_metric_for_trip(trip)
|
|
35
|
+
increment_route_by(route_metric, line_item.quantity)
|
|
36
|
+
|
|
37
|
+
route = trip.route
|
|
38
|
+
increment_route_by(route, line_item.quantity) if route
|
|
37
39
|
end
|
|
38
40
|
|
|
39
|
-
def
|
|
40
|
-
SpreeCmCommissioner::
|
|
41
|
+
def find_or_create_route_metric_for_trip(trip)
|
|
42
|
+
SpreeCmCommissioner::RouteMetric.find_or_create_by(
|
|
41
43
|
origin_place_id: trip.origin_place_id,
|
|
42
|
-
destination_place_id: trip.destination_place_id
|
|
44
|
+
destination_place_id: trip.destination_place_id,
|
|
45
|
+
route_type: trip.route_type
|
|
43
46
|
)
|
|
44
47
|
end
|
|
45
48
|
|
|
46
|
-
def ensure_trip_route(trip, route)
|
|
47
|
-
trip_route_id = trip.respond_to?(:route_id) ? trip.route_id : nil
|
|
48
|
-
|
|
49
|
-
return unless trip.respond_to?(:update_column) && trip_route_id != route.id
|
|
50
|
-
|
|
51
|
-
trip.update_column(:route_id, route.id) # rubocop:disable Rails/SkipsModelValidations
|
|
52
|
-
end
|
|
53
|
-
|
|
54
49
|
def increment_route_by(route, qty)
|
|
55
50
|
route.with_lock do
|
|
56
51
|
current_value = route.public_send(attribute) || 0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Routes
|
|
3
|
+
class Create
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
# @param vendor [Spree::Vendor]
|
|
7
|
+
# @param route_params [Hash]
|
|
8
|
+
# @param route_stops [SpreeCmCommissioner::Transit::RouteStopCollection]
|
|
9
|
+
def call(vendor:, route_params:, route_stops:)
|
|
10
|
+
# vendor_id, tenant_id, origin_place_id, destination_place_id are excluded and set automatically.
|
|
11
|
+
attrs = ::Spree::PermittedAttributes.route_attributes
|
|
12
|
+
.index_with { |attr_key| route_params[attr_key] }
|
|
13
|
+
.except(:vendor_id, :tenant_id, :route_stops, :origin_place_id, :destination_place_id)
|
|
14
|
+
.compact
|
|
15
|
+
|
|
16
|
+
return failure(nil, 'Route stops are required') if route_stops.length < 2
|
|
17
|
+
|
|
18
|
+
origin_place = find_place_for(route_stops, route_stops.first)
|
|
19
|
+
destination_place = find_place_for(route_stops, route_stops.last)
|
|
20
|
+
|
|
21
|
+
return failure(nil, 'Origin or destination place could not be determined') if origin_place.nil? || destination_place.nil?
|
|
22
|
+
return failure(nil, 'Route with origin & destination already exists') if vendor.routes.exists?(
|
|
23
|
+
origin_place_id: origin_place.id,
|
|
24
|
+
destination_place_id: destination_place.id
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
attrs = attrs.merge(
|
|
28
|
+
tenant_id: vendor.tenant_id,
|
|
29
|
+
route_name: attrs[:route_name] || "#{origin_place.name} -> #{destination_place.name}",
|
|
30
|
+
origin_place_id: origin_place.id,
|
|
31
|
+
destination_place_id: destination_place.id,
|
|
32
|
+
route_stops: route_stops
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
route = vendor.routes.new(attrs)
|
|
36
|
+
if route.save
|
|
37
|
+
success(route: route)
|
|
38
|
+
else
|
|
39
|
+
failure(route.errors)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def find_place_for(route_stops, route_stop)
|
|
44
|
+
return nil if route_stop.nil?
|
|
45
|
+
|
|
46
|
+
@locations ||= SpreeCmCommissioner::VendorPlace.where(id: route_stops.map(&:location_id).uniq).index_by(&:id)
|
|
47
|
+
@locations[route_stop.location_id]&.place
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module Routes
|
|
3
|
+
class Update
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(vendor:, route:, route_params:)
|
|
7
|
+
# vendor_id, tenant_id, origin_place_id, destination_place_id are excluded and set automatically.
|
|
8
|
+
# route_stops is not updateable.
|
|
9
|
+
attrs = ::Spree::PermittedAttributes.route_attributes
|
|
10
|
+
.index_with { |attr_key| route_params[attr_key] }
|
|
11
|
+
.except(:vendor_id, :tenant_id, :route_stops, :origin_place_id, :destination_place_id)
|
|
12
|
+
.compact
|
|
13
|
+
|
|
14
|
+
route = vendor.routes.find_by(id: route.id)
|
|
15
|
+
return failure(nil, :route_not_found) if route.nil?
|
|
16
|
+
|
|
17
|
+
if route.update(attrs)
|
|
18
|
+
success(route: route)
|
|
19
|
+
else
|
|
20
|
+
failure(route.errors)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SpreeCmCommissioner::TransitOrder::Create creates a new order for a entire journey, including outbound and (if present) inbound directions.
|
|
2
2
|
#
|
|
3
3
|
# Attributes:
|
|
4
4
|
# - outbound_date: [Date] The date of outbound transit
|
|
@@ -12,25 +12,22 @@
|
|
|
12
12
|
#
|
|
13
13
|
# Note: inbound_legs and inbound_date are optional; the order may represent a one-way (outbound only) journey.
|
|
14
14
|
module SpreeCmCommissioner
|
|
15
|
-
module
|
|
16
|
-
class
|
|
17
|
-
|
|
18
|
-
:inbound_date,
|
|
19
|
-
:outbound_legs,
|
|
20
|
-
:inbound_legs,
|
|
21
|
-
:user, to: :context
|
|
15
|
+
module TransitOrder
|
|
16
|
+
class Create
|
|
17
|
+
prepend ::Spree::ServiceModule::Base
|
|
22
18
|
|
|
23
|
-
def call
|
|
24
|
-
return
|
|
19
|
+
def call(outbound_date:, inbound_date:, outbound_legs:, inbound_legs: [], user: nil)
|
|
20
|
+
return failure(nil, 'Outbound legs are missing') if outbound_legs.blank?
|
|
25
21
|
|
|
26
22
|
begin
|
|
27
|
-
|
|
23
|
+
order = create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user)
|
|
24
|
+
success(order: order)
|
|
28
25
|
rescue StandardError => e
|
|
29
|
-
|
|
26
|
+
failure(nil, e.message)
|
|
30
27
|
end
|
|
31
28
|
end
|
|
32
29
|
|
|
33
|
-
def create_order!
|
|
30
|
+
def create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user)
|
|
34
31
|
order = Spree::Order.new(state: 'cart', use_billing: true, user: user)
|
|
35
32
|
|
|
36
33
|
outbound_line_items = build_line_items_for_legs!(order: order, legs: outbound_legs, initial_date: outbound_date)
|
|
@@ -112,10 +109,10 @@ module SpreeCmCommissioner
|
|
|
112
109
|
|
|
113
110
|
def insert_saved_guests_per_line_items_leg(line_items)
|
|
114
111
|
line_items.flat_map(&:guests).each_with_index do |guest, index|
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
@saved_guests ||= []
|
|
113
|
+
@saved_guests << SpreeCmCommissioner::SavedGuest.new if @saved_guests[index].blank?
|
|
117
114
|
|
|
118
|
-
guest.saved_guest =
|
|
115
|
+
guest.saved_guest = @saved_guests[index]
|
|
119
116
|
end
|
|
120
117
|
|
|
121
118
|
line_items
|