공개 이슈(gnuboard/g7) 17건 전수 대조에서 "진짜 누락"으로 판정된 5건을 해소한다.
— 서버가 만들어 내보내는 상점 주소가 각 지점에서 `/shop` 리터럴이나
`"/{$routePath}/..."` 조립으로 흩어져 있었다. 기본값이 아닌 상점에서는 그 주소가
존재하지 않는 화면을 가리키는데, 서버는 문자열을 만들어 내려보냈을 뿐이라 예외도
404 로그도 남지 않는다 — 링크만 조용히 죽는다. `ShopPathResolver` 를 단일 해석
지점으로 두고 주문 완료 이동·비회원 조회 안내·알림 메일·통합검색·상품문의·SEO
캐시·사이트맵 전 지점을 경유시켰다. 같은 값에 종속된 PG 4종 리다이렉트는
`{shopBase}` 자리표시자로, 편집기 상태 scope 는 선택 세그먼트 토큰 `/*?`
(engine-v1.58.0)로 해소했다. 기설치본은 업그레이드 스텝이 백필한다.
M-02 — 답변 깊이 상한이 config 는 1~10 인데 컬럼 comment 만 1~5 로 남아,
comment 에서 자동 생성되는 계약 문서 4곳이 실제보다 좁은 상한을 공개하고 있었다.
L-01 — 관리자 게시글 폼에 첨부 안내가 아예 없었고, 대신 사장된 고정 문구
("최대 5개 파일, 각 10MB")가 남아 있었다. 게시판마다 다른 실제 설정값을 렌더한다.
— 목록 1페이지가 공지 전량을 상한 없이 읽던 것에 안전상한을 두고(구조 무변경,
limit 부가만), 조회수 정렬 목록 술어를 덮는 복합 색인을 신설했다.
브라우저 실측 검수에서 발견한 사전 결함 1건(사용자 게시판 목록이 URL 정렬
파라미터를 데이터소스로 전달하지 않던 문제)도 함께 고쳤다. 폴백을 빈 문자열로 둬
URL 에 정렬이 없을 때 게시판 설정을 덮어쓰지 않게 했다.
228 lines
9.7 KiB
PHP
228 lines
9.7 KiB
PHP
<?php
|
|
|
|
namespace Plugins\Sirsoft\PayNhnkcp;
|
|
|
|
use App\Extension\AbstractPlugin;
|
|
|
|
/**
|
|
* NHN KCP PG 플러그인
|
|
*
|
|
* NHN KCP Standard Pay(카드/계좌이체/가상계좌/휴대폰) 연동을 제공합니다.
|
|
* sirsoft-ecommerce 모듈 전용 플러그인입니다.
|
|
*/
|
|
class Plugin extends AbstractPlugin
|
|
{
|
|
public function getMetadata(): array
|
|
{
|
|
return [
|
|
'author' => 'Sirsoft',
|
|
'license' => 'MIT',
|
|
'homepage' => 'https://sir.kr',
|
|
'keywords' => ['payment', 'nhnkcp', 'kcp', 'pg', 'card', 'ecommerce'],
|
|
];
|
|
}
|
|
|
|
public function getSettingsSchema(): array
|
|
{
|
|
return [
|
|
'is_test_mode' => [
|
|
'type' => 'boolean',
|
|
'default' => true,
|
|
'label' => ['ko' => '테스트 모드', 'en' => 'Test Mode'],
|
|
'hint' => [
|
|
'ko' => '테스트 모드에서는 실제 결제가 발생하지 않습니다.',
|
|
'en' => 'No real payments occur in test mode.',
|
|
],
|
|
],
|
|
'test_site_cd' => [
|
|
'type' => 'string',
|
|
'default' => 'T0000',
|
|
'label' => ['ko' => '테스트 사이트 코드 (site_cd)', 'en' => 'Test Site Code (site_cd)'],
|
|
'hint' => [
|
|
'ko' => 'KCP에서 발급받은 테스트 사이트 코드 (기본값: T0000)',
|
|
'en' => 'Test site code issued by KCP (default: T0000)',
|
|
],
|
|
],
|
|
'test_site_key' => [
|
|
'type' => 'string',
|
|
'default' => '',
|
|
'sensitive' => true,
|
|
'label' => ['ko' => '테스트 사이트 키 (site_key)', 'en' => 'Test Site Key (site_key)'],
|
|
'hint' => [
|
|
'ko' => 'KCP에서 발급받은 테스트 사이트 키',
|
|
'en' => 'Test site key issued by KCP',
|
|
],
|
|
],
|
|
'live_site_cd' => [
|
|
'type' => 'string',
|
|
'default' => '',
|
|
'label' => ['ko' => '라이브 사이트 코드 (site_cd)', 'en' => 'Live Site Code (site_cd)'],
|
|
'hint' => [
|
|
'ko' => 'KCP에서 발급받은 라이브 사이트 코드 (SR prefix 제외하고 입력)',
|
|
'en' => 'Live site code issued by KCP (enter without SR prefix)',
|
|
],
|
|
],
|
|
'live_site_key' => [
|
|
'type' => 'string',
|
|
'default' => '',
|
|
'sensitive' => true,
|
|
'label' => ['ko' => '라이브 사이트 키 (site_key)', 'en' => 'Live Site Key (site_key)'],
|
|
'hint' => [
|
|
'ko' => '외부에 노출되지 않도록 주의하세요.',
|
|
'en' => 'Keep this key secret.',
|
|
],
|
|
],
|
|
'redirect_success_url' => [
|
|
'type' => 'string',
|
|
'default' => '{shopBase}/orders/{orderId}/complete',
|
|
'label' => ['ko' => '결제 성공 리다이렉트 URL', 'en' => 'Payment Success Redirect URL'],
|
|
'hint' => [
|
|
'ko' => '{shopBase}는 상점 주소 설정을 따라 자동으로 채워집니다. 전체 URL(https://...)을 직접 넣어도 됩니다. {orderId}는 주문번호로 자동 치환됩니다.',
|
|
'en' => '{shopBase} is filled in from the storefront address setting. You may also enter a full URL (https://...). {orderId} will be replaced with the actual order number.',
|
|
],
|
|
],
|
|
'redirect_fail_url' => [
|
|
'type' => 'string',
|
|
'default' => '{shopBase}/checkout',
|
|
'label' => ['ko' => '결제 실패 리다이렉트 URL', 'en' => 'Payment Failure Redirect URL'],
|
|
'hint' => [
|
|
'ko' => '상대 경로 또는 전체 URL 모두 가능합니다. 오류 정보는 쿼리 파라미터로 자동 추가됩니다.',
|
|
'en' => 'Supports relative paths or full URLs. Error details are appended as query parameters.',
|
|
],
|
|
],
|
|
'use_escrow' => [
|
|
'type' => 'boolean',
|
|
'default' => false,
|
|
'label' => ['ko' => '에스크로 결제 활성화', 'en' => 'Enable Escrow Payment'],
|
|
'hint' => [
|
|
'ko' => 'KCP 에스크로 결제 사용 시 활성화. 별도 site_cd 가 필요합니다.',
|
|
'en' => 'Enable KCP escrow payment. A separate site_cd is required.',
|
|
],
|
|
],
|
|
'escrow_test_site_cd' => [
|
|
'type' => 'string',
|
|
'default' => '',
|
|
'label' => ['ko' => '테스트 에스크로 사이트 코드', 'en' => 'Test Escrow Site Code'],
|
|
'hint' => [
|
|
'ko' => 'KCP 에스크로 테스트 site_cd. 미입력 시 일반 test_site_cd 를 그대로 사용.',
|
|
'en' => 'KCP escrow test site_cd. Falls back to regular test_site_cd if empty.',
|
|
],
|
|
],
|
|
'vbank_expire_days' => [
|
|
'type' => 'integer',
|
|
'default' => 3,
|
|
'min' => 1,
|
|
'max' => 30,
|
|
'label' => ['ko' => '가상계좌 입금 만료(일)', 'en' => 'Virtual Account Expiry (days)'],
|
|
'hint' => [
|
|
'ko' => '가상계좌 발급 후 입금 가능 기간. 모바일 vcnt_expire_term 값으로 전달.',
|
|
'en' => 'Days the virtual account remains payable after issuance.',
|
|
],
|
|
],
|
|
'easy_pay_allow_with_other_pg' => ['type' => 'boolean', 'default' => false],
|
|
'easy_pay_payco' => ['type' => 'boolean', 'default' => false],
|
|
'easy_pay_naverpay' => ['type' => 'boolean', 'default' => false],
|
|
'easy_pay_naverpay_point' => ['type' => 'boolean', 'default' => false],
|
|
'easy_pay_kakaopay' => ['type' => 'boolean', 'default' => false],
|
|
'easy_pay_applepay' => ['type' => 'boolean', 'default' => false],
|
|
];
|
|
}
|
|
|
|
public function getConfigValues(): array
|
|
{
|
|
return [
|
|
'is_test_mode' => true,
|
|
'test_site_cd' => 'T0000',
|
|
'test_site_key' => '',
|
|
'live_site_cd' => '',
|
|
'live_site_key' => '',
|
|
'redirect_success_url' => '{shopBase}/orders/{orderId}/complete',
|
|
'redirect_fail_url' => '{shopBase}/checkout',
|
|
'use_escrow' => false,
|
|
'escrow_test_site_cd' => '',
|
|
'vbank_expire_days' => 3,
|
|
'easy_pay_allow_with_other_pg' => false,
|
|
'easy_pay_payco' => false,
|
|
'easy_pay_naverpay' => false,
|
|
'easy_pay_naverpay_point' => false,
|
|
'easy_pay_kakaopay' => false,
|
|
'easy_pay_applepay' => false,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 이 플러그인이 등록할 HTTP 미들웨어 선언을 반환합니다.
|
|
*
|
|
* IP 화이트리스트(RestrictKcpIp)는 KCP 서버 발신 webhook 라우트에만 부착합니다.
|
|
* 브라우저 POST 콜백(payment.callback)은 사용자 IP 라 대상에서 제외 — 결제 회귀 방지.
|
|
* 코어 ExtensionMiddlewareGate 가 요청 시점에 실행합니다.
|
|
*
|
|
* @return array<int, array{class: class-string, groups: array<int, string>, timing?: string, targets: array<int, string>}>
|
|
*/
|
|
public function getMiddleware(): array
|
|
{
|
|
return [
|
|
[
|
|
'class' => Http\Middleware\RestrictKcpIp::class,
|
|
'groups' => ['web'],
|
|
'targets' => [
|
|
'web.plugins.sirsoft-pay_nhnkcp.payment.vbank-notify',
|
|
'web.plugins.sirsoft-pay_nhnkcp.payment.escrow-common-notify',
|
|
],
|
|
],
|
|
];
|
|
}
|
|
|
|
public function getHookListeners(): array
|
|
{
|
|
return [
|
|
Listeners\RegisterPgProviderListener::class,
|
|
Listeners\PaymentRefundListener::class,
|
|
Listeners\CancelActivityLogListener::class,
|
|
Listeners\RegisterEasyPayMethodsListener::class,
|
|
Listeners\AdjustEcommercePaymentMethodsLayoutListener::class,
|
|
Listeners\EnsureAdminOrderListTestBadgeLayoutListener::class,
|
|
Listeners\EnsureAdminOrderDetailPaymentQueryLayoutListener::class,
|
|
Listeners\RestoreLayoutExtensionsAfterUpdateListener::class,
|
|
];
|
|
}
|
|
|
|
public function getHooks(): array
|
|
{
|
|
return [
|
|
[
|
|
'name' => 'sirsoft-pay_nhnkcp.payment.before_confirm',
|
|
'type' => 'action',
|
|
'description' => [
|
|
'ko' => 'KCP 결제 승인 확인 전',
|
|
'en' => 'Before KCP payment confirmation',
|
|
],
|
|
],
|
|
[
|
|
'name' => 'sirsoft-pay_nhnkcp.payment.after_confirm',
|
|
'type' => 'action',
|
|
'description' => [
|
|
'ko' => 'KCP 결제 승인 확인 완료 후',
|
|
'en' => 'After KCP payment confirmation completed',
|
|
],
|
|
],
|
|
[
|
|
'name' => 'sirsoft-pay_nhnkcp.payment.before_cancel',
|
|
'type' => 'action',
|
|
'description' => [
|
|
'ko' => 'KCP 결제 취소 API 호출 전 (본인인증 등 확장 지점)',
|
|
'en' => 'Before KCP cancel API call (extension point for re-auth, etc.)',
|
|
],
|
|
],
|
|
[
|
|
'name' => 'sirsoft-pay_nhnkcp.payment.after_cancel',
|
|
'type' => 'action',
|
|
'description' => [
|
|
'ko' => 'KCP 결제 취소 완료 후',
|
|
'en' => 'After KCP cancel completed',
|
|
],
|
|
],
|
|
];
|
|
}
|
|
}
|