fix(payment): 나이스페이 인증 실패 재시도 상태 유지
인증 단계 실패는 PG 승인 전이므로 주문과 결제, 주문옵션을 취소 상태로 전환하지 않고 체크아웃에서 재시도할 수 있게 한다.
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- 나이스페이먼츠 인증 단계 실패(`AuthResultCode != 0000`)는 실제 PG 승인 전이므로 주문/결제/주문옵션을 취소 상태로 바꾸지 않고 체크아웃 재시도가 가능하도록 수정했습니다.
|
||||
- 다통화 주문의 환율 스냅샷이 누락되거나 0인 경우 SignData, 결제 승인 콜백, 결제창 닫힘 보고에서 예외가 일반 승인 오류로 뭉개지지 않도록 결제 통화 설정 오류로 명시 처리했습니다.
|
||||
- 나이스페이먼츠 간편결제 주문이 주문완료, 마이페이지 주문상세, 관리자 주문목록/상세에서 실제 간편결제 수단 대신 `신용카드`로만 표시되던 문제를 수정했습니다.
|
||||
- 관리자 주문목록과 주문상세 레이아웃이 리뉴얼되거나 플러그인 업데이트 과정에서 나이스페이먼츠 테스트결제 배지, 테스트 모드 안내, 결제 조회/결제 정보 패널이 누락될 수 있던 문제를 수정했습니다.
|
||||
|
||||
-50
@@ -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) ?? [];
|
||||
|
||||
+13
-5
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user