- Increased icon sizes in service items, service orders, users, and technician management for better visibility. - Added custom loading indicators with appropriate icons in search fields for vehicles, work orders, and technicians. - Introduced invoice management routes for better organization and access control. - Created a new test for the estimate PDF functionality to ensure proper rendering and data integrity.
215 lines
10 KiB
PHP
215 lines
10 KiB
PHP
<div class="max-w-7xl mx-auto">
|
|
<div class="mb-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-semibold text-gray-900">Create Invoice from Estimate</h1>
|
|
<p class="mt-1 text-sm text-gray-600">Converting estimate #{{ $estimate->estimate_number }} to invoice</p>
|
|
</div>
|
|
<div class="flex space-x-3">
|
|
<flux:button variant="outline" href="{{ route('estimates.show', $estimate) }}">
|
|
Back to Estimate
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Estimate Reference -->
|
|
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
|
|
<div class="flex items-center">
|
|
<flux:icon name="document-text" class="h-5 w-5 text-blue-400 mr-2" />
|
|
<div>
|
|
<h3 class="text-sm font-medium text-blue-800">Source Estimate</h3>
|
|
<p class="text-sm text-blue-600">{{ $estimate->subject }} - {{ $estimate->estimate_number }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form wire:submit="save" class="space-y-6">
|
|
<!-- Basic Information -->
|
|
<div class="bg-white shadow rounded-lg p-6">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-4">Invoice Details</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Subject</flux:label>
|
|
<flux:input wire:model="subject" placeholder="Invoice subject" />
|
|
<flux:error name="subject" />
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Branch</flux:label>
|
|
<flux:select wire:model="branch_id">
|
|
<flux:option value="">Select branch</flux:option>
|
|
@foreach($branches as $branch)
|
|
<flux:option value="{{ $branch->id }}">{{ $branch->name }}</flux:option>
|
|
@endforeach
|
|
</flux:select>
|
|
<flux:error name="branch_id" />
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Invoice Date</flux:label>
|
|
<flux:input type="date" wire:model="invoice_date" />
|
|
<flux:error name="invoice_date" />
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Due Date</flux:label>
|
|
<flux:input type="date" wire:model="due_date" />
|
|
<flux:error name="due_date" />
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div class="md:col-span-2">
|
|
<flux:field>
|
|
<flux:label>Description</flux:label>
|
|
<flux:textarea wire:model="description" rows="3" placeholder="Invoice description..." />
|
|
<flux:error name="description" />
|
|
</flux:field>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Line Items -->
|
|
<div class="bg-white shadow rounded-lg p-6">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-medium text-gray-900">Line Items</h3>
|
|
<flux:button type="button" wire:click="addLineItem" variant="outline">
|
|
Add Item
|
|
</flux:button>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
@foreach($lineItems as $index => $item)
|
|
<div class="border border-gray-200 rounded-lg p-4">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h4 class="text-sm font-medium text-gray-900">Item {{ $index + 1 }}</h4>
|
|
@if(count($lineItems) > 1)
|
|
<flux:button type="button" wire:click="removeLineItem({{ $index }})" variant="danger" size="sm">
|
|
Remove
|
|
</flux:button>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-6 gap-4">
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Type</flux:label>
|
|
<flux:select wire:model="lineItems.{{ $index }}.type">
|
|
<flux:option value="service">Service</flux:option>
|
|
<flux:option value="part">Part</flux:option>
|
|
<flux:option value="other">Other</flux:option>
|
|
</flux:select>
|
|
</flux:field>
|
|
</div>
|
|
|
|
@if($item['type'] === 'service')
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Service Item</flux:label>
|
|
<flux:select wire:model="lineItems.{{ $index }}.service_item_id">
|
|
<flux:option value="">Select service</flux:option>
|
|
@foreach($serviceItems as $serviceItem)
|
|
<flux:option value="{{ $serviceItem->id }}">{{ $serviceItem->name }} - ${{ number_format($serviceItem->price, 2) }}</flux:option>
|
|
@endforeach
|
|
</flux:select>
|
|
</flux:field>
|
|
</div>
|
|
@elseif($item['type'] === 'part')
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Part</flux:label>
|
|
<select wire:model="lineItems.{{ $index }}.part_id" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
|
|
<option value="">Select part</option>
|
|
@foreach($parts as $part)
|
|
<option value="{{ $part->id }}">{{ $part->part_number }} - {{ $part->name }} - ${{ number_format($part->sell_price, 2) }}</option>
|
|
@endforeach
|
|
</select>
|
|
</flux:field>
|
|
</div>
|
|
@else
|
|
<div></div>
|
|
@endif
|
|
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Description</flux:label>
|
|
<flux:input wire:model="lineItems.{{ $index }}.description" placeholder="Description" />
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Quantity</flux:label>
|
|
<flux:input type="number" wire:model="lineItems.{{ $index }}.quantity" min="1" step="1" />
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Unit Price</flux:label>
|
|
<flux:input type="number" wire:model="lineItems.{{ $index }}.unit_price" step="0.01" min="0" />
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Total</flux:label>
|
|
<flux:input value="${{ number_format($item['total'], 2) }}" readonly />
|
|
</flux:field>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Invoice Summary -->
|
|
<div class="bg-white shadow rounded-lg p-6">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-4">Invoice Summary</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<flux:field>
|
|
<flux:label>Tax Rate (%)</flux:label>
|
|
<flux:input type="number" wire:model="tax_rate" step="0.01" min="0" max="100" />
|
|
<flux:error name="tax_rate" />
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<div class="flex justify-between">
|
|
<span class="text-sm text-gray-600">Subtotal:</span>
|
|
<span class="text-sm font-medium">${{ number_format($this->subtotal, 2) }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-sm text-gray-600">Tax ({{ $tax_rate }}%):</span>
|
|
<span class="text-sm font-medium">${{ number_format($this->taxAmount, 2) }}</span>
|
|
</div>
|
|
<div class="flex justify-between border-t pt-2">
|
|
<span class="text-base font-semibold">Total:</span>
|
|
<span class="text-base font-semibold">${{ number_format($this->total, 2) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="flex justify-end space-x-3">
|
|
<flux:button type="button" variant="outline" href="{{ route('estimates.show', $estimate) }}">
|
|
Cancel
|
|
</flux:button>
|
|
<flux:button type="submit" variant="primary">
|
|
Create Invoice
|
|
</flux:button>
|
|
</div>
|
|
</form>
|
|
</div>
|