Deploy Ladill Merchant / deploy (push) Successful in 1m5s
Standardize customer-facing Ladill Pay checkout shells across products, open them on all viewports, and escape iframe callbacks back to the product flow.
116 lines
3.5 KiB
PHP
116 lines
3.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Public;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\QrCode;
|
|
use App\Services\Merchant\BookingSlotService;
|
|
use App\Services\Merchant\MerchantSaleService;
|
|
use App\Support\LadillLink;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
use RuntimeException;
|
|
|
|
class BookingController extends Controller
|
|
{
|
|
public function __construct(
|
|
private BookingSlotService $slots,
|
|
private MerchantSaleService $sales,
|
|
) {}
|
|
|
|
public function slots(Request $request, string $shortCode): JsonResponse
|
|
{
|
|
$qrCode = $this->resolveBookingQr($shortCode);
|
|
$validated = $request->validate([
|
|
'date' => ['required', 'date', 'after_or_equal:today'],
|
|
'service_index' => ['required', 'integer', 'min:0'],
|
|
]);
|
|
|
|
return response()->json([
|
|
'slots' => $this->slots->availableSlots(
|
|
$qrCode,
|
|
$validated['date'],
|
|
(int) $validated['service_index'],
|
|
),
|
|
]);
|
|
}
|
|
|
|
public function store(Request $request, string $shortCode): JsonResponse
|
|
{
|
|
$qrCode = $this->resolveBookingQr($shortCode);
|
|
|
|
$validated = $request->validate([
|
|
'customer_name' => ['required', 'string', 'max:120'],
|
|
'customer_email' => ['nullable', 'email', 'max:200'],
|
|
'customer_phone' => ['required', 'string', 'max:30'],
|
|
'service_index' => ['required', 'integer', 'min:0'],
|
|
'starts_at' => ['required', 'date'],
|
|
]);
|
|
|
|
try {
|
|
$result = $this->sales->initiateBooking($qrCode, $validated);
|
|
} catch (RuntimeException $e) {
|
|
return response()->json(['error' => $e->getMessage()], 422);
|
|
}
|
|
|
|
if ($result['checkout_url']) {
|
|
return response()->json([
|
|
'checkout_url' => $result['checkout_url'],
|
|
'callback_url' => $result['callback_url'],
|
|
]);
|
|
}
|
|
|
|
return response()->json([
|
|
'confirmed' => true,
|
|
'redirect_url' => LadillLink::path($shortCode, 'booking/confirmed/'.$result['booking']->id),
|
|
]);
|
|
}
|
|
|
|
public function callback(Request $request, string $shortCode): View
|
|
{
|
|
$reference = trim((string) $request->query('reference', ''));
|
|
if ($reference === '') {
|
|
return view('public.payment-return', [
|
|
'redirect' => LadillLink::url($shortCode),
|
|
]);
|
|
}
|
|
|
|
try {
|
|
$booking = $this->sales->completeBooking($reference);
|
|
} catch (\Throwable) {
|
|
return view('public.payment-return', [
|
|
'redirect' => LadillLink::url($shortCode),
|
|
]);
|
|
}
|
|
|
|
return view('public.payment-return', [
|
|
'redirect' => LadillLink::path($shortCode, 'booking/confirmed/'.$booking->id),
|
|
]);
|
|
}
|
|
|
|
public function confirmed(string $shortCode, int $booking): View
|
|
{
|
|
$qrCode = $this->resolveBookingQr($shortCode);
|
|
$record = $qrCode->bookings()->whereKey($booking)->firstOrFail();
|
|
|
|
return view('public.qr.booking-confirmed', [
|
|
'qrCode' => $qrCode,
|
|
'booking' => $record,
|
|
]);
|
|
}
|
|
|
|
private function resolveBookingQr(string $shortCode): QrCode
|
|
{
|
|
$qrCode = QrCode::query()
|
|
->where('short_code', $shortCode)
|
|
->where('is_active', true)
|
|
->firstOrFail();
|
|
|
|
abort_unless($qrCode->isBookingType(), 404);
|
|
|
|
return $qrCode;
|
|
}
|
|
}
|