@fleetbase/fleetops-engine 0.6.16 → 0.6.18
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/addon/components/layout/fleet-ops-sidebar.hbs +25 -0
- package/addon/templates/virtual.hbs +3 -3
- package/composer.json +3 -2
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/migrations/2025_08_11_170800_add_company_index_to_routes_table.php +21 -0
- package/server/migrations/2025_08_28_054920_create_warranties_table.php +56 -0
- package/server/migrations/2025_08_28_054921_create_telematics_table.php +60 -0
- package/server/migrations/2025_08_28_054922_create_assets_table.php +94 -0
- package/server/migrations/2025_08_28_054925_create_devices_table.php +190 -0
- package/server/migrations/2025_08_28_054926_create_device_events_table.php +99 -0
- package/server/migrations/2025_08_28_054926_create_sensors_table.php +62 -0
- package/server/migrations/2025_08_28_054927_create_parts_table.php +73 -0
- package/server/migrations/2025_08_28_054929_create_equipments_table.php +58 -0
- package/server/migrations/2025_08_28_054930_create_work_orders_table.php +85 -0
- package/server/migrations/2025_08_28_054931_create_maintenances_table.php +79 -0
- package/server/migrations/2025_08_28_082002_update_vehicles_table_telematics.php +60 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +19 -1
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +31 -8
- package/server/src/Http/Resources/v1/Order.php +111 -60
- package/server/src/Models/Asset.php +548 -0
- package/server/src/Models/Contact.php +2 -0
- package/server/src/Models/Device.php +435 -0
- package/server/src/Models/DeviceEvent.php +501 -0
- package/server/src/Models/Driver.php +2 -0
- package/server/src/Models/Entity.php +27 -50
- package/server/src/Models/Equipment.php +483 -0
- package/server/src/Models/Fleet.php +2 -0
- package/server/src/Models/FuelReport.php +2 -0
- package/server/src/Models/Issue.php +2 -0
- package/server/src/Models/Maintenance.php +549 -0
- package/server/src/Models/Order.php +32 -112
- package/server/src/Models/OrderConfig.php +8 -0
- package/server/src/Models/Part.php +502 -0
- package/server/src/Models/Payload.php +101 -20
- package/server/src/Models/Place.php +10 -4
- package/server/src/Models/Sensor.php +510 -0
- package/server/src/Models/ServiceArea.php +1 -1
- package/server/src/Models/Telematic.php +336 -0
- package/server/src/Models/Vehicle.php +45 -1
- package/server/src/Models/VehicleDevice.php +1 -1
- package/server/src/Models/Vendor.php +2 -0
- package/server/src/Models/Warranty.php +413 -0
- package/server/src/Models/Waypoint.php +2 -0
- package/server/src/Models/WorkOrder.php +532 -0
- package/server/src/Support/Utils.php +5 -0
- package/server/src/Traits/HasTrackingNumber.php +64 -10
- package/server/src/Traits/Maintainable.php +307 -0
- package/server/src/Traits/PayloadAccessors.php +126 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Traits;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Models\Maintenance;
|
|
6
|
+
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Trait Maintainable.
|
|
10
|
+
*
|
|
11
|
+
* Provides maintenance-related functionality for models that can be maintained.
|
|
12
|
+
* This trait can be used by Asset, Equipment, and other maintainable entities.
|
|
13
|
+
*/
|
|
14
|
+
trait Maintainable
|
|
15
|
+
{
|
|
16
|
+
/**
|
|
17
|
+
* Get all maintenances for this maintainable entity.
|
|
18
|
+
*/
|
|
19
|
+
public function maintenances(): MorphMany
|
|
20
|
+
{
|
|
21
|
+
return $this->morphMany(Maintenance::class, 'maintainable');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get scheduled maintenances.
|
|
26
|
+
*/
|
|
27
|
+
public function scheduledMaintenances(): MorphMany
|
|
28
|
+
{
|
|
29
|
+
return $this->maintenances()->where('status', 'scheduled');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get completed maintenances.
|
|
34
|
+
*/
|
|
35
|
+
public function completedMaintenances(): MorphMany
|
|
36
|
+
{
|
|
37
|
+
return $this->maintenances()->where('status', 'completed');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get overdue maintenances.
|
|
42
|
+
*/
|
|
43
|
+
public function overdueMaintenances(): MorphMany
|
|
44
|
+
{
|
|
45
|
+
return $this->maintenances()
|
|
46
|
+
->where('status', 'scheduled')
|
|
47
|
+
->where('scheduled_at', '<', now());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get the last completed maintenance.
|
|
52
|
+
*/
|
|
53
|
+
public function getLastMaintenanceAttribute(): ?Maintenance
|
|
54
|
+
{
|
|
55
|
+
return $this->completedMaintenances()
|
|
56
|
+
->orderBy('completed_at', 'desc')
|
|
57
|
+
->first();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get the next scheduled maintenance.
|
|
62
|
+
*/
|
|
63
|
+
public function getNextMaintenanceAttribute(): ?Maintenance
|
|
64
|
+
{
|
|
65
|
+
return $this->scheduledMaintenances()
|
|
66
|
+
->orderBy('scheduled_at', 'asc')
|
|
67
|
+
->first();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check if the entity needs maintenance.
|
|
72
|
+
*/
|
|
73
|
+
public function needsMaintenance(): bool
|
|
74
|
+
{
|
|
75
|
+
// Check if there's overdue maintenance
|
|
76
|
+
if ($this->overdueMaintenances()->exists()) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check maintenance intervals based on usage metrics
|
|
81
|
+
return $this->checkMaintenanceIntervals();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check maintenance intervals based on usage metrics.
|
|
86
|
+
*/
|
|
87
|
+
protected function checkMaintenanceIntervals(): bool
|
|
88
|
+
{
|
|
89
|
+
$lastMaintenance = $this->last_maintenance;
|
|
90
|
+
|
|
91
|
+
if (!$lastMaintenance) {
|
|
92
|
+
// If no maintenance history, check against purchase/creation date
|
|
93
|
+
$baseDate = $this->purchased_at ?? $this->created_at;
|
|
94
|
+
|
|
95
|
+
return $this->checkIntervalsSinceDate($baseDate);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Check intervals since last maintenance
|
|
99
|
+
return $this->checkIntervalsSinceDate($lastMaintenance->completed_at);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check maintenance intervals since a specific date.
|
|
104
|
+
*
|
|
105
|
+
* @param \Carbon\Carbon $date
|
|
106
|
+
*/
|
|
107
|
+
protected function checkIntervalsSinceDate($date): bool
|
|
108
|
+
{
|
|
109
|
+
$specs = $this->specs ?? [];
|
|
110
|
+
$meta = $this->meta ?? [];
|
|
111
|
+
|
|
112
|
+
// Check time-based intervals
|
|
113
|
+
$maintenanceIntervalDays = $specs['maintenance_interval_days'] ?? $meta['maintenance_interval_days'] ?? null;
|
|
114
|
+
if ($maintenanceIntervalDays && $date->diffInDays(now()) >= $maintenanceIntervalDays) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Check odometer-based intervals (for assets with odometer)
|
|
119
|
+
if (isset($this->odometer) && isset($specs['maintenance_interval_miles'])) {
|
|
120
|
+
$lastOdometer = $this->last_maintenance?->odometer ?? 0;
|
|
121
|
+
$milesSinceLastMaintenance = $this->odometer - $lastOdometer;
|
|
122
|
+
if ($milesSinceLastMaintenance >= $specs['maintenance_interval_miles']) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check engine hours-based intervals (for assets with engine hours)
|
|
128
|
+
if (isset($this->engine_hours) && isset($specs['maintenance_interval_hours'])) {
|
|
129
|
+
$lastEngineHours = $this->last_maintenance?->engine_hours ?? 0;
|
|
130
|
+
$hoursSinceLastMaintenance = $this->engine_hours - $lastEngineHours;
|
|
131
|
+
if ($hoursSinceLastMaintenance >= $specs['maintenance_interval_hours']) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Schedule maintenance for the entity.
|
|
141
|
+
*/
|
|
142
|
+
public function scheduleMaintenance(string $type, \DateTime $scheduledAt, array $details = []): Maintenance
|
|
143
|
+
{
|
|
144
|
+
return Maintenance::create([
|
|
145
|
+
'company_uuid' => $this->company_uuid,
|
|
146
|
+
'maintainable_type' => static::class,
|
|
147
|
+
'maintainable_uuid' => $this->uuid,
|
|
148
|
+
'type' => $type,
|
|
149
|
+
'status' => 'scheduled',
|
|
150
|
+
'scheduled_at' => $scheduledAt,
|
|
151
|
+
'odometer' => $this->odometer ?? null,
|
|
152
|
+
'engine_hours' => $this->engine_hours ?? null,
|
|
153
|
+
'summary' => $details['summary'] ?? null,
|
|
154
|
+
'notes' => $details['notes'] ?? null,
|
|
155
|
+
'priority' => $details['priority'] ?? 'medium',
|
|
156
|
+
'created_by_uuid' => auth()->id(),
|
|
157
|
+
]);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get maintenance cost for a specific period.
|
|
162
|
+
*/
|
|
163
|
+
public function getMaintenanceCost(int $days = 365): float
|
|
164
|
+
{
|
|
165
|
+
$startDate = now()->subDays($days);
|
|
166
|
+
|
|
167
|
+
return $this->completedMaintenances()
|
|
168
|
+
->where('completed_at', '>=', $startDate)
|
|
169
|
+
->sum('total_cost') ?? 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get maintenance frequency (maintenances per year).
|
|
174
|
+
*/
|
|
175
|
+
public function getMaintenanceFrequency(int $days = 365): float
|
|
176
|
+
{
|
|
177
|
+
$startDate = now()->subDays($days);
|
|
178
|
+
$maintenanceCount = $this->completedMaintenances()
|
|
179
|
+
->where('completed_at', '>=', $startDate)
|
|
180
|
+
->count();
|
|
181
|
+
|
|
182
|
+
return ($maintenanceCount / $days) * 365;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get average maintenance duration in hours.
|
|
187
|
+
*/
|
|
188
|
+
public function getAverageMaintenanceDuration(int $days = 365): ?float
|
|
189
|
+
{
|
|
190
|
+
$startDate = now()->subDays($days);
|
|
191
|
+
$maintenances = $this->completedMaintenances()
|
|
192
|
+
->where('completed_at', '>=', $startDate)
|
|
193
|
+
->whereNotNull('started_at')
|
|
194
|
+
->whereNotNull('completed_at')
|
|
195
|
+
->get();
|
|
196
|
+
|
|
197
|
+
if ($maintenances->isEmpty()) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
$totalHours = $maintenances->sum(function ($maintenance) {
|
|
202
|
+
return $maintenance->started_at->diffInHours($maintenance->completed_at);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
return $totalHours / $maintenances->count();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get maintenance efficiency rating.
|
|
210
|
+
*/
|
|
211
|
+
public function getMaintenanceEfficiency(int $days = 365): ?float
|
|
212
|
+
{
|
|
213
|
+
$startDate = now()->subDays($days);
|
|
214
|
+
$maintenances = $this->completedMaintenances()
|
|
215
|
+
->where('completed_at', '>=', $startDate)
|
|
216
|
+
->get();
|
|
217
|
+
|
|
218
|
+
if ($maintenances->isEmpty()) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
$onTimeCount = $maintenances->filter(function ($maintenance) {
|
|
223
|
+
return $maintenance->wasCompletedOnTime();
|
|
224
|
+
})->count();
|
|
225
|
+
|
|
226
|
+
return ($onTimeCount / $maintenances->count()) * 100;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get upcoming maintenance due dates.
|
|
231
|
+
*
|
|
232
|
+
* @return \Illuminate\Database\Eloquent\Collection
|
|
233
|
+
*/
|
|
234
|
+
public function getUpcomingMaintenance(int $days = 30)
|
|
235
|
+
{
|
|
236
|
+
$endDate = now()->addDays($days);
|
|
237
|
+
|
|
238
|
+
return $this->scheduledMaintenances()
|
|
239
|
+
->where('scheduled_at', '<=', $endDate)
|
|
240
|
+
->orderBy('scheduled_at', 'asc')
|
|
241
|
+
->get();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Create preventive maintenance schedule.
|
|
246
|
+
*/
|
|
247
|
+
public function createPreventiveMaintenanceSchedule(array $intervals = []): array
|
|
248
|
+
{
|
|
249
|
+
$schedule = [];
|
|
250
|
+
$specs = $this->specs ?? [];
|
|
251
|
+
$defaultIntervals = $specs['maintenance_intervals'] ?? [];
|
|
252
|
+
|
|
253
|
+
$intervals = array_merge($defaultIntervals, $intervals);
|
|
254
|
+
|
|
255
|
+
foreach ($intervals as $type => $interval) {
|
|
256
|
+
$lastMaintenance = $this->completedMaintenances()
|
|
257
|
+
->where('type', $type)
|
|
258
|
+
->orderBy('completed_at', 'desc')
|
|
259
|
+
->first();
|
|
260
|
+
|
|
261
|
+
$baseDate = $lastMaintenance?->completed_at ?? $this->created_at;
|
|
262
|
+
$nextDue = $baseDate->copy()->addDays($interval['days'] ?? 365);
|
|
263
|
+
|
|
264
|
+
if ($nextDue->isFuture()) {
|
|
265
|
+
$schedule[] = [
|
|
266
|
+
'type' => $type,
|
|
267
|
+
'due_date' => $nextDue,
|
|
268
|
+
'interval_days' => $interval['days'] ?? 365,
|
|
269
|
+
'priority' => $interval['priority'] ?? 'medium',
|
|
270
|
+
'description' => $interval['description'] ?? "Scheduled {$type} maintenance",
|
|
271
|
+
];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return $schedule;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Get maintenance history summary.
|
|
280
|
+
*/
|
|
281
|
+
public function getMaintenanceHistorySummary(int $days = 365): array
|
|
282
|
+
{
|
|
283
|
+
$startDate = now()->subDays($days);
|
|
284
|
+
$maintenances = $this->maintenances()
|
|
285
|
+
->where('created_at', '>=', $startDate)
|
|
286
|
+
->get();
|
|
287
|
+
|
|
288
|
+
$completed = $maintenances->where('status', 'completed');
|
|
289
|
+
$scheduled = $maintenances->where('status', 'scheduled');
|
|
290
|
+
$overdue = $scheduled->filter(function ($maintenance) {
|
|
291
|
+
return $maintenance->scheduled_at->isPast();
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
return [
|
|
295
|
+
'total_maintenances' => $maintenances->count(),
|
|
296
|
+
'completed_count' => $completed->count(),
|
|
297
|
+
'scheduled_count' => $scheduled->count(),
|
|
298
|
+
'overdue_count' => $overdue->count(),
|
|
299
|
+
'total_cost' => $completed->sum('total_cost'),
|
|
300
|
+
'average_cost' => $completed->avg('total_cost'),
|
|
301
|
+
'total_downtime_hours' => $completed->sum('duration_hours'),
|
|
302
|
+
'average_duration_hours' => $completed->avg('duration_hours'),
|
|
303
|
+
'on_time_percentage' => $this->getMaintenanceEfficiency($days),
|
|
304
|
+
'most_common_type' => $completed->groupBy('type')->sortByDesc->count()->keys()->first(),
|
|
305
|
+
];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Traits;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Models\Order;
|
|
6
|
+
use Fleetbase\FleetOps\Models\Payload;
|
|
7
|
+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
8
|
+
use Illuminate\Support\Str;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* PayloadAccessors.
|
|
12
|
+
*
|
|
13
|
+
* Drop this trait into the model that has the `payload()` relationship and a `payload_uuid` FK.
|
|
14
|
+
* It provides:
|
|
15
|
+
* - getPayload(): returns the related Payload if present (with global scopes applied)
|
|
16
|
+
* - getTrashedPayload(): returns the related Payload without global scopes (e.g., soft-deleted)
|
|
17
|
+
* - getOrder(): returns the Order associated through Payload (or null)
|
|
18
|
+
*
|
|
19
|
+
* Design notes / best practices:
|
|
20
|
+
* - Avoids unconditional eager loading; checks relation cache first via relationLoaded().
|
|
21
|
+
* - Uses the relationship query as the primary source of truth, falling back to a direct lookup by UUID.
|
|
22
|
+
* - When resolving via direct lookup, caches the relation with setRelation() to prevent repeat queries.
|
|
23
|
+
* - Keeps the “ignore global scopes” behavior in a single private helper.
|
|
24
|
+
*
|
|
25
|
+
* Assumptions:
|
|
26
|
+
* - The host model defines `public function payload(): BelongsTo`.
|
|
27
|
+
* - `payload_uuid` stores a UUID, and `Payload`’s primary key is configured for UUIDs (so `find()` works).
|
|
28
|
+
*/
|
|
29
|
+
trait PayloadAccessors
|
|
30
|
+
{
|
|
31
|
+
/**
|
|
32
|
+
* Get the associated Payload with global scopes applied.
|
|
33
|
+
*
|
|
34
|
+
* @return \App\Models\Payload|null
|
|
35
|
+
*/
|
|
36
|
+
public function getPayload(): ?Payload
|
|
37
|
+
{
|
|
38
|
+
return $this->resolvePayload(ignoreGlobalScopes: false);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get the associated Payload without global scopes (e.g., include soft-deleted).
|
|
43
|
+
*
|
|
44
|
+
* @return \App\Models\Payload|null
|
|
45
|
+
*/
|
|
46
|
+
public function getTrashedPayload(): ?Payload
|
|
47
|
+
{
|
|
48
|
+
return $this->resolvePayload(ignoreGlobalScopes: true);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Convenience accessor: get the Order via the associated Payload.
|
|
53
|
+
*
|
|
54
|
+
* @return \App\Models\Order|null
|
|
55
|
+
*/
|
|
56
|
+
public function getOrder(): ?Order
|
|
57
|
+
{
|
|
58
|
+
// Leverage PHP nullsafe operator; no extra branching needed.
|
|
59
|
+
return $this->getPayload()?->order;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Core resolver for the Payload relation.
|
|
64
|
+
*
|
|
65
|
+
* Strategy:
|
|
66
|
+
* 1) If the relation is already loaded and we are NOT ignoring global scopes, return it.
|
|
67
|
+
* 2) Otherwise, query via the relationship, optionally disabling global scopes.
|
|
68
|
+
* 3) If still not found and payload_uuid looks like a UUID, do a direct lookup on Payload,
|
|
69
|
+
* optionally disabling global scopes. If found, cache back into the relation.
|
|
70
|
+
*
|
|
71
|
+
* @param bool $ignoreGlobalScopes when true, fetch via `withoutGlobalScopes()`
|
|
72
|
+
*
|
|
73
|
+
* @return \App\Models\Payload|null
|
|
74
|
+
*/
|
|
75
|
+
protected function resolvePayload(bool $ignoreGlobalScopes = false): ?Payload
|
|
76
|
+
{
|
|
77
|
+
// (1) If relation is already loaded and we accept scoped data, return it.
|
|
78
|
+
if (!$ignoreGlobalScopes && $this->relationLoaded('payload')) {
|
|
79
|
+
$related = $this->getRelation('payload');
|
|
80
|
+
if ($related instanceof Payload) {
|
|
81
|
+
return $related;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// (2) Query through the relationship (preferred, keeps FK semantics consistent).
|
|
86
|
+
$relation = $this->payload();
|
|
87
|
+
$query = $ignoreGlobalScopes ? $relation->withoutGlobalScopes() : $relation;
|
|
88
|
+
|
|
89
|
+
/** @var \App\Models\Payload|null $payload */
|
|
90
|
+
$payload = $query->first();
|
|
91
|
+
|
|
92
|
+
if ($payload instanceof Payload) {
|
|
93
|
+
// Cache the resolved relation for subsequent access on this model instance.
|
|
94
|
+
$this->setRelation('payload', $payload);
|
|
95
|
+
|
|
96
|
+
return $payload;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// (3) Fallback: direct lookup by UUID (useful if relation is not properly hydrated).
|
|
100
|
+
$uuid = $this->payload_uuid ?? null;
|
|
101
|
+
if ($uuid && Str::isUuid($uuid)) {
|
|
102
|
+
$payloadQuery = Payload::query();
|
|
103
|
+
if ($ignoreGlobalScopes) {
|
|
104
|
+
$payloadQuery->withoutGlobalScopes();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
$payload = $payloadQuery->find($uuid); // relies on Payload PK being 'uuid'
|
|
108
|
+
|
|
109
|
+
if ($payload instanceof Payload) {
|
|
110
|
+
// Keep the relation cache consistent for this instance.
|
|
111
|
+
$this->setRelation('payload', $payload);
|
|
112
|
+
|
|
113
|
+
return $payload;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Relationship stub (documentational).
|
|
122
|
+
* Ensure your model actually defines this in the host model—not strictly required here,
|
|
123
|
+
* but included as a guide for expected signature.
|
|
124
|
+
*/
|
|
125
|
+
abstract public function payload(): BelongsTo;
|
|
126
|
+
}
|