Files
Gnuboard7/plugins/_bundled/sirsoft-pay_nicepayments/dist/js/plugin.iife.js
T
HeuJung 90f154ecc0 fix(security): 배포본 소스맵 노출 차단 + 관리자 설정 탭 지연로딩 + 동반 결함 수정
## 소스맵 노출 차단 (공개 이슈 )

배포본에 .map 이 포함돼 원본 TS/TSX 전문(sourcesContent, 한글 주석 포함)이
그대로 노출됐다. 생성·서빙·저장소 유입 3계층을 모두 막는다.

- 빌드 config 15곳(코어 3 + _bundled 12): sourcemap 하드코딩 제거.
 G7_BUILD_SOURCEMAP 판정식으로 교체 — 미설정(로컬 npm run build)이면 생성해
 개발 디버깅 경험을 보존하고, 0 이면 미생성.
- Build{Core,Module,Plugin,Template}Command: 죽어 있던 --production 플래그 복구.
 $productionMode 를 콘솔 문자열에만 쓰고 npm 프로세스에 env 를 넘기지 않아
 산출물이 개발 빌드와 동일했다. runNpmCommand 에 $env 를 추가해 주입
 (--watch 에는 미주입). Symfony Process 는 부모 환경에 병합하므로 PATH 유실 없음.
- Allowed{Module,Plugin}FileType / {Module,Plugin}Service::getMimeType:
 허용 확장자 map 제거 — 익명 200 서빙 차단(템플릿은 원래 미허용, 3종 정책 일치).
- ExtensionBundleService: CSS 번들의 /*# sourceMappingURL=... */ strip 추가.
 CSS 는 블록 주석이라 JS 의 //# 패턴으로는 검출되지 않던 구멍.
- 추적 .map 13개 삭제 + .gitignore 전역 *.map 규칙(경로 한정 시 새 확장에서 누락).

실측: 산출 JS 의 sourceMappingURL 13 → 0, 추적 .map 13 → 0,
확장 디렉토리 npm run build 는 여전히 map 생성(개발 경험 회귀 없음).

## 관리자 환경설정 탭 지연 로딩

코어/이커머스/게시판 환경설정 화면이 진입 즉시 전 탭의 데이터소스를 한꺼번에
호출했다. 각 데이터소스에 활성 탭 조건(if)을 걸어 해당 탭에서만 fetch 하도록
변경하고, 결제 플러그인 3종의 테스트모드 상태 조회도 주문설정 탭으로 한정.

## 동반 결함 수정 (무관 결함 — 재발 방지 목적으로 같은 세션 처리)

- 나이스페이먼츠: 체크아웃 캐시 프리페치가 라우트를 가리지 않아 플러그인 번들이
 로드되는 모든 페이지(홈/게시판/로그인)에서 주문서를 조회 → 비회원 매번 422.
 형제 플러그인(kginicis)의 기존 가드 패턴을 적용해 체크아웃 경로로 한정.
- admin smoke 8건: 대부분 구현이 아니라 테스트 결함이었다 — URL 오타(단수 board),
 존재하지 않는 권한키, 앱 로케일이 en 인데 한국어 라벨 로케이터, DataGrid 버튼을
 먼저 잡던 휴리스틱 로케이터. 레이아웃에는 sticky className / 안정 id 를 부여.
- PHPDoc ↔ Pint 충돌 3건: 설명 없는 @param 은 no_superfluous_phpdoc_tags 가
 삭제해 audit phpdoc-public-method 와 무한 충돌. 한국어 설명을 붙여 양쪽 충족
 (리스너 3종의 설명 누락 메서드도 전수 보강).
- Log::spy 500 3건: spy 가 Log::channel('activity') 를 null 로 만들고
 logActivity 가 null->info 로 \Error → 같은 줄 catch(\Exception) 은 못 잡아
 통과. 운영에선 채널이 항상 로거이므로 제품 무결 → 테스트에 activity 채널
 보존 헬퍼 추가.
- NhnKcpApiServiceTest 5건: 스텁이 Unix 바이너리만 만들어 Windows 분기
 (pp_cli_exe.exe)에서만 실패. #!/bin/sh 는 Windows 실행 불가 → 파일 내 기존
 컨벤션대로 skip 가드.

## 테스트

- 소스맵 범위 130 passed (신규: BuildCommandSourcemapEnv, NoSourcemapArtifacts,
 ExtensionBundleService CSS strip, Allowed*FileType 반전, 자산 서빙 거부)
- 결제 3플러그인 505 passed / 0 failed (skipped 9 = Windows 전용 CLI, 사유 명시)
- 나이스페이먼츠 프론트 38 passed (가드 제거 시 red 실증 후 복원)
- E2E: production-sourcemap-exposure.spec.ts 6건 + 시나리오 매니페스트

버전: sirsoft-admin_basic 1.0.2 → 1.0.3, sirsoft-board 1.0.1 → 1.0.2
(각 manifest/package/lock/composer 동기화). 코어 7.0.4 는 미출시 누적.
2026-07-14 12:50:23 +09:00

2 lines
36 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function(){"use strict";function $e(e){return/^https?:\/\//i.test(e)||e.startsWith("/api/")?e:e.startsWith("/plugins/")?`/api${e}`:e.startsWith("plugins/")?`/api/${e}`:e}function De(e){return e.trim().slice(0,160)}async function Be(e,t="nicepay-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:De(t)||"nicepay-window-closed"};try{const a=window.G7Core?.api;if(typeof a?.post=="function"){await a.post(e.closeReportUrl,n);return}await fetch($e(e.closeReportUrl),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),keepalive:!0})}catch(a){console.warn("[sirsoft-pay_nicepayments] failed to report payment window close",a)}}function Ge(e){return new Promise((t,n)=>{if(document.querySelector(`script[src="${e}"]`)){t();return}const a=document.createElement("script");a.src=e,a.onload=()=>t(),a.onerror=()=>n(new Error(`Failed to load script: ${e}`)),document.head.appendChild(a)})}function je(e,t){const n=document.createElement("form");n.id="nicepayForm",n.method="post",n.action=e,n.acceptCharset="utf-8";for(const[a,o]of Object.entries(t)){const r=document.createElement("input");r.type="hidden",r.name=a,r.value=o,n.appendChild(r)}return document.body.appendChild(n),n}const qe="/plugins/sirsoft-pay_nicepayments/payment/callback",Fe="https://web.nicepay.co.kr/v3/v3Payment.jsp";function He(){if(typeof navigator>"u")return!1;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 J(e,t){const{pgPaymentData:n,paymentMethod:a}=e.params??{},o=window.__templateApp?.globalState?._local,r=a??o?.paymentMethod??"card";if(!n){console.error("[sirsoft-pay_nicepayments] pgPaymentData is required");return}const i=window.G7Core;try{const s=await i.api.get("/modules/sirsoft-ecommerce/payments/client-config/nicepayments");if(!s.data){console.error("[sirsoft-pay_nicepayments] Failed to fetch client config",s);return}const l=s.data,u=He();if(!u&&(await Ge(l.sdk_url),typeof window.goPay!="function")){i?.toast?.error?.("나이스페이먼츠 SDK를 불러올 수 없습니다. 잠시 후 다시 시도해주세요."),i?.state?.setLocal?.({isSubmittingOrder:!1,paymentMethod:r});return}const b=window.location.origin+l.sign_data_url,m=typeof localStorage<"u"?localStorage.getItem("auth_token"):null,p={"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest",Accept:"application/json"};m&&(p.Authorization=`Bearer ${m}`);const P=await fetch(b,{method:"POST",credentials:"include",headers:p,body:JSON.stringify({amt:n.amount,moid:n.order_number,buyer_email:n.customer_email??"",buyer_phone:n.customer_phone??""})});if(!P.ok)throw new Error("SignData 생성에 실패했습니다.");const g=await P.json(),I=window.location.origin+qe,f=typeof r=="string"&&r.startsWith("nicepay_"),N=f?"CARD":{card:"CARD",vbank:"VBANK",bank:"BANK",phone:"CELLPHONE"}[r??"card"]??"CARD",d={PayMethod:N,GoodsName:n.order_name,Amt:String(n.amount),MID:g.mid,Moid:n.order_number,BuyerName:n.customer_name??"",BuyerEmail:n.customer_email??"",BuyerTel:n.customer_phone??"",ReturnURL:I,EdiDate:g.ediDate,SignData:g.signData,CharSet:"utf-8",GoodsCl:"1",DirectShowOpt:"",DirectEasyPay:"",NicepayReserved:"",EasyPayMethod:"",MallReserved:"",MallReserved1:""};N==="CELLPHONE"&&(d.GoodsCl=n.goods_cl??"1");const c=l.useEscrow&&!f;if(d.TransType=c?"1":"0",f)switch(d.DirectShowOpt="CARD",d.MallReserved=`nicepay_easy_pay_method=${encodeURIComponent(r)}`,d.MallReserved1=r,r){case"nicepay_naverpay":d.DirectEasyPay="E020",d.EasyPayMethod="E020=CARD";break;case"nicepay_kakaopay":d.NicepayReserved="DirectKakao=Y";break;case"nicepay_samsungpay":d.DirectEasyPay="E021";break;case"nicepay_applepay":d.DirectEasyPay="E025";break;case"nicepay_payco":d.NicepayReserved="DirectPayco=Y";break;case"nicepay_skpay":d.NicepayReserved="DirectPay11=Y";break;case"nicepay_ssgpay":d.DirectEasyPay="E007";break;case"nicepay_lpay":d.DirectEasyPay="E018";break}try{const w=(await i.api.get(`/modules/sirsoft-ecommerce/user/orders/${n.order_number}`))?.data;if(w){const T=Number(w.total_tax_amount??0),E=Number(w.total_vat_amount??0),Oe=Number(w.total_tax_free_amount??0);(T>0||E>0||Oe>0)&&(d.TaxAmt=String(T),d.VatAmt=String(E),d.TaxFreeAmt=String(Oe))}}catch{}const y=je(I,d);if(u){y.action=Fe,y.acceptCharset="euc-kr";const S=y.querySelector('input[name="CharSet"]');S&&(S.value="euc-kr"),y.submit();return}window.nicepaySubmit=()=>{y.submit()};let k=!1;const z=new Set(document.body.children),Re=(S,w)=>{if(k)return;k=!0;const T=[S,w].filter(Boolean).join(": ")||"nicepay-window-closed";Be({closeReportUrl:l.close_report_url,oid:n.order_number,price:Number(n.amount),buyer_email:n.customer_email??"",buyer_phone:n.customer_phone??"",payment_method:r},T),window.removeEventListener("popstate",Me),Array.from(document.body.children).forEach(E=>{z.has(E)||E.remove()}),y.parentNode&&y.parentNode.removeChild(y),window.__sirsoftNicepayPaymentInProgress=!1,i?.state?.setLocal?.({isSubmittingOrder:!1,paymentMethod:r}),w&&i?.toast?.error?.(w)};window.nicepayClose=Re;const Me=()=>Re("","");window.history.pushState({nicepayOpen:!0},""),window.addEventListener("popstate",Me),window.goPay(y)}catch(s){console.error("[sirsoft-pay_nicepayments] requestPayment error",s),window.__sirsoftNicepayPaymentInProgress=!1,i?.state?.setLocal?.({isSubmittingOrder:!1,paymentMethod:r}),i?.toast?.error?.("결제 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.")}}const Ye={nicepay_naverpay:"네이버페이",nicepay_kakaopay:"카카오페이",nicepay_samsungpay:"삼성페이",nicepay_applepay:"애플페이",nicepay_payco:"PAYCO",nicepay_skpay:"11pay",nicepay_ssgpay:"SSG페이",nicepay_lpay:"L.pay"},Ue="0 0 0 2px #ffffff, 0 0 0 5px rgba(0,0,0,0.55)";function X(){const e=document.getElementById("nicepay_checkout_payment_section");if(!e)return null;const t=e.querySelectorAll("p");for(const n of t)if(n.textContent?.includes("간편결제"))return n.nextElementSibling;return null}function Q(){const e=X();e&&e.querySelectorAll("button").forEach(t=>{t.style.boxShadow="",t.style.outline=""})}function Ke(e){const t=X();if(!t)return;const n=Ye[e];t.querySelectorAll("button").forEach(a=>{a.textContent?.trim()===n?(a.style.boxShadow=Ue,a.style.outline="none"):(a.style.boxShadow="",a.style.outline="")})}function We(e){const t=e.params?.paymentMethod;if(!t)return;const n=typeof t=="string"&&t.indexOf("nicepay_")===0;window.G7Core?.state?.setLocal?.({paymentMethod:t,serverPaymentMethod:n?"card":t}),n?Ke(t):Q()}function Z(){const e=window.__templateApp;typeof e?.onGlobalStateChange=="function"&&e.onGlobalStateChange(t=>{const n=t?._local?.paymentMethod;typeof n=="string"&&(n.startsWith("nicepay_")||Q())})}const ee={requestPayment:J,setPaymentMethod:We},te="/user/orders",Ve="sirsoft-nicepayments",R="sirsoft-pay_nicepayments",ne="__sirsoftNicepayFetchInterceptorInstalled",ae="/api/modules/sirsoft-ecommerce/checkout",M="__sirsoftNicepayPaymentInProgress",_="__sirsoftNicepayCheckoutCache",ze=/^\/shop\/checkout\/?$/,h={info:(...e)=>console.info(`[${R}]`,...e),warn:(...e)=>console.warn(`[${R}]`,...e),error:(...e)=>console.error(`[${R}]`,...e)};function Je(){return window.location.pathname+window.location.search+window.location.hash}function Xe(e,t){if(t.toUpperCase()!=="POST")return!1;const n=(e??"").split("?")[0].split("#")[0];return n===te||n.endsWith(te)}function O(e,t){if(t.toUpperCase()!=="GET")return!1;const n=(e??"").split("?")[0].split("#")[0];return n===ae||n.endsWith(ae)}function Qe(){return ze.test(window.location.pathname)}function Ze(e){if(!e)return;let t=null;if(typeof e=="string")try{t=JSON.parse(e)}catch{return}else typeof e=="object"&&(t=e);if(!t)return;const n=t.payment_method;return typeof n=="string"&&n.length>0?n:void 0}function et(e,t){try{const n=JSON.parse(e);if("payment_method"in n)return JSON.stringify({...n,payment_method:t})}catch{}return e}function tt(e){const t=[e.total_due_amount,e.total_amount];for(const n of t){const a=Number(n??0);if(Number.isFinite(a)&&a>0)return Math.floor(a)}return 0}function nt(){const e=window;if(e[ne])return;e[ne]=!0;const t="__sirsoftPgOriginalFetch";e[t]||(e[t]=window.fetch.bind(window));const n=e[t],a=window.fetch.bind(window);window.fetch=async(o,r)=>{const i=typeof o=="string"?o:o instanceof URL?o.href:o.url,s=r?.method??(o instanceof Request?o.method:"GET");if(O(i,s)){if(e[M]&&e[_])return h.info("payment in progress — serving cached checkout response"),new Response(e[_],{status:200,headers:{"Content-Type":"application/json"}});const c=await a(o,r);if(c.ok){const y=await c.text();return e[_]=y,new Response(y,{status:c.status,statusText:c.statusText,headers:c.headers})}return c}if(!Xe(i,s))return a(o,r);let l,u=!1,b=r;if(r?.body&&typeof r.body=="string"){const c=Ze(r.body);typeof c=="string"&&c.length>0&&(l=c,c.startsWith("nicepay_")&&(u=!0,b={...r,body:et(r.body,"card")},h.info(`easy pay detected: replacing payment_method '${c}' → 'card'`)))}const p=await(u?n:a)(o,b);if(!p.ok)return p;let P=null;try{P=await p.clone().json()}catch{return p}const g=P?.data??P;if(!g?.requires_pg_payment&&!u)return p;const I=g.pg_provider===Ve;if(!u&&!I)return p;let f=g.pg_payment_data;if(!f&&u){const c=g.order;if(c){const y=c.options,k=y?.[0]?.product_name??String(c.order_number??""),z=(y?.length??0)>1?`${k} 외 ${(y?.length??0)-1}건`:k;f={order_number:c.order_number,order_name:z,amount:tt(c),currency:"KRW",customer_name:c.orderer_name??null,customer_email:c.orderer_email??null,customer_phone:String(c.orderer_phone??"").replace(/[^0-9]/g,""),customer_key:c.user_id??null},h.info("pg_payment_data constructed from order (기본 PG 미설정)",{order_number:f.order_number,amount:f.amount})}}if(!f)return h.warn("nicepayments order detected but pg_payment_data missing"),p;const V=l??"card";h.info("intercepted order create response — opening PG popup",{paymentMethod:V}),J({params:{pgPaymentData:f,paymentMethod:V}}),e[M]=!0;const N={...g,requires_pg_payment:!1,redirect_url:Je()},d=P?.data?{...P,data:N}:N;return new Response(JSON.stringify(d),{status:p.status,statusText:p.statusText,headers:p.headers})},h.info("fetch order interceptor installed"),oe(e,15)}const re="__sirsoftNicepayAxiosCheckoutInterceptorInstalled";function oe(e,t){const n=window?.G7Core?.api?.client;if(!n?.interceptors){t>0&&setTimeout(()=>oe(e,t-1),300);return}e[re]||(e[re]=!0,n.interceptors.response.use(a=>{const o=(a?.config?.method??"").toLowerCase(),r=String((a?.config?.baseURL??"")+(a?.config?.url??""));return o==="get"&&O(r,"GET")&&a?.status===200&&(e[_]=JSON.stringify(a.data),h.info("checkout response cached (axios)")),a}),n.interceptors.request.use(a=>{const o=(a?.method??"").toLowerCase(),r=String((a?.baseURL??"")+(a?.url??""));return o==="get"&&O(r,"GET")&&e[M]&&e[_]&&(h.info("payment in progress — serving cached checkout response (axios)"),a.adapter=()=>Promise.resolve({data:JSON.parse(e[_]),status:200,statusText:"OK (cached)",headers:{"content-type":"application/json"},config:a,request:{}})),a}),h.info("axios checkout interceptor installed"),Qe()&&!e[_]&&(async()=>{try{await window?.G7Core?.api?.get?.("/modules/sirsoft-ecommerce/checkout")}catch{}})())}const at="sirsoft-pay_nicepayments",ie="__nicepayCheckoutEasyPayInjectorInstalled",rt=/^\/shop\/checkout\/?$/,se="__nicepayCheckoutEasyPaySyncListenerAttached",ot=200,it=120,st="nicepay_checkout_payment_section",ce=[{id:"nicepay_naverpay",labels:["네이버페이 (나이스페이먼츠)","네이버페이로 결제 (나이스페이먼츠)","Naver Pay (NicePayments)","Pay with Naver Pay (NicePayments)"],ko:{heading:"네이버페이 (나이스페이먼츠)",description:"네이버페이로 결제 (나이스페이먼츠)",title:"네이버페이로 결제 (나이스페이먼츠)"},en:{heading:"Naver Pay (NicePayments)",description:"Pay with Naver Pay (NicePayments)",title:"Pay with Naver Pay (NicePayments)"},markText:"N",markClassName:"bg-green-500 text-white"},{id:"nicepay_kakaopay",labels:["카카오페이 (나이스페이먼츠)","카카오페이로 결제 (나이스페이먼츠)","Kakao Pay (NicePayments)","Pay with Kakao Pay (NicePayments)"],ko:{heading:"카카오페이 (나이스페이먼츠)",description:"카카오페이로 결제 (나이스페이먼츠)",title:"카카오페이로 결제 (나이스페이먼츠)"},en:{heading:"Kakao Pay (NicePayments)",description:"Pay with Kakao Pay (NicePayments)",title:"Pay with Kakao Pay (NicePayments)"},markText:"K",markClassName:"bg-yellow-400 text-gray-950"},{id:"nicepay_samsungpay",labels:["삼성페이 (나이스페이먼츠)","삼성페이로 결제 (나이스페이먼츠)","Samsung Pay (NicePayments)","Pay with Samsung Pay (NicePayments)"],ko:{heading:"삼성페이 (나이스페이먼츠)",description:"삼성페이로 결제 (나이스페이먼츠)",title:"삼성페이로 결제 (나이스페이먼츠)"},en:{heading:"Samsung Pay (NicePayments)",description:"Pay with Samsung Pay (NicePayments)",title:"Pay with Samsung Pay (NicePayments)"},markText:"S",markClassName:"bg-blue-600 text-white"},{id:"nicepay_applepay",labels:["애플페이 (나이스페이먼츠)","애플페이로 결제 (나이스페이먼츠)","Apple Pay (NicePayments)","Pay with Apple Pay (NicePayments)"],ko:{heading:"애플페이 (나이스페이먼츠)",description:"애플페이로 결제 (나이스페이먼츠)",title:"애플페이로 결제 (나이스페이먼츠)"},en:{heading:"Apple Pay (NicePayments)",description:"Pay with Apple Pay (NicePayments)",title:"Pay with Apple Pay (NicePayments)"},markText:"A",markClassName:"bg-gray-900 text-white"},{id:"nicepay_payco",labels:["PAYCO (나이스페이먼츠)","PAYCO로 결제 (나이스페이먼츠)","PAYCO (NicePayments)","Pay with PAYCO (NicePayments)"],ko:{heading:"PAYCO (나이스페이먼츠)",description:"PAYCO로 결제 (나이스페이먼츠)",title:"PAYCO로 결제 (나이스페이먼츠)"},en:{heading:"PAYCO (NicePayments)",description:"Pay with PAYCO (NicePayments)",title:"Pay with PAYCO (NicePayments)"},markText:"P",markClassName:"bg-red-500 text-white"},{id:"nicepay_skpay",labels:["11pay (나이스페이먼츠)","11pay로 결제 (나이스페이먼츠)","11pay (NicePayments)","Pay with 11pay (NicePayments)"],ko:{heading:"11pay (나이스페이먼츠)",description:"11pay로 결제 (나이스페이먼츠)",title:"11pay로 결제 (나이스페이먼츠)"},en:{heading:"11pay (NicePayments)",description:"Pay with 11pay (NicePayments)",title:"Pay with 11pay (NicePayments)"},markText:"11",markClassName:"bg-orange-500 text-white"},{id:"nicepay_ssgpay",labels:["SSG페이 (나이스페이먼츠)","SSG페이로 결제 (나이스페이먼츠)","SSG Pay (NicePayments)","Pay with SSG Pay (NicePayments)"],ko:{heading:"SSG페이 (나이스페이먼츠)",description:"SSG페이로 결제 (나이스페이먼츠)",title:"SSG페이로 결제 (나이스페이먼츠)"},en:{heading:"SSG Pay (NicePayments)",description:"Pay with SSG Pay (NicePayments)",title:"Pay with SSG Pay (NicePayments)"},markText:"SSG",markClassName:"bg-red-700 text-white"},{id:"nicepay_lpay",labels:["L.pay (나이스페이먼츠)","L.pay로 결제 (나이스페이먼츠)","L.pay (NicePayments)","Pay with L.pay (NicePayments)"],ko:{heading:"L.pay (나이스페이먼츠)",description:"L.pay로 결제 (나이스페이먼츠)",title:"L.pay로 결제 (나이스페이먼츠)"},en:{heading:"L.pay (NicePayments)",description:"Pay with L.pay (NicePayments)",title:"Pay with L.pay (NicePayments)"},markText:"L",markClassName:"bg-purple-600 text-white"}];let le=null,x=null,$=!1;function ct(){return window}function D(){return rt.test(window.location.pathname)}function lt(e){return(e??"").replace(/\s+/g," ").trim()}function dt(e){return lt(e).replace(/\u200B/g,"")}function ut(){return(document.documentElement.lang||navigator.language||"").toLowerCase().startsWith("ko")}function yt(e){return ut()?e.ko:e.en}function de(e){return e.replaceAll("네이버페이","네이​버페이").replaceAll("카카오페이","카카​오페이").replaceAll("삼성페이","삼성​페이").replaceAll("Naver Pay","Naver​ Pay").replaceAll("Kakao Pay","Kakao​ Pay").replaceAll("Samsung Pay","Samsung​ Pay").replaceAll("L.pay","L.​pay")}function pt(e){return ce.find(t=>t.id===e)??null}function mt(e){const t=pt(e.dataset.nicepayEasyPayMethod);if(t)return t;const n=dt(e.textContent);return ce.find(a=>a.labels.some(o=>n.includes(o)))??null}function ue(e){return e.querySelector(".flex.items-center.gap-2, .flex.items-center.gap-3")??e.querySelector(".flex.items-center")}function ft(e,t,n){e.style.textAlign="left";const a=ue(e);a&&(a.style.justifyContent="flex-start",a.style.textAlign="left",a.style.width="100%");const o=t?.parentElement??n?.parentElement;o instanceof HTMLElement&&(o.style.textAlign="left",o.style.minWidth="0")}function ht(e){const t=document.createElement("span");return t.dataset.nicepayEasyPayMark="true",t.dataset.nicepayEasyPayMethod=e.id,t.setAttribute("aria-hidden","true"),t.className=`inline-flex items-center justify-center rounded-lg text-xs font-bold ${e.markClassName}`,t.style.width="32px",t.style.height="32px",t.style.flex="0 0 32px",t.textContent=e.markText,t}function gt(e){delete e.dataset.kginicisBrandPaymentButton,delete e.dataset.kginicisBrandPaymentMethod,delete e.dataset.kginicisNaverpayBrandButton,delete e.dataset.nhnkcpEasyPayMethod,delete e.dataset.nhnkcpEasyPayVisible,delete e.dataset.nhnkcpEasyPayHidden,e.querySelectorAll('[data-kginicis-brand-payment-mark="true"], [data-kginicis-naverpay-mark="true"], [data-nhnkcp-easy-pay-mark="true"]').forEach(t=>{t.remove()})}function Pt(e){return e.querySelector('[data-nicepay-easy-pay-mark="true"]')??e.querySelector('[data-kginicis-brand-payment-mark="true"], [data-kginicis-naverpay-mark="true"], [data-nhnkcp-easy-pay-mark="true"]')??e.querySelector("svg")??e.querySelector('i[class*="fa-"], i[role="img"], i')}function wt(e,t){const n=e.querySelector('[data-nicepay-easy-pay-mark="true"]');if(n){n.dataset.nicepayEasyPayMethod=t.id,n.className=`inline-flex items-center justify-center rounded-lg text-xs font-bold ${t.markClassName}`,n.textContent=t.markText;return}const a=ht(t),o=Pt(e);if(o&&o.parentElement){o.replaceWith(a);return}ue(e)?.prepend(a)}function _t(e,t){const n=Array.from(e.querySelectorAll("p")),a=yt(t),o=de(a.heading),r=de(a.description),i=n[0],s=n[1];i&&i.textContent!==o&&(i.textContent=o),i&&(i.setAttribute("aria-label",a.heading),i.style.textAlign="left",i.style.whiteSpace="normal",i.style.wordBreak="keep-all",i.style.overflowWrap="anywhere"),s&&s.textContent!==r&&(s.textContent=r),s&&(s.style.textAlign="left",s.style.fontSize="12px",s.style.lineHeight="1rem",s.style.whiteSpace="normal",s.style.wordBreak="keep-all",s.style.overflowWrap="anywhere"),ft(e,i,s),e.title=a.title}function bt(e,t){e.hidden&&(e.hidden=!1),e.disabled&&(e.disabled=!1),e.style.display==="none"&&e.style.removeProperty("display"),e.removeAttribute("aria-hidden"),e.dataset.nicepayEasyPayMethod=t.id,e.dataset.nicepayEasyPayVisible="true",gt(e),wt(e,t),_t(e,t)}function Ct(){const e=document.getElementById(st);return e?(e.remove(),!0):!1}async function B(e=document){if(typeof window>"u"||typeof document>"u"||!D())return!1;let t=Ct();return e.querySelectorAll("button").forEach(n=>{const a=mt(n);a&&(bt(n,a),t=!0)}),t}function Nt(){$||($=!0,window.setTimeout(()=>{$=!1,B()},0))}function ye(){x!==null&&(window.clearInterval(x),x=null)}function G(){if(!D())return;ye(),B();let e=0;x=window.setInterval(()=>{e+=1,B(),e>=it&&ye()},ot);const t=document.body;t[se]||(t[se]=!0,le=new MutationObserver(()=>Nt()),le.observe(document.body,{childList:!0,subtree:!0,characterData:!0}))}function pe(){D()&&G()}function kt(){if(typeof window>"u"||typeof document>"u")return;const e=ct();if(e[ie])return;e[ie]=!0,console.info(`[${at}] checkout easy pay method sync installed`),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>G()):G();const t=history.pushState.bind(history);history.pushState=(...n)=>{t(...n),window.setTimeout(()=>pe(),200)},window.addEventListener("popstate",()=>window.setTimeout(()=>pe(),200))}const j="sirsoft-pay_nicepayments",me="__nicepayOcReceiptInjectorInstalled",fe="nicepay-oc-receipt-btn",St=/^\/shop\/orders\/([^/]+)\/complete$/;function he(){return localStorage.getItem("auth_token")}async function Et(e){const t=he();if(!t)return null;try{const n=await fetch(`/api/modules/sirsoft-ecommerce/user/orders/${e}`,{headers:{Authorization:`Bearer ${t}`,Accept:"application/json"}});return n.ok?(await n.json())?.data?.payment??null:null}catch{return null}}async function ge(e){const t=he();if(!t)return null;try{const n=await fetch(`/api/plugins/${j}/user/orders/${e}/receipt`,{headers:{Authorization:`Bearer ${t}`,Accept:"application/json"}});return n.ok?await n.json():null}catch{return null}}function xt(e){if(!e)return!1;const t=Array.from(document.querySelectorAll("div"));for(const n of t){const a=Array.from(n.children).filter(i=>i instanceof HTMLElement&&i.tagName==="SPAN");if(a.length<2)continue;const o=a[0].textContent?.trim();if(o!=="결제 방법"&&o!=="결제수단"&&o!=="결제 방식")continue;const r=a[a.length-1];return r.textContent?.trim()!==e&&(r.textContent=e,r.dataset.nicepayPaymentMethodPatched="true"),n.dataset.nicepayPaymentMethodRow="true",!0}return!1}async function At(e){if(document.getElementById(fe))return;const t=await Et(e);if(!t||t.pg_provider!=="nicepayments"||!t.transaction_id||!t.paid_at)return;const n=Array.from(document.querySelectorAll('button[type="button"]')).find(s=>s.className.includes("bg-blue-600"));if(!n?.parentElement)return;const a=await ge(e);xt(a?.payment_method_display_label);const o=n.parentElement,r=document.createElement("button");r.id=fe,r.type="button",r.className=n.className.replace(/bg-blue-\d+/g,"bg-green-600").replace(/hover:bg-blue-\d+/g,"hover:bg-green-700"),r.textContent="영수증 조회",r.addEventListener("click",async()=>{r.disabled=!0,r.textContent="로딩 중...";const s=await ge(e);r.disabled=!1,r.textContent="영수증 조회";const l=s?.receipt_url??null;l&&window.open(l,"nicepay_receipt","width=800,height=600,scrollbars=yes,resizable=yes")});const i=o.lastElementChild;o.insertBefore(r,i),console.info(`[${j}] receipt button injected on order complete page`)}function vt(){const e=location.pathname.match(St);e&&At(e[1])}function Lt(){if(typeof window>"u")return;const e=window;if(e[me])return;e[me]=!0,console.info(`[${j}] order complete receipt injector installed`);const t=(a=1200)=>setTimeout(vt,a);document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>t()):t();const n=history.pushState.bind(history);history.pushState=(...a)=>{n(...a),t()},window.addEventListener("popstate",()=>t(500))}const A="sirsoft-pay_nicepayments",Pe="__nicepayOrderShowInjectorInstalled",we="nicepay-mp-receipt-row",_e="nicepay-mp-vbank-info",It=/^\/mypage\/orders\/([^/]+)$/;function Tt(e){try{const n=window.G7Core?.getState,r=n?.()?.currentDataContext?.order?.data;return!r||r.order_number!==e?null:r}catch{return null}}function Rt(){return localStorage.getItem("auth_token")}async function be(e){const t=Rt();if(!t)return null;try{const n=await fetch(`/api/plugins/${A}/user/orders/${e}/receipt`,{headers:{Authorization:`Bearer ${t}`,Accept:"application/json"}});return n.ok?await n.json():null}catch{return null}}function Mt(e,t){if(!t)return!1;const n=Array.from(e.querySelectorAll("div"));for(const a of n){const o=Array.from(a.children).filter(s=>s instanceof HTMLElement&&s.tagName==="SPAN");if(o.length<2)continue;const r=o[0].textContent?.trim();if(r!=="결제 방법"&&r!=="결제수단"&&r!=="Payment Method")continue;const i=o[o.length-1];return i.textContent?.trim()!==t&&(i.textContent=t,i.dataset.nicepayPaymentMethodPatched="true"),a.dataset.nicepayPaymentMethodRow="true",!0}return!1}function Ot(){const e=document.getElementById("order_payment_info_panel");if(e)return Array.from(e.children).find(a=>a.className?.includes("space-y"))??e;const t=Array.from(document.querySelectorAll("h3")).find(a=>a.textContent?.includes("결제 정보"));if(!t)return null;const n=t.parentElement?.parentElement;return n?Array.from(n.children).find(a=>a.className?.includes("space-y"))??n:null}function $t(e){const t=document.createElement("div");t.id=we,t.className="flex items-center justify-between";const n=document.createElement("span");n.className="text-gray-500 dark:text-gray-400 text-sm",n.textContent="영수증";const a=document.createElement("button");return a.type="button",a.className="inline-flex items-center gap-1 text-sm text-blue-600 dark:text-blue-400 hover:underline disabled:opacity-50",a.textContent="영수증 조회",a.addEventListener("click",async()=>{a.disabled=!0,a.textContent="로딩 중...";const o=await be(e);a.disabled=!1,a.textContent="영수증 조회";const r=o?.receipt_url??null;r&&window.open(r,"nicepay_receipt","width=800,height=600,scrollbars=yes,resizable=yes")}),t.appendChild(n),t.appendChild(a),t}function Dt(e){if(!e)return"";try{const t=new Date(e);if(Number.isNaN(t.getTime()))return e;const n=a=>String(a).padStart(2,"0");return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`}catch{return e}}function v(e,t,n="font-medium text-gray-900 dark:text-white"){const a=document.createElement("div");a.className="flex justify-between text-sm";const o=document.createElement("span");o.className="text-gray-600 dark:text-gray-400",o.textContent=e;const r=document.createElement("span");return r.className=n,r.textContent=t,a.appendChild(o),a.appendChild(r),a}function Bt(e){const t=e.payment??{},n=document.createElement("div");n.id=_e,n.className="pt-4 mt-2 border-t border-gray-200 dark:border-gray-700";const a=document.createElement("div");a.className="bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-700 rounded-lg p-4";const o=document.createElement("h3");o.className="text-sm font-semibold text-blue-800 dark:text-blue-300 mb-3",o.textContent="가상계좌 입금 안내";const r=document.createElement("div");r.className="space-y-2",r.appendChild(v("은행",t.vbank_name??"")),r.appendChild(v("계좌번호",t.vbank_number??"","font-medium font-mono text-gray-900 dark:text-white")),r.appendChild(v("예금주",t.vbank_holder??"")),r.appendChild(v("입금 금액",e.total_amount_formatted??"","font-bold text-blue-600 dark:text-blue-400"));const i=t.vbank_due_at;if(i){const s=document.createElement("div");s.className="flex justify-between text-sm pt-2 border-t border-blue-200 dark:border-blue-700 mt-2";const l=document.createElement("span");l.className="text-gray-600 dark:text-gray-400",l.textContent="입금 기한";const u=document.createElement("span");u.className="font-medium text-red-600 dark:text-red-400",u.textContent=Dt(i),s.appendChild(l),s.appendChild(u),r.appendChild(s)}if(a.appendChild(o),a.appendChild(r),!t.paid_at){const s=document.createElement("p");s.className="text-xs text-blue-700 dark:text-blue-300 mt-3",s.textContent="입금 기한 내에 입금이 완료되지 않으면 주문이 자동 취소됩니다.",a.appendChild(s)}return n.appendChild(a),n}async function Gt(e){const t=Tt(e);if(!t)return!1;const{payment:n}=t;if(!n||n.pg_provider!=="nicepayments")return!0;const a=Ot();if(!a)return!1;const o=await be(e);return Mt(a,o?.payment_method_display_label),n.payment_method==="vbank"&&n.vbank_number&&!document.getElementById(_e)&&(a.appendChild(Bt(t)),console.info(`[${A}] vbank info injected on mypage order show`)),!n.transaction_id||!n.paid_at||document.getElementById(we)||(a.appendChild($t(e)),console.info(`[${A}] receipt button injected on mypage order show`)),!0}function jt(e){let t=0;const n=setInterval(()=>{t++,Gt(e).then(a=>{(a||t>=30)&&clearInterval(n)})},400)}function qt(){const e=location.pathname.match(It);e&&jt(e[1])}function Ft(){if(typeof window>"u")return;const e=window;if(e[Pe])return;e[Pe]=!0,console.info(`[${A}] mypage order show injector installed`);const t=(a=1500)=>setTimeout(qt,a);document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>t()):t();const n=history.pushState.bind(history);history.pushState=(...a)=>{n(...a),t(600)},window.addEventListener("popstate",()=>t(500))}const Ht="sirsoft-pay_nicepayments",Ce="__nicepayAdminPaymentMethodBrandInjectorInstalled",Ne="__nicepayAdminPaymentMethodBrandSyncListenerAttached",Yt=/^\/admin\/ecommerce\/settings\/?$/,ke='[data-nicepay-admin-payment-brand-mark="true"]',Ut=200,Kt=120,Wt=[{id:"nicepay_naverpay",labels:["네이버페이 (나이스페이먼츠)","네이버페이로 결제 (나이스페이먼츠)","Naver Pay (NicePayments)","Pay with Naver Pay (NicePayments)"],shortLabels:[],markLines:["N"],markClassName:"bg-green-500 text-white"},{id:"nicepay_kakaopay",labels:["카카오페이 (나이스페이먼츠)","카카오페이로 결제 (나이스페이먼츠)","Kakao Pay (NicePayments)","Pay with Kakao Pay (NicePayments)"],shortLabels:[],markLines:["K"],markClassName:"bg-yellow-400 text-gray-950"},{id:"nicepay_samsungpay",labels:["삼성페이 (나이스페이먼츠)","삼성페이로 결제 (나이스페이먼츠)","Samsung Pay (NicePayments)","Pay with Samsung Pay (NicePayments)"],shortLabels:[],markLines:["S"],markClassName:"bg-blue-600 text-white"},{id:"nicepay_applepay",labels:["애플페이 (나이스페이먼츠)","애플페이로 결제 (나이스페이먼츠)","Apple Pay (NicePayments)","Pay with Apple Pay (NicePayments)"],shortLabels:[],markLines:["A"],markClassName:"bg-gray-900 text-white"},{id:"nicepay_payco",labels:["PAYCO (나이스페이먼츠)","PAYCO로 결제 (나이스페이먼츠)","PAYCO (NicePayments)","Pay with PAYCO (NicePayments)"],shortLabels:[],markLines:["P"],markClassName:"bg-red-500 text-white"},{id:"nicepay_skpay",labels:["11pay (나이스페이먼츠)","11pay로 결제 (나이스페이먼츠)","11pay (NicePayments)","Pay with 11pay (NicePayments)"],shortLabels:[],markLines:["11"],markClassName:"bg-orange-500 text-white"},{id:"nicepay_ssgpay",labels:["SSG페이 (나이스페이먼츠)","SSG페이로 결제 (나이스페이먼츠)","SSG Pay (NicePayments)","Pay with SSG Pay (NicePayments)"],shortLabels:[],markLines:["SSG"],markClassName:"bg-red-700 text-white"},{id:"nicepay_lpay",labels:["L.pay (나이스페이먼츠)","L.pay로 결제 (나이스페이먼츠)","L.pay (NicePayments)","Pay with L.pay (NicePayments)"],shortLabels:[],markLines:["L"],markClassName:"bg-purple-600 text-white"}];let Se=null,L=null,q=!1;function Vt(){return window}function F(){if(!Yt.test(window.location.pathname))return!1;const e=new URLSearchParams(window.location.search).get("tab");return e===null||e===""||e==="order_settings"}function zt(e){return e instanceof HTMLElement?e.className:""}function Ee(e){return(e??"").replace(/\u200B/g,"").replace(/\s+/g," ").trim()}function Jt(e){const t=zt(e);return t.includes("excel-card")||t.includes("flex-center")&&t.includes("border")&&t.includes("gap-4")}function xe(e){return e.querySelector(".font-medium")}function Xt(e){const t=Ee(xe(e)?.textContent),n=Ee(e.textContent);return Wt.find(a=>a.shortLabels.some(o=>t===o)||a.labels.some(o=>n.includes(o)))??null}function Qt(e){return Array.from(e.querySelectorAll("div")).filter(Jt)}function Zt(e){return Array.from(e.querySelectorAll("svg, [data-icon], i")).find(n=>!n.closest("[data-drag-handle]")&&!n.closest(ke)&&!n.closest('.row-stack, .excel-card-body, button, select, [role="switch"]'))??null}function Ae(e,t){e.dataset.nicepayAdminPaymentBrandMark="true",e.dataset.nicepayAdminPaymentMethod=t.id,e.setAttribute("aria-hidden","true"),e.className=`inline-flex items-center justify-center rounded-lg font-bold ${t.markClassName}`,e.style.width="32px",e.style.height="32px",e.style.flex="0 0 32px",e.style.lineHeight="1",e.style.fontSize=t.markLines.join("").length>2?"9px":"12px";const n=t.markLines.join("");e.textContent!==n&&(e.textContent=t.markLines[0]??"")}function en(e){const t=document.createElement("span");return Ae(t,e),t}function tn(e,t){const n=e.querySelector(ke);if(n instanceof HTMLSpanElement)return e.dataset.nicepayAdminPaymentMethod=t.id,Ae(n,t),!0;const a=en(t),o=Zt(e);if(o&&o.parentElement)return e.dataset.nicepayAdminPaymentMethod=t.id,o.replaceWith(a),!0;const r=xe(e);return r&&r.parentElement?(e.dataset.nicepayAdminPaymentMethod=t.id,r.parentElement.insertBefore(a,r),!0):!1}function H(e=document){if(typeof window>"u"||typeof document>"u"||!F())return!1;let t=!1;return Qt(e).forEach(n=>{const a=Xt(n);a&&tn(n,a)&&(t=!0)}),t}function nn(){q||(q=!0,window.setTimeout(()=>{q=!1,H()},0))}function Y(){L!==null&&(window.clearInterval(L),L=null)}function U(){if(!F())return;Y(),H();let e=0;L=window.setInterval(()=>{e+=1,H(),e>=Kt&&Y()},Ut);const t=document.body;t[Ne]||(t[Ne]=!0,Se=new MutationObserver(()=>nn()),Se.observe(document.body,{childList:!0,subtree:!0,characterData:!0}))}function ve(){if(F()){U();return}Y()}function an(){if(typeof window>"u"||typeof document>"u")return;const e=Vt();if(e[Ce])return;e[Ce]=!0,console.info(`[${Ht}] admin payment method brand sync installed`),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>U()):U();const t=history.pushState.bind(history);history.pushState=(...n)=>{t(...n),window.setTimeout(()=>ve(),200)},window.addEventListener("popstate",()=>window.setTimeout(()=>ve(),200))}const K="sirsoft-pay_nicepayments",Le="__nicepayAdminPaymentDisplayInjectorInstalled",rn=/^\/admin\/ecommerce\/orders\/([^/]+)$/;function on(){return localStorage.getItem("auth_token")}async function sn(e){const t=on();if(!t)return null;try{const n=await fetch(`/api/plugins/${K}/admin/orders/${e}/transaction-status`,{headers:{Authorization:`Bearer ${t}`,Accept:"application/json"}});if(!n.ok)return null;const a=await n.json();return("data"in a?a.data:a)??null}catch{return null}}function cn(e){return Array.from(e.children).filter(t=>t instanceof HTMLElement)}function ln(e,t){let n=!1;const a=Array.from(e.querySelectorAll("div"));for(const o of a){const r=cn(o),i=r.findIndex(m=>m.textContent?.trim()==="결제수단");if(i<0)continue;const s=r.slice(i+1).find(m=>m.textContent?.trim()&&m.textContent.trim()!=="결제수단");if(!s)continue;const l=r.slice(i+2).find(m=>/^\(.+\)$/.test(m.textContent?.trim()??"")),u=l?.textContent?.trim().replace(/^\(|\)$/g,"")??"",b=u&&t.endsWith(")")?t.replace(/\)$/,`, ${u})`):t;s.textContent?.trim()!==b&&(s.textContent=b,s.dataset.nicepayPaymentMethodPatched="true"),o.dataset.nicepayPaymentMethodRow="admin-order",l&&u&&(l.textContent="",l.style.display="none",l.dataset.nicepayPaymentInstallmentHidden="true"),n=!0}return n}function dn(e,t,n){const o=Array.from(e.querySelectorAll("span")).filter(r=>r.textContent?.trim()===t).find(r=>{const i=typeof r.className=="string"?r.className:"";return i.includes("rounded-full")||i.includes("font-medium")});return o?(o.textContent=n,o.dataset.nicepayPaymentMethodPatched="true",o.dataset.nicepayPaymentMethodBadge="admin-order",!0):!1}function un(e,t){const n=t?._pay_method_label,a=t?._embedded_pg_provider_label,o=t?._base_pay_method_label;if(!n||!a)return!1;const r=ln(e,n),i=o?dn(e,o,a):!1;return r||i}async function yn(e){const t=document.getElementById("section_payment_info")??document.getElementById("payment_info_card");if(!t)return!1;const n=await sn(e);return n&&un(t,n)&&console.info(`[${K}] payment method display patched on admin order detail`),!0}function pn(e){let t=0;const n=setInterval(()=>{t++,yn(e).then(a=>{(a||t>=30)&&clearInterval(n)})},400)}function mn(){const e=location.pathname.match(rn);e&&pn(e[1])}function fn(){if(typeof window>"u")return;const e=window;if(e[Le])return;e[Le]=!0,console.info(`[${K}] admin order payment display injector installed`);const t=(a=1500)=>setTimeout(mn,a);document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>t()):t();const n=history.pushState.bind(history);history.pushState=(...a)=>{n(...a),t(600)},window.addEventListener("popstate",()=>t(500))}const C="sirsoft-pay_nicepayments",W={info:(...e)=>console.info(`[${C}]`,...e),warn:(...e)=>console.warn(`[${C}]`,...e),error:(...e)=>console.error(`[${C}]`,...e)};function Ie(){const e=window.G7Core;if(!e)return 0;const t=e.getActionDispatcher;if(typeof t!="function")return 0;const n=t();if(!n||typeof n.registerHandler!="function")return 0;let a=0;for(const[o,r]of Object.entries(ee)){const i=`${C}.${o}`;n.registerHandler(i,r,{category:"plugin",source:C}),a++}return a}function Te(){nt(),kt(),Lt(),Ft(),an(),fn();const e=()=>{const t=Ie();if(t>0){W.info(`${t} handler(s) registered`),Z();return}let n=0;const a=50,o=setInterval(()=>{n++;const r=Ie();if(r>0){clearInterval(o),W.info(`${r} handler(s) registered (after ${n} retries)`),Z();return}n>=a&&(clearInterval(o),W.warn("ActionDispatcher not available after timeout"))},100)};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e):e()}Te(),window.__SirsoftNicepayments={identifier:C,handlers:Object.keys(ee),initPlugin:Te}})();