@fleetbase/fleetops-engine 0.6.17 → 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_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 +6 -1
- 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 +2 -0
- 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/WorkOrder.php +532 -0
- package/server/src/Support/Utils.php +5 -0
- package/server/src/Traits/Maintainable.php +307 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Illuminate\Database\Migrations\Migration;
|
|
4
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
5
|
+
use Illuminate\Support\Facades\Schema;
|
|
6
|
+
|
|
7
|
+
return new class extends Migration {
|
|
8
|
+
/**
|
|
9
|
+
* Run the migrations.
|
|
10
|
+
*/
|
|
11
|
+
public function up(): void
|
|
12
|
+
{
|
|
13
|
+
Schema::create('sensors', function (Blueprint $table) {
|
|
14
|
+
$table->increments('id');
|
|
15
|
+
$table->uuid('uuid')->index();
|
|
16
|
+
$table->string('_key')->nullable()->index();
|
|
17
|
+
$table->foreignUuid('company_uuid')->constrained('companies', 'uuid')->cascadeOnDelete();
|
|
18
|
+
|
|
19
|
+
$table->string('name')->nullable()->index();
|
|
20
|
+
$table->string('slug')->nullable()->index();
|
|
21
|
+
$table->string('sensor_type')->index(); // temp, humidity, door, fuel, pressure, vibration, cargo-weight, etc.
|
|
22
|
+
$table->string('unit')->nullable(); // C, F, %, psi, kg, etc.
|
|
23
|
+
$table->float('min_threshold')->nullable();
|
|
24
|
+
$table->float('max_threshold')->nullable();
|
|
25
|
+
$table->boolean('threshold_inclusive')->default(true);
|
|
26
|
+
$table->string('type')->nullable()->index();
|
|
27
|
+
|
|
28
|
+
$table->timestamp('last_reading_at')->nullable()->index();
|
|
29
|
+
$table->string('last_value')->nullable(); // use string to store raw value
|
|
30
|
+
$table->json('calibration')->nullable(); // { offset, slope, notes }
|
|
31
|
+
$table->unsignedInteger('report_frequency_sec')->nullable();
|
|
32
|
+
|
|
33
|
+
// A sensor can belong to a device, asset, or any other entity
|
|
34
|
+
$table->string('sensorable_type')->nullable();
|
|
35
|
+
$table->uuid('sensorable_uuid')->nullable();
|
|
36
|
+
$table->index(['sensorable_type', 'sensorable_uuid']);
|
|
37
|
+
|
|
38
|
+
// Optionally coupled to a device (if it streams via a device)
|
|
39
|
+
$table->foreignUuid('device_uuid')->nullable()->constrained('devices', 'uuid')->nullOnDelete();
|
|
40
|
+
$table->foreignUuid('warranty_uuid')->nullable()->constrained('warranties', 'uuid')->nullOnDelete();
|
|
41
|
+
|
|
42
|
+
$table->json('meta')->nullable();
|
|
43
|
+
$table->foreignUuid('created_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
44
|
+
$table->foreignUuid('updated_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
45
|
+
|
|
46
|
+
$table->softDeletes();
|
|
47
|
+
$table->timestamps();
|
|
48
|
+
|
|
49
|
+
$table->index(['company_uuid', 'sensor_type']);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Reverse the migrations.
|
|
55
|
+
*/
|
|
56
|
+
public function down(): void
|
|
57
|
+
{
|
|
58
|
+
Schema::disableForeignKeyConstraints();
|
|
59
|
+
Schema::dropIfExists('sensors');
|
|
60
|
+
Schema::enableForeignKeyConstraints();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Illuminate\Database\Migrations\Migration;
|
|
4
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
5
|
+
use Illuminate\Support\Facades\Schema;
|
|
6
|
+
|
|
7
|
+
return new class extends Migration {
|
|
8
|
+
/**
|
|
9
|
+
* Run the migrations.
|
|
10
|
+
*/
|
|
11
|
+
public function up(): void
|
|
12
|
+
{
|
|
13
|
+
Schema::create('parts', function (Blueprint $table) {
|
|
14
|
+
$table->increments('id');
|
|
15
|
+
$table->uuid('uuid')->index();
|
|
16
|
+
$table->string('_key')->nullable()->index();
|
|
17
|
+
$table->foreignUuid('company_uuid')->constrained('companies', 'uuid')->cascadeOnDelete();
|
|
18
|
+
$table->foreignUuid('category_uuid')->nullable()->constrained('categories', 'uuid')->nullOnDelete();
|
|
19
|
+
|
|
20
|
+
$table->string('sku')->nullable()->index();
|
|
21
|
+
$table->string('name')->index();
|
|
22
|
+
$table->string('manufacturer')->nullable()->index();
|
|
23
|
+
$table->string('model')->nullable();
|
|
24
|
+
$table->string('serial_number')->nullable()->index();
|
|
25
|
+
$table->string('barcode')->nullable()->index();
|
|
26
|
+
$table->string('type')->nullable()->index();
|
|
27
|
+
$table->string('slug')->nullable()->index();
|
|
28
|
+
|
|
29
|
+
$table->text('description')->nullable();
|
|
30
|
+
$table->foreignUuid('vendor_uuid')->nullable()->constrained('vendors', 'uuid')->nullOnDelete();
|
|
31
|
+
|
|
32
|
+
$table->integer('quantity_on_hand')->default(0);
|
|
33
|
+
$table->decimal('unit_cost', 12, 2)->nullable();
|
|
34
|
+
$table->decimal('msrp', 12, 2)->nullable();
|
|
35
|
+
$table->integer('reorder_point')->default(5);
|
|
36
|
+
$table->integer('reorder_quantity')->default(10);
|
|
37
|
+
$table->integer('max_stock_level')->nullable();
|
|
38
|
+
$table->integer('reserved_quantity')->default(0);
|
|
39
|
+
|
|
40
|
+
$table->integer('allocated_quantity')->default(0); // -- Allocated but not used
|
|
41
|
+
$table->string('inventory_method')->default('fifo'); // -- fifo, lifo, weighted_average
|
|
42
|
+
|
|
43
|
+
// Optional default target (e.g., a part kept for a specific asset or vehicle)
|
|
44
|
+
$table->string('asset_type')->nullable();
|
|
45
|
+
$table->uuid('asset_uuid')->nullable();
|
|
46
|
+
$table->index(['asset_type', 'asset_uuid']);
|
|
47
|
+
|
|
48
|
+
$table->foreignUuid('warranty_uuid')->nullable()->constrained('warranties', 'uuid')->nullOnDelete();
|
|
49
|
+
|
|
50
|
+
$table->json('specs')->nullable();
|
|
51
|
+
$table->json('meta')->nullable();
|
|
52
|
+
|
|
53
|
+
$table->foreignUuid('created_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
54
|
+
$table->foreignUuid('updated_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
55
|
+
|
|
56
|
+
$table->timestamp('last_ordered_at')->nullable();
|
|
57
|
+
$table->softDeletes();
|
|
58
|
+
$table->timestamps();
|
|
59
|
+
|
|
60
|
+
$table->unique(['company_uuid', 'sku']);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Reverse the migrations.
|
|
66
|
+
*/
|
|
67
|
+
public function down(): void
|
|
68
|
+
{
|
|
69
|
+
Schema::disableForeignKeyConstraints();
|
|
70
|
+
Schema::dropIfExists('parts');
|
|
71
|
+
Schema::enableForeignKeyConstraints();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Illuminate\Database\Migrations\Migration;
|
|
4
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
5
|
+
use Illuminate\Support\Facades\Schema;
|
|
6
|
+
|
|
7
|
+
return new class extends Migration {
|
|
8
|
+
/**
|
|
9
|
+
* Run the migrations.
|
|
10
|
+
*/
|
|
11
|
+
public function up(): void
|
|
12
|
+
{
|
|
13
|
+
Schema::create('equipments', function (Blueprint $table) {
|
|
14
|
+
$table->increments('id');
|
|
15
|
+
$table->uuid('uuid')->index();
|
|
16
|
+
$table->string('_key')->nullable()->index();
|
|
17
|
+
$table->foreignUuid('company_uuid')->constrained('companies', 'uuid')->cascadeOnDelete();
|
|
18
|
+
$table->foreignUuid('category_uuid')->nullable()->constrained('categories', 'uuid')->nullOnDelete();
|
|
19
|
+
|
|
20
|
+
$table->string('name')->index();
|
|
21
|
+
$table->string('code')->nullable()->index();
|
|
22
|
+
$table->string('type')->nullable()->index(); // ppe, tool, accessory, fridge unit, etc.
|
|
23
|
+
$table->string('status')->default('active')->index();
|
|
24
|
+
$table->string('slug')->nullable()->index();
|
|
25
|
+
$table->string('serial_number')->nullable()->index();
|
|
26
|
+
$table->string('manufacturer')->nullable();
|
|
27
|
+
$table->string('model')->nullable();
|
|
28
|
+
|
|
29
|
+
// Can be assigned to an asset, device, driver, or facility
|
|
30
|
+
$table->string('equipable_type')->nullable();
|
|
31
|
+
$table->uuid('equipable_uuid')->nullable();
|
|
32
|
+
$table->index(['equipable_type', 'equipable_uuid']);
|
|
33
|
+
|
|
34
|
+
$table->date('purchased_at')->nullable();
|
|
35
|
+
$table->integer('purchase_price')->nullable();
|
|
36
|
+
$table->string('currency')->nullable();
|
|
37
|
+
|
|
38
|
+
$table->foreignUuid('warranty_uuid')->nullable()->constrained('warranties', 'uuid')->nullOnDelete();
|
|
39
|
+
|
|
40
|
+
$table->json('meta')->nullable();
|
|
41
|
+
$table->foreignUuid('created_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
42
|
+
$table->foreignUuid('updated_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
43
|
+
|
|
44
|
+
$table->softDeletes();
|
|
45
|
+
$table->timestamps();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Reverse the migrations.
|
|
51
|
+
*/
|
|
52
|
+
public function down(): void
|
|
53
|
+
{
|
|
54
|
+
Schema::disableForeignKeyConstraints();
|
|
55
|
+
Schema::dropIfExists('equipments');
|
|
56
|
+
Schema::enableForeignKeyConstraints();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Illuminate\Database\Migrations\Migration;
|
|
4
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
5
|
+
use Illuminate\Support\Facades\Schema;
|
|
6
|
+
|
|
7
|
+
return new class extends Migration {
|
|
8
|
+
/**
|
|
9
|
+
* Run the migrations.
|
|
10
|
+
*/
|
|
11
|
+
public function up(): void
|
|
12
|
+
{
|
|
13
|
+
Schema::create('work_orders', function (Blueprint $table) {
|
|
14
|
+
$table->increments('id');
|
|
15
|
+
$table->uuid('uuid')->index();
|
|
16
|
+
$table->string('_key')->nullable()->index();
|
|
17
|
+
$table->foreignUuid('company_uuid')->constrained('companies', 'uuid')->cascadeOnDelete();
|
|
18
|
+
$table->foreignUuid('category_uuid')->nullable()->constrained('categories', 'uuid')->nullOnDelete();
|
|
19
|
+
|
|
20
|
+
$table->string('code')->nullable()->index(); // external WO number
|
|
21
|
+
$table->string('subject')->index();
|
|
22
|
+
$table->string('status')->default('open')->index(); // open, in_progress, blocked, done, canceled
|
|
23
|
+
$table->string('priority')->nullable()->index(); // low, normal, high, critical
|
|
24
|
+
|
|
25
|
+
// What the WO is for asset, equipment, device, place, etc.
|
|
26
|
+
$table->string('target_type')->nullable();
|
|
27
|
+
$table->uuid('target_uuid')->nullable();
|
|
28
|
+
$table->index(['target_type', 'target_uuid']);
|
|
29
|
+
|
|
30
|
+
// Who it's assigned to (contact/technician/team/user/vendor)
|
|
31
|
+
$table->string('assignee_type')->nullable();
|
|
32
|
+
$table->uuid('assignee_uuid')->nullable();
|
|
33
|
+
$table->index(['assignee_type', 'assignee_uuid']);
|
|
34
|
+
|
|
35
|
+
$table->timestamp('opened_at')->nullable()->index();
|
|
36
|
+
$table->timestamp('due_at')->nullable()->index();
|
|
37
|
+
$table->timestamp('closed_at')->nullable()->index();
|
|
38
|
+
|
|
39
|
+
// -- Resource Planning
|
|
40
|
+
$table->json('required_skills')->nullable(); // -- Skills needed for work
|
|
41
|
+
$table->json('required_certifications')->nullable(); // -- Certs needed
|
|
42
|
+
$table->integer('estimated_duration_hours')->nullable();
|
|
43
|
+
$table->integer('actual_duration_hours')->nullable();
|
|
44
|
+
$table->json('resource_requirements')->nullable(); // -- Tools, parts, etc.
|
|
45
|
+
|
|
46
|
+
// -- Scheduling & Dependencies
|
|
47
|
+
$table->timestamp('earliest_start_date')->nullable();
|
|
48
|
+
$table->timestamp('latest_completion_date')->nullable();
|
|
49
|
+
$table->string('scheduling_priority')->default('normal'); // -- low, normal, high, urgent
|
|
50
|
+
$table->boolean('can_be_split')->default(false); // -- Can work be divided
|
|
51
|
+
|
|
52
|
+
// -- Cost Management
|
|
53
|
+
$table->integer('estimated_cost')->nullable();
|
|
54
|
+
$table->integer('approved_budget')->nullable();
|
|
55
|
+
$table->integer('actual_cost')->nullable();
|
|
56
|
+
$table->string('currency')->nullable();
|
|
57
|
+
$table->json('cost_breakdown')->nullable(); // -- Labor, parts, overhead
|
|
58
|
+
$table->string('cost_center')->nullable()->index();
|
|
59
|
+
$table->string('budget_code')->nullable()->index();
|
|
60
|
+
|
|
61
|
+
$table->text('instructions')->nullable();
|
|
62
|
+
$table->text('completion_notes')->nullable();
|
|
63
|
+
$table->json('checklist')->nullable(); // [{title, required, done_at}, ...]
|
|
64
|
+
$table->json('meta')->nullable();
|
|
65
|
+
|
|
66
|
+
$table->foreignUuid('created_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
67
|
+
$table->foreignUuid('updated_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
68
|
+
|
|
69
|
+
$table->softDeletes();
|
|
70
|
+
$table->timestamps();
|
|
71
|
+
|
|
72
|
+
$table->index(['company_uuid', 'status', 'priority']);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Reverse the migrations.
|
|
78
|
+
*/
|
|
79
|
+
public function down(): void
|
|
80
|
+
{
|
|
81
|
+
Schema::disableForeignKeyConstraints();
|
|
82
|
+
Schema::dropIfExists('work_orders');
|
|
83
|
+
Schema::enableForeignKeyConstraints();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Illuminate\Database\Migrations\Migration;
|
|
4
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
5
|
+
use Illuminate\Support\Facades\Schema;
|
|
6
|
+
|
|
7
|
+
return new class extends Migration {
|
|
8
|
+
/**
|
|
9
|
+
* Run the migrations.
|
|
10
|
+
*/
|
|
11
|
+
public function up(): void
|
|
12
|
+
{
|
|
13
|
+
Schema::create('maintenances', function (Blueprint $table) {
|
|
14
|
+
$table->increments('id');
|
|
15
|
+
$table->uuid('uuid')->index();
|
|
16
|
+
$table->string('_key')->nullable()->index();
|
|
17
|
+
$table->foreignUuid('company_uuid')->constrained('companies', 'uuid')->cascadeOnDelete();
|
|
18
|
+
$table->foreignUuid('category_uuid')->nullable()->constrained('categories', 'uuid')->nullOnDelete();
|
|
19
|
+
|
|
20
|
+
// Target of maintenance (usually an asset; could be equipment)
|
|
21
|
+
$table->string('maintainable_type')->nullable();
|
|
22
|
+
$table->uuid('maintainable_uuid')->nullable();
|
|
23
|
+
$table->index(['maintainable_type', 'maintainable_uuid']);
|
|
24
|
+
|
|
25
|
+
$table->foreignUuid('work_order_uuid')->nullable()->constrained('work_orders', 'uuid')->nullOnDelete();
|
|
26
|
+
|
|
27
|
+
$table->string('type')->nullable()->index(); // scheduled, unscheduled, inspection, corrective
|
|
28
|
+
$table->string('status')->default('open')->index(); // open, in_progress, done, canceled
|
|
29
|
+
$table->string('priority')->nullable()->index(); // low, normal, high, critical
|
|
30
|
+
|
|
31
|
+
$table->timestamp('scheduled_at')->nullable()->index();
|
|
32
|
+
$table->timestamp('started_at')->nullable()->index();
|
|
33
|
+
$table->timestamp('completed_at')->nullable()->index();
|
|
34
|
+
|
|
35
|
+
$table->unsignedBigInteger('odometer')->nullable();
|
|
36
|
+
$table->unsignedBigInteger('engine_hours')->nullable();
|
|
37
|
+
|
|
38
|
+
// Downtime
|
|
39
|
+
$table->integer('estimated_downtime_hours')->nullable();
|
|
40
|
+
$table->timestamp('downtime_start')->nullable();
|
|
41
|
+
$table->timestamp('downtime_end')->nullable();
|
|
42
|
+
|
|
43
|
+
// Vendor or internal performer
|
|
44
|
+
$table->string('performed_by_type')->nullable();
|
|
45
|
+
$table->uuid('performed_by_uuid')->nullable();
|
|
46
|
+
$table->index(['performed_by_type', 'performed_by_uuid']);
|
|
47
|
+
|
|
48
|
+
$table->text('summary')->nullable();
|
|
49
|
+
$table->text('notes')->nullable();
|
|
50
|
+
$table->json('line_items')->nullable(); // [{part_uuid, qty, unit_cost}, ...]
|
|
51
|
+
$table->integer('labor_cost')->nullable();
|
|
52
|
+
$table->integer('parts_cost')->nullable();
|
|
53
|
+
$table->integer('tax')->nullable();
|
|
54
|
+
$table->integer('total_cost')->nullable();
|
|
55
|
+
$table->string('currency')->nullable();
|
|
56
|
+
|
|
57
|
+
$table->json('attachments')->nullable();
|
|
58
|
+
$table->json('meta')->nullable();
|
|
59
|
+
|
|
60
|
+
$table->foreignUuid('created_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
61
|
+
$table->foreignUuid('updated_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
|
|
62
|
+
|
|
63
|
+
$table->softDeletes();
|
|
64
|
+
$table->timestamps();
|
|
65
|
+
|
|
66
|
+
$table->index(['company_uuid', 'status', 'type']);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Reverse the migrations.
|
|
72
|
+
*/
|
|
73
|
+
public function down(): void
|
|
74
|
+
{
|
|
75
|
+
Schema::disableForeignKeyConstraints();
|
|
76
|
+
Schema::dropIfExists('maintenances');
|
|
77
|
+
Schema::enableForeignKeyConstraints();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Illuminate\Database\Migrations\Migration;
|
|
4
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
5
|
+
use Illuminate\Support\Facades\Schema;
|
|
6
|
+
|
|
7
|
+
return new class extends Migration {
|
|
8
|
+
/**
|
|
9
|
+
* Run the migrations.
|
|
10
|
+
*/
|
|
11
|
+
public function up(): void
|
|
12
|
+
{
|
|
13
|
+
Schema::table('vehicles', function (Blueprint $table) {
|
|
14
|
+
$table->foreignUuid('telematic_uuid')->after('company_uuid')->nullable()->constrained('telematics', 'uuid')->nullOnDelete();
|
|
15
|
+
$table->foreignUuid('warranty_uuid')->after('telematic_uuid')->nullable()->constrained('warranties', 'uuid')->nullOnDelete();
|
|
16
|
+
$table->foreignUuid('category_uuid')->after('telematic_uuid')->nullable()->constrained('categories', 'uuid')->nullOnDelete();
|
|
17
|
+
|
|
18
|
+
// Identification
|
|
19
|
+
$table->string('serial_number')->nullable()->after('plate_number');
|
|
20
|
+
$table->string('call_sign')->nullable()->after('plate_number');
|
|
21
|
+
|
|
22
|
+
// Financial Tracking
|
|
23
|
+
$table->integer('acquisition_cost')->nullable()->after('vin_data');
|
|
24
|
+
$table->integer('current_value')->nullable()->after('vin_data');
|
|
25
|
+
$table->integer('depreciation_rate')->nullable()->after('vin_data'); // -- Annual percentage
|
|
26
|
+
$table->integer('insurance_value')->nullable()->after('vin_data');
|
|
27
|
+
$table->string('currency')->nullable()->after('vin_data');
|
|
28
|
+
$table->string('financing_status')->nullable()->index()->after('vin_data'); // -- owned, leased, financed
|
|
29
|
+
$table->timestamp('lease_expires_at')->nullable()->index()->after('slug');
|
|
30
|
+
$table->timestamp('purchased_at')->nullable()->index()->after('slug');
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Reverse the migrations.
|
|
36
|
+
*/
|
|
37
|
+
public function down(): void
|
|
38
|
+
{
|
|
39
|
+
Schema::disableForeignKeyConstraints();
|
|
40
|
+
Schema::table('vehicles', function (Blueprint $table) {
|
|
41
|
+
$table->dropForeign(['telematic_uuid']);
|
|
42
|
+
$table->dropForeign(['warranty_uuid']);
|
|
43
|
+
$table->dropForeign(['category_uuid']);
|
|
44
|
+
$table->dropColumn('telematic_uuid');
|
|
45
|
+
$table->dropColumn('warranty_uuid');
|
|
46
|
+
$table->dropColumn('category_uuid');
|
|
47
|
+
$table->dropColumn('serial_number');
|
|
48
|
+
$table->dropColumn('call_sign');
|
|
49
|
+
$table->dropColumn('acquisition_cost');
|
|
50
|
+
$table->dropColumn('current_value');
|
|
51
|
+
$table->dropColumn('depreciation_rate');
|
|
52
|
+
$table->dropColumn('insurance_value');
|
|
53
|
+
$table->dropColumn('currency');
|
|
54
|
+
$table->dropColumn('financing_status');
|
|
55
|
+
$table->dropColumn('lease_expires_at');
|
|
56
|
+
$table->dropColumn('purchased_at');
|
|
57
|
+
});
|
|
58
|
+
Schema::enableForeignKeyConstraints();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
@@ -36,6 +36,7 @@ use Illuminate\Http\Request;
|
|
|
36
36
|
use Illuminate\Http\UploadedFile;
|
|
37
37
|
use Illuminate\Support\Arr;
|
|
38
38
|
use Illuminate\Support\Carbon;
|
|
39
|
+
use Illuminate\Support\Facades\Log;
|
|
39
40
|
use Illuminate\Support\Facades\Storage;
|
|
40
41
|
use Illuminate\Support\Str;
|
|
41
42
|
use Illuminate\Validation\ValidationException;
|
|
@@ -910,7 +911,11 @@ class OrderController extends Controller
|
|
|
910
911
|
$order->save();
|
|
911
912
|
|
|
912
913
|
// trigger start event
|
|
913
|
-
|
|
914
|
+
try {
|
|
915
|
+
event(new OrderStarted($order));
|
|
916
|
+
} catch (\Exception $e) {
|
|
917
|
+
Log::debug('Unable to complete order started event', ['error' => $e->getMessage(), 'order' => $order]);
|
|
918
|
+
}
|
|
914
919
|
|
|
915
920
|
// set order as drivers current order
|
|
916
921
|
$driver->current_job_uuid = $order->uuid;
|
|
@@ -15,68 +15,119 @@ class Order extends FleetbaseResource
|
|
|
15
15
|
* Transform the resource into an array.
|
|
16
16
|
*
|
|
17
17
|
* @param \Illuminate\Http\Request $request
|
|
18
|
-
*
|
|
19
|
-
* @return array
|
|
20
18
|
*/
|
|
21
|
-
public function toArray($request)
|
|
19
|
+
public function toArray($request): array
|
|
22
20
|
{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
'
|
|
41
|
-
'
|
|
42
|
-
'
|
|
43
|
-
'
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
'
|
|
47
|
-
'
|
|
48
|
-
'
|
|
49
|
-
'
|
|
50
|
-
'
|
|
51
|
-
'
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
'
|
|
64
|
-
'
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
'
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
'
|
|
78
|
-
'
|
|
79
|
-
|
|
21
|
+
$isInternal = Http::isInternalRequest();
|
|
22
|
+
$isPublic = Http::isPublicRequest();
|
|
23
|
+
|
|
24
|
+
// Precompute expensive bits safely
|
|
25
|
+
$orderConfigPublicId = data_get($this->orderConfig, 'public_id');
|
|
26
|
+
|
|
27
|
+
// Driver / vehicle relations (prevent eager noise)
|
|
28
|
+
$driverAssignedModel = $this->driverAssigned()->without(['jobs', 'currentJob'])->first();
|
|
29
|
+
$vehicleAssignedModel = $this->vehicleAssigned()->without(['fleets', 'vendor'])->first();
|
|
30
|
+
|
|
31
|
+
// Tracker helpers (avoid calling ->tracker() twice)
|
|
32
|
+
$withTrackerData = $request->has('with_tracker_data') || !empty($this->resource->tracker_data);
|
|
33
|
+
$withEta = $request->has('with_eta') || !empty($this->resource->eta);
|
|
34
|
+
$tracker = ($withTrackerData || $withEta) ? $this->resource->tracker() : null;
|
|
35
|
+
|
|
36
|
+
return $this->withCustomFields([
|
|
37
|
+
// IDs
|
|
38
|
+
'id' => $this->when($isInternal, $this->id, $this->public_id),
|
|
39
|
+
'uuid' => $this->when($isInternal, $this->uuid),
|
|
40
|
+
'public_id' => $this->when($isInternal, $this->public_id),
|
|
41
|
+
'internal_id' => $this->internal_id,
|
|
42
|
+
|
|
43
|
+
// FKs (internal only)
|
|
44
|
+
'company_uuid' => $this->when($isInternal, $this->company_uuid),
|
|
45
|
+
'transaction_uuid' => $this->when($isInternal, $this->transaction_uuid),
|
|
46
|
+
'customer_uuid' => $this->when($isInternal, $this->customer_uuid),
|
|
47
|
+
'customer_type' => $this->when($isInternal, $this->customer_type),
|
|
48
|
+
'facilitator_uuid' => $this->when($isInternal, $this->facilitator_uuid),
|
|
49
|
+
'facilitator_type' => $this->when($isInternal, $this->facilitator_type),
|
|
50
|
+
'payload_uuid' => $this->when($isInternal, $this->payload_uuid),
|
|
51
|
+
'route_uuid' => $this->when($isInternal, $this->route_uuid),
|
|
52
|
+
'purchase_rate_uuid' => $this->when($isInternal, $this->purchase_rate_uuid),
|
|
53
|
+
'tracking_number_uuid' => $this->when($isInternal, $this->tracking_number_uuid),
|
|
54
|
+
'driver_assigned_uuid' => $this->when($isInternal, $this->driver_assigned_uuid),
|
|
55
|
+
'vehicle_assigned_uuid'=> $this->when($isInternal, $this->vehicle_assigned_uuid),
|
|
56
|
+
'service_quote_uuid' => $this->when($isInternal, $this->service_quote_uuid),
|
|
57
|
+
'has_driver_assigned' => $this->when($isInternal, $this->has_driver_assigned),
|
|
58
|
+
'is_scheduled' => $this->when($isInternal, $this->is_scheduled),
|
|
59
|
+
|
|
60
|
+
// Order config: internal gets the relation; public gets the public_id (or null)
|
|
61
|
+
'order_config_uuid' => $this->when($isInternal, $this->order_config_uuid),
|
|
62
|
+
'order_config' => $this->when(
|
|
63
|
+
$isInternal,
|
|
64
|
+
$this->whenLoaded('orderConfig', function () {
|
|
65
|
+
return $this->orderConfig;
|
|
66
|
+
}),
|
|
67
|
+
$orderConfigPublicId
|
|
68
|
+
),
|
|
69
|
+
|
|
70
|
+
// Custom field values (internal only) — the relation collection is fine for internal,
|
|
71
|
+
// public callers will not see this key at all
|
|
72
|
+
'custom_field_values' => $this->when($isInternal, $this->customFieldValues),
|
|
73
|
+
|
|
74
|
+
// Morph resources
|
|
75
|
+
'customer' => $this->setCustomerType(Resolve::resourceForMorph($this->customer_type, $this->customer_uuid)),
|
|
76
|
+
'payload' => new Payload($this->payload),
|
|
77
|
+
'facilitator' => $this->setFacilitatorType(Resolve::resourceForMorph($this->facilitator_type, $this->facilitator_uuid)),
|
|
78
|
+
|
|
79
|
+
// Assigned entities
|
|
80
|
+
'driver_assigned' => new Driver($driverAssignedModel),
|
|
81
|
+
'vehicle_assigned' => new Vehicle($vehicleAssignedModel),
|
|
82
|
+
|
|
83
|
+
// Tracking
|
|
84
|
+
'tracking_number' => new TrackingNumber($this->trackingNumber),
|
|
85
|
+
'tracking_statuses' => $this->whenLoaded('trackingStatuses', function () {
|
|
86
|
+
return TrackingStatus::collection($this->trackingStatuses);
|
|
87
|
+
}),
|
|
88
|
+
'tracking' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->tracking_number : null),
|
|
89
|
+
'barcode' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->barcode : null),
|
|
90
|
+
'qr_code' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->qr_code : null),
|
|
91
|
+
|
|
92
|
+
// Comments & files (internal gets raw; public gets resource collections)
|
|
93
|
+
'comments' => $this->when($isInternal, Comment::collection($this->comments)),
|
|
94
|
+
'files' => $this->when($isInternal, $this->files, File::collection($this->files)),
|
|
95
|
+
|
|
96
|
+
// Pricing / notes
|
|
97
|
+
'purchase_rate' => new PurchaseRate($this->purchaseRate),
|
|
98
|
+
'notes' => $this->notes,
|
|
99
|
+
|
|
100
|
+
// Expose only keys list publicly
|
|
101
|
+
'custom_fields' => $this->when($isPublic, function () {
|
|
102
|
+
return $this->getCustomFieldKeys();
|
|
103
|
+
}),
|
|
104
|
+
|
|
105
|
+
// Basic attrs
|
|
106
|
+
'type' => $this->type,
|
|
107
|
+
'status' => $this->status,
|
|
108
|
+
'pod_method' => $this->pod_method,
|
|
109
|
+
'pod_required' => (bool) data_get($this, 'pod_required', false),
|
|
110
|
+
'dispatched' => (bool) data_get($this, 'dispatched', false),
|
|
111
|
+
'adhoc' => (bool) data_get($this, 'adhoc', false),
|
|
112
|
+
'adhoc_distance' => (int) $this->getAdhocDistance(),
|
|
113
|
+
'distance' => (int) $this->distance,
|
|
114
|
+
'time' => (int) $this->time,
|
|
115
|
+
|
|
116
|
+
// Tracker derived data (computed only when requested/present)
|
|
117
|
+
'tracker_data' => $this->when($withTrackerData, function () use ($tracker) {
|
|
118
|
+
return $this->resource->tracker_data ?? ($tracker ? $tracker->toArray() : null);
|
|
119
|
+
}),
|
|
120
|
+
'eta' => $this->when($withEta, function () use ($tracker) {
|
|
121
|
+
return $this->resource->eta ?? ($tracker ? $tracker->eta() : null);
|
|
122
|
+
}),
|
|
123
|
+
|
|
124
|
+
'meta' => data_get($this, 'meta', Utils::createObject()),
|
|
125
|
+
'dispatched_at' => $this->dispatched_at,
|
|
126
|
+
'started_at' => $this->started_at,
|
|
127
|
+
'scheduled_at' => $this->scheduled_at,
|
|
128
|
+
'updated_at' => $this->updated_at,
|
|
129
|
+
'created_at' => $this->created_at,
|
|
130
|
+
]);
|
|
80
131
|
}
|
|
81
132
|
|
|
82
133
|
/**
|