Skip to content
View in the app

A better way to browse. Learn more.

DoniaWeB

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
     

Vehicle Management System - Complete Implementation Guide

Vehicle Management System for Ultimate POS

This comprehensive guide covers the complete implementation of a Vehicle Management system in Ultimate POS with Laravel, including CRUD operations, transaction integration, and reporting capabilities.

Overview

The Vehicle Management system provides:

  • Complete CRUD operations for vehicles

  • Detailed vehicle information tracking (model, license, insurance, etc.)

  • Vehicle assignment to sales and purchase transactions

  • Comprehensive vehicle reports and analytics

  • Excel export functionality

  • Multi-business support with data isolation

  • Permission-based access control

Screenshots

  • Vehicle Index Page

Vehicle Index Page

  • Vehicle Create Modal

Vehicle Create Modal

  • Vehicle Edit Modal

Vehicle Edit Modal

  • Vehicle View Modal

Vehicle View Modal

  • Vehicle Load Reports

vehicle transactions and loads

  • Sell list

vehicle in sells list index

  • Sell create page

vehicle in sells create page

  • POS create page

vehicle in POS create page

Download Template for Phase 1

vehicle-management-system-all-files.zip


Database Setup

Single Comprehensive Migration

File: database/migrations/2025_09_29_180000_create_vehicle_management_system.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // Create vehicles table with all fields
        Schema::create('vehicles', function (Blueprint $table) {
            $table->id();
            $table->integer('business_id')->unsigned();
            $table->foreign('business_id')->references('id')->on('business')->onDelete('cascade');

            // Basic Information
            $table->string('vehicle_number')->unique();
            $table->string('driver_name');
            $table->string('vehicle_type');
            $table->enum('status', ['active', 'inactive'])->default('active');

            // Vehicle Details
            $table->string('vehicle_model')->nullable();
            $table->string('license_plate')->nullable();
            $table->string('vin_number')->nullable();
            $table->year('year')->nullable();
            $table->string('color')->nullable();
            $table->string('fuel_type')->nullable();
            $table->string('engine_capacity')->nullable();

            // Operational Data
            $table->decimal('current_mileage', 10, 2)->nullable();
            $table->date('purchase_date')->nullable();
            $table->decimal('purchase_price', 22, 4)->nullable();
            $table->date('insurance_expiry')->nullable();
            $table->date('registration_expiry')->nullable();
            $table->date('last_service_date')->nullable();
            $table->date('next_service_due')->nullable();

            // Performance Tracking
            $table->decimal('fuel_efficiency', 8, 2)->nullable()->comment('L/100km');
            $table->decimal('max_load_capacity', 10, 2)->nullable()->comment('in tons');
            $table->decimal('daily_rate', 22, 4)->nullable();
            $table->decimal('cost_per_km', 22, 4)->nullable();

            // Contact & Assignment
            $table->string('driver_phone')->nullable();
            $table->string('driver_license')->nullable();
            $table->string('assigned_route')->nullable();
            $table->string('home_location')->nullable();

            // System Fields
            $table->integer('created_by')->unsigned();
            $table->timestamps();
            $table->softDeletes();

            // Indexes
            $table->index('business_id');
            $table->index('status');
            $table->index('vehicle_type');
        });

        // Add vehicle_id to transactions table
        Schema::table('transactions', function (Blueprint $table) {
            $table->unsignedBigInteger('vehicle_id')->nullable()->after('business_id');
            $table->foreign('vehicle_id')
                  ->references('id')
                  ->on('vehicles')
                  ->onDelete('set null');
            $table->index('vehicle_id');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // Remove vehicle_id from transactions table
        Schema::table('transactions', function (Blueprint $table) {
            $table->dropForeign(['vehicle_id']);
            $table->dropIndex(['vehicle_id']);
            $table->dropColumn('vehicle_id');
        });

        // Drop vehicles table
        Schema::dropIfExists('vehicles');
    }
};

Run Migration:

# Run the migration
php artisan migrate

# Or run specific file
php artisan migrate --path=database/migrations/2025_09_29_180000_create_vehicle_management_system.php

Why Single Migration Approach:

  •  Simple: Everything in one file

  •  Complete: Full table structure from the start

  •  Clean: No dependency management needed

  •  Fast: One-step deployment

  •  Easy Rollback: Single rollback removes everything cleanly

What This Creates:

  • Complete vehicles table with all 28 fields

  • vehicle_id link to transactions table

  • Proper indexes for performance

  • Foreign key with SET NULL on delete

  • Soft deletes support

  • Business-level data isolation

Migration Management

To check migration status:

php artisan migrate:status | grep vehicle

To rollback the migration:

# Rollback the vehicle management system
php artisan migrate:rollback --step=1

To rollback and re-run:

php artisan migrate:refresh --step=1

Current Migration File:

  • 2025_09_29_180000_create_vehicle_management_system.php - Complete vehicle management system


Model Implementation

File: app/Vehicle.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Vehicle extends Model
{
    use SoftDeletes;

    protected $guarded = ['id'];

    protected $fillable = [
        'vehicle_number', 'driver_name', 'vehicle_type', 'status', 'business_id', 'created_by',
        // Vehicle Details
        'vehicle_model', 'license_plate', 'vin_number', 'year', 'color', 'fuel_type', 'engine_capacity',
        // Operational Data
        'current_mileage', 'purchase_date', 'purchase_price', 'insurance_expiry', 'registration_expiry',
        'last_service_date', 'next_service_due',
        // Performance Tracking
        'fuel_efficiency', 'max_load_capacity', 'daily_rate', 'cost_per_km',
        // Contact & Assignment
        'driver_phone', 'driver_license', 'assigned_route', 'home_location'
    ];

    protected $casts = [
        'purchase_date' => 'date',
        'insurance_expiry' => 'date',
        'registration_expiry' => 'date',
        'last_service_date' => 'date',
        'next_service_due' => 'date',
        'current_mileage' => 'decimal:2',
        'purchase_price' => 'decimal:2',
        'fuel_efficiency' => 'decimal:2',
        'max_load_capacity' => 'decimal:2',
        'daily_rate' => 'decimal:2',
        'cost_per_km' => 'decimal:2',
    ];

    /**
     * Get vehicles for dropdown
     */
    public static function forDropdown($business_id, $show_none = false)
    {
        $vehicles = Vehicle::where('business_id', $business_id)
            ->where('status', 'active')
            ->orderBy('vehicle_number', 'asc')
            ->pluck('vehicle_number', 'id');

        if ($show_none) {
            $vehicles->prepend(__('lang_v1.none'), '');
        }

        return $vehicles;
    }

    /**
     * Accessor: Display name
     */
    public function getDisplayNameAttribute()
    {
        return $this->vehicle_number . ' (' . $this->driver_name . ')';
    }

    /**
     * Accessor: Full details
     */
    public function getFullDetailsAttribute()
    {
        $details = $this->vehicle_number;
        if ($this->vehicle_model) {
            $details .= ' - ' . $this->vehicle_model;
        }
        if ($this->license_plate) {
            $details .= ' (' . $this->license_plate . ')';
        }
        return $details;
    }

    /**
     * Scopes for filtering
     */
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    public function scopeByFuelType($query, $fuel_type)
    {
        return $query->where('fuel_type', $fuel_type);
    }

    public function scopeInsuranceExpiringSoon($query, $days = 30)
    {
        return $query->whereDate('insurance_expiry', '<=', now()->addDays($days))
                    ->whereDate('insurance_expiry', '>=', now());
    }
}

Controller Implementation

File: app/Http/Controllers/VehicleController.php

The controller includes:

  • Index with DataTables

  • Create/Store methods

  • Edit/Update methods

  • Delete (soft delete)

  • Show (detail view)

  • Reports method

  • Excel export

See docs/Vehicle-Management-System/files/VehicleController.php for complete code.


View Templates

All view files are located in resources/views/vehicle/:

1. Index Page (index.blade.php)

  • Lists all vehicles in DataTable

  • Search and filter functionality

  • Action buttons (Edit, Delete, View)

2. Create Modal (create.blade.php)

  • Full vehicle form with all fields

  • Validation

  • Ajax submission

3. Edit Modal (edit.blade.php)

  • Pre-populated form

  • Update functionality

4. Show Page (show.blade.php)

  • Detailed vehicle information

  • Related transactions

5. Reports Page (reports.blade.php)

  • Vehicle analytics

  • Transaction history

  • Excel export

All view files are available in docs/Vehicle-Management-System/files/vehicle/


Transaction Integration

Sales (POS) Integration

1. Add vehicle selection to POS create form:

Edit resources/views/sale_pos/partials/pos_form.blade.php:

<!-- Vehicle Selection -->
<div class="col-md-4 col-sm-6">
    <div class="form-group">
        <label>@lang('lang_v1.vehicle'):</label>
        <div class="input-group">
            <span class="input-group-addon">
                <i class="fa fa-car"></i>
            </span>
            {!! Form::select('vehicle_id', $vehicles, null, [
                'class' => 'form-control select2',
                'id' => 'vehicle_id',
                'placeholder' => __('lang_v1.select_vehicle')
            ]) !!}
        </div>
    </div>
</div>

2. Add vehicle selection to POS edit form:

Edit resources/views/sale_pos/partials/pos_form_edit.blade.php:

<!-- Vehicle Selection Row -->
<div class="row">
    <div class="col-md-4 col-sm-6">
        <div class="form-group">
            <label>@lang('lang_v1.vehicle'):</label>
            <div class="input-group">
                <span class="input-group-addon">
                    <i class="fa fa-car"></i>
                </span>
                {!! Form::select('vehicle_id', $vehicles, $transaction->vehicle_id, [
                    'class' => 'form-control select2',
                    'id' => 'vehicle_id',
                    'placeholder' => __('lang_v1.select_vehicle')
                ]) !!}
            </div>
        </div>
    </div>
</div>

3. Update SellPosController:

In app/Http/Controllers/SellPosController.php:

// In create() method - add vehicles to view
$vehicles = \App\Vehicle::forDropdown($business_id, true);
return view('sale_pos.create')
    ->with(compact(..., 'vehicles'));

// In edit() method - add vehicles to view
$vehicles = \App\Vehicle::forDropdown($business_id, true);
return view('sale_pos.edit')
    ->with(compact(..., 'vehicles'));

// In store() method - save vehicle_id
$input['vehicle_id'] = $request->has('vehicle_id') && !empty($request->input('vehicle_id'))
    ? $request->input('vehicle_id') : null;

// In update() method - save vehicle_id
$input['vehicle_id'] = $request->has('vehicle_id') && !empty($request->input('vehicle_id'))
    ? $request->input('vehicle_id') : null;

4. Update TransactionUtil:

In app/Utils/TransactionUtil.php, add to updateSellTransaction() method:

$update_date = [
    // ... existing fields
    'vehicle_id' => ! empty($input['vehicle_id']) ? $input['vehicle_id'] : null,
    // ... rest of fields
];

Purchase Integration

1. Add vehicle selection to purchase create form:

Edit resources/views/purchase/partials/purchase_entry_row.blade.php or main purchase form:

<div class="col-sm-4">
    <div class="form-group">
        {!! Form::label('vehicle_id', __('lang_v1.vehicle') . ':') !!}
        <div class="input-group">
            <span class="input-group-addon">
                <i class="fa fa-car"></i>
            </span>
            {!! Form::select('vehicle_id', $vehicles, null, [
                'class' => 'form-control select2',
                'placeholder' => __('lang_v1.select_vehicle')
            ]) !!}
        </div>
    </div>
</div>

2. Update PurchaseController:

Follow similar pattern as SellPosController to add vehicles to create/edit methods.


Reporting System

Export Class

File: app/Exports/VehicleReportsExport.php

Handles Excel export of vehicle transaction reports using Laravel Excel.

Report Views

1. Main Reports Page:

  • Filter by date range

  • Filter by vehicle

  • Transaction type filter (sales/purchases/both)

  • Summary statistics

2. PDF Export: Partial template at resources/views/vehicle/partials/pdf_export.blade.php


Menu & Permissions

Add Menu Item

Edit app/Http/Middleware/AdminSidebarMenu.php:

// Vehicles menu (add before Settings Dropdown)
if (auth()->user()->can('vehicle.view')) {
    $menu->url(action([\App\Http\Controllers\VehicleController::class, 'index']),
        __('lang_v1.vehicles'), [
        'icon' => '<svg aria-hidden="true" class="tw-size-5 tw-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none">
            <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
            <path d="M7 17m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path>
            <path d="M17 17m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path>
            <path d="M5 17h-2v-11a1 1 0 0 1 1 -1h9v12m-4 0h6m-6 -9h8l2 3v6"></path>
        </svg>',
        'active' => request()->segment(1) == 'vehicles'
    ])->order(85);
}

Add Permissions

Run SQL or add to seeder:

INSERT INTO permissions (name, guard_name, created_at, updated_at) VALUES
('vehicle.view', 'web', NOW(), NOW()),
('vehicle.create', 'web', NOW(), NOW()),
('vehicle.update', 'web', NOW(), NOW()),
('vehicle.delete', 'web', NOW(), NOW());

-- Assign to Admin role (adjust role_id as needed)
INSERT INTO role_has_permissions (permission_id, role_id)
SELECT id, 1 FROM permissions WHERE name LIKE 'vehicle.%';

Add Routes

Edit routes/web.php:

Route::resource('vehicles', 'VehicleController');
Route::get('vehicles-reports', 'VehicleController@reports');
Route::get('vehicles-reports/export', 'VehicleController@exportReport');

Language Keys

Add to resources/lang/en/lang_v1.php:

// Vehicles
'vehicles' => 'Vehicles',
'vehicle' => 'Vehicle',
'select_vehicle' => 'Select Vehicle',
'vehicle_help' => 'Optional: Assign a vehicle to this transaction',
'manage_your_vehicles' => 'Manage your vehicles',
'all_your_vehicles' => 'All Your Vehicles',
'add_vehicle' => 'Add Vehicle',
'edit_vehicle' => 'Edit Vehicle',
'vehicle_details' => 'Vehicle Details',
'vehicle_number' => 'Vehicle Number',
'driver_name' => 'Driver Name',
'driver_phone' => 'Driver Phone',
'driver_license' => 'Driver License',
'vehicle_type' => 'Vehicle Type',
'vehicle_model' => 'Vehicle Model',
'license_plate' => 'License Plate',
'vin_number' => 'VIN Number',
'fuel_type' => 'Fuel Type',
'engine_capacity' => 'Engine Capacity',
'current_mileage' => 'Current Mileage',
'purchase_price' => 'Purchase Price',
'insurance_expiry' => 'Insurance Expiry',
'registration_expiry' => 'Registration Expiry',
'last_service_date' => 'Last Service Date',
'next_service_due' => 'Next Service Due',
'fuel_efficiency' => 'Fuel Efficiency (L/100km)',
'max_load_capacity' => 'Max Load Capacity',
'daily_rate' => 'Daily Rate',
'cost_per_km' => 'Cost Per KM',
'assigned_route' => 'Assigned Route',
'home_location' => 'Home Location',
'vehicle_added_success' => 'Vehicle added successfully',
'vehicle_updated_success' => 'Vehicle updated successfully',
'vehicle_deleted_success' => 'Vehicle deleted successfully',
'vehicle_reports' => 'Vehicle Reports',
'vehicle_transactions' => 'Vehicle Transactions',
'no_vehicle_assigned' => 'No Vehicle Assigned',

Complete File Package

All implementation files are available in the files directory:

Structure:

docs/Vehicle-Management-System/files/
├── Vehicle.php                          # Model
├── VehicleController.php                # Controller
├── VehicleReportsExport.php            # Excel Export
├── migrations/
│   ├── 2025_09_29_180000_create_vehicle_management_system.php
│   └── create_vehicle_management_system.php  # Alternative version
└── vehicle/                             # Views
    ├── index.blade.php
    ├── create.blade.php
    ├── edit.blade.php
    ├── show.blade.php
    ├── reports.blade.php
    └── partials/
        └── pdf_export.blade.php

Installation Steps

  1. Copy Model:

    cp files/Vehicle.php app/
    
  2. Copy Controller:

    cp files/VehicleController.php app/Http/Controllers/
    
  3. Copy Export:

    cp files/VehicleReportsExport.php app/Exports/
    
  4. Copy Views:

    cp -r files/vehicle resources/views/
    
  5. Copy Migration:

    cp files/migrations/2025_09_29_180000_create_vehicle_management_system.php database/migrations/
    
  6. Run Migration:

    php artisan migrate
    
  7. Add Routes, Menu, Permissions (see sections above)


Features Summary

Complete CRUD Operations

  • Create vehicles with comprehensive details

  • Edit existing vehicles

  • View individual vehicle details

  • Soft delete vehicles

  • Status management (active/inactive)

Transaction Integration

  • Assign vehicles to sales transactions

  • Assign vehicles to purchase transactions

  • Track vehicle usage across all transactions

  • Filter transactions by vehicle

Advanced Reporting

  • Vehicle transaction history

  • Sales and purchase summaries by vehicle

  • Date range filtering

  • Excel export functionality

  • Performance metrics

Business Features

  • Multi-business support

  • Permission-based access control

  • Business-level data isolation

  • Soft deletes for data integrity

  • Audit trail (created_by tracking)

User Experience

  • DataTables with server-side processing

  • Ajax-powered modals

  • Select2 dropdowns

  • Responsive design

  • Consistent with Ultimate POS UI


Testing

Sample Data

INSERT INTO vehicles (vehicle_number, driver_name, vehicle_type, vehicle_model, license_plate, status, business_id, created_by, created_at, updated_at) VALUES
('TRK-001', 'John Smith', 'Truck', 'Ford F-150', 'ABC-1234', 'active', 1, 1, NOW(), NOW()),
('VAN-002', 'Mike Johnson', 'Van', 'Mercedes Sprinter', 'XYZ-5678', 'active', 1, 1, NOW(), NOW()),
('TRK-003', 'David Wilson', 'Heavy Truck', 'Volvo FH16', 'DEF-9012', 'active', 1, 1, NOW(), NOW());

Test Checklist

  •  Create new vehicle

  •  Edit vehicle details

  •  Delete vehicle (soft delete)

  •  View vehicle details

  •  Assign vehicle to sale

  •  Assign vehicle to purchase

  •  Filter by vehicle in reports

  •  Export vehicle report to Excel

  •  Check permissions (view/create/edit/delete)

  •  Test multi-business isolation


Troubleshooting

Common Issues

1. Vehicle not showing in dropdown:

  • Check vehicle status is 'active'

  • Verify business_id matches current business

  • Clear cache: php artisan cache:clear

2. Migration errors:

  • Ensure transactions table exists first

  • Check foreign key constraints

  • Verify business table exists for foreign key reference

3. Permission denied:

  • Verify permissions are seeded

  • Check role assignments

  • Clear permission cache: php artisan permission:cache-reset

4. Table already exists error: If you get "table vehicles already exists" error:

# Check current status
php artisan migrate:status | grep vehicle

# If needed, rollback and start fresh
php artisan migrate:rollback --step=1
php artisan migrate

5. Foreign key constraint errors:

# Make sure transactions table exists
mysql -u username -p database_name -e "SHOW TABLES LIKE 'transactions';"

# If vehicle_id column exists but causing issues
mysql -u username -p database_name -e "SHOW COLUMNS FROM transactions WHERE Field='vehicle_id';"

# Manual cleanup if needed (use with caution)
mysql -u username -p database_name -e "ALTER TABLE transactions DROP FOREIGN KEY transactions_vehicle_id_foreign;"
mysql -u username -p database_name -e "ALTER TABLE transactions DROP COLUMN vehicle_id;"

6. Migration partially applied: If migration fails midway:

# Check what exists
php artisan migrate:status | grep vehicle
mysql -u username -p database_name -e "SHOW TABLES LIKE 'vehicles';"

# Force rollback
php artisan migrate:rollback --step=1 --force

# Or manual cleanup
mysql -u username -p database_name -e "DROP TABLE IF EXISTS vehicles;"
mysql -u username -p database_name -e "ALTER TABLE transactions DROP COLUMN IF EXISTS vehicle_id;"

# Delete migration record
mysql -u username -p database_name -e "DELETE FROM migrations WHERE migration LIKE '%vehicle%';"

# Run again
php artisan migrate

Compatible with: Ultimate POS 6.x+ Laravel Version: 9.x / 10.x

0 Comments

Recommended Comments

There are no comments to display.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Add a comment...

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.