- 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.
172 lines
5.8 KiB
PHP
172 lines
5.8 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Invoices;
|
|
|
|
use App\Models\Invoice;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Component;
|
|
|
|
class Show extends Component
|
|
{
|
|
public Invoice $invoice;
|
|
|
|
public function mount(Invoice $invoice)
|
|
{
|
|
$this->invoice = $invoice->load([
|
|
'customer',
|
|
'branch',
|
|
'createdBy',
|
|
'serviceOrder.vehicle',
|
|
'jobCard.vehicle',
|
|
'estimate',
|
|
'lineItems.part',
|
|
'lineItems.serviceItem',
|
|
]);
|
|
}
|
|
|
|
public function downloadPDF()
|
|
{
|
|
try {
|
|
// Generate HTML from the template
|
|
$html = view('invoices.pdf', ['invoice' => $this->invoice])->render();
|
|
|
|
if (empty($html)) {
|
|
throw new \Exception('Failed to generate PDF template');
|
|
}
|
|
|
|
// Try different approaches for PDF generation
|
|
try {
|
|
// Approach 1: Use Laravel's PDF facade if available
|
|
if (class_exists('\Barryvdh\DomPDF\Facade\Pdf')) {
|
|
$pdf = \Barryvdh\DomPDF\Facade\Pdf::loadHtml($html);
|
|
$pdf->setPaper('letter', 'portrait');
|
|
$output = $pdf->output();
|
|
} else {
|
|
throw new \Exception('PDF facade not available');
|
|
}
|
|
} catch (\Exception $e1) {
|
|
try {
|
|
// Approach 2: Direct DomPDF instantiation
|
|
$dompdf = new \Dompdf\Dompdf;
|
|
$dompdf->loadHtml($html);
|
|
$dompdf->setPaper('letter', 'portrait');
|
|
$dompdf->render();
|
|
$output = $dompdf->output();
|
|
} catch (\Exception $e2) {
|
|
// Approach 3: Return HTML for now
|
|
$filename = 'invoice-'.$this->invoice->invoice_number.'.html';
|
|
|
|
return response()->streamDownload(function () use ($html) {
|
|
echo $html;
|
|
}, $filename, [
|
|
'Content-Type' => 'text/html',
|
|
'Content-Disposition' => 'attachment; filename="'.$filename.'"',
|
|
]);
|
|
}
|
|
}
|
|
|
|
// Create filename with invoice number
|
|
$filename = 'invoice-'.$this->invoice->invoice_number.'.pdf';
|
|
|
|
// Return PDF for download
|
|
return response()->streamDownload(function () use ($output) {
|
|
echo $output;
|
|
}, $filename, [
|
|
'Content-Type' => 'application/pdf',
|
|
'Content-Disposition' => 'attachment; filename="'.$filename.'"',
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
// Log the error for debugging
|
|
Log::error('PDF generation failed for invoice '.$this->invoice->id, [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString(),
|
|
]);
|
|
|
|
// Show user-friendly error message
|
|
session()->flash('error', 'Failed to generate PDF: '.$e->getMessage());
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public function markAsPaid()
|
|
{
|
|
if (! auth()->user()->can('update', $this->invoice)) {
|
|
session()->flash('error', 'You do not have permission to update this invoice.');
|
|
|
|
return;
|
|
}
|
|
|
|
$this->invoice->markAsPaid('manual', null, 'Marked as paid from invoice view');
|
|
$this->invoice->refresh();
|
|
session()->flash('success', 'Invoice marked as paid successfully.');
|
|
}
|
|
|
|
public function sendInvoice()
|
|
{
|
|
if (! auth()->user()->can('update', $this->invoice)) {
|
|
session()->flash('error', 'You do not have permission to send this invoice.');
|
|
|
|
return;
|
|
}
|
|
|
|
// This would typically integrate with email service
|
|
$this->invoice->markAsSent('email', $this->invoice->customer->email);
|
|
$this->invoice->refresh();
|
|
session()->flash('success', 'Invoice sent successfully.');
|
|
}
|
|
|
|
public function duplicateInvoice()
|
|
{
|
|
if (! auth()->user()->can('create', Invoice::class)) {
|
|
session()->flash('error', 'You do not have permission to create invoices.');
|
|
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$newInvoice = $this->invoice->replicate();
|
|
$newInvoice->invoice_number = Invoice::generateInvoiceNumber($this->invoice->branch->code);
|
|
$newInvoice->status = 'draft';
|
|
$newInvoice->invoice_date = now()->toDateString();
|
|
$newInvoice->due_date = now()->addDays(30)->toDateString();
|
|
$newInvoice->paid_at = null;
|
|
$newInvoice->payment_method = null;
|
|
$newInvoice->payment_reference = null;
|
|
$newInvoice->payment_notes = null;
|
|
$newInvoice->sent_at = null;
|
|
$newInvoice->sent_method = null;
|
|
$newInvoice->sent_to = null;
|
|
$newInvoice->created_by = auth()->id();
|
|
$newInvoice->save();
|
|
|
|
// Duplicate line items
|
|
foreach ($this->invoice->lineItems as $lineItem) {
|
|
$newLineItem = $lineItem->replicate();
|
|
$newLineItem->invoice_id = $newInvoice->id;
|
|
$newLineItem->save();
|
|
}
|
|
|
|
// Recalculate totals
|
|
$newInvoice->recalculateTotals();
|
|
|
|
return redirect()->route('invoices.edit', $newInvoice);
|
|
} catch (\Exception $e) {
|
|
Log::error('Failed to duplicate invoice', [
|
|
'invoice_id' => $this->invoice->id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
session()->flash('error', 'Failed to duplicate invoice. Please try again.');
|
|
}
|
|
}
|
|
|
|
#[Layout('components.layouts.app.sidebar')]
|
|
public function render()
|
|
{
|
|
return view('livewire.invoices.show');
|
|
}
|
|
}
|