313 lines
9.5 KiB
PHP
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');
|
|
}
|
|
}
|