# 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