where('short_code', $shortCode) ->where('type', QrCode::TYPE_CHURCH) ->where('is_active', true) ->firstOrFail(); if (! $qrCode->acceptsOrders()) { return response()->json(['error' => 'This giving page does not accept donations.'], 422); } $validated = $request->validate([ 'customer_name' => ['required', 'string', 'max:120'], 'customer_email' => ['nullable', 'email', 'max:200'], 'customer_phone' => ['required', 'string', 'max:30'], 'items' => ['required', 'array', 'min:1'], 'items.*.name' => ['required', 'string', 'max:200'], 'items.*.price' => ['required', 'numeric', 'min:0.01'], 'items.*.qty' => ['required', 'integer', 'min:1', 'max:1'], ]); try { $result = $this->donations->initiateOrder($qrCode, $validated); } catch (RuntimeException $e) { return response()->json(['error' => $e->getMessage()], 422); } return response()->json([ 'checkout_url' => $result['checkout_url'], 'callback_url' => $result['callback_url'], ]); } 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 { $donation = $this->donations->complete($reference); } catch (\Throwable) { return view('public.payment-return', [ 'redirect' => LadillLink::url($shortCode), ]); } return view('public.payment-return', [ 'redirect' => route('qr.public.donation.confirmed', [ 'shortCode' => $shortCode, 'reference' => $donation->payment_reference, ], absolute: true), ]); } public function confirmed(string $shortCode, string $reference): View { $donation = GiveDonation::query() ->with('qrCode') ->where('payment_reference', $reference) ->where('status', GiveDonation::STATUS_PAID) ->whereHas('qrCode', fn ($q) => $q->where('short_code', $shortCode)) ->firstOrFail(); return view('public.qr.donation-confirmed', [ 'donation' => $donation, 'qrCode' => $donation->qrCode, ]); } }