Booking Payment System Implementation Guide

📄 General
← Back to Documentation
# Booking Payment System Implementation Guide ## Overview Complete deposit payment system with check-in/check-out payment flow integrated with Financial Settings. ## Architecture ### 1. Database Structure #### Payments Table (`payments`) Tracks all payment transactions for bookings with stages: - **deposit** - Initial deposit payment (online via client UI) - **check_in** - Remaining balance payment at check-in (in-person) - **check_out** - Additional charges payment at check-out (in-person) - **full** - Full payment upfront - **partial** - Partial payment installments - **refund** - Refund transactions #### Booking Payment Fields (added to `bookings` table) - `payment_status` - Overall payment status - `deposit_amount` - Required deposit amount - `deposit_paid` - Boolean flag - `deposit_paid_at` - Timestamp - `total_amount` - Total booking amount - `paid_amount` - Total amount paid - `remaining_amount` - Remaining balance - `tax_amount` - Tax amount - `subtotal_amount` - Subtotal before tax - `payment_confirmed` - Payment confirmation flag - `payment_confirmed_at` - Confirmation timestamp ### 2. Models #### BookingPayment Model - Tracks individual payment transactions - Scoped by company and workspace - Supports multiple payment methods - Tracks payment stages and status - Includes fiscal receipt integration #### Booking Model (Updated) Added relationships: - `payments()` - All payment transactions - `bookingServices()` - Services in booking - `bookingPackages()` - Packages in booking - `bookingSpots()` - Spots in booking - `bookingProducts()` - Products in booking ### 3. BookingPaymentService Comprehensive service for all payment calculations and operations. #### Key Methods **Calculation Methods:** ```php // Calculate total booking amount with tax calculateBookingTotal(Booking $booking): array // Calculate deposit amount based on settings calculateDepositAmount(Booking $booking): float // Calculate remaining balance after deposit calculateRemainingBalance(Booking $booking): float // Calculate amount due at check-in calculateCheckInAmount(Booking $booking): float // Calculate amount due at check-out (additional charges) calculateCheckOutAmount(Booking $booking): float // Get total paid amount getTotalPaidAmount(Booking $booking): float ``` **Status Check Methods:** ```php // Check if deposit has been paid isDepositPaid(Booking $booking): bool // Check if booking is fully paid isFullyPaid(Booking $booking): bool // Get payment status: 'unpaid', 'partially_paid', 'deposit_paid', 'paid' getPaymentStatus(Booking $booking): string // Check if booking can be confirmed (deposit requirement) canConfirmBooking(Booking $booking): bool ``` **Payment Processing Methods:** ```php // Process deposit payment (online) processDepositPayment(Booking $booking, string $paymentMethod, ?string $transactionId): BookingPayment // Process check-in payment (in-person) processCheckInPayment(Booking $booking, float $amount, string $paymentMethod): BookingPayment // Process check-out payment (in-person) processCheckOutPayment(Booking $booking, float $amount, string $paymentMethod): BookingPayment // Get payment summary getPaymentSummary(Booking $booking): array ``` ## Payment Flow ### 1. Booking Creation (Client UI) When a client creates a booking: ```php use App\Services\BookingPaymentService; $paymentService = new BookingPaymentService(); // Calculate totals $totals = $paymentService->calculateBookingTotal($booking); // Calculate deposit required $depositAmount = $paymentService->calculateDepositAmount($booking); // If deposit is enabled and required if (financial_setting('enable_deposit_payments') && financial_setting('require_deposit_for_booking')) { // Show payment form for deposit // Redirect to payment gateway // Process payment $payment = $paymentService->processDepositPayment( $booking, 'stripe', // or 'paypal', 'card', etc. $transactionId ); // Update booking $booking->update([ 'deposit_amount' => $depositAmount, 'deposit_paid' => true, 'deposit_paid_at' => now(), 'payment_status' => 'deposit_paid', 'status' => 'confirmed', // Auto-confirm if deposit paid ]); } ``` ### 2. Check-In Process When staff performs check-in: ```php $paymentService = new BookingPaymentService(); // Calculate amount due at check-in $checkInAmount = $paymentService->calculateCheckInAmount($booking); if ($checkInAmount > 0) { // Show payment form to staff // Process in-person payment $payment = $paymentService->processCheckInPayment( $booking, $checkInAmount, 'cash' // or 'card', 'bank_transfer' ); // Update booking $booking->update([ 'paid_amount' => $paymentService->getTotalPaidAmount($booking), 'remaining_amount' => $paymentService->calculateRemainingBalance($booking), 'payment_status' => $paymentService->getPaymentStatus($booking), 'checked_in_at' => now(), 'status' => 'checked_in', ]); } ``` ### 3. Check-Out Process When staff performs check-out: ```php $paymentService = new BookingPaymentService(); // Calculate any additional charges $checkOutAmount = $paymentService->calculateCheckOutAmount($booking); if ($checkOutAmount > 0) { // Show payment form for additional charges $payment = $paymentService->processCheckOutPayment( $booking, $checkOutAmount, 'card' ); // Update booking $booking->update([ 'paid_amount' => $paymentService->getTotalPaidAmount($booking), 'remaining_amount' => 0, 'payment_status' => 'paid', 'checked_out_at' => now(), 'status' => 'completed', ]); } ``` ## Tax Calculation The service automatically applies tax based on Financial Settings: ```php // Tax settings from config/financial-settings.php 'tax' => [ 'default_tax_rate_type' => 'global', // or 'per_category' 'default_tax_rate' => 20.0, 'tax_inclusive_pricing' => true, // Tax included in price 'tax_display_mode' => 'separate', // How to display tax 'tax_rates_by_category' => [ ['category' => 'accommodation', 'tax_rate' => 20], ['category' => 'service', 'tax_rate' => 10], ], ] ``` ### Tax Calculation Logic **Tax-Inclusive Pricing (default):** ```php // Price already includes tax - extract it $taxAmount = $price - ($price / (1 + ($taxRate / 100))); $netAmount = $price - $taxAmount; ``` **Tax-Exclusive Pricing:** ```php // Tax is added on top $netAmount = $price; $taxAmount = $price * ($taxRate / 100); $total = $netAmount + $taxAmount; ``` **Category-Specific Rates:** ```php // Each item type can have different tax rate - Accommodation: 20% - Services: 10% - Products: 20% - Packages: Based on contents ``` ## Integration Points ### 1. Client Booking Flow **File:** `app/Filament/Client/Resources/BookingResource.php` (or similar) ```php use App\Services\BookingPaymentService; protected function afterCreate(): void { $paymentService = new BookingPaymentService(); // Calculate and store totals $totals = $paymentService->calculateBookingTotal($this->record); $depositAmount = $paymentService->calculateDepositAmount($this->record); $this->record->update([ 'total_amount' => $totals['total'], 'subtotal_amount' => $totals['subtotal'], 'tax_amount' => $totals['tax_amount'], 'deposit_amount' => $depositAmount, ]); // If deposit required, redirect to payment if ($depositAmount > 0 && financial_setting('require_deposit_for_booking')) { return redirect()->route('client.booking.payment', $this->record); } } ``` ### 2. Check-In Action **File:** `app/Filament/Resources/BookingResource/Pages/CheckIn.php` ```php use App\Services\BookingPaymentService; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Select; public function form(Form $form): Form { $paymentService = new BookingPaymentService(); $amountDue = $paymentService->calculateCheckInAmount($this->record); return $form->schema([ TextInput::make('amount_due') ->label('Amount Due') ->default($amountDue) ->disabled() ->prefix('€'), Select::make('payment_method') ->label('Payment Method') ->options([ 'cash' => 'Cash', 'card' => 'Card', 'bank_transfer' => 'Bank Transfer', ]) ->required() ->visible(fn() => $amountDue > 0), ]); } protected function handleCheckIn(array $data): void { $paymentService = new BookingPaymentService(); $amountDue = $paymentService->calculateCheckInAmount($this->record); if ($amountDue > 0) { $paymentService->processCheckInPayment( $this->record, $amountDue, $data['payment_method'] ); } $this->record->update([ 'status' => 'checked_in', 'checked_in_at' => now(), 'payment_status' => $paymentService->getPaymentStatus($this->record), ]); } ``` ### 3. Check-Out Action **File:** `app/Filament/Resources/BookingResource/Pages/CheckOut.php` ```php use App\Services\BookingPaymentService; public function form(Form $form): Form { $paymentService = new BookingPaymentService(); $amountDue = $paymentService->calculateCheckOutAmount($this->record); return $form->schema([ TextInput::make('additional_charges') ->label('Additional Charges') ->default($amountDue) ->numeric() ->prefix('€'), Select::make('payment_method') ->label('Payment Method') ->options([ 'cash' => 'Cash', 'card' => 'Card', ]) ->required() ->visible(fn() => $amountDue > 0), ]); } protected function handleCheckOut(array $data): void { $paymentService = new BookingPaymentService(); if ($data['additional_charges'] > 0) { $paymentService->processCheckOutPayment( $this->record, $data['additional_charges'], $data['payment_method'] ); } $this->record->update([ 'status' => 'completed', 'checked_out_at' => now(), 'payment_status' => 'paid', ]); } ``` ## Usage Examples ### Get Payment Summary ```php $paymentService = new BookingPaymentService(); $summary = $paymentService->getPaymentSummary($booking); /* Returns: [ 'subtotal' => 100.00, 'tax_amount' => 20.00, 'total' => 120.00, 'deposit_required' => 36.00, 'deposit_paid' => true, 'total_paid' => 36.00, 'remaining_balance' => 84.00, 'payment_status' => 'deposit_paid', 'fully_paid' => false, 'items' => [...], ] */ ``` ### Check Payment Status ```php $paymentService = new BookingPaymentService(); if (!$paymentService->canConfirmBooking($booking)) { // Deposit not paid - cannot confirm return back()->withErrors(['Deposit payment required']); } if ($paymentService->isFullyPaid($booking)) { // Booking is fully paid } $status = $paymentService->getPaymentStatus($booking); // Returns: 'unpaid', 'partially_paid', 'deposit_paid', 'paid' ``` ## Migration Steps 1. **Run migrations:** ```bash php artisan migrate ``` 2. **Update existing bookings** (if needed): ```php use App\Services\BookingPaymentService; $paymentService = new BookingPaymentService(); Booking::chunk(100, function ($bookings) use ($paymentService) { foreach ($bookings as $booking) { $totals = $paymentService->calculateBookingTotal($booking); $booking->update([ 'total_amount' => $totals['total'], 'subtotal_amount' => $totals['subtotal'], 'tax_amount' => $totals['tax_amount'], ]); } }); ``` 3. **Configure Financial Settings:** - Enable deposit payments - Set deposit type (percentage/fixed) - Set deposit percentage - Configure tax rates - Set tax-inclusive pricing 4. **Implement UI components:** - Client booking payment page - Check-in payment modal - Check-out payment modal - Payment history view ## Next Steps 1. Create payment gateway integration (Stripe/PayPal) 2. Add payment receipt generation 3. Implement fiscal receipt printing 4. Add payment notifications (email/SMS) 5. Create payment reports and analytics 6. Add refund processing 7. Implement partial payment installments ## Summary ✅ **Database structure** - Payments table and booking payment fields ✅ **Models** - BookingPayment model with relationships ✅ **Service layer** - Comprehensive BookingPaymentService ✅ **Tax calculation** - Automatic tax calculation based on settings ✅ **Payment stages** - Deposit, check-in, check-out flow ✅ **Status tracking** - Payment status and validation ✅ **Integration ready** - Ready for UI implementation The system is now ready for UI integration and payment gateway setup!