fix(nicepayments): 가상계좌 close-report 상태 보존
가상계좌 발급 후 입금대기 상태인 주문에 PC 결제창 닫힘 보고가 뒤늦게 도착해도 주문/결제 상태를 실패로 덮지 않도록 READY 상태만 실패 처리 대상으로 제한한다.
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- 나이스페이먼츠 가상계좌 발급 후 뒤늦게 PC 결제창 닫힘 보고가 들어와도 입금대기 주문이 결제실패/취소로 덮이지 않도록 보강했습니다.
|
||||
- 이미 부분취소된 나이스페이먼츠 거래의 남은 잔액을 다시 취소할 때 PG 취소 요청이 전액취소로 잘못 전달되어 실패하던 문제를 수정했습니다.
|
||||
- 비회원 나이스페이먼츠 주문완료/주문상세에서 매출전표 조회가 인증 사용자 전용 라우트에 막히지 않도록 게스트 주문 토큰과 결제 성공 후 임시 영수증 쿠키 접근을 지원했습니다.
|
||||
- 나이스페이먼츠 인증 단계 실패(`AuthResultCode != 0000`)는 실제 PG 승인 전이므로 주문/결제/주문옵션을 취소 상태로 바꾸지 않고 체크아웃 재시도가 가능하도록 수정했습니다.
|
||||
|
||||
+7
-4
@@ -8,6 +8,7 @@ use App\Helpers\ResponseHelper;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Modules\Sirsoft\Ecommerce\Enums\PaymentStatusEnum;
|
||||
use Modules\Sirsoft\Ecommerce\Models\Order;
|
||||
use Modules\Sirsoft\Ecommerce\Services\OrderProcessingService;
|
||||
use Plugins\Sirsoft\PayNicepayments\Concerns\RecordsPaymentWindowClosure;
|
||||
@@ -129,13 +130,15 @@ class PaymentCloseReportController
|
||||
$payment = $lockedOrder->payment()->lockForUpdate()->first();
|
||||
$lockedOrder->setRelation('payment', $payment);
|
||||
|
||||
// 결제 성공 콜백과 결제창 닫힘 보고가 경쟁할 때, 카드 주문은 승인 직전까지
|
||||
// order_status=PENDING_ORDER(=isBeforePayment) 라 위 가드를 통과한다. payment_status 가
|
||||
// 이미 PAID 면 결제가 성공한 것이므로 실패 처리하지 않는다(markPaymentWindowClosed 가
|
||||
// 옵션을 취소로 덮어 주문/옵션 상태가 어긋나는 race 차단). 행 락 획득 직후 재확인한다.
|
||||
// close-report 는 결제창이 승인/발급 단계로 넘어가기 전 READY 상태만 실패 처리한다.
|
||||
// 카드 승인 콜백과 경쟁해 PAID 가 먼저 저장됐거나, 가상계좌 발급으로 WAITING_DEPOSIT 이
|
||||
// 된 주문은 닫힘 보고가 뒤늦게 도착해도 주문/결제 상태를 덮으면 안 된다.
|
||||
if ($payment?->isPaid()) {
|
||||
return ['status' => 'ignored', 'reason' => 'payment_already_paid'];
|
||||
}
|
||||
if (! $payment || $payment->payment_status !== PaymentStatusEnum::READY) {
|
||||
return ['status' => 'ignored', 'reason' => 'payment_not_ready'];
|
||||
}
|
||||
|
||||
$expectedPrice = $this->resolveExpectedPaymentPriceOrNull($lockedOrder, 'close_report_locked', [
|
||||
'oid' => $oid,
|
||||
|
||||
+47
@@ -293,6 +293,53 @@ class PaymentCloseReportControllerTest extends PluginTestCase
|
||||
$this->assertNotEquals(OrderStatusEnum::CANCELLED, $order->order_status);
|
||||
}
|
||||
|
||||
public function test_close_report_ignores_vbank_order_waiting_for_deposit(): void
|
||||
{
|
||||
$order = OrderFactory::new()->create([
|
||||
'order_number' => 'ORD-NICE-CLOSE-VBANK-WAIT',
|
||||
'order_status' => OrderStatusEnum::PENDING_ORDER,
|
||||
'currency' => 'KRW',
|
||||
'currency_snapshot' => self::krwCurrencySnapshot(),
|
||||
'subtotal_amount' => 10000,
|
||||
'total_amount' => 10000,
|
||||
'total_due_amount' => 10000,
|
||||
'total_paid_amount' => 0,
|
||||
]);
|
||||
OrderPaymentFactory::new()->create([
|
||||
'order_id' => $order->id,
|
||||
'payment_status' => PaymentStatusEnum::WAITING_DEPOSIT,
|
||||
'payment_method' => PaymentMethodEnum::VBANK,
|
||||
'pg_provider' => 'nicepayments',
|
||||
'paid_amount_local' => 0,
|
||||
'transaction_id' => 'TID_VBANK_WAITING',
|
||||
'vbank_name' => '국민은행',
|
||||
'vbank_number' => '1234567890',
|
||||
'vbank_issued_at' => now(),
|
||||
'payment_meta' => [
|
||||
'vbank_tid' => 'TID_VBANK_WAITING',
|
||||
'vbank_num' => '1234567890',
|
||||
'vbank_name' => '국민은행',
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $this->postJson('/api/plugins/sirsoft-pay_nicepayments/payment/close-report', [
|
||||
'oid' => 'ORD-NICE-CLOSE-VBANK-WAIT',
|
||||
'price' => 10000,
|
||||
'payment_method' => 'vbank',
|
||||
'reason' => 'nicepay-window-closed',
|
||||
]);
|
||||
|
||||
$response->assertOk()
|
||||
->assertJsonPath('data.status', 'ignored')
|
||||
->assertJsonPath('data.reason', 'payment_not_ready');
|
||||
|
||||
$order->refresh();
|
||||
$this->assertEquals(OrderStatusEnum::PENDING_ORDER, $order->order_status);
|
||||
$this->assertEquals(PaymentStatusEnum::WAITING_DEPOSIT, $order->payment->payment_status);
|
||||
$this->assertSame('TID_VBANK_WAITING', $order->payment->transaction_id);
|
||||
$this->assertNull($order->order_meta['payment_failure_code'] ?? null);
|
||||
}
|
||||
|
||||
private function makeOrder(string $orderNumber, int $amount): Order
|
||||
{
|
||||
$order = new Order;
|
||||
|
||||
Reference in New Issue
Block a user