Invoice & Booking Integration Guide

📄 General
← Back to Documentation
# Invoice & Booking Integration Guide ## Overview The Invoice system has been comprehensively enhanced to work seamlessly with the Booking entity, supporting invoicing for: - **Accommodations** (rooms, houses, apartments via VenueObjects) - **Spots** (beach spots, parking spots via VenueSpots) - **Services** (medical, legal, beauty services via VenueServices) - **Packages** (service bundles via VenuePackages) - **Additional Products** (minibar items, insurance, damage fees, etc.) ## Database Schema ### Enhanced Invoices Table ```sql - booking_id (foreign key to bookings) - client_id (foreign key to clients) - company_id (foreign key to companies) - workspace_id (foreign key to workspaces) - reservation_id (foreign key to reservations - legacy support) - invoice_number (unique identifier: INV-YYYYMMDD-XXXXXX) - invoice_type (proforma, final, credit_note, debit_note) - fiscal_receipt_number - fiscal_status (pending, printed, failed, cancelled) - fiscal_printed_at -- Pricing - subtotal - tax_rate - tax_amount - service_fee - discount - discount_amount - discount_type (percentage, fixed) - total - paid -- Payment tracking - payment_status (unpaid, partially_paid, paid, refunded, cancelled) - payment_method - payment_date - paid_at -- Metadata - metadata (JSON) - notes - cancelled_at - cancellation_reason ``` ### Enhanced Invoice Items Table ```sql - invoice_id (foreign key) - itemable_type (polymorphic - VenueObject, VenueSpot, VenueService, etc.) - itemable_id (polymorphic) - category (accommodation, spot, service, package, product, fee, tax, discount, other) -- Item details - item (name) - description - note -- Pricing - qty - unit_price - price - discount - discount_amount - tax_rate - tax_amount - total -- Duration tracking - duration_type (night, day, hour, session, unit) - duration_value - start_date - end_date -- Additional - options (JSON) - is_free - is_returned - returned_qty - returned ``` ## Usage Examples ### 1. Create Invoice from Booking ```php use App\Services\InvoiceService; use App\Models\Booking; $invoiceService = new InvoiceService(); $booking = Booking::find(1); // Create final invoice $invoice = $invoiceService->createFromBooking($booking); // Create with options $invoice = $invoiceService->createFromBooking($booking, [ 'invoice_type' => 'final', 'status' => 'pending', 'due_date' => now()->addDays(15), 'notes' => 'Payment due within 15 days', ]); ``` ### 2. Create Proforma Invoice ```php // Create proforma (draft) invoice $proforma = $invoiceService->createProformaFromBooking($booking); // Later, convert to final invoice $finalInvoice = $invoiceService->convertProformaToFinal($proforma); ``` ### 3. Add Additional Products ```php use App\Models\Product; $product = Product::where('name', 'Minibar Consumption')->first(); // Add minibar charges $invoiceService->addProductToInvoice($invoice, $product, [ 'quantity' => 3, 'price' => 15.00, 'tax_rate' => 20, ]); // Add insurance $insurance = Product::where('name', 'Car Insurance')->first(); $invoiceService->addProductToInvoice($invoice, $insurance, [ 'quantity' => 1, 'price' => 50.00, ]); ``` ### 4. Add Custom Fees ```php // Add cleaning fee $invoiceService->addCustomFee($invoice, 'Cleaning Fee', 30.00, 'Final cleaning service'); // Add damage fee $invoiceService->addCustomFee($invoice, 'Damage Fee', 100.00, 'Broken window'); // Add late checkout fee $invoiceService->addCustomFee($invoice, 'Late Checkout Fee', 25.00); ``` ### 5. Apply Discounts ```php // Fixed amount discount $invoiceService->addDiscount($invoice, 50.00, 'Early booking discount'); // Percentage discount $invoiceService->applyPercentageDiscount($invoice, 10, 'Loyalty discount'); ``` ### 6. Payment Tracking ```php // Mark as fully paid $invoice->markAsPaid(); // Add partial payment $invoice->addPayment(100.00); // Check payment status if ($invoice->isPaid()) { // Invoice is fully paid } if ($invoice->isPartiallyPaid()) { $remaining = $invoice->getRemainingAmount(); echo "Remaining: €{$remaining}"; } if ($invoice->isOverdue()) { // Send reminder } ``` ### 7. Create Credit Note ```php // Full credit note (refund entire invoice) $creditNote = $invoiceService->createCreditNote($invoice, [], 'Customer cancellation'); // Partial credit note (specific items) $creditNote = $invoiceService->createCreditNote($invoice, [ [ 'category' => 'product', 'item' => 'Minibar Item', 'qty' => 1, 'unit_price' => 15.00, 'price' => 15.00, 'total' => 15.00, ] ], 'Minibar item not consumed'); ``` ### 8. Query Invoices ```php // Get all invoices for a booking $invoices = $booking->invoices; // Get unpaid invoices $unpaidInvoices = Invoice::unpaid()->get(); // Get overdue invoices $overdueInvoices = Invoice::overdue()->get(); // Get proforma invoices $proformas = Invoice::proforma()->get(); // Get invoices by payment status $partiallyPaid = Invoice::partiallyPaid()->get(); ``` ### 9. Access Invoice Items by Category ```php // Get accommodation items $accommodations = $invoice->accommodationItems; // Get service items $services = $invoice->serviceItems; // Get product items (minibar, insurance, etc.) $products = $invoice->productItems; // Get all fees $fees = $invoice->feeItems; // Get discounts $discounts = $invoice->discountItems; ``` ### 10. Working with Invoice Items ```php // Access polymorphic relationship foreach ($invoice->invoiceItems as $item) { // Get the actual bookable item (VenueObject, Product, etc.) $bookableItem = $item->itemable; // Get duration info if ($item->duration_type === 'night') { $nights = $item->getDurationInNights(); echo "Booked for {$nights} nights"; } // Get pricing details $subtotal = $item->getSubtotal(); $totalWithoutTax = $item->getTotalWithoutTax(); } ``` ## Controller Example ```php namespace App\Http\Controllers; use App\Models\Booking; use App\Services\InvoiceService; use Illuminate\Http\Request; class InvoiceController extends Controller { protected $invoiceService; public function __construct(InvoiceService $invoiceService) { $this->invoiceService = $invoiceService; } /** * Generate invoice for booking */ public function generateFromBooking(Request $request, Booking $booking) { $invoice = $this->invoiceService->createFromBooking($booking, [ 'due_date' => now()->addDays(30), 'notes' => $request->input('notes'), ]); return redirect() ->route('invoices.show', $invoice) ->with('success', 'Invoice generated successfully'); } /** * Add product to existing invoice */ public function addProduct(Request $request, Invoice $invoice) { $validated = $request->validate([ 'product_id' => 'required|exists:products,id', 'quantity' => 'required|integer|min:1', 'price' => 'nullable|numeric|min:0', ]); $product = Product::findOrFail($validated['product_id']); $this->invoiceService->addProductToInvoice($invoice, $product, [ 'quantity' => $validated['quantity'], 'price' => $validated['price'] ?? $product->price, ]); return back()->with('success', 'Product added to invoice'); } /** * Record payment */ public function recordPayment(Request $request, Invoice $invoice) { $validated = $request->validate([ 'amount' => 'required|numeric|min:0', 'payment_method' => 'required|string', ]); $invoice->addPayment($validated['amount']); $invoice->payment_method = $validated['payment_method']; $invoice->save(); return back()->with('success', 'Payment recorded successfully'); } } ``` ## Filament Resource Integration ```php use App\Services\InvoiceService; use Filament\Actions\Action; // In your BookingResource public static function getActions(): array { return [ Action::make('generate_invoice') ->label('Generate Invoice') ->icon('heroicon-o-document-text') ->action(function (Booking $record) { $invoiceService = app(InvoiceService::class); $invoice = $invoiceService->createFromBooking($record); Notification::make() ->title('Invoice Generated') ->success() ->send(); return redirect()->route('filament.admin.resources.invoices.view', $invoice); }) ->visible(fn (Booking $record) => $record->invoices()->count() === 0), ]; } ``` ## Best Practices ### 1. Always Use Transactions ```php DB::transaction(function () use ($booking) { $invoice = $invoiceService->createFromBooking($booking); // Additional operations }); ``` ### 2. Recalculate Totals After Modifications ```php $invoice->recalculateTotals(); $invoice->save(); ``` ### 3. Use Polymorphic Relationships ```php // Store reference to actual bookable item InvoiceItem::create([ 'itemable_type' => VenueObject::class, 'itemable_id' => $venueObject->id, // ... ]); ``` ### 4. Track Duration for Time-Based Bookings ```php InvoiceItem::create([ 'duration_type' => 'night', 'duration_value' => 3, 'start_date' => $booking->check_in, 'end_date' => $booking->check_out, // ... ]); ``` ### 5. Use Categories for Organization ```php // Makes it easy to filter and display items $invoice->accommodationItems; // All rooms/houses $invoice->productItems; // All minibar/insurance $invoice->feeItems; // All fees ``` ## Migration Instructions 1. **Run the migration:** ```bash php artisan migrate ``` 2. **Update existing invoices (if needed):** ```php // Script to link existing invoices to bookings Invoice::whereNull('booking_id')->each(function ($invoice) { if ($invoice->reservation_id) { $booking = Booking::where('reservation_id', $invoice->reservation_id)->first(); if ($booking) { $invoice->update(['booking_id' => $booking->id]); } } }); ``` 3. **Test the integration:** ```bash php artisan tinker ``` ```php $booking = Booking::first(); $service = app(InvoiceService::class); $invoice = $service->createFromBooking($booking); dd($invoice->toArray()); ``` ## Tax Configuration Override the `getTaxRate()` method in `InvoiceService` to implement custom tax logic: ```php protected function getTaxRate(Booking $booking): float { // Example: Different rates by location if ($booking->location?->country === 'BG') { return 20.0; // Bulgaria VAT } // Example: Different rates by booking type if ($booking->booking_type === 'services') { return 0.0; // Services exempt } // Example: Get from venue settings return $booking->venue?->tax_rate ?? 20.0; } ``` ## Fiscal Receipt Integration The invoice model includes fiscal receipt fields for integration with fiscal printers: ```php $invoice->fiscal_receipt_number = 'FR-2025-001234'; $invoice->fiscal_status = 'printed'; $invoice->fiscal_printed_at = now(); $invoice->save(); ``` ## Summary This enhanced invoice system provides: - ✅ Complete booking integration - ✅ Support for all booking types (spots, rentals, services) - ✅ Flexible product additions (minibar, insurance, etc.) - ✅ Comprehensive payment tracking - ✅ Proforma and credit note support - ✅ Polymorphic item relationships - ✅ Automatic total calculations - ✅ Category-based organization - ✅ Duration tracking for time-based bookings - ✅ Fiscal receipt integration ready