Skip to main content
The customer and equipment modules form the foundation of ElectroFix AI’s service management. Customers own equipment, equipment requires service, and service orders track repair history.

Customer Management

Customer Structure

Each customer record contains essential contact information:
protected $fillable = [
    'company_id',
    'name',
    'email',
    'phone',
    'address',
];
See: app/Models/Customer.php:14-20

Creating Customers

Workers and admins create customers through the interface:
Customer::create([
    'company_id' => $user->company_id,
    'name' => 'María González',
    'email' => '[email protected]',
    'phone' => '+52 33 1234 5678',
    'address' => 'Av. Revolución 123, Guadalajara',
]);
See: app/Http/Controllers/Worker/CustomerController.php:36-44

Validation Rules

From app/Http/Requests/StoreCustomerRequest.php:14-22:
FieldTypeRules
namestringRequired, max 255 chars
emailstringRequired, valid email, max 255
phonestringOptional, max 50 chars
addressstringOptional, max 255 chars
Authorization: Workers, admins, and developers can create customers. Find customers by name, email, or phone:
if ($search = trim($request->query('search'))) {
    $query->where(function ($q) use ($search) {
        $q->where('name', 'like', "%{$search}%")
            ->orWhere('email', 'like', "%{$search}%")
            ->orWhere('phone', 'like', "%{$search}%");
    });
}
See: app/Http/Controllers/Worker/CustomerController.php:21-27

Customer Display Name

Billing documents show appropriate customer names:
public function customerDisplayName(): string
{
    if ($this->customer_mode === 'walk_in') {
        return $this->walk_in_name ?: 'Cliente de Mostrador';
    }
    
    return $this->customer?->name ?: 'Cliente no disponible';
}
See: app/Models/BillingDocument.php:63-70

Equipment Management

Equipment Structure

Equipment records track devices requiring service:
protected $fillable = [
    'company_id',
    'customer_id',
    'type',           // e.g., "Refrigerador", "Lavadora"
    'brand',          // e.g., "Samsung", "LG"
    'model',          // e.g., "RT38K5930SL"
    'serial_number',  // Optional unique identifier
];
See: app/Models/Equipment.php:16-23

Creating Equipment

Link equipment to existing customers:
$customer = Customer::findOrFail($request->integer('customer_id'));

if ($customer->company_id !== $user->company_id) {
    abort(403, 'Customer does not belong to your company.');
}

Equipment::create([
    'company_id' => $customer->company_id,
    'customer_id' => $customer->id,
    'type' => 'Refrigerador',
    'brand' => 'Samsung',
    'model' => 'RT38K5930SL',
    'serial_number' => 'A1B2C3D4',
]);
See: app/Http/Controllers/Worker/EquipmentController.php:44-58

Validation Rules

From app/Http/Requests/StoreEquipmentRequest.php:14-23:
FieldTypeRules
customer_idintegerRequired, must exist
typestringRequired, max 100 chars
brandstringRequired, max 100 chars
modelstringOptional, max 150 chars
serial_numberstringOptional, max 150 chars

By Brand

where('brand', 'like', "%Samsung%")

By Model

where('model', 'like', "%RT38K%")

By Type

where('type', 'like', "%Refri%")
Also searches by customer name:
$equipments->where(function ($q) use ($search) {
    $q->where('brand', 'like', "%{$search}%")
        ->orWhere('model', 'like', "%{$search}%")
        ->orWhere('type', 'like', "%{$search}%")
        ->orWhereHas('customer', function ($cq) use ($search) {
            $cq->where('name', 'like', "%{$search}%");
        });
});
See: app/Http/Controllers/Worker/EquipmentController.php:25-34

Service History

Customer Service History

Customers maintain relationships with all their service orders:
public function orders(): HasMany
{
    return $this->hasMany(Order::class);
}
Example query for customer history:
$customer = Customer::with([
    'orders' => function ($query) {
        $query->latest()->limit(10);
    },
    'orders.equipment'
])->find($customerId);

Equipment Service History

Equipment tracks all repairs performed:
public function orders(): HasMany
{
    return $this->hasMany(Order::class);
}
Example query for equipment history:
$equipment = Equipment::with([
    'orders' => function ($query) {
        $query->orderByDesc('created_at');
    }
])->find($equipmentId);

foreach ($equipment->orders as $order) {
    echo $order->symptoms;
    echo $order->status;
    echo $order->created_at;
}
See: app/Models/Equipment.php:35-38

Billing History

Customers link to all billing documents:
public function billingDocuments(): HasMany
{
    return $this->hasMany(BillingDocument::class);
}
Retrieve customer’s invoices:
$invoices = BillingDocument::query()
    ->where('customer_id', $customer->id)
    ->where('document_type', 'invoice')
    ->with('items')
    ->latest()
    ->get();
See: app/Models/Customer.php:37-40

Relations

Customer Relations

public function company(): BelongsTo
{
    return $this->belongsTo(Company::class);
}

public function equipments(): HasMany
{
    return $this->hasMany(Equipment::class);
}

public function orders(): HasMany
{
    return $this->hasMany(Order::class);
}

public function billingDocuments(): HasMany
{
    return $this->hasMany(BillingDocument::class);
}
Relationship hierarchy:
  • Company → Customers (one-to-many)
  • Customer → Equipment (one-to-many)
  • Customer → Orders (one-to-many)
  • Customer → Billing Documents (one-to-many)
See: app/Models/Customer.php:22-40

Equipment Relations

public function company(): BelongsTo
{
    return $this->belongsTo(Company::class);
}

public function customer(): BelongsTo
{
    return $this->belongsTo(Customer::class);
}

public function orders(): HasMany
{
    return $this->hasMany(Order::class);
}
Relationship hierarchy:
  • Company → Equipment (one-to-many)
  • Customer → Equipment (one-to-many)
  • Equipment → Orders (one-to-many)
See: app/Models/Equipment.php:25-38

Business Rules

Cross-Company Restrictions

Users can only view and manage customers from their own company:
if ($request->user()->role !== 'developer') {
    $query->where('company_id', $request->user()->company_id);
}
Developers can access all companies.
When creating equipment, customer must belong to user’s company:
if ($request->user()->role !== 'developer' && 
    $customer->company_id !== $request->user()->company_id) {
    abort(403, 'Customer does not belong to your company.');
}
Customer and equipment must belong to same company:
if ($customer->company_id !== $equipment->company_id) {
    abort(422, 'Customer and equipment must belong to same company.');
}
See: app/Services/OrderCreationService.php:28-30

Data Display

Customer List View

Typical customer listing:
$customers = Customer::query()
    ->where('company_id', $user->company_id)
    ->orderByDesc('created_at')
    ->paginate(20);

Equipment with Customer

Show equipment with owner information:
$equipments = Equipment::query()
    ->with('customer')
    ->where('company_id', $user->company_id)
    ->orderByDesc('created_at')
    ->paginate(18);

foreach ($equipments as $equipment) {
    echo $equipment->brand . ' ' . $equipment->model;
    echo 'Owner: ' . $equipment->customer->name;
}
See: app/Http/Controllers/Worker/EquipmentController.php:16-22

Order Context Loading

When displaying orders, load related customer and equipment:
$orders = Order::query()
    ->with(['customer', 'equipment'])
    ->where('company_id', $companyId)
    ->orderByDesc('created_at')
    ->get();

foreach ($orders as $order) {
    echo 'Customer: ' . $order->customer->name;
    echo 'Equipment: ' . $order->equipment->brand . ' ' . $order->equipment->model;
    echo 'Status: ' . $order->status;
}
See: app/Http/Controllers/Worker/OrderController.php:25-27

Build docs developers (and LLMs) love