Skip to main content

Overview

The Vehicle data model is central to MotorDesk’s fleet management system. It tracks vehicle information, ownership, habitual drivers, and maintenance history through integrated mileage tracking.

TypeScript Interface

interface Vehicle {
  id: string;
  propietarioId: string;
  conductorHabitualId: string | null;
  placa: string;
  marca: string;
  modelo: string;
  anio: number;
  color: string;
  kilometrajeActual: number;
  createdAt: string;
  syncedAt: string;
  isDeleted: boolean;
}

Field Reference

id
string
required
Unique identifier for the vehicleFormat: veh-XXX where XXX is a sequential numberExample: veh-001
propietarioId
string
required
Reference to the customer who owns this vehicleType: Foreign key to Customer modelExample: cust-001Validation: Must reference an existing customer ID
conductorHabitualId
string | null
Reference to the customer who is the habitual driverType: Foreign key to Customer model (nullable)Example: cust-002 or nullNote: Can be null if no habitual driver is assigned, or can be the same as propietarioId
placa
string
required
Vehicle license plate numberFormat: Typically follows format XXX-### (3 letters, dash, 3 numbers)Example: ABC-123Validation: Must be unique across all vehicles
marca
string
required
Vehicle manufacturer/brandExample: Toyota, Hyundai, Mercedes-Benz
modelo
string
required
Vehicle model nameExample: Hilux, Tucson, Sprinter
anio
number
required
Year of manufactureType: Integer (4-digit year)Example: 2020, 2018, 2022Validation: Should be a reasonable year (e.g., 1900-current year + 1)
color
string
required
Vehicle colorExample: Blanco, Rojo, Plata
kilometrajeActual
number
required
Current odometer reading in kilometersType: Integer or floatExample: 45000, 62500Note: This value is updated with each sale/service transaction
createdAt
string
required
Timestamp when the vehicle record was createdFormat: ISO 8601 datetime stringExample: 2023-10-25T10:00:00Z
syncedAt
string
required
Timestamp of last synchronization with remote serverFormat: ISO 8601 datetime stringExample: 2023-10-25T10:01:00ZNote: Used for offline-first data synchronization
isDeleted
boolean
required
Soft delete flagDefault: falseNote: Vehicles are soft-deleted to maintain referential integrity with historical sales data

Relationships

Each vehicle must have exactly one owner, referenced by propietarioId.
// Get vehicle owner
const owner = customers.find(c => c.id === vehicle.propietarioId);
A vehicle may have an assigned habitual driver, referenced by conductorHabitualId. This field is nullable.
// Get habitual driver (if assigned)
const driver = vehicle.conductorHabitualId 
  ? customers.find(c => c.id === vehicle.conductorHabitualId)
  : null;
Vehicles have a one-to-many relationship with sales transactions. This enables maintenance history tracking.
// Get vehicle's service history
const serviceHistory = sales
  .filter(s => s.vehicleId === vehicle.id)
  .sort((a, b) => 
    new Date(b.fechaEmision).getTime() - new Date(a.fechaEmision).getTime()
  );
Vehicles can have frequently used products associated with them for quick service recommendations.
// Get vehicle's usual products
const usualProducts = vehicleUsualProducts
  .filter(vup => vup.vehicleId === vehicle.id);

Example Data

Toyota Hilux (2020)

{
  "id": "veh-001",
  "propietarioId": "cust-001",
  "conductorHabitualId": "cust-002",
  "placa": "ABC-123",
  "marca": "Toyota",
  "modelo": "Hilux",
  "anio": 2020,
  "color": "Blanco",
  "kilometrajeActual": 45000,
  "createdAt": "2023-10-25T10:00:00Z",
  "syncedAt": "2023-10-25T10:01:00Z",
  "isDeleted": false
}

Mercedes-Benz Sprinter (2022)

{
  "id": "veh-003",
  "propietarioId": "cust-004",
  "conductorHabitualId": null,
  "placa": "MNO-456",
  "marca": "Mercedes-Benz",
  "modelo": "Sprinter",
  "anio": 2022,
  "color": "Plata",
  "kilometrajeActual": 15000,
  "createdAt": "2023-10-28T09:30:00Z",
  "syncedAt": "2023-10-28T09:35:00Z",
  "isDeleted": false
}

Business Logic

Mileage Tracking

The vehicle’s current mileage is automatically updated based on the most recent sale transaction:
const getVehicleCurrentMileage = (vehicleId: string) => {
  // Find most recent sale for this vehicle
  const latestSale = sales
    .filter(s => s.vehicleId === vehicleId)
    .sort((a, b) => 
      new Date(b.fechaEmision).getTime() - new Date(a.fechaEmision).getTime()
    )[0];
  
  // Use sale's recorded mileage, or fall back to vehicle's base mileage
  return latestSale?.kilometrajeIngreso || vehicle.kilometrajeActual || 0;
};

Service Due Calculation

Calculate when the next service is due based on product maintenance intervals:
const getNextServiceDue = (vehicleId: string) => {
  const latestSale = sales
    .filter(s => s.vehicleId === vehicleId)
    .sort((a, b) => 
      new Date(b.fechaEmision).getTime() - new Date(a.fechaEmision).getTime()
    )[0];
  
  return {
    currentKm: latestSale?.kilometrajeIngreso || 0,
    nextServiceKm: latestSale?.proximoCambioKm || 0,
    kmUntilService: (latestSale?.proximoCambioKm || 0) - 
                    (latestSale?.kilometrajeIngreso || 0)
  };
};

Soft Delete Implementation

Important: Soft DeletesVehicles are never permanently deleted from the database. Instead, the isDeleted flag is set to true. This preserves referential integrity with historical sales data and allows for data recovery if needed.
const deleteVehicle = (vehicleId: string) => {
  // Soft delete - set flag instead of removing record
  vehicle.isDeleted = true;
  vehicle.syncedAt = new Date().toISOString();
};

// Filter out deleted vehicles in queries
const activeVehicles = vehicles.filter(v => !v.isDeleted);

Enhanced Vehicle Display Data

The application enriches vehicle data with related information for display:
interface EnhancedVehicle extends Vehicle {
  clienteNombre: string;           // Owner's name
  clienteDocumento: string;        // Owner's document number
  choferNombre: string;            // Driver's name
  kmActual: number;                // Latest mileage from sales
  kmProximo: number;               // Next service due at
  historial: SaleWithDetails[];    // Service history with products
}

Data Storage

Mock Data Location

/src/data/mock/vehicles.tsTypeScript export with sample vehicle data

JSON Data Location

/src/data/json/vehicles.jsonRaw JSON array of vehicle objects
  • Customers - Vehicle owners and drivers
  • Sales - Service and maintenance transactions
  • Products - Products used in vehicle maintenance

Usage Examples

Complete Vehicle Information

const getCompleteVehicleInfo = (vehicleId: string) => {
  const vehicle = vehicles.find(v => v.id === vehicleId);
  if (!vehicle || vehicle.isDeleted) return null;
  
  const owner = customers.find(c => c.id === vehicle.propietarioId);
  const driver = vehicle.conductorHabitualId
    ? customers.find(c => c.id === vehicle.conductorHabitualId)
    : null;
  
  const serviceHistory = sales
    .filter(s => s.vehicleId === vehicleId)
    .sort((a, b) => 
      new Date(b.fechaEmision).getTime() - new Date(a.fechaEmision).getTime()
    )
    .map(sale => {
      const details = saleDetails
        .filter(sd => sd.saleId === sale.id)
        .map(sd => ({
          ...sd,
          product: products.find(p => p.id === sd.productId)
        }));
      return { ...sale, items: details };
    });
  
  return {
    ...vehicle,
    owner,
    driver,
    serviceHistory
  };
};

Search Vehicles

const searchVehicles = (searchTerm: string) => {
  const term = searchTerm.toLowerCase();
  
  return vehicles
    .filter(v => !v.isDeleted)
    .filter(v => {
      const owner = customers.find(c => c.id === v.propietarioId);
      
      return (
        v.placa.toLowerCase().includes(term) ||
        v.marca.toLowerCase().includes(term) ||
        v.modelo.toLowerCase().includes(term) ||
        owner?.nombreRazonSocial.toLowerCase().includes(term)
      );
    });
};
When creating a new service transaction from the vehicle module:
const initiateServiceFromVehicle = (vehicle: Vehicle, pastSale?: Sale) => {
  // Pre-fill sale form with vehicle data
  navigate('/sales', {
    state: {
      prefillData: {
        vehicleId: vehicle.id,
        customerId: vehicle.propietarioId,
        choferId: vehicle.conductorHabitualId,
        placa: vehicle.placa,
        kilometrajeActual: vehicle.kmActual || 0,
        // If repeating past service, include products
        cartItems: pastSale?.items || [],
        kmProximo: pastSale?.proximoCambioKm || 0
      }
    }
  });
};

Build docs developers (and LLMs) love