@fleetbase/fleetops-engine 0.6.22 → 0.6.23
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.
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/src/Console/Commands/DispatchAdhocOrders.php +47 -75
- package/server/src/Console/Commands/FixInvalidPolymorphicRelationTypeNamespaces.php +1 -1
- package/server/src/Console/Commands/TrackOrderDistanceAndTime.php +109 -65
- package/server/src/Models/Order.php +20 -8
- package/server/src/Models/Place.php +4 -5
- package/server/src/Providers/FleetOpsServiceProvider.php +1 -1
package/composer.json
CHANGED
package/extension.json
CHANGED
package/package.json
CHANGED
|
@@ -18,37 +18,42 @@ class DispatchAdhocOrders extends Command
|
|
|
18
18
|
*
|
|
19
19
|
* @var string
|
|
20
20
|
*/
|
|
21
|
-
protected $signature = 'fleetops:dispatch-adhoc
|
|
21
|
+
protected $signature = 'fleetops:dispatch-adhoc
|
|
22
|
+
{--sandbox : Run in sandbox mode}
|
|
23
|
+
{--testing : Enable testing mode (no geospatial filters)}
|
|
24
|
+
{--days=2 : Only include orders dispatched in the past N days (default: 2)}';
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* The console command description.
|
|
25
28
|
*
|
|
26
29
|
* @var string
|
|
27
30
|
*/
|
|
28
|
-
protected $description = 'Dispatch & ping
|
|
31
|
+
protected $description = 'Dispatch & ping ad-hoc orders without assigned drivers (within a recent time window)';
|
|
29
32
|
|
|
30
33
|
/**
|
|
31
34
|
* Execute the console command.
|
|
32
|
-
*
|
|
33
|
-
* Processes and dispatches ad-hoc orders based on their scheduled dispatch time and driver availability.
|
|
34
|
-
* Orders without an assigned driver and that have surpassed the dispatch time threshold are considered for dispatch.
|
|
35
|
-
* The command supports sandbox and testing modes for different operational environments.
|
|
36
35
|
*/
|
|
37
36
|
public function handle(): void
|
|
38
37
|
{
|
|
39
38
|
date_default_timezone_set('UTC');
|
|
40
39
|
|
|
41
40
|
$sandboxMode = Utils::castBoolean($this->option('sandbox'));
|
|
41
|
+
$testingMode = Utils::castBoolean($this->option('testing'));
|
|
42
|
+
$days = max(1, (int) $this->option('days'));
|
|
43
|
+
|
|
42
44
|
$this->info('Running in ' . ($sandboxMode ? 'sandbox' : 'production') . ' mode.');
|
|
45
|
+
$this->info("Looking back {$days} day(s) for dispatchable orders...");
|
|
46
|
+
|
|
47
|
+
$orders = $this->getDispatchableOrders($days);
|
|
43
48
|
|
|
44
|
-
$orders
|
|
49
|
+
if ($orders->isEmpty()) {
|
|
50
|
+
$this->info('No dispatchable orders found in the given timeframe.');
|
|
51
|
+
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
45
54
|
|
|
46
55
|
$this->alert($orders->count() . ' orders found for ad-hoc dispatch. Current Time: ' . Carbon::now()->toDateTimeString());
|
|
47
|
-
$this->table(['Order', 'Dispatched At'], $orders->map(
|
|
48
|
-
function ($order) {
|
|
49
|
-
return [$order->public_id, $order->dispatched_at];
|
|
50
|
-
}
|
|
51
|
-
));
|
|
56
|
+
$this->table(['Order', 'Dispatched At'], $orders->map(fn ($order) => [$order->public_id, $order->dispatched_at]));
|
|
52
57
|
|
|
53
58
|
foreach ($orders as $order) {
|
|
54
59
|
$pickup = $order->getPickupLocation();
|
|
@@ -59,7 +64,7 @@ class DispatchAdhocOrders extends Command
|
|
|
59
64
|
continue;
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
$drivers = $this->getNearbyDriversForOrder($order, $pickup, $distance);
|
|
67
|
+
$drivers = $this->getNearbyDriversForOrder($order, $pickup, $distance, $testingMode);
|
|
63
68
|
|
|
64
69
|
$this->line('Checking order ' . $order->public_id . ' for nearby drivers within ' . $distance . ' meters.');
|
|
65
70
|
|
|
@@ -68,7 +73,6 @@ class DispatchAdhocOrders extends Command
|
|
|
68
73
|
$this->info('Order ' . $order->public_id . ' dispatched successfully to ' . $drivers->count() . ' nearby drivers.');
|
|
69
74
|
foreach ($drivers as $driver) {
|
|
70
75
|
$this->info('Pinging driver ' . $driver->name . ' (' . $driver->public_id . ') ...');
|
|
71
|
-
// Do the ping
|
|
72
76
|
$driver->notify(new OrderPing($order, $distance));
|
|
73
77
|
}
|
|
74
78
|
} else {
|
|
@@ -78,44 +82,36 @@ class DispatchAdhocOrders extends Command
|
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
/**
|
|
81
|
-
* Retrieve a collection of dispatchable orders
|
|
82
|
-
*
|
|
83
|
-
* This method queries orders that are eligible for dispatching based on multiple constraints:
|
|
84
|
-
* - Orders must be adhoc, dispatched, but not yet started.
|
|
85
|
-
* - Orders must have a `dispatched_at` timestamp within a configurable time window:
|
|
86
|
-
* - Not older than the given expiry limit (default 72 hours).
|
|
87
|
-
* - At least the given interval old (default 4 minutes).
|
|
88
|
-
* - Orders must not have a driver already assigned and must not be deleted or canceled.
|
|
89
|
-
* - Orders must belong to companies that have at least one associated user with an online driver.
|
|
90
|
-
* - Orders must have an associated payload.
|
|
85
|
+
* Retrieve a collection of dispatchable orders created or dispatched within the last N days.
|
|
91
86
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
87
|
+
* @param int $days Number of days to look back (default: 2)
|
|
88
|
+
* @param int $intervalMinutes Minimum age of the order in minutes to be considered dispatchable (default: 4)
|
|
89
|
+
* @param int $expiryHours Maximum dispatchable age in hours (default: 72)
|
|
94
90
|
*
|
|
95
|
-
* @
|
|
96
|
-
* @param int $expiryHours maximum age of the order in hours before it expires and is no longer dispatchable (default: 72)
|
|
97
|
-
*
|
|
98
|
-
* @return \Illuminate\Support\Collection a collection of eligible `Order` models with their related `company` and `payload`
|
|
91
|
+
* @return \Illuminate\Support\Collection
|
|
99
92
|
*/
|
|
100
|
-
public function getDispatchableOrders(int $
|
|
93
|
+
public function getDispatchableOrders(int $days = 2, int $intervalMinutes = 4, int $expiryHours = 72): Collection
|
|
101
94
|
{
|
|
102
|
-
$sandbox
|
|
95
|
+
$sandbox = Utils::castBoolean($this->option('sandbox'));
|
|
96
|
+
|
|
97
|
+
$cutoffDate = Carbon::now()->subDays($days);
|
|
98
|
+
$now = Carbon::now();
|
|
103
99
|
|
|
104
100
|
return Order::on($sandbox ? 'sandbox' : 'mysql')
|
|
105
101
|
->withoutGlobalScopes()
|
|
106
102
|
->where(['adhoc' => 1, 'dispatched' => 1, 'started' => 0])
|
|
107
103
|
->whereBetween('dispatched_at', [
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
$now->subHours($expiryHours), // not older than 72 hours
|
|
105
|
+
$now->subMinutes($intervalMinutes),
|
|
110
106
|
])
|
|
107
|
+
->where('created_at', '>=', $cutoffDate)
|
|
111
108
|
->whereNull('driver_assigned_uuid')
|
|
112
109
|
->whereNull('deleted_at')
|
|
113
110
|
->where('status', '!=', 'canceled')
|
|
114
111
|
->whereHas('company', function ($q) {
|
|
115
112
|
$q->whereHas('users', function ($q) {
|
|
116
113
|
$q->whereHas('driver', function ($q) {
|
|
117
|
-
$q->where('online', 1);
|
|
118
|
-
$q->whereNull('deleted_at');
|
|
114
|
+
$q->where('online', 1)->whereNull('deleted_at');
|
|
119
115
|
});
|
|
120
116
|
});
|
|
121
117
|
})
|
|
@@ -125,48 +121,24 @@ class DispatchAdhocOrders extends Command
|
|
|
125
121
|
}
|
|
126
122
|
|
|
127
123
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* Retrieves drivers who are within a specified distance from the pickup location of the order.
|
|
131
|
-
* The method supports a testing mode to simulate driver availability.
|
|
132
|
-
*
|
|
133
|
-
* @param Order $order the order for which drivers are being sought
|
|
134
|
-
* @param Point $pickup the geographic point representing the pickup location
|
|
135
|
-
* @param int $distance the maximum distance (in meters) within which drivers should be located
|
|
136
|
-
*
|
|
137
|
-
* @return Collection returns a collection of nearby drivers
|
|
124
|
+
* Fetch nearby drivers for a given order.
|
|
138
125
|
*/
|
|
139
|
-
public function getNearbyDriversForOrder(Order $order, Point $pickup, int $distance): Collection
|
|
126
|
+
public function getNearbyDriversForOrder(Order $order, Point $pickup, int $distance, bool $testing = false): Collection
|
|
140
127
|
{
|
|
141
|
-
$
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
->
|
|
153
|
-
->withoutGlobalScopes()
|
|
154
|
-
->get();
|
|
155
|
-
} else {
|
|
156
|
-
$drivers = Driver::where(['online' => 1])
|
|
157
|
-
->where(function ($q) use ($order) {
|
|
158
|
-
$q->where('company_uuid', $order->company_uuid);
|
|
159
|
-
$q->orWhereHas('user', function ($q) use ($order) {
|
|
160
|
-
$q->where('company_uuid', $order->company_uuid);
|
|
161
|
-
});
|
|
162
|
-
})
|
|
163
|
-
->whereNull('deleted_at')
|
|
164
|
-
->distanceSphere('location', $pickup, $distance)
|
|
165
|
-
->distanceSphereValue('location', $pickup)
|
|
166
|
-
->withoutGlobalScopes()
|
|
167
|
-
->get();
|
|
128
|
+
$driverQuery = Driver::query()
|
|
129
|
+
->where(['online' => 1])
|
|
130
|
+
->where(function ($q) use ($order) {
|
|
131
|
+
$q->where('company_uuid', $order->company_uuid)
|
|
132
|
+
->orWhereHas('user', fn ($q) => $q->where('company_uuid', $order->company_uuid));
|
|
133
|
+
})
|
|
134
|
+
->whereNull('deleted_at')
|
|
135
|
+
->withoutGlobalScopes();
|
|
136
|
+
|
|
137
|
+
if (!$testing) {
|
|
138
|
+
$driverQuery->distanceSphere('location', $pickup, $distance)
|
|
139
|
+
->distanceSphereValue('location', $pickup);
|
|
168
140
|
}
|
|
169
141
|
|
|
170
|
-
return $
|
|
142
|
+
return $driverQuery->get();
|
|
171
143
|
}
|
|
172
144
|
}
|
|
@@ -5,91 +5,135 @@ namespace Fleetbase\FleetOps\Console\Commands;
|
|
|
5
5
|
use Fleetbase\FleetOps\Models\Order;
|
|
6
6
|
use Illuminate\Console\Command;
|
|
7
7
|
use Illuminate\Support\Carbon;
|
|
8
|
+
use Illuminate\Support\Facades\Cache;
|
|
8
9
|
|
|
9
10
|
class TrackOrderDistanceAndTime extends Command
|
|
10
11
|
{
|
|
11
12
|
/**
|
|
12
13
|
* The name and signature of the console command.
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
+
* Options:
|
|
16
|
+
* --provider= : distance/time provider (calculate, google, osrm). Defaults to config(fleetops.distance_matrix.provider)
|
|
17
|
+
* --days= : only include orders created in last N days (default: 2)
|
|
18
|
+
* --chunk= : records per chunk (default: 250)
|
|
19
|
+
* --no-lock : skip single-run lock (not recommended)
|
|
20
|
+
* --dry : dry-run, do not mutate anything
|
|
15
21
|
*/
|
|
16
|
-
protected $signature = 'fleetops:update-estimations
|
|
22
|
+
protected $signature = 'fleetops:update-estimations
|
|
23
|
+
{--provider= : The distance and time calculation provider (calculate, google, or osrm)}
|
|
24
|
+
{--days=2 : Only include orders created in the last N days}
|
|
25
|
+
{--chunk=250 : How many orders to process per chunk}
|
|
26
|
+
{--no-lock : Skip process locking}
|
|
27
|
+
{--dry : Dry run (don\'t persist changes)}';
|
|
17
28
|
|
|
18
|
-
|
|
19
|
-
* The console command description.
|
|
20
|
-
*
|
|
21
|
-
* @var string
|
|
22
|
-
*/
|
|
23
|
-
protected $description = 'Track and update order distance and time estimations';
|
|
29
|
+
protected $description = 'Track and update order distance and time estimations for recent, active orders';
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
* Execute the console command.
|
|
27
|
-
*
|
|
28
|
-
* @return int
|
|
29
|
-
*/
|
|
30
|
-
public function handle()
|
|
31
|
+
public function handle(): int
|
|
31
32
|
{
|
|
32
|
-
//
|
|
33
|
+
// Always operate in UTC
|
|
33
34
|
date_default_timezone_set('UTC');
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
$
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
$
|
|
44
|
-
|
|
45
|
-
//
|
|
46
|
-
$
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
$order->setDistanceAndTime(['provider' => $provider]);
|
|
54
|
-
$updated++;
|
|
55
|
-
$this->info("Order ID {$order->id} - Distance & Time estimations updated.");
|
|
56
|
-
} catch (\Exception $e) {
|
|
57
|
-
$this->error("Failed to update Order ID {$order->id} - Error: " . $e->getMessage());
|
|
36
|
+
$provider = $this->option('provider') ?: (string) config('fleetops.distance_matrix.provider');
|
|
37
|
+
$days = max(1, (int) $this->option('days')); // guardrail
|
|
38
|
+
$perChunk = max(50, (int) $this->option('chunk')); // sane lower bound
|
|
39
|
+
$dryRun = (bool) $this->option('dry');
|
|
40
|
+
$useLock = !$this->option('no-lock');
|
|
41
|
+
|
|
42
|
+
$this->info("Using provider: {$provider}");
|
|
43
|
+
$this->info("Looking back: last {$days} day(s)");
|
|
44
|
+
$this->info("Chunk size: {$perChunk}" . ($dryRun ? ' (dry-run)' : ''));
|
|
45
|
+
|
|
46
|
+
// Prevent overlapping executions (e.g., cron overlap)
|
|
47
|
+
$lock = null;
|
|
48
|
+
if ($useLock) {
|
|
49
|
+
$lock = Cache::lock('fleetops:update-estimations', 3600); // 1h lock window
|
|
50
|
+
if (!$lock->get()) {
|
|
51
|
+
$this->warn('Another run appears to be in progress (lock active). Use --no-lock to bypass.');
|
|
52
|
+
|
|
53
|
+
return self::SUCCESS;
|
|
58
54
|
}
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
try {
|
|
58
|
+
$cutoff = Carbon::now()->subDays($days);
|
|
59
|
+
|
|
60
|
+
// Build the base query (no data loaded yet)
|
|
61
|
+
$base = $this->activeOrdersQuery($cutoff);
|
|
62
|
+
|
|
63
|
+
// Count total to set up a progress bar without loading all rows
|
|
64
|
+
$total = (clone $base)->count('id');
|
|
65
|
+
if ($total === 0) {
|
|
66
|
+
$this->info('No qualifying orders found. Exiting.');
|
|
67
|
+
|
|
68
|
+
return self::SUCCESS;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
$this->alert('Found ' . number_format($total) . ' orders to update. Current Time: ' . Carbon::now()->toDateTimeString());
|
|
72
|
+
$bar = $this->output->createProgressBar($total);
|
|
73
|
+
$bar->start();
|
|
74
|
+
|
|
75
|
+
$updated = 0;
|
|
76
|
+
$errors = 0;
|
|
77
|
+
|
|
78
|
+
// Stream through the dataset in stable primary-key order
|
|
79
|
+
$base->orderBy('id')->chunkById($perChunk, function ($orders) use ($provider, $dryRun, $bar, &$updated, &$errors) {
|
|
80
|
+
// Eager-load relationships per chunk to avoid N+1
|
|
81
|
+
$orders->load(['payload', 'payload.waypoints', 'payload.pickup', 'payload.dropoff']);
|
|
82
|
+
|
|
83
|
+
foreach ($orders as $order) {
|
|
84
|
+
try {
|
|
85
|
+
if (!$dryRun) {
|
|
86
|
+
$order->setDistanceAndTime(['provider' => $provider]);
|
|
87
|
+
}
|
|
88
|
+
$updated++;
|
|
89
|
+
} catch (\Throwable $e) {
|
|
90
|
+
$errors++;
|
|
91
|
+
$this->error("Order {$order->id} failed: {$e->getMessage()}");
|
|
92
|
+
} finally {
|
|
93
|
+
$bar->advance();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Optional: small micro-sleep can smooth out DB/API burstiness
|
|
98
|
+
// usleep(20000); // 20ms
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
$bar->finish();
|
|
102
|
+
$this->newLine(2);
|
|
103
|
+
|
|
104
|
+
$this->info(($dryRun ? '[Dry Run] ' : '') . "Updated {$updated}/" . number_format($total) . ' orders.');
|
|
105
|
+
if ($errors > 0) {
|
|
106
|
+
$this->warn("Encountered {$errors} error(s). Check logs for details.");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return self::SUCCESS;
|
|
110
|
+
} finally {
|
|
111
|
+
if ($lock) {
|
|
112
|
+
$lock->release();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
63
115
|
}
|
|
64
116
|
|
|
65
117
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* This method returns a collection of active orders with the following conditions:
|
|
69
|
-
* - Not in 'completed' or 'canceled' status.
|
|
70
|
-
* - Not marked as deleted (`deleted_at` is null).
|
|
71
|
-
* - Associated with a company (`company_uuid` is not null).
|
|
72
|
-
* - The order process has started (`started_at` is not null).
|
|
73
|
-
* - Contains a payload (`payload` relationship exists).
|
|
74
|
-
* - Created within the past month.
|
|
75
|
-
*
|
|
76
|
-
* The result includes related payload data, waypoints, and information about pickup and dropoff points.
|
|
77
|
-
* Global scopes are not applied to this query.
|
|
118
|
+
* Base query for "active" orders in the last N days.
|
|
78
119
|
*
|
|
79
|
-
*
|
|
120
|
+
* Conditions:
|
|
121
|
+
* - Not completed/canceled
|
|
122
|
+
* - Not soft-deleted
|
|
123
|
+
* - Has company & started_at
|
|
124
|
+
* - Has payload
|
|
125
|
+
* - created_at >= cutoff
|
|
126
|
+
* - Without global scopes (as in original)
|
|
80
127
|
*/
|
|
81
|
-
protected function
|
|
128
|
+
protected function activeOrdersQuery(Carbon $cutoff)
|
|
82
129
|
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
->with(['payload', 'payload.waypoints', 'payload.pickup', 'payload.dropoff'])
|
|
92
|
-
->withoutGlobalScopes()
|
|
93
|
-
->get();
|
|
130
|
+
return Order::query()
|
|
131
|
+
->withoutGlobalScopes()
|
|
132
|
+
->whereNotIn('status', ['completed', 'canceled'])
|
|
133
|
+
->whereNull('deleted_at')
|
|
134
|
+
->whereNotNull('company_uuid')
|
|
135
|
+
->whereNotNull('started_at')
|
|
136
|
+
->where('created_at', '>=', $cutoff)
|
|
137
|
+
->whereHas('payload');
|
|
94
138
|
}
|
|
95
139
|
}
|
|
@@ -881,7 +881,7 @@ class Order extends Model
|
|
|
881
881
|
$route = new Route($attributes);
|
|
882
882
|
$route->save();
|
|
883
883
|
|
|
884
|
-
$this->
|
|
884
|
+
$this->updateQuietly(['route_uuid' => $route->uuid]);
|
|
885
885
|
|
|
886
886
|
return $this;
|
|
887
887
|
}
|
|
@@ -998,7 +998,7 @@ class Order extends Model
|
|
|
998
998
|
'meta' => $meta,
|
|
999
999
|
]);
|
|
1000
1000
|
|
|
1001
|
-
return $this->
|
|
1001
|
+
return $this->updateQuietly([
|
|
1002
1002
|
'purchase_rate_uuid' => $purchasedRate->uuid,
|
|
1003
1003
|
]);
|
|
1004
1004
|
}
|
|
@@ -1030,7 +1030,7 @@ class Order extends Model
|
|
|
1030
1030
|
'status' => 'success',
|
|
1031
1031
|
]);
|
|
1032
1032
|
|
|
1033
|
-
$this->
|
|
1033
|
+
$this->updateQuietly(['transaction_uuid' => $transaction->uuid]);
|
|
1034
1034
|
} catch (\Throwable $e) {
|
|
1035
1035
|
}
|
|
1036
1036
|
|
|
@@ -1518,7 +1518,7 @@ class Order extends Model
|
|
|
1518
1518
|
|
|
1519
1519
|
$matrix = Utils::getPreliminaryDistanceMatrix($origin, $destination);
|
|
1520
1520
|
|
|
1521
|
-
$this->
|
|
1521
|
+
$this->updateQuietly(['distance' => $matrix->distance, 'time' => $matrix->time]);
|
|
1522
1522
|
|
|
1523
1523
|
return $this;
|
|
1524
1524
|
}
|
|
@@ -1529,16 +1529,28 @@ class Order extends Model
|
|
|
1529
1529
|
*
|
|
1530
1530
|
* @return Order the updated Order instance
|
|
1531
1531
|
*/
|
|
1532
|
-
public function setDistanceAndTime($options = []):
|
|
1532
|
+
public function setDistanceAndTime(array $options = []): self
|
|
1533
1533
|
{
|
|
1534
1534
|
$origin = $this->getCurrentOriginPosition();
|
|
1535
1535
|
$destination = $this->getDestinationPosition();
|
|
1536
|
-
|
|
1537
|
-
if (
|
|
1536
|
+
|
|
1537
|
+
if (!$origin || !$destination) {
|
|
1538
1538
|
return $this;
|
|
1539
1539
|
}
|
|
1540
1540
|
|
|
1541
|
-
|
|
1541
|
+
// Fetch distance/time — bail early if external call fails
|
|
1542
|
+
$matrix = Utils::getDrivingDistanceAndTime($origin, $destination, $options);
|
|
1543
|
+
if (!$matrix || !isset($matrix->distance, $matrix->time)) {
|
|
1544
|
+
return $this;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
// Only update if values changed to prevent redundant writes
|
|
1548
|
+
if ($this->distance !== $matrix->distance || $this->time !== $matrix->time) {
|
|
1549
|
+
$this->updateQuietly([
|
|
1550
|
+
'distance' => $matrix->distance,
|
|
1551
|
+
'time' => $matrix->time,
|
|
1552
|
+
]);
|
|
1553
|
+
}
|
|
1542
1554
|
|
|
1543
1555
|
return $this;
|
|
1544
1556
|
}
|
|
@@ -555,14 +555,13 @@ class Place extends Model
|
|
|
555
555
|
}
|
|
556
556
|
|
|
557
557
|
// If has $attributes['address']
|
|
558
|
-
$address = $place
|
|
559
|
-
if (
|
|
560
|
-
// return static::createFromGeocodingLookup($place['address'], $saveInstance);
|
|
558
|
+
$address = data_get($place, 'address');
|
|
559
|
+
if ($address) {
|
|
561
560
|
return static::create(array_merge($place, static::getValuesFromGeocodingLookup($address)));
|
|
562
561
|
}
|
|
563
562
|
|
|
564
|
-
// Perform google lookup to fill
|
|
565
|
-
$street1 = $place
|
|
563
|
+
// Perform google lookup to fill street1
|
|
564
|
+
$street1 = data_get($place, 'street1');
|
|
566
565
|
if ($street1) {
|
|
567
566
|
return static::create(array_merge($place, static::getValuesFromGeocodingLookup($street1)));
|
|
568
567
|
}
|
|
@@ -95,7 +95,7 @@ class FleetOpsServiceProvider extends CoreServiceProvider
|
|
|
95
95
|
$this->scheduleCommands(function ($schedule) {
|
|
96
96
|
$schedule->command('fleetops:dispatch-orders')->everyMinute()->withoutOverlapping()->storeOutputInDb();
|
|
97
97
|
$schedule->command('fleetops:dispatch-adhoc')->everyMinute()->withoutOverlapping()->storeOutputInDb();
|
|
98
|
-
$schedule->command('fleetops:update-estimations')->
|
|
98
|
+
$schedule->command('fleetops:update-estimations')->everyTenMinutes()->withoutOverlapping();
|
|
99
99
|
$schedule->command('fleetops:purge-service-quotes')->daily()->withoutOverlapping();
|
|
100
100
|
});
|
|
101
101
|
$this->registerNotifications();
|