From c59819645a77ef0e6dee2d007faf8493f78a7d65 Mon Sep 17 00:00:00 2001 From: thisgun Date: Sat, 4 Jul 2026 12:48:53 +0900 Subject: [PATCH] =?UTF-8?q?fix(payment):=20=EB=82=98=EC=9D=B4=EC=8A=A4?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=20=EC=9D=B8=EC=A6=9D=20=EC=8B=A4=ED=8C=A8=20?= =?UTF-8?q?=EC=9E=AC=EC=8B=9C=EB=8F=84=20=EC=83=81=ED=83=9C=20=EC=9C=A0?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 인증 단계 실패는 PG 승인 전이므로 주문과 결제, 주문옵션을 취소 상태로 전환하지 않고 체크아웃에서 재시도할 수 있게 한다. --- .../sirsoft-pay_nicepayments/CHANGELOG.md | 1 + .../Controllers/PaymentCallbackController.php | 50 ------------------- .../PaymentCallbackControllerTest.php | 18 +++++-- 3 files changed, 14 insertions(+), 55 deletions(-) diff --git a/plugins/_bundled/sirsoft-pay_nicepayments/CHANGELOG.md b/plugins/_bundled/sirsoft-pay_nicepayments/CHANGELOG.md index 48dbd0a5..dfaa6125 100644 --- a/plugins/_bundled/sirsoft-pay_nicepayments/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-pay_nicepayments/CHANGELOG.md @@ -17,6 +17,7 @@ ### Fixed +- 나이스페이먼츠 인증 단계 실패(`AuthResultCode != 0000`)는 실제 PG 승인 전이므로 주문/결제/주문옵션을 취소 상태로 바꾸지 않고 체크아웃 재시도가 가능하도록 수정했습니다. - 다통화 주문의 환율 스냅샷이 누락되거나 0인 경우 SignData, 결제 승인 콜백, 결제창 닫힘 보고에서 예외가 일반 승인 오류로 뭉개지지 않도록 결제 통화 설정 오류로 명시 처리했습니다. - 나이스페이먼츠 간편결제 주문이 주문완료, 마이페이지 주문상세, 관리자 주문목록/상세에서 실제 간편결제 수단 대신 `신용카드`로만 표시되던 문제를 수정했습니다. - 관리자 주문목록과 주문상세 레이아웃이 리뉴얼되거나 플러그인 업데이트 과정에서 나이스페이먼츠 테스트결제 배지, 테스트 모드 안내, 결제 조회/결제 정보 패널이 누락될 수 있던 문제를 수정했습니다. diff --git a/plugins/_bundled/sirsoft-pay_nicepayments/src/Controllers/PaymentCallbackController.php b/plugins/_bundled/sirsoft-pay_nicepayments/src/Controllers/PaymentCallbackController.php index 3405e72b..c7567fc9 100644 --- a/plugins/_bundled/sirsoft-pay_nicepayments/src/Controllers/PaymentCallbackController.php +++ b/plugins/_bundled/sirsoft-pay_nicepayments/src/Controllers/PaymentCallbackController.php @@ -175,13 +175,6 @@ class PaymentCallbackController 'ip' => $request->ip(), ]); - $this->markAuthPhaseFailureIfOrderMatches( - $moid, - isset($validated['Amt']) ? (int) $validated['Amt'] : null, - $authResultCode, - $authResultMsg, - ); - return redirect($this->resolveFailUrl([])); } @@ -968,49 +961,6 @@ class PaymentCallbackController && $payment->paid_at === null; } - private function markAuthPhaseFailureIfOrderMatches( - string $moid, - ?int $amount, - string $failureCode, - string $failureMessage, - ): void { - if (trim($moid) === '' || $amount === null || $amount < 1) { - return; - } - - try { - $order = $this->orderService->findByOrderNumber($moid); - if (! $order) { - return; - } - - $expectedAmount = $this->resolveExpectedPaymentPriceOrNull($order, 'auth_phase_failure', [ - 'moid' => $moid, - 'received_amt' => $amount, - ]); - if ($expectedAmount === null || $amount !== $expectedAmount) { - return; - } - - $message = trim($failureMessage) !== '' - ? $failureMessage - : '나이스페이먼츠 인증 단계가 완료되지 않았습니다.'; - - $this->markPaymentWindowClosed( - $this->orderService, - $order, - $failureCode !== '' ? $failureCode : 'USER_CANCEL', - $message, - $message, - ); - } catch (\Throwable $e) { - Log::warning('NicePayments: failed to record auth phase payment cancellation', [ - 'moid' => $moid, - 'error' => $e->getMessage(), - ]); - } - } - private function resolveSuccessUrl(string $orderId): string { $settings = $this->pluginSettingsService->get(self::PLUGIN_IDENTIFIER) ?? []; diff --git a/plugins/_bundled/sirsoft-pay_nicepayments/tests/Feature/Controllers/PaymentCallbackControllerTest.php b/plugins/_bundled/sirsoft-pay_nicepayments/tests/Feature/Controllers/PaymentCallbackControllerTest.php index aef36264..d485bd99 100644 --- a/plugins/_bundled/sirsoft-pay_nicepayments/tests/Feature/Controllers/PaymentCallbackControllerTest.php +++ b/plugins/_bundled/sirsoft-pay_nicepayments/tests/Feature/Controllers/PaymentCallbackControllerTest.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; use Mockery; use Modules\Sirsoft\Ecommerce\Database\Factories\OrderFactory; +use Modules\Sirsoft\Ecommerce\Database\Factories\OrderOptionFactory; use Modules\Sirsoft\Ecommerce\Database\Factories\OrderPaymentFactory; use Modules\Sirsoft\Ecommerce\Enums\OrderStatusEnum; use Modules\Sirsoft\Ecommerce\Enums\PaymentMethodEnum; @@ -576,9 +577,12 @@ class PaymentCallbackControllerTest extends PluginTestCase } } - public function test_auth_callback_records_pre_authorize_failure_when_amount_matches_order(): void + public function test_auth_callback_keeps_pre_authorize_failure_retryable_when_amount_matches_order(): void { $order = $this->createTestOrder(50000); + $option = OrderOptionFactory::new()->forOrder($order)->create([ + 'option_status' => OrderStatusEnum::PENDING_ORDER, + ]); $this->mockPluginSettings(); $response = $this->post('/plugins/sirsoft-pay_nicepayments/payment/callback', [ @@ -592,10 +596,14 @@ class PaymentCallbackControllerTest extends PluginTestCase $this->assertStringNotContainsString('error=', $response->headers->get('Location')); $order->refresh(); - $this->assertEquals(OrderStatusEnum::CANCELLED, $order->order_status); - $this->assertEquals('0021', $order->order_meta['payment_failure_code'] ?? null); - $this->assertEquals(PaymentStatusEnum::FAILED, $order->payment->payment_status); - $this->assertNull($order->payment->cancelled_at); + $payment = $order->payment->fresh(); + + $this->assertEquals(OrderStatusEnum::PENDING_ORDER, $order->order_status); + $this->assertArrayNotHasKey('payment_failure_code', $order->order_meta ?? []); + $this->assertEquals(PaymentStatusEnum::READY, $payment->payment_status); + $this->assertArrayNotHasKey('failure_code', $payment->payment_meta ?? []); + $this->assertNull($payment->cancelled_at); + $this->assertEquals(OrderStatusEnum::PENDING_ORDER, $option->refresh()->option_status); } public function test_auth_callback_redirects_to_fail_on_mid_mismatch(): void