dscf-marketplace 0.7.3 → 0.7.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42792144bb56d00c7a6767aa3f8e2b4a0704fbbd815de3647bb942a764b34bb7
4
- data.tar.gz: cb649cc916dedf3729a38b12e08714242647f34fd98971741decc3344fe8a776
3
+ metadata.gz: 6868f5b7cbade52d287939591c2011a7140b76eda6f3223ba7f66a3a51fb3d08
4
+ data.tar.gz: dd56581029c76743ec281f4de717f00410a38d780b68ad57a13a11cd36e8ddd2
5
5
  SHA512:
6
- metadata.gz: 8ed6fa17b79144e124102e838d34322d4b1735a77f2c9b9015c55f939669c6a6f16d059550394464e66402ceb9002ae33e8213c8da7af84e084c0dc15b9e9d83
7
- data.tar.gz: babc3f0ccf9eef0f5be066fa59b0e77046ba03dae121c243ea8a946b3e49c3bfdea146c944486fe5bb1994d08a8e72e88cdcd8d362c2da4e802ba866c6db018c
6
+ metadata.gz: 1d7737babebba09f37154720fea2502464ad2c71cac4007114a40d3d22529efc664091d8f96a26086140bdd66696cfffa0bf7b1d828b6764f833e1497327940e
7
+ data.tar.gz: a2f2b76706da91f693a76cbe47e6b913b97819777f81ef3dacd354a83e59d8106dfcca11402af054493c1dcda586edca8b998858adbcfaeb11297aea302ffff2
@@ -9,7 +9,7 @@ module Dscf::Marketplace
9
9
  def assign_driver(delivery_order, driver)
10
10
  raise ArgumentError, "Delivery order is required" unless delivery_order
11
11
  raise ArgumentError, "Driver is required" unless driver
12
-
12
+
13
13
  validate_assignment(delivery_order)
14
14
 
15
15
  delivery_order.driver_id = driver.id
@@ -35,9 +35,15 @@ module Dscf::Marketplace
35
35
  delivery_order = create_delivery_order(vehicle_type, pickup_address, delivery_notes)
36
36
  create_delivery_stops_and_items(delivery_order, orders, pickup_address)
37
37
  associate_orders_with_delivery(delivery_order, orders)
38
-
39
- # Optimize route using Gebeta Maps
40
- RouteOptimizationService.new(delivery_order).optimize!
38
+
39
+ # Best-effort route optimization using Gebeta Maps.
40
+ begin
41
+ RouteOptimizationService.new(delivery_order).optimize!
42
+ rescue StandardError => e
43
+ Rails.logger.warn(
44
+ "[DeliveryOrderService] Route optimization skipped for delivery_order=#{delivery_order.id}: #{e.class} - #{e.message}"
45
+ )
46
+ end
41
47
 
42
48
  delivery_order
43
49
  end
@@ -79,7 +85,7 @@ module Dscf::Marketplace
79
85
  def create_delivery_stops_and_items(delivery_order, orders, pickup_address)
80
86
  # Group orders by dropoff address to create stops
81
87
  orders_by_address = orders.group_by(&:dropoff_address_id)
82
-
88
+
83
89
  orders_by_address.each do |dropoff_address_id, address_orders|
84
90
  # Create stop
85
91
  stop = DeliveryStop.create!(
@@ -87,7 +93,7 @@ module Dscf::Marketplace
87
93
  dropoff_address_id: dropoff_address_id,
88
94
  status: :pending
89
95
  )
90
-
96
+
91
97
  # Create items for this stop
92
98
  address_orders.each do |order|
93
99
  order.order_items.reload.each do |order_item|
@@ -10,83 +10,71 @@ module Dscf
10
10
  def optimize!
11
11
  return unless delivery_order.pickup_address && delivery_order.delivery_stops.any?
12
12
 
13
- # 1. Collect Coordinates
14
- # Format: [[pickup_lat, pickup_lng], [stop1_lat, stop1_lng], ...]
15
- pickup_coords = [delivery_order.pickup_address.latitude.to_f, delivery_order.pickup_address.longitude.to_f]
16
-
17
- # We map stops to their dropoff coordinates.
18
- # We need to keep track of the mapping between original index and stop ID to re-order later.
19
- stops = delivery_order.delivery_stops.includes(:dropoff_address).to_a
20
- stop_coords = stops.map { |stop| [stop.dropoff_address.latitude.to_f, stop.dropoff_address.longitude.to_f] }
21
-
22
- all_locations = [pickup_coords] + stop_coords
23
-
24
- # 2. Call Gebeta API
25
- response = GebetaService.new.tsp(all_locations)
26
-
27
- # 3. Process Response
28
-
29
- # New Response Format:
30
- # {
31
- # "best_order": [
32
- # {"lat":..., "lon":...}, # Start (Pickup)
33
- # {"lat":..., "original_index": 2}, # Stop A
34
- # {"lat":..., "original_index": 1} # Stop B
35
- # ],
36
- # "total_distance": 13.474, # In KM? Diagnostic showed 13.474 for small distance. Need to verify unit.
37
- # "time_taken": 1033.263,
38
- # "Direction": [[lat,lon], ...]
39
- # }
40
-
41
- # 'best_order' includes the start point at index 0 (usually without original_index or it's 0/1 based?)
42
- # Based on diagnostic: "original_index": 2 for the 3rd point (index 2).
43
- # So original_index is 0-based index from the input array.
44
-
45
- best_order = response["best_order"]
46
-
47
- # Filter out the pickup location (which should be the first one, or original_index == 0)
48
- # We only want to re-sequence the STOPS.
49
- # Stops in 'stops' array correspond to input indices 1..N.
50
-
51
- ordered_stops_data = best_order.select { |node| node["original_index"].to_i > 0 }
52
-
13
+ stops = []
14
+ locations = []
15
+
16
+ stops = ordered_stops
17
+ locations = build_locations(stops)
18
+
19
+ apply_remote_optimization(stops, locations)
20
+ rescue StandardError => e
21
+ Rails.logger.warn(
22
+ "[RouteOptimizationService] Falling back to local route for delivery_order=#{delivery_order.id}: #{e.class} - #{e.message}"
23
+ )
24
+
25
+ apply_local_fallback(stops, locations)
26
+ end
27
+
28
+ private
29
+
30
+ def apply_remote_optimization(stops, locations)
31
+ response = GebetaService.new.tsp(locations)
32
+ best_order = Array(response["best_order"])
33
+ ordered_stops_data = best_order.select { |node| node["original_index"].to_i.positive? }
34
+
53
35
  ActiveRecord::Base.transaction do
54
36
  ordered_stops_data.each_with_index do |node, seq_num|
55
- original_idx = node["original_index"]
56
- # stops array is 0-indexed, corresponding to input indices 1, 2, 3...
57
- # If original_idx is 1, it means stops[0]. If 2, stops[1].
37
+ original_idx = node["original_index"].to_i
58
38
  stop = stops[original_idx - 1]
59
-
60
- if stop
61
- stop.update!(sequence_number: seq_num + 1)
62
- end
39
+ stop.update!(sequence_number: seq_num + 1) if stop
63
40
  end
64
41
 
65
- # Update DeliveryOrder metrics
66
- # Check units:
67
- # time_taken: 1033.263 (likely seconds ~ 17 mins for decent distance).
68
- # total_distance: 13.474. If this is KM, it's reasonable. (Distance between 9.02,38.80 and 9.028,38.75 is ~ small).
69
- # If meters, 13 meters is too small. 1000 seconds for 13 meters is wrong.
70
- # So total_distance is likely KM.
71
-
72
42
  distance_km = response["total_distance"].to_f
73
-
43
+
74
44
  delivery_order.update!(
75
45
  estimated_delivery_time: Time.current + response["time_taken"].to_f.seconds,
76
- estimated_delivery_price: calculate_price(distance_km * 1000), # pass meters to calc
77
- optimized_route: response["Direction"]
46
+ estimated_delivery_price: calculate_price(distance_km * 1000),
47
+ optimized_route: response["Direction"]
78
48
  )
79
49
  end
80
50
  end
81
51
 
82
- private
52
+ def apply_local_fallback(stops, locations)
53
+ ActiveRecord::Base.transaction do
54
+ stops.each_with_index do |stop, index|
55
+ stop.update!(sequence_number: index + 1)
56
+ end
57
+
58
+ delivery_order.update!(optimized_route: locations)
59
+ end
60
+ end
61
+
62
+ def ordered_stops
63
+ delivery_order.delivery_stops.includes(:dropoff_address).order(:id).to_a
64
+ end
65
+
66
+ def build_locations(stops)
67
+ pickup_coords = [ delivery_order.pickup_address.latitude.to_f, delivery_order.pickup_address.longitude.to_f ]
68
+ stop_coords = stops.map { |stop| [ stop.dropoff_address.latitude.to_f, stop.dropoff_address.longitude.to_f ] }
69
+
70
+ [ pickup_coords ] + stop_coords
71
+ end
83
72
 
84
- # Placeholder pricing logic
85
73
  def calculate_price(distance_meters)
86
74
  base_rate = 50.0
87
- km_rate = 10.0 # 10 ETB per km
75
+ km_rate = 10.0
88
76
  distance_km = distance_meters / 1000.0
89
-
77
+
90
78
  base_rate + (distance_km * km_rate)
91
79
  end
92
80
  end
@@ -1,5 +1,5 @@
1
1
  module Dscf
2
2
  module Marketplace
3
- VERSION = "0.7.3".freeze
3
+ VERSION = "0.7.4".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dscf-marketplace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asrat
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-04-17 00:00:00.000000000 Z
10
+ date: 2026-04-24 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails