diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/CHANGELOG.md b/plugins/_bundled/sirsoft-pay_nhnkcp/CHANGELOG.md deleted file mode 100644 index 9931ac07..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/CHANGELOG.md +++ /dev/null @@ -1,113 +0,0 @@ -# Changelog - -이 프로젝트의 모든 주요 변경사항을 기록합니다. -형식은 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/)를 따르며, -[Semantic Versioning](https://semver.org/lang/ko/)을 준수합니다. - -## [Unreleased] - -### Fixed - -- 비회원 NHN KCP 주문완료/주문상세에서 매출전표 조회가 인증 사용자 전용 라우트에 막히지 않도록 게스트 주문 토큰과 결제 성공 후 임시 영수증 쿠키 접근을 지원했습니다. -- 관리자 주문상세의 NHN KCP 결제 정보 패널이 원승인 정보와 현재 취소/환불 상태를 함께 표시하도록 보강했습니다. -- PC 결제창 close-report와 승인 콜백이 경쟁할 때 결제 성공 주문이 실패 처리로 덮이지 않도록 주문번호 단위 콜백 락과 최신 결제 상태 가드를 적용했습니다. -- NHN KCP 부분취소 요청에서 `rem_mny`를 취소 후 잔액이 아닌 현재 부분취소 가능 금액으로 전달해 큰 금액 부분취소가 거절될 수 있던 문제를 수정했습니다. -- 이커머스 주문설정 화면에서 NHN KCP 플러그인이 테스트 모드일 때 운영 전환 경고와 설정 이동 버튼을 표시하도록 보강했습니다. - -## [1.0.0-beta.5] - 2026-06-23 - -### Fixed - -- 간편결제 주문의 원 결제수단이 사용자 주문완료/주문상세, 관리자 주문목록/주문상세에서 신용카드로만 보이지 않도록 표시 라벨과 관리자 목록 표시 맵을 보강했습니다. -- 동일 주문의 NHN KCP 승인/가상계좌 콜백이 동시에 도착해도 결제완료 훅과 주문 부작용이 중복 실행되지 않도록 주문번호 단위 콜백 락을 추가했습니다. -- 다통화 주문의 환율 스냅샷이 누락되거나 0인 경우 close-report, 재시도 API, 모바일 승인키, 승인 콜백에서 500 오류로 이어지지 않고 결제 통화 설정 오류로 명시 처리되도록 보강했습니다. -- 결제창 닫힘, 인증 취소, 승인 실패, 금액 불일치 등 NHN KCP 실패 경로에서 주문 실패 상태와 결제 레코드의 PG별 실패 메타가 함께 기록되도록 보강했습니다. -- 결제 실패/취소 후 같은 주문번호로 결제창을 다시 열 때 안전한 실패 주문만 `pending_order` / `ready` 상태로 복구하는 재시도 준비 API를 추가했습니다. -- PC/모바일 결제창 호출 직전에 재시도 준비 API를 호출해 사용자가 결제 실패 후 동일 주문 결제를 다시 시도할 수 있도록 보강했습니다. - -## [1.0.0-beta.4] - 2026-06-03 - -### Added - -- 이커머스 주문설정 결제수단 목록에 PAYCO, 네이버페이, 네이버페이 포인트, 카카오페이, Apple Pay 간편결제를 추가했습니다. -- 레이아웃 편집기에서 이 플러그인의 설정 화면을 테스트 모드/운영 모드 상태로 전환해 미리볼 수 있도록 했습니다. -- 레이아웃 편집기 데이터 소스 목록에서 이 확장이 제공하는 데이터 소스가 친화 명칭으로 표시되고, 어느 확장이 제공했는지 출처가 함께 표시됩니다. - -### Security - -- 가상계좌 입금통보와 에스크로 공통통보가 주문번호만으로 처리되지 않도록 저장된 KCP 거래번호, site_cd, 계좌번호, 금액을 교차 검증하도록 보강했습니다. -- 모바일 승인키 발급 시 주문 소유자와 결제금액을 검증해 타인 주문번호 또는 변조 금액으로 승인키가 발급되지 않도록 차단했습니다. -- 무서명 브라우저 실패 콜백만으로 진행 중 주문이 취소/실패 상태로 바뀌지 않도록 차단했습니다. -- NHN KCP가 지원하지 않는 비-KRW 주문이 결제창/승인 콜백으로 진행되지 않도록 서버와 프론트 가드를 추가했습니다. -- KCP CLI 디버그 로그와 에스크로 배송등록 PG 응답 저장에서 비밀키, 카드번호, 수령자 개인정보 등 원문 민감값이 남지 않도록 축소했습니다. -- 에스크로 공통통보 replay 시 동일 payload가 내부 hook을 중복 발행하지 않도록 보강했습니다. - -### Fixed - -- NHN KCP 간편결제 성공 시 원 결제수단이 주문 결제 메타와 간편결제 PG 필드에 보존되도록 보강했습니다. -- 이미 결제 완료된 주문의 카드 승인 콜백이 중복 도착하면 KCP 승인 API를 다시 호출하지 않고 멱등 성공 응답으로 처리하도록 보강했습니다. -- 플러그인 설정 화면에 NHN KCP 상점관리자의 결제취소 서버 IP 등록 필요 안내와 서버 IP 복사 기능을 추가해 운영 모드 결제취소 실패 원인을 사전에 확인할 수 있도록 했습니다. -- 관리자 주문목록과 주문상세 레이아웃이 리뉴얼되거나 플러그인 업데이트 과정에서 NHN KCP 테스트결제 배지, 테스트 모드 안내, 결제 조회/결제 정보 패널이 누락될 수 있던 문제를 수정했습니다. -- 복합과세 모바일/PC 결제 필드의 공급가액, 부가세, 비과세 합계가 할인/마일리지 반영 후 실결제액과 일치하도록 재배분했습니다. -- 에스크로 테스트 site_cd가 비어 있으면 빈 값이 아닌 일반 테스트 site_cd로 fallback되도록 보정했습니다. -- 환불 처리 시 결제 당시 KCP site_cd와 테스트/운영 모드를 복원하도록 보강했습니다. -- KCP webhook IP 가드가 설정 누락 시 테스트 모드로 우회되지 않고 차단되도록 변경했습니다. -- 이커머스 관리자 주문설정 결제수단 목록에서 NHN KCP 간편결제 항목이 브랜드 텍스트 배지로 표시되도록 보강했습니다. -- 체크아웃에서 주문설정으로 활성화한 NHN KCP 간편결제가 숨겨지거나 KG 이니시스 브랜드 문구로 잘못 보정되는 문제를 수정했습니다. -- 결제 취소/부분취소 시 KCP CLI 내부 필드 구분자가 안전성 검사에 막혀 취소 요청이 실패할 수 있던 문제를 수정했습니다. -- 활성 관리자 테마에 최신 시맨틱 CSS가 없어도 플러그인 설정 화면의 여백, 카드 경계, 하단 저장 영역이 깨지지 않도록 보강했습니다. -- NHN KCP PC 결제창을 사용자가 닫거나 취소 콜백이 들어온 경우 임시 주문이 `pending_order` / `ready` 상태로 남지 않고 결제실패/취소 상태로 기록되도록 보강했습니다. -- KCP PC 결제창 내부 취소 버튼이 외부 iframe을 제거하는 흐름에서도 `close-report`가 호출되도록 감시 로직을 추가했습니다. - -### Changed - -- 환경설정 / 주문 화면 결제 영역 외형을 sirsoft-admin_basic 표준 시맨틱과 정합 — 다른 화면과 같은 결로 통일. -- 관리자 화면 좌우 정렬 컨테이너(섹션 헤더 · 액션바 · 카드 상단부 등) 외형을 표준 시맨틱(.flex-between)으로 정리 — 시각 변경 없음, 향후 톤 조정이 한 곳에서 가능. -- 플러그인 환경설정 화면의 하단 저장 버튼이 스크롤 중에도 화면에 고정되도록 개선. -- 환경설정 화면의 가상계좌 입금 통보 URL · 에스크로 통보 URL 표시 입력의 외형을 관리자 표준 외형으로 정렬 — 글자가 옅은 회색으로 표시되어 "참조용 잠긴 정보" 임을 한눈에 구분. -- 플러그인 환경설정 화면의 폼 라벨 / 보조 설명 / 에러 메시지 시각 시맨틱을 sirsoft-admin_basic 표준 시맨틱과 정합 — 다른 관리자 화면과 같은 결로 통일. -- 플러그인 환경설정 화면 곳곳의 텍스트 톤 (보조 설명 · 라벨 · 본문 · 강조 · 작은 보조) 시각 시맨틱을 관리자 표준 시맨틱과 정합 — 같은 결의 글자 톤이 한 곳에서 일괄 조정 가능. -- 플러그인 환경설정 화면의 세로 정렬 컨테이너 / 입력 박스를 sirsoft-admin_basic 표준 시맨틱 (.row-stack / .input) 과 정합 — 입력 행 사이에 옅은 회색 구분선(1px) 이 자동 적용되어 행 묶음 가독성이 개선되고, 입력 박스 외형이 일관 표시되도록 정리. - -## [1.0.0-beta.3] - 2026-05-20 - -### Fixed - -- 결제창 종료 등으로 KCP 콜백의 `res_cd` 가 빈 값으로 들어온 경우 validation 오류가 아닌 사용자 취소 흐름으로 조용히 복귀하도록 수정했습니다. - -### Security - -- 결제 승인/가상계좌 통보 응답 원문 저장을 필요한 필드만 남기는 방식으로 축소 — PG 응답에 섞일 수 있는 카드번호, 구매자 연락처, 계좌 관련 민감 정보의 메타 저장 위험을 줄였습니다. - -## [1.0.0-beta.2] - 2026-05-20 - -### Added - -- PG 측 결제 취소가 확인된 시점에 활동 로그가 별도로 기록되도록 보강 — 운영자가 PG 응답 시각 / 취소 거래번호 등 사후 추적에 활용 가능. - -### Fixed - -- PC 결제 승인 시 간헐적으로 발생하던 "연동 모듈 호출 오류" 가 결제 직전 자동으로 자가 복구되도록 개선 — 플러그인 업데이트 직후 실행 권한 회귀로 인한 결제 실패를 차단합니다. 자동 복구가 불가능한 환경에서는 권한 조치 안내가 포함된 명확한 오류 메시지로 즉시 중단되어 운영자가 빠르게 대응할 수 있습니다. -- KCP CLI 바이너리가 저장소에 실행 가능 권한으로 기록되도록 정정 — 신규 설치 또는 플러그인 업데이트 직후에도 별도 권한 조치 없이 PC 결제가 바로 동작합니다. (Windows 환경은 영향 없음) -- 부분취소 시 PG 가 전액취소로 잘못 처리되어 거부될 수 있던 문제 수정 — 부분취소 금액과 원래 결제금액이 올바르게 전달되도록 정정. - -### Security - -- KCP CLI 호출 시 결제 메타가 평문으로 디스크에 누적되던 문제 차단 — 카드번호 등 민감 정보가 플러그인 내부 로그 파일에 더 이상 저장되지 않습니다. (PCI DSS 평문 저장 우려 해소 + 비표준 서버 배치에서의 직접 다운로드 위험 차단) -- 결제 콜백 중복 처리 방어 추가 — 동일 거래번호로 콜백이 두 번 도착해도 결제완료/마일리지 적립 등이 중복 실행되지 않도록 멱등 응답 처리 -- 결제 처리 중 오류 발생 시 결제 자동 취소 추가 — 카드 승인 후 후속 처리(금액 검증 등) 실패 시 PG 측 결제도 자동 취소하여 사용자 환불 누락 방지 -- Windows 환경의 결제 모듈 호출 시 입력값 안전성 강화 — 위험 문자 사전 거부로 잠재적 명령 주입 차단 - -## [1.0.0-beta.1] - 2026-04-22 - -### Changed - -- 플러그인 식별자를 `sirsoft-pay-nhnkcp`에서 `sirsoft-pay_nhnkcp`로 변경 — G7 코어가 권장하는 `vendor-name` 2-part 명명 규칙에 맞추기 위함 -- 환불 메시지를 한국어/영어 다국어로 분리 — 운영 언어에 따라 자동 노출 -- PG 프로바이더 표시명을 다국어 키로 분리 — 활성 언어팩으로 자동 보강되어 다른 PG 플러그인과 동일한 컨벤션으로 정렬 - -### Added - -- 오픈 베타 릴리즈 -- `sirsoft-pay_nhnkcp.payment.before_cancel` / `after_cancel` 액션 훅 — 외부 소비자가 결제 취소 지점에 본인인증 등 확장 로직을 붙일 수 있도록 확장점 제공 -- PG 도메인 전용 예외 도입 — 외부 소비자가 NHN KCP 도메인 오류만 선택적으로 처리할 수 있도록 개선 diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/LICENSE b/plugins/_bundled/sirsoft-pay_nhnkcp/LICENSE deleted file mode 100644 index 9c330b41..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/LICENSE +++ /dev/null @@ -1,47 +0,0 @@ -프로그램 명칭 : 그누보드7용 NHN KCP 플러그인 (sirsoft-pay-nhnkcp) - -저작자 : (주)에스아이알소프트 - ------ MIT 라이선스 (한국어 번역) -------------------------------------------------------- - -MIT 라이선스 - -Copyright (c) 2026 (주)에스아이알소프트 - -이 소프트웨어와 관련 문서 파일(이하 "소프트웨어")의 복사본을 취득하는 모든 사람에게 -소프트웨어를 제한 없이 사용, 복사, 수정, 병합, 출판, 배포, 서브라이선스 허여 및/또는 -판매할 수 있는 권리를 무상으로 부여합니다. 다만, 소프트웨어를 제공받은 사람은 다음 -조건을 따라야 합니다: - -위 저작권 고지와 본 허가 고지는 소프트웨어의 모든 복사본 또는 상당 부분에 포함되어야 -합니다. - -소프트웨어는 "있는 그대로" 제공되며, 명시적이든 묵시적이든 어떠한 종류의 보증도 하지 -않습니다. 여기에는 상품성, 특정 목적에의 적합성 및 비침해에 대한 보증이 포함되나 이에 -국한되지 않습니다. 어떠한 경우에도 저작자 또는 저작권자는 소프트웨어나 소프트웨어의 -사용 또는 기타 거래로 인해 발생하는 계약, 불법행위 또는 기타 청구, 손해 또는 기타 -책임에 대해 책임을 지지 않습니다. - ------ MIT License (English Original) -------------------------------------------------------- - -The MIT License (MIT) - -Copyright (c) 2026 SIRSOFT - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/README.md b/plugins/_bundled/sirsoft-pay_nhnkcp/README.md deleted file mode 100644 index e71edf19..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/README.md +++ /dev/null @@ -1,249 +0,0 @@ -# NHN KCP Plugin for G7 - -NHN KCP Standard Pay 결제를 G7 `sirsoft-ecommerce` 모듈에 연결하는 결제 플러그인입니다. - -PC 결제는 KCP `payplus_web.jsp` 결제창과 KCP CLI 승인 모듈을 사용하고, 모바일 결제는 SmartPhone Pay SOAP 승인키를 받은 뒤 KCP 모바일 결제창으로 이동합니다. - -## 주요 기능 - -- 신용카드, 계좌이체, 가상계좌, 휴대폰결제 지원 -- PC Standard Pay 결제창 연동 -- 모바일 SmartPhone Pay 승인키 발급 및 모바일 결제창 연동 -- PAYCO, 네이버페이, 네이버페이 포인트, 카카오페이, Apple Pay 간편결제 버튼 주입 -- 가상계좌 발급, 입금통보, 테스트 모드 모의입금 처리 -- 에스크로 결제, 에스크로 배송 등록, 공통통보 처리 -- 결제 취소 및 부분취소 연동 -- PG 측 결제 취소 확인 시점의 활동 로그 별도 기록 (PG 응답 시각·취소 거래번호 사후 추적) -- 주문 완료/마이페이지 영수증, 현금영수증 조회 버튼 주입 -- 관리자 주문 상세의 KCP 거래 정보 표시 -- 관리자 설정 화면의 KCP 실행 환경 점검 - -## 요구 사항 - -| 항목 | 내용 | -|------|------| -| G7 | `>= 7.0.0-beta.2` | -| 의존 모듈 | `sirsoft-ecommerce >= 1.0.0-beta.5` | -| PHP | `^8.2` | -| PC 결제 | PHP `exec()` 사용 가능, KCP CLI 바이너리, `pub.key` | -| 모바일 결제 | PHP SOAP 확장, KCP WSDL 파일 | -| 운영 환경 | HTTPS 도메인, 올바른 `APP_URL`, KCP 가맹점 계약 정보 | - -`bin/` 디렉토리에는 아래 파일이 필요합니다. - -```text -bin/pp_cli -bin/pp_cli_x64 -bin/pp_cli_exe.exe -bin/pub.key -bin/KCPPaymentService.wsdl -bin/real_KCPPaymentService.wsdl -``` - -Linux 서버에서는 현재 OS 아키텍처에 맞는 CLI 파일에 실행 권한이 필요합니다. - -```bash -chmod 755 plugins/sirsoft-pay_nhnkcp/bin/pp_cli -chmod 755 plugins/sirsoft-pay_nhnkcp/bin/pp_cli_x64 -``` - -관리자 설정 화면의 시스템 점검 API가 실행 권한을 자동 복구할 수 있지만, 서버 권한 정책에 따라 직접 조치가 필요할 수 있습니다. - -## 설치 - -플러그인을 G7 프로젝트의 플러그인 디렉토리에 배치합니다. - -```text -plugins/sirsoft-pay_nhnkcp -``` - -프론트엔드 에셋을 수정한 경우 플러그인 디렉토리에서 빌드합니다. - -```bash -npm install -npm run build -``` - -그다음 G7 관리자에서 플러그인을 활성화하고, 이커머스 결제 설정에서 PG 제공자를 `NHN KCP`로 선택합니다. - -## 관리자 설정 - -관리자 플러그인 설정 화면에서 KCP 계약 정보를 입력합니다. - -| 설정 | 설명 | -|------|------| -| 테스트 모드 | 활성화 시 KCP 테스트 환경을 사용합니다. | -| 테스트 사이트 코드 | 기본값은 `T0000`입니다. | -| 테스트 사이트 키 | KCP 테스트 site key입니다. | -| 라이브 사이트 코드 | 운영 site code입니다. `SR` prefix 없이 입력해도 플러그인이 자동 보정합니다. | -| 라이브 사이트 키 | 운영 site key입니다. 외부에 노출하지 마세요. | -| 결제 성공 URL | 기본값은 `/shop/orders/{orderId}/complete`입니다. | -| 결제 실패 URL | 기본값은 `/shop/checkout`입니다. | -| 가상계좌 입금 만료일 | 가상계좌 발급 후 입금 가능 기간입니다. | -| 에스크로 결제 사용 | 활성화 시 KCP 에스크로 결제 파라미터를 함께 전달합니다. | -| 에스크로 테스트 사이트 코드 | 테스트 에스크로 site code입니다. 기본 fallback은 `T0007`입니다. | -| 간편결제 | KCP 계약이 완료된 간편결제만 활성화하세요. | -| 타 PG와 사용가능함 | 다른 PG가 기본값이어도 KCP 간편결제 버튼을 체크아웃 화면에 표시합니다. | - -PAYCO 테스트 결제는 내부 기본값으로 간편결제 테스트 site code `S6729`를 사용합니다. - -## 콜백 및 통보 URL - -KCP 가맹점 관리자에 아래 URL을 등록합니다. 도메인은 실제 운영 도메인으로 바꿔 입력하세요. - -| 용도 | URL | -|------|-----| -| 결제 결과 Return URL | `https://your-domain.com/plugins/sirsoft-pay_nhnkcp/payment/callback` | -| 가상계좌 입금통보 URL | `https://your-domain.com/plugins/sirsoft-pay_nhnkcp/payment/vbank-notify` | -| 에스크로 공통통보 URL | `https://your-domain.com/plugins/sirsoft-pay_nhnkcp/payment/escrow-common-notify` | - -결제 결과 Return URL은 브라우저가 POST하는 경로이므로 IP 제한을 적용하지 않습니다. 가상계좌 입금통보와 에스크로 공통통보는 KCP 서버가 직접 호출하므로 운영 모드에서 IP 화이트리스트를 적용합니다. - -## IP 화이트리스트 - -운영 모드에서는 아래 IP에서 들어온 KCP 서버 통보만 허용합니다. 테스트 모드에서는 개발과 KCP testadmin 모의입금을 위해 IP 제한을 우회합니다. - -| IP | -|----| -| `203.238.36.58` | -| `203.238.36.160` | -| `203.238.36.161` | -| `203.238.36.173` | -| `203.238.36.178` | -| `103.215.144.173` | -| `103.215.144.174` | -| `103.215.145.30` | -| `210.122.72.173` | - -운영 전 KCP 가맹점 관리자와 최신 연동 가이드의 통보 서버 IP를 다시 확인하세요. - -## 결제 흐름 - -### PC 결제 - -```text -체크아웃 주문 생성 -→ 프론트엔드 핸들러가 payplus_web.jsp 결제창 실행 -→ KCP가 /payment/callback 으로 enc_data, enc_info POST -→ 서버가 KCP CLI로 승인 확인 -→ 주문 결제 완료 처리 -→ 성공 URL로 리다이렉트 -``` - -### 모바일 결제 - -```text -체크아웃 주문 생성 -→ /api/plugins/sirsoft-pay_nhnkcp/mobile/approval-key 호출 -→ 서버가 KCP SOAP approve 로 approval_key, pay_url 획득 -→ 브라우저가 pay_url 로 form POST -→ KCP가 /payment/callback 으로 결과 POST -→ 주문 결제 완료 처리 -→ 성공 URL로 리다이렉트 -``` - -### 가상계좌 - -```text -결제창에서 가상계좌 발급 -→ 주문 결제 정보에 은행, 계좌번호, 예금주, 만료일 저장 -→ 주문은 입금대기 상태 유지 -→ KCP가 /payment/vbank-notify 로 입금통보 POST -→ 입금 금액 검증 후 주문 결제 완료 처리 -``` - -테스트 모드에서는 마이페이지 주문 상세에 KCP testadmin 모의입금 폼이 표시될 수 있습니다. - -### 에스크로 - -에스크로를 활성화하면 결제 요청에 `escw_used=Y`, `pay_mod=O`를 전달합니다. 에스크로 결제 완료 후 관리자 주문 상세에서 운송장번호와 택배사를 입력해 KCP 배송 등록을 호출할 수 있습니다. - -KCP 공통통보는 아래 이벤트를 처리합니다. - -| tx_cd | 조건 | 처리 | -|-------|------|------| -| `TX02` | `cl_status=2` | 구매확인 훅 실행 | -| `TX02` | `cl_status=8` | 구매취소 훅 실행 | -| `TX02` | `cl_status=3` | 구매취소 확인 훅 실행 | -| `TX03` | - | 배송시작 훅 실행 | - -### 결제 취소 / 부분취소 - -```text -관리자 주문 취소 요청 (cancel_pg=true) -→ 코어가 sirsoft-ecommerce.payment.refund 필터 훅 발화 -→ PaymentRefundListener 가 KCP cancelPayment API 호출 - · 전액취소: isPartial=false - · 부분취소: isPartial=true, totalAmt=원래 결제금액 -→ 코어가 환불 레코드 생성 + 쿠폰 / 마일리지 / 재고 복원 -→ CancelActivityLogListener 가 PG 응답 시각·취소 거래번호를 활동 로그에 기록 -``` - -배송비가 포함된 주문은 전체취소 시 배송비도 함께 환불 레코드에 반영되고, 쿠폰이 적용된 주문은 실결제금액(쿠폰 차감 후) 이 PG cancelAmt 로 전달됩니다. 부분취소 시 쿠폰 최소 주문금액 조건을 더 이상 충족하지 못하면 코어가 취소 자체를 거부 (422) 하여 PG 호출이 발생하지 않습니다. KCP API 호출이 실패하면 주문 상태 변경이 롤백됩니다. - -## API - -### 사용자 API - -| Method | Path | 설명 | -|--------|------|------| -| `GET` | `/api/plugins/sirsoft-pay_nhnkcp/user/orders/{orderNumber}/receipt` | KCP 영수증, 현금영수증 URL 조회 | -| `GET` | `/api/plugins/sirsoft-pay_nhnkcp/user/orders/{orderNumber}/vbank-mock-deposit-info` | 테스트 모드 가상계좌 모의입금 정보 조회 | -| `POST` | `/api/plugins/sirsoft-pay_nhnkcp/mobile/approval-key` | 모바일 결제 승인키 발급 | - -### 관리자 API - -| Method | Path | 설명 | -|--------|------|------| -| `GET` | `/api/plugins/sirsoft-pay_nhnkcp/admin/vbank-notify-url` | 가상계좌/에스크로 통보 URL 조회 | -| `GET` | `/api/plugins/sirsoft-pay_nhnkcp/admin/orders/test-mode-map` | 주문목록 테스트 모드 배지용 맵 조회 | -| `GET` | `/api/plugins/sirsoft-pay_nhnkcp/admin/orders/{orderNumber}/transaction-status` | 저장된 KCP 거래 정보 조회 | -| `GET` | `/api/plugins/sirsoft-pay_nhnkcp/admin/orders/{orderNumber}/escrow-delivery` | 에스크로 배송 등록 폼 데이터 조회 | -| `POST` | `/api/plugins/sirsoft-pay_nhnkcp/admin/orders/{orderNumber}/escrow-delivery` | KCP 에스크로 배송 등록 | -| `GET` | `/api/plugins/sirsoft-pay_nhnkcp/admin/health` | KCP 실행 환경 점검 | - -## 훅 - -다른 모듈이나 플러그인에서 아래 훅에 연결해 결제 흐름을 확장할 수 있습니다. - -| 훅 | 타입 | 시점 | -|----|------|------| -| `sirsoft-pay_nhnkcp.payment.before_confirm` | action | KCP CLI 승인 확인 전 | -| `sirsoft-pay_nhnkcp.payment.after_confirm` | action | KCP CLI 승인 확인 후 | -| `sirsoft-pay_nhnkcp.payment.before_cancel` | action | KCP 취소 API 호출 전 | -| `sirsoft-pay_nhnkcp.payment.after_cancel` | action | KCP 취소 API 호출 후 | -| `sirsoft-pay_nhnkcp.escrow.purchase_confirmed` | action | 에스크로 구매확인 통보 수신 | -| `sirsoft-pay_nhnkcp.escrow.purchase_cancelled` | action | 에스크로 구매취소 통보 수신 | -| `sirsoft-pay_nhnkcp.escrow.denial_confirmed` | action | 에스크로 구매취소 확인 통보 수신 | -| `sirsoft-pay_nhnkcp.escrow.delivery_started` | action | 에스크로 배송시작 통보 수신 | - -## 보안 및 운영 참고 - -- 운영 도메인의 `APP_URL`을 HTTPS 절대 URL로 정확히 설정하세요. -- 운영 site key는 외부에 노출하지 마세요. -- 운영 모드에서는 KCP 서버 통보 IP 화이트리스트가 적용됩니다. -- 결제 승인 후 서버 후속 처리에 실패하면 PG 잔존 승인을 자동 취소합니다. -- 동일 거래번호 콜백은 중복 처리하지 않도록 방어합니다. -- KCP CLI 호출 인자는 위험 문자와 제어문자를 사전에 거부합니다. -- 가상계좌와 에스크로 통보 URL은 KCP 가맹점 관리자에 반드시 등록해야 합니다. -- KCP 계약이 없는 결제수단이나 간편결제를 활성화하면 KCP 오류가 발생할 수 있습니다. - -## 테스트 - -플러그인을 G7 프로젝트에 배치한 뒤 G7 루트에서 PHP 테스트를 실행합니다. - -```bash -php artisan test plugins/sirsoft-pay_nhnkcp/tests -``` - -프론트엔드 테스트와 빌드는 플러그인 디렉토리에서 실행합니다. - -```bash -npm install -npm run test:run -npm run build -``` - -## 라이선스 - -MIT diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/KCPPaymentService.wsdl b/plugins/_bundled/sirsoft-pay_nhnkcp/bin/KCPPaymentService.wsdl deleted file mode 100644 index c950ca53..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/KCPPaymentService.wsdl +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli b/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli deleted file mode 100755 index 1d74a66a..00000000 Binary files a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli and /dev/null differ diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli_exe.exe b/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli_exe.exe deleted file mode 100644 index cb05cd57..00000000 Binary files a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli_exe.exe and /dev/null differ diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli_x64 b/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli_x64 deleted file mode 100755 index 4707f2c1..00000000 Binary files a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pp_cli_x64 and /dev/null differ diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pub.key b/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pub.key deleted file mode 100644 index 8b0c51e4..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/pub.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN RSA PUBLIC KEY----- -MIGJAoGBAMEn9niy+ZB7GGn9JOA9csyJo2vTpd3/ieHW8nCfiDf77YJvEtUmudCU -JXMNQ1uBuHq7+IzajoJhhvGXyOHVr9w+Oq/d8XZPPe7X2agh1WAMDV4mjQNaAncr -DU1qxlTFuAdKRkK7qkqyWSHHtq0HaW/zmBmcIoGn4RwY9y7oKFBpAgMBAAE= ------END RSA PUBLIC KEY----- diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/real_KCPPaymentService.wsdl b/plugins/_bundled/sirsoft-pay_nhnkcp/bin/real_KCPPaymentService.wsdl deleted file mode 100644 index 21c74fab..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/bin/real_KCPPaymentService.wsdl +++ /dev/null @@ -1,145 +0,0 @@ - - - - KCP Payment Service - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/composer.json b/plugins/_bundled/sirsoft-pay_nhnkcp/composer.json deleted file mode 100644 index 0a909f1f..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "plugins/sirsoft-pay_nhnkcp", - "description": "NHN KCP PG Plugin for G7 platform", - "version": "1.0.0-beta.4", - "type": "library", - "authors": [ - { - "name": "sirsoft", - "email": "contact@sirsoft.com" - } - ], - "require": { - "php": "^8.2" - }, - "autoload": { - "psr-4": { - "Plugins\\Sirsoft\\PayNhnkcp\\": ["src/", "./"] - } - } -} diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/composer.lock b/plugins/_bundled/sirsoft-pay_nhnkcp/composer.lock deleted file mode 100644 index 8ba2f579..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/composer.lock +++ /dev/null @@ -1,20 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "88988d859f2433db8b07b8700f481c2d", - "packages": [], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": {}, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^8.2" - }, - "platform-dev": {}, - "plugin-api-version": "2.6.0" -} diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/config/settings/defaults.json b/plugins/_bundled/sirsoft-pay_nhnkcp/config/settings/defaults.json deleted file mode 100644 index 34c629e5..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/config/settings/defaults.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "_meta": { - "version": "1.0.0", - "description": "NHN KCP PG 플러그인 환경설정" - }, - "defaults": { - "is_test_mode": true, - "test_site_cd": "T0000", - "test_site_key": "", - "live_site_cd": "", - "live_site_key": "", - "redirect_success_url": "/shop/orders/{orderId}/complete", - "redirect_fail_url": "/shop/checkout" - }, - "frontend_schema": { - "is_test_mode": { "expose": false }, - "test_site_cd": { "expose": false }, - "test_site_key": { "expose": false }, - "live_site_cd": { "expose": false }, - "live_site_key": { "expose": false }, - "redirect_success_url": { "expose": false }, - "redirect_fail_url": { "expose": false } - } -} diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/dist/js/plugin.iife.js b/plugins/_bundled/sirsoft-pay_nhnkcp/dist/js/plugin.iife.js deleted file mode 100644 index 1e0b6a5e..00000000 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/dist/js/plugin.iife.js +++ /dev/null @@ -1,18 +0,0 @@ -(function(){"use strict";function tt(e){return/^https?:\/\//i.test(e)||e.startsWith("/api/")?e:e.startsWith("/plugins/")?`/api${e}`:e.startsWith("plugins/")?`/api/${e}`:e}function nt(e){return e.trim().slice(0,160)}function rt(e){if(e)return e.replace(/\/payment\/close-report$/,"/payment/retry")}async function ce(e,t,n=!1){const r=window.G7Core?.api;if(typeof r?.post=="function"){await r.post(e,t);return}const a=await fetch(tt(e),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),keepalive:n});if(!a.ok){let o=`NHN KCP payment request failed (${a.status})`;try{const i=await a.json(),s=Array.isArray(i?.errors?.message)?i.errors.message[0]:i?.error??i?.message;typeof s=="string"&&s.trim()!==""&&(o=s)}catch{}throw new Error(o)}}async function at(e){const t=rt(e.closeReportUrl);t&&await ce(t,{oid:e.oid,price:Number(e.price),buyer_email:e.buyer_email??"",buyer_phone:e.buyer_phone??"",payment_method:e.payment_method??""})}async function ot(e,t="kcp-window-closed"){if(!e.closeReportUrl)return;const n={oid:e.oid,price:Number(e.price),buyer_email:e.buyer_email??"",buyer_phone:e.buyer_phone??"",payment_method:e.payment_method??"",reason:nt(t)||"kcp-window-closed"};try{await ce(e.closeReportUrl,n,!0)}catch(r){console.warn("[sirsoft-pay_nhnkcp] failed to report payment window close",r)}}const it="nhnkcp_applepay";function M(e){return e===it}function S(){if(typeof navigator>"u")return!1;const e=navigator,t=(e.userAgent||"").toLowerCase(),n=((e.userAgentData?.platform??e.platform)||"").toLowerCase(),r=e.maxTouchPoints??0;return/iphone|ipad|ipod/.test(t)||/iphone|ipad|ipod|ios/.test(n)?!0:/macintosh|mac os x/.test(t)&&r>1}function H(){return((typeof document<"u"?document.documentElement.lang:"")||"").toLowerCase().startsWith("ko")?"애플페이는 IOS 기기에 모바일결제만 가능합니다.":"Apple Pay is available only for mobile payments on iOS devices."}function B(e){return(e??"KRW").trim().toUpperCase()||"KRW"}function st(e){return B(e)==="KRW"}function ct(e){const t=B(e);return((typeof document<"u"?document.documentElement.lang:"")||"").toLowerCase().startsWith("ko")?`NHN KCP는 KRW 결제만 지원합니다. (${t})`:`NHN KCP supports KRW payments only. (${t})`}function dt(e){const t=Math.max(0,Math.round(Number(e.amount??0))),n=Math.min(Math.max(0,Math.round(Number(e.tax_free_amount??0))),t);if(n<=0)return{};const r=Math.max(0,Math.round(Number(e.tax_amount??0))),a=Math.max(0,Math.round(Number(e.vat_amount??0))),o=Math.max(0,t-n),i=o>0&&r>0&&a>0?Math.min(o,Math.round(o*(a/r))):0,s=o-i;return{tax_flag:"TG03",comm_tax_mny:String(s),comm_vat_mny:String(i),comm_free_mny:String(n)}}class D extends Error{constructor(t){super(t??"결제가 취소되었습니다."),this.name="KcpCancelledError"}}const lt={card:"100000000000",bank_transfer:"010000000000",virtual_account:"001000000000",mobile:"000010000000",bank:"010000000000",vbank:"001000000000",phone:"000010000000"},de={nhnkcp_payco:{payco_direct:"Y"},nhnkcp_naverpay:{naverpay_direct:"Y"},nhnkcp_naverpay_point:{naverpay_direct:"Y",naverpay_point_direct:"Y"},nhnkcp_kakaopay:{kakaopay_direct:"Y"},nhnkcp_applepay:{applepay_direct:"Y"}};function ut(e,t){const n=e.toLowerCase();return!t||!Object.prototype.hasOwnProperty.call(de,n)?{}:{param_opt_1:n,nhnkcp_easy_pay_method:n}}function pt(e){if(!e.isConnected)return!0;const t=window.getComputedStyle(e);if(t.display==="none"||t.visibility==="hidden")return!0;const n=e.getBoundingClientRect();return n.width<=0||n.height<=0}function mt(e,t){let n=!1,r,a;const o=()=>{n=!0,a&&(a.disconnect(),a=void 0),r!==void 0&&(window.clearInterval(r),r=void 0)},i=()=>{n||!pt(e)||(o(),t())},s=document.body??document.documentElement;return s&&typeof MutationObserver<"u"&&(a=new MutationObserver(i),a.observe(s,{attributes:!0,attributeFilter:["class","hidden","style"],childList:!0,subtree:!0})),r=window.setInterval(i,300),o}function yt(){if(typeof navigator>"u")return!1;if(S())return!0;const e=navigator;if(e.userAgentData?.mobile!==void 0)return e.userAgentData.mobile;const t=(navigator.userAgent||"").toLowerCase();return!!(/android|iphone|ipod|windows phone|iemobile|blackberry|opera mini|mobile safari/.test(t)||(navigator.maxTouchPoints??0)>1&&!t.includes("windows")&&!t.includes("macintosh"))}async function le(e,t){const{pgPaymentData:n,paymentMethod:r}=e.params||{};if(!n){console.error("[sirsoft-pay_nhnkcp] pgPaymentData is required");return}const a=r??n.pay_method??"card",o=typeof a=="string"&&a.startsWith("nhnkcp_"),i=window.G7Core;let s=null;try{if(!st(n.currency)){const u=ct(n.currency);i?.state?.setLocal?.({paymentErrorMessage:u,isSubmittingOrder:!1,paymentMethod:a}),i?.modal?.open?.("nhnkcp_payment_error_modal");return}if(M(a)&&!S()){const u=H();i?.state?.setLocal?.({paymentErrorMessage:u,isSubmittingOrder:!1,paymentMethod:a}),i?.modal?.open?.("nhnkcp_payment_error_modal");return}const c=await i.api.get("/modules/sirsoft-ecommerce/payments/client-config/nhnkcp");if(!c.data){console.error("[sirsoft-pay_nhnkcp] Failed to fetch client config",c);return}const d=c.data;s={closeReportUrl:d.callback_urls.close_report,oid:n.order_number,price:Number(n.amount),buyer_email:n.customer_email??"",buyer_phone:n.customer_phone??"",payment_method:a};const l=window.location.origin+d.callback_urls.callback;await at(s),yt()?await ft(i,n,a,o,l):await ht(d,n,a,o,l)}catch(c){if(c instanceof D){s&&await ot(s,c.message||"kcp-window-closed"),i?.state?.setLocal?.({isSubmittingOrder:!1,paymentMethod:a});return}console.error("[sirsoft-pay_nhnkcp] requestPayment error",c);const l=c?.response?.data,u=l?.errors?Object.values(l.errors)[0]?.[0]:void 0,m=l?.error??l?.message??u??(c instanceof Error?c.message:"Unknown error");i?.state?.setLocal?.({paymentErrorMessage:m,isSubmittingOrder:!1,paymentMethod:a}),i?.modal?.open?.("nhnkcp_payment_error_modal")}}async function ft(e,t,n,r,a){const o=await e.api.post("/plugins/sirsoft-pay_nhnkcp/mobile/approval-key",{order_number:t.order_number,amount:t.amount,good_name:t.order_name,pay_method:n,buyr_name:t.customer_name??"",buyr_mail:t.customer_email??"",buyr_tel1:t.customer_phone??"",ret_url:a,currency:B(t.currency)});if(!o.success||!o.data){const d=o.errors,l=d?Object.values(d)[0]?.[0]:void 0;throw new Error(o.error??o.message??l??"KCP 모바일 승인키 획득 실패")}const{pay_url:i,fields:s}=o.data,c=document.createElement("form");c.method="POST",c.action=i,c.acceptCharset="euc-kr",c.style.display="none";for(const[d,l]of Object.entries(s)){const u=document.createElement("input");u.type="hidden",u.name=d,u.value=String(l),c.appendChild(u)}document.body.appendChild(c),c.submit(),await new Promise(()=>{})}async function ht(e,t,n,r,a){const o=r?"100000000000":lt[t.pay_method??"card"]??"100000000000",s={site_cd:n==="nhnkcp_payco"?e.easy_pay_client_id??e.client_id:e.use_escrow&&!r?e.escrow_client_id??e.client_id:e.client_id,ordr_idxx:t.order_number,good_name:t.order_name,good_mny:String(t.amount),buyr_name:t.customer_name??"",buyr_mail:t.customer_email??"",buyr_tel1:t.customer_phone??"",pay_method:o,Ret_URL:a};if(Object.assign(s,dt(t)),Object.assign(s,ut(n,r)),o==="001000000000"&&(s.vcnt_expire_term=String(e.vbank_expire_days??3),s.disp_tax_yn="N"),e.use_escrow&&!r&&(s.escw_used="Y",s.pay_mod="O"),r){s.payco_direct="",s.naverpay_direct="A",s.kakaopay_direct="A",s.applepay_direct="A";const d=de[n];d&&Object.assign(s,d)}const c=Object.entries(s).map(([d,l])=>``).join("");await new Promise((d,l)=>{document.getElementById("kcp-sdk-iframe")?.remove(),document.getElementById("kcp-dim-overlay")?.remove();const u=document.createElement("div");u.id="kcp-dim-overlay",u.style.cssText="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.6);z-index:99998;",document.body.appendChild(u);const m=document.createElement("iframe");m.id="kcp-sdk-iframe",m.setAttribute("allowtransparency","true"),m.style.cssText="position:fixed;top:0;left:0;width:100%;height:100%;border:0;z-index:99999;background:transparent;",document.body.appendChild(m);const y=m.contentWindow;let x=!1,h,f;const se=()=>{f?.(),f=void 0,h!==void 0&&(clearTimeout(h),h=void 0),m.remove(),u.remove()},v=_=>{x||(x=!0,se(),l(_))},w=()=>{x=!0,f?.(),f=void 0,h!==void 0&&(clearTimeout(h),h=void 0)};f=mt(m,()=>{v(new D("kcp-payment-frame-closed"))}),y.m_Completepayment=function(_){const E=_.elements.res_cd?.value??"",p=_.elements.res_msg?.value??"";if(E==="0000"){w();const g=y.document.forms.namedItem("order_info"),k=g&&g!==_?g:_;if(g&&g!==_)for(let I=0;I<_.elements.length;I++){const L=_.elements[I];if(!L.name)continue;let A=g.elements.namedItem(L.name);A||(A=y.document.createElement("input"),A.type="hidden",A.name=L.name,g.appendChild(A)),A.value=L.value}k.action=a,k.method="POST",k.target="_top",y.document.body.appendChild(k),k.submit()}else{const g=E===""||E==="7777"||p.includes("취소");v(g?new D(p):new Error(`KCP 오류 [${E}]: ${p}`))}},y.__kcpFail=_=>{v(_)};const C=m.contentDocument||y.document;C.open(),C.write(` -