Files
Gnuboard7/plugins/_bundled/sirsoft-pay_kginicis/src/Controllers/AdminEscrowDenyConfirmController.php
T
HeuJung 6c8381f164 fix(core,board,ecommerce,plugins): API 문서 미채움 마커 전수 채움 + 미해석 lang 키 정정 + IDV 조회 시도횟수 비노출
이슈 본연: API 레퍼런스의 미채움 마커 5종(실측 제외/TODO/필드 없음/대표 에러 없음)
1,194건을 코드에서 읽어 전수 채우고(0건), api:docgen 재생성이 사람이 채운 내용을
손실·열화시키던 멱등성 결함 4종(CRLF, 표 파이프 이스케이프, 에러 서술 보존, 중복
라우트명 키)을 근본 수정. --check 를 실측 제외와 드리프트가 구분되도록 재정의.
ParameterDescriber/ResourceFieldDescriber 에 leaf 폴백·SEO 스코프·공통 사전 확장.

파생 결함(문서 실측 중 발견): ResponseHelper 기본 메시지 키 6종이 존재하지 않는
messages.* 를 가리켜 응답 message 가 번역문 대신 키 문자열로 노출되던 문제를 common.*
으로 정정하고, 코어 7 + gdpr/marketing/pay_kginicis/verification/ecommerce 확장의
호출부와 누락 lang 키(게시판 10키 + 이커머스 category_images 4키 포함)를 ko/en/ja
전수 정정. 중복 그룹 키 2건은 기존 키로 호출부 통합.

보안: GET /api/identity/challenges/{id} 는 권한 가드 없는 공개 폴링 엔드포인트인데
Service::getStatus 가 attempts/max_attempts 를 응답에 담아 남은 시도 횟수를 추론할 수
있었다. 두 필드를 제거하고, 챌린지 화면(admin_basic/basic)의 서버 attempts 참조를
제거(남은 횟수 UI 는 query fallback + verify 실패 시 로컬 증가로 유지).

부수 정리(변경셋에 들어온 board 컨트롤러의 audit 사전 결함): FormRequest 4개 신설로
base Request 주입 제거, CommentController 의 Board 직접 호출을 BoardService 위임으로
전환, PHPDoc @return 보강. board 스위트에서 발견한 stale test 3건(seed SSoT 불일치,
admin 계정 user 역할 누락)도 같은 세션에서 정정.

버전 정렬(공개 release 기준): 코어 7.0.3→7.0.4, sirsoft-board 1.0.1→1.0.2,
verification_kginicis 1.0.0→1.0.1, admin_basic 1.0.1→1.0.4.
2026-08-06 14:16:40 +09:00

152 lines
5.0 KiB
PHP

<?php
declare(strict_types=1);
namespace Plugins\Sirsoft\PayKginicis\Controllers;
use App\Helpers\ResponseHelper;
use App\Http\Controllers\Api\Base\AdminBaseController;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Plugins\Sirsoft\PayKginicis\Concerns\SanitizesPgResponse;
use Plugins\Sirsoft\PayKginicis\Services\KgInicisApiService;
/**
* KG 이니시스 에스크로 구매거절확인 관리자 컨트롤러
*
* 구매자가 구매거절 선택 후 판매자(관리자)가 INIAPI v1 type=Dncf로 거절 확인 처리.
* 메뉴얼: https://manual.inicis.com/pay/escrow_pc.html#dncf
*/
class AdminEscrowDenyConfirmController extends AdminBaseController
{
use SanitizesPgResponse;
/** 에스크로 구매거절확인 PG 응답 저장 허용 필드 */
private const ESCROW_DENY_CONFIRM_RESPONSE_KEYS = [
'resultCode',
'resultMsg',
'tid',
'TID',
'originalTid',
'mid',
'MID',
'type',
];
public function __construct(
private readonly KgInicisApiService $apiService,
) {
parent::__construct();
}
/**
* confirm
*
* @param Request $request
* @param string $orderNumber
* @return JsonResponse
*/
public function confirm(Request $request, string $orderNumber): JsonResponse
{
$payment = $this->findEscrowPayment($orderNumber);
if (! $payment) {
return ResponseHelper::error('common.failed', 404, null);
}
$meta = $payment->payment_meta ? json_decode($payment->payment_meta, true) : [];
// 이미 구매거절확인 완료된 경우
if (isset($meta['escrow_deny_confirm'])) {
return ResponseHelper::error('common.failed', 422, [
'message' => ['이미 구매거절확인이 완료되었습니다.'],
]);
}
$dcnfName = trim((string) $request->input('dcnf_name', '관리자'));
Log::info('KG Inicis: escrow deny confirm requested', [
'order_number' => $orderNumber,
'tid' => $payment->transaction_id,
]);
try {
$this->apiService->useEscrowCredentials(true);
$pgResponse = $this->apiService->denyConfirmEscrow([
'originalTid' => $payment->transaction_id,
'dcnfName' => $dcnfName,
]);
$resultCode = $pgResponse['resultCode'] ?? '';
$sanitizedPgResponse = $this->sanitizePgResponse($pgResponse, self::ESCROW_DENY_CONFIRM_RESPONSE_KEYS);
if ($resultCode !== '00') {
Log::warning('KG Inicis: escrow deny confirm failed', [
'order_number' => $orderNumber,
'result_code' => $resultCode,
'result_msg' => $pgResponse['resultMsg'] ?? '',
'pg_response' => $sanitizedPgResponse,
]);
return ResponseHelper::error('common.failed', 502, [
'message' => [$pgResponse['resultMsg'] ?? '구매거절확인에 실패했습니다.'],
]);
}
// payment_meta에 구매거절확인 이력 저장
$meta['pg_response_sanitized'] = true;
$meta['escrow_deny_confirm'] = [
'confirmed_at' => now()->toDateTimeString(),
'dcnf_name' => $dcnfName,
'pg_response' => $sanitizedPgResponse,
];
DB::table('ecommerce_order_payments')
->where('id', $payment->id)
->update([
'payment_meta' => json_encode($meta, JSON_UNESCAPED_UNICODE),
'updated_at' => now(),
]);
Log::info('KG Inicis: escrow deny confirm completed', [
'order_number' => $orderNumber,
'tid' => $payment->transaction_id,
]);
return ResponseHelper::success('common.success', [
'result_code' => $resultCode,
'result_msg' => $pgResponse['resultMsg'] ?? 'OK',
]);
} catch (\Exception $e) {
Log::error('KG Inicis: escrow deny confirm exception', [
'order_number' => $orderNumber,
'error' => $e->getMessage(),
]);
return ResponseHelper::error('common.failed', 500, [
'message' => [$e->getMessage()],
]);
}
}
private function findEscrowPayment(string $orderNumber): ?object
{
return DB::table('ecommerce_order_payments as p')
->join('ecommerce_orders as o', 'o.id', '=', 'p.order_id')
->where('o.order_number', $orderNumber)
->where('p.pg_provider', 'kginicis')
->where('p.is_escrow', true)
->whereNotNull('p.transaction_id')
->select([
'p.id',
'p.transaction_id',
'p.payment_meta',
])
->first();
}
}