397 lines
20 KiB
PHP
397 lines
20 KiB
PHP
<div class="space-y-6">
|
|
<!-- Header -->
|
|
<div class="flex items-center justify-between">
|
|
<flux:heading size="xl">Create Service Order</flux:heading>
|
|
<flux:button href="/service-orders" variant="outline" size="sm">
|
|
<flux:icon name="arrow-left" class="size-4" />
|
|
Back to Service Orders
|
|
</flux:button>
|
|
</div>
|
|
|
|
<form wire:submit="createServiceOrder" class="space-y-6">
|
|
|
|
<!-- Customer & Vehicle Information -->
|
|
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-6">
|
|
<flux:heading size="lg" class="mb-4">Customer & Vehicle Information</flux:heading>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Customer *</flux:label>
|
|
<select wire:model.live="customer_id" class="w-full rounded-md border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-2 focus:ring-blue-500">
|
|
<option value="">Select Customer</option>
|
|
@foreach($customers as $customer)
|
|
<option value="{{ $customer->id }}">{{ $customer->full_name }}</option>
|
|
@endforeach
|
|
</select>
|
|
<flux:error name="customer_id" />
|
|
</flux:field>
|
|
</div>
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Vehicle *</flux:label>
|
|
<select wire:model.live="vehicle_id" class="w-full rounded-md border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-2 focus:ring-blue-500">
|
|
<option value="">Select Vehicle</option>
|
|
@foreach($vehicles as $vehicle)
|
|
<option value="{{ $vehicle->id }}">{{ $vehicle->display_name }} ({{ $vehicle->license_plate }})</option>
|
|
@endforeach
|
|
</select>
|
|
<flux:error name="vehicle_id" />
|
|
</flux:field>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Service Order Details -->
|
|
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-6">
|
|
<flux:heading size="lg" class="mb-4">Service Order Details</flux:heading>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Customer Complaint *</flux:label>
|
|
<flux:textarea
|
|
wire:model="customer_complaint"
|
|
placeholder="Describe the customer's complaint or reason for service..."
|
|
rows="3"
|
|
/>
|
|
<flux:error name="customer_complaint" />
|
|
</flux:field>
|
|
</div>
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Recommended Services</flux:label>
|
|
<flux:textarea
|
|
wire:model="recommended_services"
|
|
placeholder="List any recommended services based on inspection..."
|
|
rows="3"
|
|
/>
|
|
<flux:error name="recommended_services" />
|
|
</flux:field>
|
|
</div>
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Priority *</flux:label>
|
|
<select wire:model="priority" class="w-full rounded-md border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-2 focus:ring-blue-500">
|
|
<option value="low">Low</option>
|
|
<option value="normal">Normal</option>
|
|
<option value="high">High</option>
|
|
<option value="urgent">Urgent</option>
|
|
</select>
|
|
<flux:error name="priority" />
|
|
</flux:field>
|
|
</div>
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Status *</flux:label>
|
|
<select wire:model="status" class="w-full rounded-md border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-2 focus:ring-blue-500">
|
|
<option value="pending">Pending</option>
|
|
<option value="in_progress">In Progress</option>
|
|
<option value="on_hold">On Hold</option>
|
|
</select>
|
|
<flux:error name="status" />
|
|
</flux:field>
|
|
</div>
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Assigned Technician</flux:label>
|
|
<select wire:model="assigned_technician_id" class="w-full rounded-md border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-2 focus:ring-blue-500">
|
|
<option value="">Unassigned</option>
|
|
@foreach($technicians as $technician)
|
|
<option value="{{ $technician->id }}">{{ $technician->full_name }}</option>
|
|
@endforeach
|
|
</select>
|
|
<flux:error name="assigned_technician_id" />
|
|
</flux:field>
|
|
</div>
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Scheduled Date</flux:label>
|
|
<flux:input
|
|
type="date"
|
|
wire:model="scheduled_date"
|
|
/>
|
|
<flux:error name="scheduled_date" />
|
|
</flux:field>
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Estimated Hours</flux:label>
|
|
<flux:input
|
|
type="number"
|
|
step="0.5"
|
|
min="0"
|
|
wire:model="estimated_hours"
|
|
placeholder="0.0"
|
|
/>
|
|
<flux:error name="estimated_hours" />
|
|
</flux:field>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Service Items -->
|
|
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-6">
|
|
<flux:heading size="lg" class="mb-4">Service Items</flux:heading>
|
|
|
|
<!-- Add New Service Item -->
|
|
<div class="border border-zinc-200 dark:border-gray-600 rounded-lg p-4 mb-4">
|
|
<h4 class="font-medium mb-3">Add Service Item</h4>
|
|
<div class="grid grid-cols-1 md:grid-cols-5 gap-3">
|
|
<div>
|
|
<flux:input
|
|
wire:model="newServiceItem.service_name"
|
|
placeholder="Service Name"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<flux:input
|
|
wire:model="newServiceItem.category"
|
|
placeholder="Category"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<flux:input
|
|
type="number"
|
|
step="0.01"
|
|
min="0"
|
|
wire:model="newServiceItem.labor_rate"
|
|
placeholder="Labor Rate"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<flux:input
|
|
type="number"
|
|
step="0.1"
|
|
min="0.1"
|
|
wire:model="newServiceItem.estimated_hours"
|
|
placeholder="Hours"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<flux:button type="button" wire:click="addServiceItem" size="sm">
|
|
Add Item
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
<div class="mt-2">
|
|
<flux:input
|
|
wire:model="newServiceItem.description"
|
|
placeholder="Service Description (optional)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Service Items List -->
|
|
@if(count($serviceItems) > 0)
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full">
|
|
<thead>
|
|
<tr class="border-b border-zinc-200 dark:border-gray-600">
|
|
<th class="text-left py-2 px-2">Service</th>
|
|
<th class="text-left py-2 px-2">Category</th>
|
|
<th class="text-left py-2 px-2">Rate</th>
|
|
<th class="text-left py-2 px-2">Hours</th>
|
|
<th class="text-left py-2 px-2">Cost</th>
|
|
<th class="text-left py-2 px-2">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($serviceItems as $index => $item)
|
|
<tr class="border-b border-gray-100 dark:border-zinc-700">
|
|
<td class="py-2 px-2">
|
|
<div class="font-medium">{{ $item['service_name'] }}</div>
|
|
@if($item['description'])
|
|
<div class="text-sm text-zinc-500 dark:text-zinc-400">{{ $item['description'] }}</div>
|
|
@endif
|
|
</td>
|
|
<td class="py-2 px-2">{{ $item['category'] }}</td>
|
|
<td class="py-2 px-2">${{ number_format($item['labor_rate'], 2) }}</td>
|
|
<td class="py-2 px-2">{{ $item['estimated_hours'] }}</td>
|
|
<td class="py-2 px-2">${{ number_format($item['labor_cost'], 2) }}</td>
|
|
<td class="py-2 px-2">
|
|
<flux:button
|
|
type="button"
|
|
wire:click="removeServiceItem({{ $index }})"
|
|
variant="danger"
|
|
size="sm"
|
|
>
|
|
Remove
|
|
</flux:button>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@else
|
|
<div class="text-center py-4 text-zinc-500 dark:text-zinc-400">
|
|
No service items added yet.
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Parts -->
|
|
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-6">
|
|
<flux:heading size="lg" class="mb-4">Parts</flux:heading>
|
|
|
|
<!-- Add New Part -->
|
|
<div class="border border-zinc-200 dark:border-gray-600 rounded-lg p-4 mb-4">
|
|
<h4 class="font-medium mb-3">Add Part</h4>
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-3">
|
|
<div class="md:col-span-2">
|
|
<select wire:model.live="newPart.part_id" class="w-full rounded-md border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-2 focus:ring-blue-500">
|
|
<option value="">Select Part</option>
|
|
@foreach($availableParts as $part)
|
|
<option value="{{ $part->id }}">{{ $part->name }} ({{ $part->part_number }}) - ${{ $part->sell_price }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<flux:input
|
|
type="number"
|
|
min="1"
|
|
wire:model="newPart.quantity_used"
|
|
placeholder="Quantity"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<flux:button type="button" wire:click="addPart" size="sm">
|
|
Add Part
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
<div class="mt-2 grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
<div>
|
|
<flux:input
|
|
type="number"
|
|
step="0.01"
|
|
min="0"
|
|
wire:model="newPart.unit_price"
|
|
placeholder="Unit Price"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<flux:input
|
|
wire:model="newPart.notes"
|
|
placeholder="Notes (optional)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Parts List -->
|
|
@if(count($selectedParts) > 0)
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full">
|
|
<thead>
|
|
<tr class="border-b border-zinc-200 dark:border-gray-600">
|
|
<th class="text-left py-2 px-2">Part</th>
|
|
<th class="text-left py-2 px-2">Part #</th>
|
|
<th class="text-left py-2 px-2">Qty</th>
|
|
<th class="text-left py-2 px-2">Unit Price</th>
|
|
<th class="text-left py-2 px-2">Total</th>
|
|
<th class="text-left py-2 px-2">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($selectedParts as $index => $part)
|
|
<tr class="border-b border-gray-100 dark:border-zinc-700">
|
|
<td class="py-2 px-2">{{ $part['part_name'] }}</td>
|
|
<td class="py-2 px-2">{{ $part['part_number'] }}</td>
|
|
<td class="py-2 px-2">{{ $part['quantity_used'] }}</td>
|
|
<td class="py-2 px-2">${{ number_format($part['unit_price'], 2) }}</td>
|
|
<td class="py-2 px-2">${{ number_format($part['total_price'], 2) }}</td>
|
|
<td class="py-2 px-2">
|
|
<flux:button
|
|
type="button"
|
|
wire:click="removePart({{ $index }})"
|
|
variant="danger"
|
|
size="sm"
|
|
>
|
|
Remove
|
|
</flux:button>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@else
|
|
<div class="text-center py-4 text-zinc-500 dark:text-zinc-400">
|
|
No parts added yet.
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Order Totals -->
|
|
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-6">
|
|
<flux:heading size="lg" class="mb-4">Order Totals</flux:heading>
|
|
<div class="space-y-2">
|
|
<div class="flex justify-between">
|
|
<span>Labor Cost:</span>
|
|
<span>${{ number_format($this->getTotalLaborCost(), 2) }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span>Parts Cost:</span>
|
|
<span>${{ number_format($this->getTotalPartsCost(), 2) }}</span>
|
|
</div>
|
|
<div class="flex justify-between border-t pt-2">
|
|
<span>Subtotal:</span>
|
|
<span>${{ number_format($this->getSubtotal(), 2) }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span>Tax (8%):</span>
|
|
<span>${{ number_format($this->getTaxAmount(), 2) }}</span>
|
|
</div>
|
|
<div class="flex justify-between border-t pt-2 font-bold text-lg">
|
|
<span>Total:</span>
|
|
<span>${{ number_format($this->getTotalAmount(), 2) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notes -->
|
|
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-6">
|
|
<flux:heading size="lg" class="mb-4">Notes</flux:heading>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Internal Notes</flux:label>
|
|
<flux:textarea
|
|
wire:model="internal_notes"
|
|
placeholder="Internal notes for technicians..."
|
|
rows="4"
|
|
/>
|
|
<flux:error name="internal_notes" />
|
|
</flux:field>
|
|
</div>
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Customer Notes</flux:label>
|
|
<flux:textarea
|
|
wire:model="customer_notes"
|
|
placeholder="Notes visible to customer..."
|
|
rows="4"
|
|
/>
|
|
<flux:error name="customer_notes" />
|
|
</flux:field>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="flex items-center justify-between pt-6 border-t border-zinc-200 dark:border-zinc-700">
|
|
<flux:button href="/service-orders" variant="outline">
|
|
Cancel
|
|
</flux:button>
|
|
<flux:button type="submit" variant="primary">
|
|
Create Service Order
|
|
</flux:button>
|
|
</div>
|
|
|
|
</form>
|
|
</div>
|