sackey e839d40a99
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
Initial commit
2025-07-30 17:15:50 +00:00

313 lines
9.5 KiB
PHP

<?php
namespace App\Livewire\ServiceOrders;
use Livewire\Component;
use App\Models\ServiceOrder;
use App\Models\Customer;
use App\Models\Vehicle;
use App\Models\Technician;
use App\Models\ServiceItem;
use App\Models\Part;
use Livewire\Attributes\Validate;
class Create extends Component
{
#[Validate('required|exists:customers,id')]
public $customer_id = '';
#[Validate('required|exists:vehicles,id')]
public $vehicle_id = '';
#[Validate('nullable|exists:technicians,id')]
public $assigned_technician_id = '';
#[Validate('required|string|max:1000')]
public $customer_complaint = '';
#[Validate('nullable|string|max:1000')]
public $recommended_services = '';
#[Validate('required|in:low,normal,high,urgent')]
public $priority = 'normal';
#[Validate('required|in:pending,in_progress,completed,cancelled,on_hold')]
public $status = 'pending';
#[Validate('nullable|date')]
public $scheduled_date = '';
#[Validate('nullable|numeric|min:0')]
public $estimated_hours = 0;
#[Validate('nullable|string|max:1000')]
public $internal_notes = '';
#[Validate('nullable|string|max:1000')]
public $customer_notes = '';
// Service Items
public $serviceItems = [];
public $newServiceItem = [
'service_name' => '',
'description' => '',
'category' => '',
'labor_rate' => 75.00,
'estimated_hours' => 1.0,
'status' => 'pending',
'technician_notes' => '',
];
// Parts
public $selectedParts = [];
public $newPart = [
'part_id' => '',
'quantity_used' => 1,
'unit_price' => 0,
'notes' => '',
];
// Available data
public $customers = [];
public $vehicles = [];
public $technicians = [];
public $availableParts = [];
public function mount()
{
$this->loadCustomers();
$this->loadTechnicians();
$this->loadParts();
// Pre-select vehicle if passed in query string
if (request()->has('vehicle')) {
$this->vehicle_id = request('vehicle');
$this->updatedVehicleId();
}
}
public function loadCustomers()
{
$this->customers = Customer::where('status', 'active')
->orderBy('first_name')
->get();
}
public function loadTechnicians()
{
$this->technicians = Technician::where('status', 'active')
->orderBy('first_name')
->get();
}
public function loadParts()
{
$this->availableParts = Part::where('status', 'active')
->where('quantity_on_hand', '>', 0)
->orderBy('name')
->get();
}
public function updatedCustomerId()
{
if ($this->customer_id) {
$this->vehicles = Vehicle::where('customer_id', $this->customer_id)
->where('status', 'active')
->orderBy('year')
->orderBy('make')
->orderBy('model')
->get();
} else {
$this->vehicles = [];
$this->vehicle_id = '';
}
}
public function updatedVehicleId()
{
if ($this->vehicle_id) {
$vehicle = Vehicle::find($this->vehicle_id);
if ($vehicle) {
$this->customer_id = $vehicle->customer_id;
$this->updatedCustomerId();
}
}
}
public function addServiceItem()
{
$this->validate([
'newServiceItem.service_name' => 'required|string|max:255',
'newServiceItem.description' => 'nullable|string|max:500',
'newServiceItem.category' => 'required|string|max:100',
'newServiceItem.labor_rate' => 'required|numeric|min:0',
'newServiceItem.estimated_hours' => 'required|numeric|min:0.1',
]);
$this->serviceItems[] = [
'service_name' => $this->newServiceItem['service_name'],
'description' => $this->newServiceItem['description'],
'category' => $this->newServiceItem['category'],
'labor_rate' => $this->newServiceItem['labor_rate'],
'estimated_hours' => $this->newServiceItem['estimated_hours'],
'labor_cost' => $this->newServiceItem['labor_rate'] * $this->newServiceItem['estimated_hours'],
'status' => $this->newServiceItem['status'],
'technician_notes' => $this->newServiceItem['technician_notes'],
];
// Reset form
$this->newServiceItem = [
'service_name' => '',
'description' => '',
'category' => '',
'labor_rate' => 75.00,
'estimated_hours' => 1.0,
'status' => 'pending',
'technician_notes' => '',
];
}
public function removeServiceItem($index)
{
unset($this->serviceItems[$index]);
$this->serviceItems = array_values($this->serviceItems);
}
public function addPart()
{
$this->validate([
'newPart.part_id' => 'required|exists:parts,id',
'newPart.quantity_used' => 'required|integer|min:1',
'newPart.unit_price' => 'required|numeric|min:0',
]);
$part = Part::find($this->newPart['part_id']);
if ($part) {
$this->selectedParts[] = [
'part_id' => $part->id,
'part_name' => $part->name,
'part_number' => $part->part_number,
'quantity_used' => $this->newPart['quantity_used'],
'unit_cost' => $part->cost_price,
'unit_price' => $this->newPart['unit_price'],
'total_cost' => $part->cost_price * $this->newPart['quantity_used'],
'total_price' => $this->newPart['unit_price'] * $this->newPart['quantity_used'],
'status' => 'requested',
'notes' => $this->newPart['notes'],
];
// Reset form
$this->newPart = [
'part_id' => '',
'quantity_used' => 1,
'unit_price' => 0,
'notes' => '',
];
}
}
public function removePart($index)
{
unset($this->selectedParts[$index]);
$this->selectedParts = array_values($this->selectedParts);
}
public function updatedNewPartPartId()
{
if ($this->newPart['part_id']) {
$part = Part::find($this->newPart['part_id']);
if ($part) {
$this->newPart['unit_price'] = $part->sell_price;
}
}
}
public function getTotalLaborCost()
{
return collect($this->serviceItems)->sum('labor_cost');
}
public function getTotalPartsCost()
{
return collect($this->selectedParts)->sum('total_price');
}
public function getSubtotal()
{
return $this->getTotalLaborCost() + $this->getTotalPartsCost();
}
public function getTaxAmount()
{
return $this->getSubtotal() * 0.08; // 8% tax
}
public function getTotalAmount()
{
return $this->getSubtotal() + $this->getTaxAmount();
}
public function createServiceOrder()
{
$this->validate();
// Create the service order
$serviceOrder = ServiceOrder::create([
'customer_id' => $this->customer_id,
'vehicle_id' => $this->vehicle_id,
'assigned_technician_id' => $this->assigned_technician_id ?: null,
'customer_complaint' => $this->customer_complaint,
'recommended_services' => $this->recommended_services,
'priority' => $this->priority,
'status' => $this->status,
'scheduled_date' => $this->scheduled_date ?: null,
'estimated_hours' => $this->estimated_hours,
'internal_notes' => $this->internal_notes,
'customer_notes' => $this->customer_notes,
'labor_cost' => $this->getTotalLaborCost(),
'parts_cost' => $this->getTotalPartsCost(),
'tax_amount' => $this->getTaxAmount(),
'discount_amount' => 0,
'total_amount' => $this->getTotalAmount(),
]);
// Create service items
foreach ($this->serviceItems as $item) {
ServiceItem::create([
'service_order_id' => $serviceOrder->id,
'service_name' => $item['service_name'],
'description' => $item['description'],
'category' => $item['category'],
'labor_rate' => $item['labor_rate'],
'estimated_hours' => $item['estimated_hours'],
'labor_cost' => $item['labor_cost'],
'status' => $item['status'],
'technician_notes' => $item['technician_notes'],
]);
}
// Attach parts
foreach ($this->selectedParts as $part) {
$serviceOrder->parts()->attach($part['part_id'], [
'quantity_used' => $part['quantity_used'],
'unit_cost' => $part['unit_cost'],
'unit_price' => $part['unit_price'],
'total_cost' => $part['total_cost'],
'total_price' => $part['total_price'],
'status' => $part['status'],
'notes' => $part['notes'],
]);
}
session()->flash('success', 'Service order created successfully!');
return $this->redirect('/service-orders/' . $serviceOrder->id, navigate: true);
}
public function render()
{
return view('livewire.service-orders.create');
}
}