@fleetbase/fleetops-engine 0.6.28 → 0.6.30

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.
Files changed (92) hide show
  1. package/addon/components/customer/create-order-form.hbs +1 -1
  2. package/addon/components/customer/order-form.hbs +34 -34
  3. package/addon/components/customer/orders.hbs +2 -2
  4. package/addon/components/display-place.hbs +1 -1
  5. package/addon/components/driver/pill.hbs +16 -17
  6. package/addon/components/driver/pill.js +5 -1
  7. package/addon/components/map/leaflet-live-map.js +35 -3
  8. package/addon/components/map/order-list-overlay/order.hbs +1 -0
  9. package/addon/components/map/order-list-overlay/order.js +42 -0
  10. package/addon/components/modals/bulk-assign-driver.hbs +2 -2
  11. package/addon/components/order/details/detail.hbs +6 -6
  12. package/addon/components/order/details/notes.js +1 -1
  13. package/addon/components/order/route-editor.hbs +3 -3
  14. package/addon/components/order-tracking-lookup.hbs +1 -1
  15. package/addon/components/service-rate/details.hbs +117 -75
  16. package/addon/components/service-rate/form.hbs +7 -4
  17. package/addon/components/service-rate/form.js +6 -0
  18. package/addon/components/vehicle/pill.hbs +32 -33
  19. package/addon/components/vehicle/pill.js +5 -1
  20. package/addon/controllers/operations/orders/index.js +1 -1
  21. package/addon/controllers/operations/scheduler/index.js +17 -2
  22. package/addon/controllers/operations/service-rates/index/edit.js +1 -7
  23. package/addon/controllers/operations/service-rates/index/new.js +0 -7
  24. package/addon/controllers/operations/service-rates/index.js +10 -2
  25. package/addon/routes/operations/orders/index/details.js +7 -0
  26. package/addon/routes/operations/scheduler/index.js +3 -3
  27. package/addon/services/driver-actions.js +20 -4
  28. package/addon/services/leaflet-routing-control.js +7 -1
  29. package/addon/services/order-list-overlay.js +0 -1
  30. package/addon/services/place-actions.js +20 -4
  31. package/addon/services/service-rate-actions.js +31 -0
  32. package/addon/services/vehicle-actions.js +20 -4
  33. package/addon/templates/operations/scheduler/index.hbs +2 -2
  34. package/addon/utils/create-full-calendar-event-from-order.js +6 -0
  35. package/composer.json +1 -1
  36. package/extension.json +1 -1
  37. package/index.js +0 -11
  38. package/package.json +4 -4
  39. package/server/migrations/2025_12_16_000001_add_subject_created_at_index_to_positions.php +40 -0
  40. package/server/migrations/2025_12_16_000003_add_performance_indexes_to_fleetops_core_tables.php +442 -0
  41. package/server/src/Console/Commands/DispatchAdhocOrders.php +7 -2
  42. package/server/src/Http/Controllers/Api/v1/DriverController.php +2 -0
  43. package/server/src/Http/Controllers/Api/v1/OrderController.php +30 -0
  44. package/server/src/Http/Controllers/Internal/v1/LiveController.php +184 -86
  45. package/server/src/Http/Controllers/Internal/v1/OrderController.php +14 -1
  46. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +5 -0
  47. package/server/src/Http/Filter/DriverFilter.php +10 -0
  48. package/server/src/Http/Filter/OrderFilter.php +8 -1
  49. package/server/src/Http/Resources/v1/Contact.php +2 -2
  50. package/server/src/Http/Resources/v1/Entity.php +1 -1
  51. package/server/src/Http/Resources/v1/Index/Customer.php +33 -0
  52. package/server/src/Http/Resources/v1/Index/Driver.php +45 -0
  53. package/server/src/Http/Resources/v1/Index/Facilitator.php +33 -0
  54. package/server/src/Http/Resources/v1/Index/Order.php +127 -0
  55. package/server/src/Http/Resources/v1/Index/Payload.php +57 -0
  56. package/server/src/Http/Resources/v1/Index/Place.php +45 -0
  57. package/server/src/Http/Resources/v1/Index/TrackingNumber.php +25 -0
  58. package/server/src/Http/Resources/v1/Index/Vehicle.php +50 -0
  59. package/server/src/Http/Resources/v1/Order.php +41 -14
  60. package/server/src/Http/Resources/v1/Place.php +1 -1
  61. package/server/src/Http/Resources/v1/Position.php +2 -1
  62. package/server/src/Http/Resources/v1/ServiceRate.php +4 -4
  63. package/server/src/Http/Resources/v1/ServiceRateFee.php +12 -12
  64. package/server/src/Http/Resources/v1/ServiceRateParcelFee.php +14 -7
  65. package/server/src/Http/Resources/v1/TrackingNumber.php +1 -1
  66. package/server/src/Http/Resources/v1/Waypoint.php +1 -1
  67. package/server/src/Listeners/HandleOrderDispatched.php +5 -0
  68. package/server/src/Models/Contact.php +2 -0
  69. package/server/src/Models/Device.php +2 -0
  70. package/server/src/Models/DeviceEvent.php +2 -0
  71. package/server/src/Models/Driver.php +2 -0
  72. package/server/src/Models/FuelReport.php +2 -0
  73. package/server/src/Models/Issue.php +2 -0
  74. package/server/src/Models/Order.php +12 -5
  75. package/server/src/Models/Place.php +2 -0
  76. package/server/src/Models/Position.php +2 -0
  77. package/server/src/Models/ServiceArea.php +2 -0
  78. package/server/src/Models/ServiceRate.php +5 -1
  79. package/server/src/Models/ServiceRateFee.php +3 -17
  80. package/server/src/Models/ServiceRateParcelFee.php +1 -12
  81. package/server/src/Models/Vehicle.php +2 -0
  82. package/server/src/Models/Vendor.php +2 -0
  83. package/server/src/Models/Zone.php +2 -0
  84. package/server/src/Observers/DriverObserver.php +23 -0
  85. package/server/src/Observers/OrderObserver.php +31 -0
  86. package/server/src/Observers/PlaceObserver.php +31 -0
  87. package/server/src/Observers/ServiceRateObserver.php +0 -18
  88. package/server/src/Observers/VehicleObserver.php +7 -0
  89. package/server/src/Support/LiveCacheService.php +165 -0
  90. package/server/src/Support/OSRM.php +49 -22
  91. package/server/src/Support/OrderTracker.php +100 -28
  92. package/translations/en-us.yaml +3 -1
@@ -9,6 +9,7 @@ use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
9
9
  use Fleetbase\Models\Model;
10
10
  use Fleetbase\Models\User;
11
11
  use Fleetbase\Traits\HasApiModelBehavior;
12
+ use Fleetbase\Traits\HasApiModelCache;
12
13
  use Fleetbase\Traits\HasCustomFields;
13
14
  use Fleetbase\Traits\HasPublicId;
14
15
  use Fleetbase\Traits\HasUuid;
@@ -22,6 +23,7 @@ class Issue extends Model
22
23
  use TracksApiCredential;
23
24
  use SpatialTrait;
24
25
  use HasApiModelBehavior;
26
+ use HasApiModelCache;
25
27
  use HasCustomFields;
26
28
 
27
29
  /**
@@ -17,6 +17,7 @@ use Fleetbase\LaravelMysqlSpatial\Types\Point;
17
17
  use Fleetbase\Models\Model;
18
18
  use Fleetbase\Models\Transaction;
19
19
  use Fleetbase\Traits\HasApiModelBehavior;
20
+ use Fleetbase\Traits\HasApiModelCache;
20
21
  use Fleetbase\Traits\HasCustomFields;
21
22
  use Fleetbase\Traits\HasInternalId;
22
23
  use Fleetbase\Traits\HasMetaAttributes;
@@ -45,6 +46,7 @@ class Order extends Model
45
46
  use HasInternalId;
46
47
  use SendsWebhooks;
47
48
  use HasApiModelBehavior;
49
+ use HasApiModelCache;
48
50
  use HasOptionsAttributes;
49
51
  use HasMetaAttributes;
50
52
  use TracksApiCredential;
@@ -492,7 +494,7 @@ class Order extends Model
492
494
  */
493
495
  public function getFacilitatorIsVendorAttribute()
494
496
  {
495
- return $this->facilitator_type === 'Fleetbase\\FleetOps\\Models\\Vendor';
497
+ return $this->facilitator_type === Vendor::class;
496
498
  }
497
499
 
498
500
  /**
@@ -502,7 +504,7 @@ class Order extends Model
502
504
  */
503
505
  public function getFacilitatorIsIntegratedVendorAttribute()
504
506
  {
505
- return $this->facilitator_type === 'Fleetbase\\FleetOps\\Models\\IntegratedVendor';
507
+ return $this->facilitator_type === IntegratedVendor::class;
506
508
  }
507
509
 
508
510
  /**
@@ -512,7 +514,7 @@ class Order extends Model
512
514
  */
513
515
  public function getFacilitatorIsContactAttribute()
514
516
  {
515
- return $this->facilitator_type === 'Fleetbase\\FleetOps\\Models\\Contact';
517
+ return $this->facilitator_type === Contact::class;
516
518
  }
517
519
 
518
520
  /**
@@ -522,7 +524,7 @@ class Order extends Model
522
524
  */
523
525
  public function getCustomerIsVendorAttribute()
524
526
  {
525
- return $this->customer_type === 'Fleetbase\\FleetOps\\Models\\Vendor';
527
+ return $this->customer_type === Vendor::class;
526
528
  }
527
529
 
528
530
  /**
@@ -532,7 +534,7 @@ class Order extends Model
532
534
  */
533
535
  public function getCustomerIsContactAttribute()
534
536
  {
535
- return $this->customer_type === 'Fleetbase\\FleetOps\\Models\\Contact';
537
+ return $this->customer_type === Contact::class;
536
538
  }
537
539
 
538
540
  /**
@@ -1830,6 +1832,11 @@ class Order extends Model
1830
1832
  });
1831
1833
  })
1832
1834
  ->whereNull('deleted_at')
1835
+ ->whereNotNull('location')->whereRaw('
1836
+ ST_Y(location) BETWEEN -90 AND 90
1837
+ AND ST_X(location) BETWEEN -180 AND 180
1838
+ AND NOT (ST_X(location) = 0 AND ST_Y(location) = 0)
1839
+ ')
1833
1840
  ->distanceSphere('location', $pickup, $distance)
1834
1841
  ->distanceSphereValue('location', $pickup)
1835
1842
  ->withoutGlobalScopes()
@@ -12,6 +12,7 @@ use Fleetbase\LaravelMysqlSpatial\Types\Point as SpatialPoint;
12
12
  use Fleetbase\Models\File;
13
13
  use Fleetbase\Models\Model;
14
14
  use Fleetbase\Traits\HasApiModelBehavior;
15
+ use Fleetbase\Traits\HasApiModelCache;
15
16
  use Fleetbase\Traits\HasCustomFields;
16
17
  use Fleetbase\Traits\HasMetaAttributes;
17
18
  use Fleetbase\Traits\HasPublicId;
@@ -28,6 +29,7 @@ class Place extends Model
28
29
  use HasUuid;
29
30
  use HasPublicId;
30
31
  use HasApiModelBehavior;
32
+ use HasApiModelCache;
31
33
  use Searchable;
32
34
  use SendsWebhooks;
33
35
  use TracksApiCredential;
@@ -6,6 +6,7 @@ use Fleetbase\Casts\PolymorphicType;
6
6
  use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
7
7
  use Fleetbase\Models\Model;
8
8
  use Fleetbase\Traits\HasApiModelBehavior;
9
+ use Fleetbase\Traits\HasApiModelCache;
9
10
  use Fleetbase\Traits\HasUuid;
10
11
  use Fleetbase\Traits\TracksApiCredential;
11
12
  use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -16,6 +17,7 @@ class Position extends Model
16
17
  use HasUuid;
17
18
  use TracksApiCredential;
18
19
  use HasApiModelBehavior;
20
+ use HasApiModelCache;
19
21
  use SpatialTrait;
20
22
 
21
23
  /**
@@ -11,6 +11,7 @@ use Fleetbase\LaravelMysqlSpatial\Types\Point;
11
11
  use Fleetbase\LaravelMysqlSpatial\Types\Polygon;
12
12
  use Fleetbase\Models\Model;
13
13
  use Fleetbase\Traits\HasApiModelBehavior;
14
+ use Fleetbase\Traits\HasApiModelCache;
14
15
  use Fleetbase\Traits\HasCustomFields;
15
16
  use Fleetbase\Traits\HasPublicId;
16
17
  use Fleetbase\Traits\HasUuid;
@@ -30,6 +31,7 @@ class ServiceArea extends Model
30
31
  use TracksApiCredential;
31
32
  use SpatialTrait;
32
33
  use HasApiModelBehavior;
34
+ use HasApiModelCache;
33
35
  use HasCustomFields;
34
36
 
35
37
  /**
@@ -238,7 +238,7 @@ class ServiceRate extends Model
238
238
  */
239
239
  public function isParcelService(): bool
240
240
  {
241
- return $this->service_type === 'parcel';
241
+ return $this->rate_calculation_method === 'parcel';
242
242
  }
243
243
 
244
244
  /**
@@ -339,6 +339,8 @@ class ServiceRate extends Model
339
339
  $updateableAttributes = collect($serviceRateFees[$i])->except(['uuid', 'created_at', 'updated_at'])->toArray();
340
340
 
341
341
  if ($updateableAttributes) {
342
+ // Apply casts before update
343
+ $updateableAttributes = ServiceRateFee::onRowInsert($updateableAttributes);
342
344
  ServiceRateFee::where('uuid', $id)->update($updateableAttributes);
343
345
  }
344
346
 
@@ -377,6 +379,8 @@ class ServiceRate extends Model
377
379
  $updateableAttributes = collect($serviceRateParcelFees[$i])->except(['uuid', 'created_at', 'updated_at'])->toArray();
378
380
 
379
381
  if ($updateableAttributes) {
382
+ // Apply casts before update
383
+ $updateableAttributes = ServiceRateParcelFee::onRowInsert($updateableAttributes);
380
384
  ServiceRateParcelFee::where('uuid', $id)->update($updateableAttributes);
381
385
  }
382
386
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  namespace Fleetbase\FleetOps\Models;
4
4
 
5
+ use Fleetbase\Casts\Money;
5
6
  use Fleetbase\FleetOps\Support\Utils;
6
7
  use Fleetbase\Models\Model;
7
8
  use Fleetbase\Traits\HasUuid;
@@ -41,7 +42,7 @@ class ServiceRateFee extends Model
41
42
  protected $casts = [
42
43
  'min' => 'integer',
43
44
  'max' => 'integer',
44
- 'fee' => 'integer',
45
+ 'fee' => Money::class,
45
46
  'distance' => 'integer',
46
47
  ];
47
48
 
@@ -61,7 +62,7 @@ class ServiceRateFee extends Model
61
62
 
62
63
  public static function onRowInsert($row)
63
64
  {
64
- $row['fee'] = Utils::numbersOnly($row['fee'] ?? null);
65
+ $row['fee'] = Money::apply($row['fee'] ?? 0);
65
66
  $row['distance'] = Utils::numbersOnly($row['distance'] ?? null);
66
67
  $row['min'] = Utils::numbersOnly($row['min'] ?? null);
67
68
  $row['max'] = Utils::numbersOnly($row['max'] ?? null);
@@ -69,21 +70,6 @@ class ServiceRateFee extends Model
69
70
  return $row;
70
71
  }
71
72
 
72
- /**
73
- * Set the fee as only numbers.
74
- *
75
- * @void
76
- */
77
- public function setFeeAttribute($value)
78
- {
79
- $this->attributes['fee'] = Utils::numbersOnly($value);
80
- }
81
-
82
- /**
83
- * Set the distance as numbers only.
84
- *
85
- * @void
86
- */
87
73
  public function setDistanceAttribute($value)
88
74
  {
89
75
  $this->attributes['distance'] = Utils::numbersOnly($value);
@@ -3,7 +3,6 @@
3
3
  namespace Fleetbase\FleetOps\Models;
4
4
 
5
5
  use Fleetbase\Casts\Money;
6
- use Fleetbase\FleetOps\Support\Utils;
7
6
  use Fleetbase\Models\Model;
8
7
  use Fleetbase\Traits\HasUuid;
9
8
  use PhpUnitsOfMeasure\PhysicalQuantity\Length;
@@ -59,21 +58,11 @@ class ServiceRateParcelFee extends Model
59
58
 
60
59
  public static function onRowInsert($row)
61
60
  {
62
- $row['fee'] = Utils::numbersOnly($row['fee']);
61
+ $row['fee'] = Money::apply($row['fee'] ?? 0);
63
62
 
64
63
  return $row;
65
64
  }
66
65
 
67
- /**
68
- * Set the fee as only numbers.
69
- *
70
- * @void
71
- */
72
- public function setFeeAttribute($value)
73
- {
74
- $this->attributes['fee'] = Utils::numbersOnly($value);
75
- }
76
-
77
66
  /**
78
67
  * The length the entity belongs to.
79
68
  *
@@ -13,6 +13,7 @@ use Fleetbase\Models\Category;
13
13
  use Fleetbase\Models\File;
14
14
  use Fleetbase\Models\Model;
15
15
  use Fleetbase\Traits\HasApiModelBehavior;
16
+ use Fleetbase\Traits\HasApiModelCache;
16
17
  use Fleetbase\Traits\HasCustomFields;
17
18
  use Fleetbase\Traits\HasMetaAttributes;
18
19
  use Fleetbase\Traits\HasPublicId;
@@ -37,6 +38,7 @@ class Vehicle extends Model
37
38
  use HasPublicId;
38
39
  use TracksApiCredential;
39
40
  use HasApiModelBehavior;
41
+ use HasApiModelCache;
40
42
  use SpatialTrait;
41
43
  use Searchable;
42
44
  use HasSlug;
@@ -6,6 +6,7 @@ use Fleetbase\Casts\Json;
6
6
  use Fleetbase\FleetOps\Support\Utils;
7
7
  use Fleetbase\Models\Model;
8
8
  use Fleetbase\Traits\HasApiModelBehavior;
9
+ use Fleetbase\Traits\HasApiModelCache;
9
10
  use Fleetbase\Traits\HasCustomFields;
10
11
  use Fleetbase\Traits\HasInternalId;
11
12
  use Fleetbase\Traits\HasPublicId;
@@ -27,6 +28,7 @@ class Vendor extends Model
27
28
  use HasUuid;
28
29
  use HasPublicId;
29
30
  use HasApiModelBehavior;
31
+ use HasApiModelCache;
30
32
  use HasInternalId;
31
33
  use TracksApiCredential;
32
34
  use Searchable;
@@ -10,6 +10,7 @@ use Fleetbase\LaravelMysqlSpatial\Types\Point;
10
10
  use Fleetbase\LaravelMysqlSpatial\Types\Polygon;
11
11
  use Fleetbase\Models\Model;
12
12
  use Fleetbase\Traits\HasApiModelBehavior;
13
+ use Fleetbase\Traits\HasApiModelCache;
13
14
  use Fleetbase\Traits\HasCustomFields;
14
15
  use Fleetbase\Traits\HasPublicId;
15
16
  use Fleetbase\Traits\HasUuid;
@@ -25,6 +26,7 @@ class Zone extends Model
25
26
  use TracksApiCredential;
26
27
  use SpatialTrait;
27
28
  use HasApiModelBehavior;
29
+ use HasApiModelCache;
28
30
  use HasCustomFields;
29
31
 
30
32
  /**
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Observers;
4
4
 
5
5
  use Fleetbase\FleetOps\Models\Driver;
6
6
  use Fleetbase\FleetOps\Models\Order;
7
+ use Fleetbase\FleetOps\Support\LiveCacheService;
7
8
  use Fleetbase\LaravelMysqlSpatial\Types\Point;
8
9
  use Fleetbase\Models\User;
9
10
 
@@ -22,6 +23,26 @@ class DriverObserver
22
23
  }
23
24
  }
24
25
 
26
+ /**
27
+ * Handle the Driver "created" event.
28
+ *
29
+ * @return void
30
+ */
31
+ public function created(Driver $driver)
32
+ {
33
+ LiveCacheService::invalidate('drivers');
34
+ }
35
+
36
+ /**
37
+ * Handle the Driver "updated" event.
38
+ *
39
+ * @return void
40
+ */
41
+ public function updated(Driver $driver)
42
+ {
43
+ LiveCacheService::invalidate('drivers');
44
+ }
45
+
25
46
  /**
26
47
  * Handle the Driver "deleting" event.
27
48
  *
@@ -48,5 +69,7 @@ class DriverObserver
48
69
  if ($user && $user->hasRole('Driver')) {
49
70
  $user->delete();
50
71
  }
72
+
73
+ LiveCacheService::invalidate('drivers');
51
74
  }
52
75
  }
@@ -3,9 +3,21 @@
3
3
  namespace Fleetbase\FleetOps\Observers;
4
4
 
5
5
  use Fleetbase\FleetOps\Models\Order;
6
+ use Fleetbase\FleetOps\Support\LiveCacheService;
7
+ use Illuminate\Support\Facades\Cache;
6
8
 
7
9
  class OrderObserver
8
10
  {
11
+ /**
12
+ * Handle the Order "created" event.
13
+ *
14
+ * @return void
15
+ */
16
+ public function created(Order $order)
17
+ {
18
+ $this->invalidateCache($order);
19
+ }
20
+
9
21
  /**
10
22
  * Handle the Order "updated" event.
11
23
  *
@@ -18,6 +30,8 @@ class OrderObserver
18
30
  if ($order->wasChanged('driver_assigned_uuid')) {
19
31
  $order->notifyDriverAssigned();
20
32
  }
33
+
34
+ $this->invalidateCache($order);
21
35
  }
22
36
 
23
37
  /**
@@ -30,5 +44,22 @@ class OrderObserver
30
44
  if ($order->isIntegratedVendorOrder()) {
31
45
  $order->facilitator->provider()->callback('onDeleted', $order);
32
46
  }
47
+
48
+ $this->invalidateCache($order);
49
+ }
50
+
51
+ /**
52
+ * Invalidate relevant cache tags for live endpoints.
53
+ *
54
+ * @param Order|null $order Optional order to invalidate specific tracker cache
55
+ */
56
+ protected function invalidateCache(?Order $order = null): void
57
+ {
58
+ LiveCacheService::invalidateMultiple(['orders', 'routes', 'coordinates']);
59
+
60
+ // Invalidate order-specific tracker cache if order is provided
61
+ if ($order && $order->uuid) {
62
+ Cache::forget("order:{$order->uuid}:tracker");
63
+ }
33
64
  }
34
65
  }
@@ -3,6 +3,7 @@
3
3
  namespace Fleetbase\FleetOps\Observers;
4
4
 
5
5
  use Fleetbase\FleetOps\Models\Place;
6
+ use Fleetbase\FleetOps\Support\LiveCacheService;
6
7
 
7
8
  class PlaceObserver
8
9
  {
@@ -23,4 +24,34 @@ class PlaceObserver
23
24
  }
24
25
  }
25
26
  }
27
+
28
+ /**
29
+ * Handle the Place "created" event.
30
+ *
31
+ * @return void
32
+ */
33
+ public function created(Place $place)
34
+ {
35
+ LiveCacheService::invalidate('places');
36
+ }
37
+
38
+ /**
39
+ * Handle the Place "updated" event.
40
+ *
41
+ * @return void
42
+ */
43
+ public function updated(Place $place)
44
+ {
45
+ LiveCacheService::invalidate('places');
46
+ }
47
+
48
+ /**
49
+ * Handle the Place "deleted" event.
50
+ *
51
+ * @return void
52
+ */
53
+ public function deleted(Place $place)
54
+ {
55
+ LiveCacheService::invalidate('places');
56
+ }
26
57
  }
@@ -7,24 +7,6 @@ use Fleetbase\FleetOps\Support\Utils;
7
7
 
8
8
  class ServiceRateObserver
9
9
  {
10
- /**
11
- * Handle the ServiceRate "creating" event.
12
- *
13
- * @return void
14
- */
15
- public function creating(ServiceRate $serviceRate)
16
- {
17
- // convert these attributes to numbers only
18
- $toNumbers = ['base_fee', 'per_km_flat_rate_fee', 'peak_hours_flat_fee', 'peak_hours_percent', 'cod_flat_fee', 'cod_percent'];
19
-
20
- // convert to numbers for all attributes above
21
- foreach ($toNumbers as $attribute) {
22
- if (isset($serviceRate->{$attribute})) {
23
- $serviceRate->{$attribute} = Utils::numbersOnly($serviceRate->{$attribute});
24
- }
25
- }
26
- }
27
-
28
10
  /**
29
11
  * Handle the ServiceRate "created" event.
30
12
  *
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Observers;
4
4
 
5
5
  use Fleetbase\FleetOps\Models\Driver;
6
6
  use Fleetbase\FleetOps\Models\Vehicle;
7
+ use Fleetbase\FleetOps\Support\LiveCacheService;
7
8
 
8
9
  class VehicleObserver
9
10
  {
@@ -28,6 +29,8 @@ class VehicleObserver
28
29
  $vehicle->setRelation('driver', $driver);
29
30
  }
30
31
  }
32
+
33
+ LiveCacheService::invalidate('vehicles');
31
34
  }
32
35
 
33
36
  /**
@@ -51,6 +54,8 @@ class VehicleObserver
51
54
  $vehicle->setRelation('driver', $driver);
52
55
  }
53
56
  }
57
+
58
+ LiveCacheService::invalidate('vehicles');
54
59
  }
55
60
 
56
61
  /**
@@ -62,5 +67,7 @@ class VehicleObserver
62
67
  {
63
68
  // Unassign the deleted vehicle from matching driver/(s)
64
69
  Driver::where(['vehicle_uuid' => $vehicle->uuid])->delete();
70
+
71
+ LiveCacheService::invalidate('vehicles');
65
72
  }
66
73
  }
@@ -0,0 +1,165 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Support;
4
+
5
+ use Illuminate\Support\Facades\Cache;
6
+
7
+ /**
8
+ * Service class to manage caching for LiveController endpoints.
9
+ */
10
+ class LiveCacheService
11
+ {
12
+ /**
13
+ * Default cache TTL in seconds (30 seconds).
14
+ */
15
+ public const DEFAULT_TTL = 30;
16
+
17
+ /**
18
+ * Generate a cache key for a specific endpoint and parameters.
19
+ * Includes version number for automatic invalidation.
20
+ *
21
+ * @param string $endpoint The endpoint name (e.g., 'orders', 'drivers')
22
+ * @param array $params Request parameters to include in the key
23
+ *
24
+ * @return string The generated cache key with version
25
+ */
26
+ public static function getCacheKey(string $endpoint, array $params = []): string
27
+ {
28
+ $company = session('company');
29
+ $version = static::getVersion($endpoint);
30
+ $paramsHash = md5(json_encode($params));
31
+
32
+ return "live:{$company}:{$endpoint}:v{$version}:{$paramsHash}";
33
+ }
34
+
35
+ /**
36
+ * Get the current version number for an endpoint.
37
+ *
38
+ * @param string $endpoint The endpoint name
39
+ *
40
+ * @return int The current version number
41
+ */
42
+ public static function getVersion(string $endpoint): int
43
+ {
44
+ $company = session('company');
45
+ $versionKey = "live:{$company}:{$endpoint}:version";
46
+
47
+ return (int) Cache::get($versionKey, 0);
48
+ }
49
+
50
+ /**
51
+ * Increment the version number for an endpoint to invalidate all caches.
52
+ *
53
+ * @param string $endpoint The endpoint name
54
+ *
55
+ * @return int The new version number
56
+ */
57
+ public static function incrementVersion(string $endpoint): int
58
+ {
59
+ $company = session('company');
60
+ $versionKey = "live:{$company}:{$endpoint}:version";
61
+
62
+ return Cache::increment($versionKey);
63
+ }
64
+
65
+ /**
66
+ * Get cache tags for the current company.
67
+ *
68
+ * @return array Array of cache tags
69
+ */
70
+ public static function getTags(): array
71
+ {
72
+ $company = session('company');
73
+
74
+ return ["live:{$company}"];
75
+ }
76
+
77
+ /**
78
+ * Get cache tags for a specific endpoint.
79
+ *
80
+ * @param string $endpoint The endpoint name
81
+ *
82
+ * @return array Array of cache tags including company and endpoint
83
+ */
84
+ public static function getEndpointTags(string $endpoint): array
85
+ {
86
+ $company = session('company');
87
+
88
+ return ["live:{$company}", "live:{$company}:{$endpoint}"];
89
+ }
90
+
91
+ /**
92
+ * Invalidate cache for a specific endpoint or all live endpoints.
93
+ * Uses version increment for cache driver compatibility.
94
+ *
95
+ * @param string|null $endpoint The endpoint to invalidate, or null for all
96
+ */
97
+ public static function invalidate(?string $endpoint = null): void
98
+ {
99
+ if ($endpoint) {
100
+ // Increment version to invalidate all caches for this endpoint
101
+ static::incrementVersion($endpoint);
102
+
103
+ // Also flush tags if supported (Redis/Memcached)
104
+ try {
105
+ Cache::tags(static::getEndpointTags($endpoint))->flush();
106
+ } catch (\Exception $e) {
107
+ // Tags not supported, version increment is sufficient
108
+ }
109
+ } else {
110
+ // Invalidate all endpoints
111
+ $endpoints = ['orders', 'routes', 'coordinates', 'drivers', 'vehicles', 'places'];
112
+ foreach ($endpoints as $ep) {
113
+ static::incrementVersion($ep);
114
+ }
115
+
116
+ // Also flush tags if supported
117
+ try {
118
+ Cache::tags(static::getTags())->flush();
119
+ } catch (\Exception $e) {
120
+ // Tags not supported, version increment is sufficient
121
+ }
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Invalidate multiple endpoints at once.
127
+ *
128
+ * @param array $endpoints Array of endpoint names to invalidate
129
+ */
130
+ public static function invalidateMultiple(array $endpoints): void
131
+ {
132
+ // Increment versions for all endpoints
133
+ foreach ($endpoints as $endpoint) {
134
+ static::incrementVersion($endpoint);
135
+ }
136
+
137
+ // Also flush tags if supported
138
+ try {
139
+ foreach ($endpoints as $endpoint) {
140
+ Cache::tags(static::getEndpointTags($endpoint))->flush();
141
+ }
142
+ } catch (\Exception $e) {
143
+ // Tags not supported, version increment is sufficient
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Remember a value in cache with tags.
149
+ *
150
+ * @param string $endpoint The endpoint name
151
+ * @param array $params Request parameters
152
+ * @param \Closure $callback The callback to execute if cache miss
153
+ * @param int|null $ttl Time to live in seconds (default: 30)
154
+ *
155
+ * @return mixed The cached or freshly computed value
156
+ */
157
+ public static function remember(string $endpoint, array $params, \Closure $callback, ?int $ttl = null)
158
+ {
159
+ $cacheKey = static::getCacheKey($endpoint, $params);
160
+ $tags = static::getEndpointTags($endpoint);
161
+ $ttl = $ttl ?? static::DEFAULT_TTL;
162
+
163
+ return Cache::tags($tags)->remember($cacheKey, $ttl, $callback);
164
+ }
165
+ }