From 2795e0b927faf837bbf9514377186e02902fb786 Mon Sep 17 00:00:00 2001 From: Dwindi Ramadhana Date: Sun, 15 Feb 2026 00:18:16 +0700 Subject: [PATCH] fix: harden pakasir qris parsing and remove legacy compose envs --- .../Controllers/Billing/PakasirController.php | 67 +++++++++++++++++-- docker-compose.yml | 9 --- 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/app/app/Http/Controllers/Billing/PakasirController.php b/app/app/Http/Controllers/Billing/PakasirController.php index a250b80..820921a 100644 --- a/app/app/Http/Controllers/Billing/PakasirController.php +++ b/app/app/Http/Controllers/Billing/PakasirController.php @@ -77,7 +77,11 @@ class PakasirController extends Controller ]; $endpoint = $apiBase.'/api/transactioncreate/qris'; - $res = Http::asForm()->timeout($timeout)->post($endpoint, $payload); + $res = Http::timeout($timeout)->post($endpoint, $payload); + if (!$res->successful()) { + // Fallback for gateways expecting x-www-form-urlencoded payloads. + $res = Http::asForm()->timeout($timeout)->post($endpoint, $payload); + } if (!$res->successful()) { Log::warning('Pakasir create transaction failed', [ @@ -89,11 +93,22 @@ class PakasirController extends Controller } $body = $res->json(); - $payment = is_array($body['payment'] ?? null) ? $body['payment'] : $body; - $paymentNumber = (string) ($payment['payment_number'] ?? ''); - $status = (string) ($payment['status'] ?? 'pending'); - $expiredAt = (string) ($payment['expired_at'] ?? ''); - $totalPayment = (int) ($payment['total_payment'] ?? $amountIdr); + if (!is_array($body)) { + Log::warning('Pakasir create transaction invalid response', [ + 'endpoint' => $endpoint, + 'body' => $res->body(), + ]); + return response()->json(['error' => 'pakasir_invalid_response'], 502); + } + + [$paymentNumber, $status, $expiredAt, $totalPayment] = $this->extractPakasirPayload($body, $amountIdr); + if ($paymentNumber === '') { + Log::warning('Pakasir create transaction missing QR value', [ + 'endpoint' => $endpoint, + 'body' => $body, + ]); + return response()->json(['error' => 'pakasir_invalid_response'], 502); + } $order->update([ 'provider_ref' => $orderRef, @@ -124,6 +139,46 @@ class PakasirController extends Controller ]); } + /** + * @param array $body + * @return array{0:string,1:string,2:string,3:int} + */ + private function extractPakasirPayload(array $body, int $amountFallback): array + { + $payment = $body; + if (is_array($body['payment'] ?? null)) { + $payment = $body['payment']; + } elseif (is_array($body['data'] ?? null)) { + $payment = $body['data']; + } + + $paymentNumber = (string) ( + $payment['payment_number'] + ?? $payment['qris_string'] + ?? $payment['qr_string'] + ?? $payment['qr_value'] + ?? '' + ); + + $status = (string) ($payment['status'] ?? $body['status'] ?? 'pending'); + $expiredAt = (string) ( + $payment['expired_at'] + ?? $payment['expires_at'] + ?? $payment['expired'] + ?? '' + ); + + $totalPayment = (int) ( + $payment['total_payment'] + ?? $payment['amount'] + ?? $body['total_payment'] + ?? $body['amount'] + ?? $amountFallback + ); + + return [$paymentNumber, $status, $expiredAt, $totalPayment]; + } + public function cancelPending(Request $request): JsonResponse { $user = $request->user(); diff --git a/docker-compose.yml b/docker-compose.yml index 4ca03e8..328a1ed 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,15 +28,6 @@ services: QUEUE_CONNECTION: ${QUEUE_CONNECTION:-sync} DEWEMOJI_BILLING_MODE: ${DEWEMOJI_BILLING_MODE:-sandbox} - DEWEMOJI_GUMROAD_ENABLED: ${DEWEMOJI_GUMROAD_ENABLED:-false} - DEWEMOJI_GUMROAD_PRODUCT_IDS: ${DEWEMOJI_GUMROAD_PRODUCT_IDS:-} - DEWEMOJI_GUMROAD_TEST_KEYS: ${DEWEMOJI_GUMROAD_TEST_KEYS:-} - DEWEMOJI_MAYAR_ENABLED: ${DEWEMOJI_MAYAR_ENABLED:-false} - DEWEMOJI_MAYAR_API_BASE: ${DEWEMOJI_MAYAR_API_BASE:-} - DEWEMOJI_MAYAR_ENDPOINT_VERIFY: ${DEWEMOJI_MAYAR_ENDPOINT_VERIFY:-/v1/license/verify} - DEWEMOJI_MAYAR_PRODUCT_IDS: ${DEWEMOJI_MAYAR_PRODUCT_IDS:-} - DEWEMOJI_MAYAR_API_KEY: ${DEWEMOJI_MAYAR_API_KEY:-} - DEWEMOJI_MAYAR_SECRET_KEY: ${DEWEMOJI_MAYAR_SECRET_KEY:-} WAIT_FOR_DB: ${WAIT_FOR_DB:-true} RUN_MIGRATIONS: ${RUN_MIGRATIONS:-true}