- 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.
179 lines
5.2 KiB
PHP
179 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Invoices;
|
|
|
|
use App\Models\Branch;
|
|
use App\Models\Invoice;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Component;
|
|
use Livewire\WithPagination;
|
|
|
|
class Index extends Component
|
|
{
|
|
use WithPagination;
|
|
|
|
public $search = '';
|
|
|
|
public $filterStatus = '';
|
|
|
|
public $filterBranch = '';
|
|
|
|
public $filterDateFrom = '';
|
|
|
|
public $filterDateTo = '';
|
|
|
|
public $sortField = 'invoice_date';
|
|
|
|
public $sortDirection = 'desc';
|
|
|
|
protected $queryString = [
|
|
'search' => ['except' => ''],
|
|
'filterStatus' => ['except' => ''],
|
|
'filterBranch' => ['except' => ''],
|
|
'sortField' => ['except' => 'invoice_date'],
|
|
'sortDirection' => ['except' => 'desc'],
|
|
];
|
|
|
|
public function mount()
|
|
{
|
|
// Set default date filter to current month
|
|
$this->filterDateFrom = now()->startOfMonth()->format('Y-m-d');
|
|
$this->filterDateTo = now()->endOfMonth()->format('Y-m-d');
|
|
}
|
|
|
|
public function updatingSearch()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatingFilterStatus()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatingFilterBranch()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function sortBy($field)
|
|
{
|
|
if ($this->sortField === $field) {
|
|
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
|
|
} else {
|
|
$this->sortField = $field;
|
|
$this->sortDirection = 'asc';
|
|
}
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function clearFilters()
|
|
{
|
|
$this->reset(['search', 'filterStatus', 'filterBranch', 'filterDateFrom', 'filterDateTo']);
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function deleteInvoice($invoiceId)
|
|
{
|
|
$invoice = Invoice::findOrFail($invoiceId);
|
|
|
|
// Check permissions
|
|
if (! auth()->user()->can('delete', $invoice)) {
|
|
session()->flash('error', 'You do not have permission to delete this invoice.');
|
|
|
|
return;
|
|
}
|
|
|
|
// Only allow deletion of draft invoices
|
|
if ($invoice->status !== 'draft') {
|
|
session()->flash('error', 'Only draft invoices can be deleted.');
|
|
|
|
return;
|
|
}
|
|
|
|
$invoice->delete();
|
|
session()->flash('success', 'Invoice deleted successfully.');
|
|
}
|
|
|
|
public function markAsPaid($invoiceId)
|
|
{
|
|
$invoice = Invoice::findOrFail($invoiceId);
|
|
|
|
if (! auth()->user()->can('update', $invoice)) {
|
|
session()->flash('error', 'You do not have permission to update this invoice.');
|
|
|
|
return;
|
|
}
|
|
|
|
$invoice->markAsPaid('manual', null, 'Marked as paid from invoice list');
|
|
session()->flash('success', 'Invoice marked as paid.');
|
|
}
|
|
|
|
public function sendInvoice($invoiceId)
|
|
{
|
|
$invoice = Invoice::findOrFail($invoiceId);
|
|
|
|
if (! auth()->user()->can('update', $invoice)) {
|
|
session()->flash('error', 'You do not have permission to send this invoice.');
|
|
|
|
return;
|
|
}
|
|
|
|
// This would typically integrate with email service
|
|
$invoice->markAsSent('email', $invoice->customer->email);
|
|
session()->flash('success', 'Invoice sent successfully.');
|
|
}
|
|
|
|
public function getInvoicesProperty()
|
|
{
|
|
return Invoice::query()
|
|
->with(['customer', 'branch', 'createdBy'])
|
|
->when($this->search, function (Builder $query) {
|
|
$query->where(function ($q) {
|
|
$q->where('invoice_number', 'like', '%'.$this->search.'%')
|
|
->orWhereHas('customer', function ($customerQuery) {
|
|
$customerQuery->where('first_name', 'like', '%'.$this->search.'%')
|
|
->orWhere('last_name', 'like', '%'.$this->search.'%')
|
|
->orWhere('email', 'like', '%'.$this->search.'%')
|
|
->orWhereRaw("CONCAT(first_name, ' ', last_name) LIKE ?", ['%'.$this->search.'%']);
|
|
});
|
|
});
|
|
})
|
|
->when($this->filterStatus, function (Builder $query) {
|
|
$query->where('status', $this->filterStatus);
|
|
})
|
|
->when($this->filterBranch, function (Builder $query) {
|
|
$query->where('branch_id', $this->filterBranch);
|
|
})
|
|
->when($this->filterDateFrom, function (Builder $query) {
|
|
$query->where('invoice_date', '>=', $this->filterDateFrom);
|
|
})
|
|
->when($this->filterDateTo, function (Builder $query) {
|
|
$query->where('invoice_date', '<=', $this->filterDateTo);
|
|
})
|
|
->orderBy($this->sortField, $this->sortDirection)
|
|
->paginate(15);
|
|
}
|
|
|
|
public function getBranchesProperty()
|
|
{
|
|
return Branch::orderBy('name')->get();
|
|
}
|
|
|
|
public function getStatusOptionsProperty()
|
|
{
|
|
return Invoice::getStatusOptions();
|
|
}
|
|
|
|
#[Layout('components.layouts.app.sidebar')]
|
|
public function render()
|
|
{
|
|
return view('livewire.invoices.index', [
|
|
'invoices' => $this->invoices,
|
|
'branches' => $this->branches,
|
|
'statusOptions' => $this->statusOptions,
|
|
]);
|
|
}
|
|
}
|