Booking Payment Integration with MyPOS

📄 General
← Back to Documentation
# Booking Payment Integration with MyPOS ## Overview Integration of booking deposit payments using your existing MyPOS checkout system. ## Files Created ### 1. Controller **`app/Http/Controllers/BookingPaymentController.php`** - Handles booking deposit payment flow - Uses existing MyPOS checkout view - Processes payment callbacks ### 2. Service Extension **`app/Services/MyPosService.php`** (extended) - Added `createBookingCheckoutSession()` method - Added `prepareBookingCartItems()` method - Reuses existing MyPOS infrastructure ## Routes to Add Add these routes to your `routes/web.php`: ```php use App\Http\Controllers\BookingPaymentController; // Booking Payment Routes Route::prefix('bookings')->name('booking.')->group(function () { // Show deposit payment page Route::get('{booking}/payment', [BookingPaymentController::class, 'showDepositPayment']) ->name('payment.show'); // Initiate deposit payment Route::post('{booking}/payment/initiate', [BookingPaymentController::class, 'initiateDepositPayment']) ->name('payment.initiate'); // Payment callbacks from MyPOS Route::get('payment/success', [BookingPaymentController::class, 'handleSuccess']) ->name('payment.success'); Route::get('payment/cancel', [BookingPaymentController::class, 'handleCancel']) ->name('payment.cancel'); Route::post('payment/notify', [BookingPaymentController::class, 'handleNotification']) ->name('payment.notify'); }); // Client routes (if using Filament Client panel) Route::prefix('client')->name('client.')->middleware(['auth'])->group(function () { Route::get('bookings/{booking}', [ClientBookingController::class, 'show']) ->name('bookings.show'); Route::get('bookings', [ClientBookingController::class, 'index']) ->name('bookings.index'); }); ``` ## Payment Flow ### 1. After Booking Creation When a client creates a booking, redirect them to payment: ```php // In your booking creation logic use App\Services\BookingPaymentService; $paymentService = new BookingPaymentService(); $depositAmount = $paymentService->calculateDepositAmount($booking); if ($depositAmount > 0 && financial_setting('require_deposit_for_booking')) { return redirect()->route('booking.payment.show', $booking); } ``` ### 2. Payment Page The payment page shows: - Booking summary - Deposit amount - Payment button **View:** `resources/views/client/bookings/deposit-payment.blade.php` ```blade @extends('layouts.client') @section('content') <div class="max-w-2xl mx-auto py-8 px-4"> <div class="bg-white rounded-lg shadow-lg p-6"> <h1 class="text-2xl font-bold mb-6">Complete Your Booking</h1> <!-- Booking Details --> <div class="mb-6"> <h2 class="text-lg font-semibold mb-3">Booking Summary</h2> <div class="space-y-2"> <div class="flex justify-between"> <span class="text-gray-600">Booking Number:</span> <span class="font-medium">{{ $booking->booking_number }}</span> </div> <div class="flex justify-between"> <span class="text-gray-600">Check-in:</span> <span class="font-medium">{{ $booking->check_in->format('d M Y') }}</span> </div> <div class="flex justify-between"> <span class="text-gray-600">Check-out:</span> <span class="font-medium">{{ $booking->check_out->format('d M Y') }}</span> </div> </div> </div> <!-- Payment Summary --> <div class="bg-gray-50 rounded-lg p-4 mb-6"> <h2 class="text-lg font-semibold mb-3">Payment Summary</h2> <div class="space-y-2"> <div class="flex justify-between"> <span class="text-gray-600">Total Amount:</span> <span class="font-medium">€{{ number_format($paymentSummary['total'], 2) }}</span> </div> <div class="flex justify-between text-blue-600"> <span class="font-semibold">Deposit Required:</span> <span class="font-bold text-xl">€{{ number_format($depositAmount, 2) }}</span> </div> <div class="flex justify-between text-gray-500 text-sm"> <span>Remaining (due at check-in):</span> <span>€{{ number_format($paymentSummary['total'] - $depositAmount, 2) }}</span> </div> </div> </div> <!-- Payment Info --> <div class="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6"> <div class="flex items-start"> <svg class="w-5 h-5 text-blue-600 mt-0.5 mr-2" fill="currentColor" viewBox="0 0 20 20"> <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/> </svg> <div class="text-sm text-blue-800"> <p class="font-semibold mb-1">Secure Payment</p> <p>You will be redirected to our secure payment partner MyPOS to complete the deposit payment.</p> </div> </div> </div> <!-- Payment Button --> <form action="{{ route('booking.payment.initiate', $booking) }}" method="POST"> @csrf <button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-lg transition duration-200"> Proceed to Payment </button> </form> <p class="text-center text-sm text-gray-500 mt-4"> By proceeding, you agree to our terms and conditions </p> </div> </div> @endsection ``` ### 3. MyPOS Checkout The system uses your **existing MyPOS checkout view**: - `resources/views/payments/mypos/mypos-checkout.blade.php` - No changes needed - it already works! ### 4. Success/Cancel Views **Success View:** `resources/views/payments/success.blade.php` ```blade @extends('layouts.client') @section('content') <div class="max-w-2xl mx-auto py-8 px-4"> <div class="bg-white rounded-lg shadow-lg p-8 text-center"> <div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4"> <svg class="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/> </svg> </div> <h1 class="text-2xl font-bold text-gray-900 mb-2">Payment Successful!</h1> <p class="text-gray-600 mb-6">{{ $message }}</p> @if(isset($booking)) <div class="bg-gray-50 rounded-lg p-4 mb-6"> <div class="text-sm text-gray-600 mb-2">Booking Number</div> <div class="text-2xl font-bold text-gray-900">{{ $booking->booking_number }}</div> </div> <div class="space-y-2 text-left mb-6"> <div class="flex justify-between"> <span class="text-gray-600">Deposit Paid:</span> <span class="font-semibold text-green-600">€{{ number_format($payment->amount ?? 0, 2) }}</span> </div> <div class="flex justify-between"> <span class="text-gray-600">Status:</span> <span class="px-2 py-1 bg-green-100 text-green-800 rounded text-sm font-medium">Confirmed</span> </div> </div> <a href="{{ route('client.bookings.show', $booking) }}" class="inline-block bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition duration-200"> View Booking Details </a> @endif </div> </div> @endsection ``` ## Database Updates Run the migrations: ```bash php artisan migrate ``` This will: 1. Add payment tracking fields to `bookings` table 2. Extend `payment_transactions` table for bookings ## Configuration Make sure your MyPOS config is set up in `config/mypos.php`: ```php return [ 'sid' => env('MYPOS_SID'), 'wallet_number' => env('MYPOS_WALLET_NUMBER'), 'key_index' => env('MYPOS_KEY_INDEX', 1), 'private_key_path' => resource_path('certs/mypos_private_key.pem'), 'public_key_path' => resource_path('certs/mypos_public_cert.pem'), 'ipc_url' => env('MYPOS_IPC_URL', 'https://www.mypos.com/vmp/checkout'), 'currency' => 'EUR', // These will be set dynamically for bookings 'url_ok' => env('MYPOS_URL_OK'), 'url_cancel' => env('MYPOS_URL_CANCEL'), 'url_notify' => env('MYPOS_URL_NOTIFY'), ]; ``` ## Testing ### 1. Test Deposit Calculation ```php use App\Services\BookingPaymentService; $paymentService = new BookingPaymentService(); $depositAmount = $paymentService->calculateDepositAmount($booking); // Should return 30% of total if deposit_percentage is 30 ``` ### 2. Test Payment Flow 1. Create a booking 2. Redirect to payment page 3. Click "Proceed to Payment" 4. Should redirect to MyPOS checkout 5. Complete payment on MyPOS 6. Should redirect back to success page 7. Check booking status - should be "confirmed" 8. Check payment record in database ### 3. Check Database ```sql -- Check payment record SELECT * FROM payment_transactions WHERE booking_id = [your_booking_id]; -- Check booking status SELECT booking_number, payment_status, deposit_paid, deposit_amount, paid_amount FROM bookings WHERE id = [your_booking_id]; ``` ## Usage in Client Booking Flow ### After Creating Booking ```php // In your booking creation controller/action use App\Services\BookingPaymentService; protected function afterCreate(): void { $paymentService = new BookingPaymentService(); // Calculate totals $totals = $paymentService->calculateBookingTotal($this->record); $depositAmount = $paymentService->calculateDepositAmount($this->record); // Update booking $this->record->update([ 'total_amount' => $totals['total'], 'subtotal_amount' => $totals['subtotal'], 'tax_amount' => $totals['tax_amount'], 'deposit_amount' => $depositAmount, 'remaining_amount' => $totals['total'] - $depositAmount, ]); // Redirect to payment if deposit required if ($depositAmount > 0 && financial_setting('require_deposit_for_booking')) { return redirect()->route('booking.payment.show', $this->record); } } ``` ## Summary ✅ **Reuses existing MyPOS checkout** - No duplicate code ✅ **Same payment flow** - Familiar to users ✅ **Unified payment tracking** - All payments in one table ✅ **Automatic booking confirmation** - When deposit is paid ✅ **Full payment history** - Visible in admin and client UI The system is ready to process booking deposit payments through MyPOS!