결제 - 키움결제 결제취소 관련 처리

This commit is contained in:
이경숙
2026-04-08 16:47:58 +09:00
parent a9c717e24c
commit c418d01f46
6 changed files with 265 additions and 183 deletions

View File

@@ -1553,17 +1553,19 @@ public class BOPayService{
*/
public Map<String, Object> cancelKiwoomPay(BOPayVO payVO) throws Exception {
log.debug("cancelKiwoomPay step1 payVO :::> {}", payVO);
//관련 키값 DB 조회
DataMap resultMap = selectPayLink(payVO.getSopmalCd());
//요청코드
String authKey = resultMap.get("kcpSecretKey").toString();
String cpId = resultMap.get("kcpMid").toString();
String payMethod = ""; //취소결제수단
String cancelReq = "Y"; //취소URL 요청여부
String amount = payVO.getCancelAmount(); //취소금액 //todo :: db연결해서 가져와야 함 nullCheck(request.getParameter("AUTHKEY"));
String trxId = payVO.getTno(); //거래번호
String cancelReason = payVO.getCancelReason(); //취소사유
String payMethod = ""; //취소결제수단
String cancelReq = "Y"; //취소URL 요청여부
//String TAXFREEAMT = nullCheck(request.getParameter("TAXFREEAMT")); //비과세 취소금액
if(payVO.getSetleTyCd().equals("01")) {
@@ -1572,8 +1574,8 @@ public class BOPayService{
//1차 요청코드
JSONObject obj = new JSONObject();
obj.put("cancelReason", payVO.getCancelReason()); //취소사유
obj.put("cancelAmount", payVO.getCancelAmount()); //취소금액 (금액이 없으면 전체취소)
obj.put("cancelReason", cancelReason); //취소사유
obj.put("cancelAmount", amount); //취소금액 (금액이 없으면 전체취소)
JSONObject jsonObj = new JSONObject();
jsonObj.put("CPID", cpId);
@@ -1584,7 +1586,21 @@ public class BOPayService{
jsonObj.put("CANCELREASON",cancelReason);
//jsonObj.put("TAXFREEAMT",TAXFREEAMT);
log.debug("cancelKiwoomPay step3 JSONObject ::: {}", jsonObj.toString());
//로그 저장 셋팅
JSONObject finalJObj = new JSONObject();
DataMap pgApiLogReqVO = new DataMap();
pgApiLogReqVO.put("reqParam", jsonObj.toString());
pgApiLogReqVO.put("ordrInnb", StringUtil.isNullToString(payVO.getOrderId()));
pgApiLogReqVO.put("sopmalCd", StringUtil.isNullToString(payVO.getSopmalCd()));
pgApiLogReqVO.put("pgCmpnyNm", StringUtil.isNullToString(payVO.getPgCmpnyNm()));
pgApiLogReqVO.put("mbrInnb", StringUtil.isNullToString(payVO.getMbrInnb()));
log.debug("cancelKiwoomPay step4 pgApiLogReqVO ::: {}", pgApiLogReqVO);
// ====== step 1. 취소URL 요청 ======
try{
//결제 API URL
String targetURL = "";
@@ -1617,6 +1633,9 @@ public class BOPayService{
int responseCode = con.getResponseCode();
String responseMsg = con.getResponseMessage();
log.debug("cancelKiwoom STEP1 승인전 responseCode ====={}",responseCode);
log.debug("cancelKiwoom STEP1 승인전 responseMsg ====={}",responseMsg);
String token = "";
String returnUrl = "";
@@ -1637,10 +1656,15 @@ public class BOPayService{
JSONObject jObj = (JSONObject)JSONValue.parse(responseBody);
token = jObj.get("TOKEN").toString();
returnUrl = jObj.get("RETURNURL").toString();
log.debug("cancelKiwoom STEP1 승인 responseBody ====={}", responseBody);
log.debug("cancelKiwoom STEP1 승인 TOKEN200 ====={}",token);
log.debug("cancelKiwoom STEP1 승인 URL200 ====={}",returnUrl);
}
con.disconnect();
log.debug("cancelKiwoom STEP1 승인 TOKEN ====={}",token);
log.debug("cancelKiwoom STEP1 승인 URL ====={}",returnUrl);
// ====== step 2. 취소 승인 요청 ======
@@ -1670,8 +1694,6 @@ public class BOPayService{
responseCode = con.getResponseCode();
responseMsg = con.getResponseMessage();
JSONObject jObj = new JSONObject();
//정상 수신 했을경우 (응답코드:200)
if(responseCode == 200){
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
@@ -1686,32 +1708,30 @@ public class BOPayService{
//응답 데이터 처리
String responseBody = response1.toString();
jObj = (JSONObject)JSONValue.parse(responseBody);
/*resultcode = checkObjNull(jObj.get("RESULTCODE")).toString();
errormessage= checkObjNull(jObj.get("ERRORMESSAGE")).toString();
if(resultcode.equals("0000")){
daoutrx = checkObjNull(jObj.get("DAOUTRX")).toString();
amount = checkObjNull(jObj.get("AMOUNT")).toString();
orderno = checkObjNull(jObj.get("ORDERNO")).toString();
canceldate = checkObjNull(jObj.get("CANCELDATE")).toString();
cpname = checkObjNull(jObj.get("CPNAME")).toString();
cpurl = checkObjNull(jObj.get("CPURL")).toString();
cptelno = checkObjNull(jObj.get("CPTELNO")).toString();
}*/
finalJObj = (JSONObject)JSONValue.parse(responseBody);
}
con.disconnect();
JSONObject finalJObj = jObj;
return new HashMap<>() {{
put("response", finalJObj);
}};
log.debug("Kiwoom 결제취소 jObj::: {}", finalJObj.toString());
pgApiLogReqVO.put("resParam", finalJObj.toString());
}catch(Exception e){
e.printStackTrace();
} finally {
log.debug("cancelKiwoomPay finally pgApiLogReqVO ::: {}", pgApiLogReqVO);
ordrLogService.insertSetleOrderPgLog(payVO, pgApiLogReqVO);
ordrLogService.insertBOPgApiLogReqRegist(pgApiLogReqVO);
}
Map<String, Object> result = new HashMap<>();
result.put("response", finalJObj.toString());
return result;
}
}

View File

@@ -1127,75 +1127,23 @@ public class BORtngudrefndService {
log.info("kiwoom api 전달 파라미터 확인 : {}", payVO);
setleCancelResultMessage = payService.cancelKiwoomPay(payVO);
log.info("결제 취소 API 결과 확인 : {}", setleCancelResultMessage);
log.info("결제 취소 API 결과 확인 : {}", setleCancelResultMessage.get("response"));
log.info("결제 취소 API 결과 확인 RESULTCODE : {}", setleCancelResultMessage.get("RESULTCODE"));
log.info("결제 취소 API 결과 확인 ERRORMESSAGE : {}", setleCancelResultMessage.get("ERRORMESSAGE"));
/*resultcode = checkObjNull(jObj.get("RESULTCODE")).toString();
errormessage= checkObjNull(jObj.get("ERRORMESSAGE")).toString();
if(resultcode.equals("0000")){
daoutrx = checkObjNull(jObj.get("DAOUTRX")).toString();
amount = checkObjNull(jObj.get("AMOUNT")).toString();
orderno = checkObjNull(jObj.get("ORDERNO")).toString();
canceldate = checkObjNull(jObj.get("CANCELDATE")).toString();
cpname = checkObjNull(jObj.get("CPNAME")).toString();
cpurl = checkObjNull(jObj.get("CPURL")).toString();
cptelno = checkObjNull(jObj.get("CPTELNO")).toString();
}*/
responseMap = (Map<String, Object>) setleCancelResultMessage.get("response");
// String jsonString = (String) setleCancelResultMessage.get("response");
// ObjectMapper objectMapper = new ObjectMapper();
// responseMap = objectMapper.readValue(jsonString, Map.class);
log.info("리스펀스 결과 : {}", responseMap);
log.info("리스펀스 결과 값 : {}", responseMap.get("res_cd"));
log.info("결제 취소 API 결과 확인 response : {}", setleCancelResultMessage.get("response"));
String jsonString = (String) setleCancelResultMessage.get("response");
ObjectMapper objectMapper = new ObjectMapper();
responseMap = objectMapper.readValue(jsonString, Map.class);
log.debug("리스펀스 결과 : {}", responseMap);
log.info("리스펀스 결과 값 : {}", responseMap.get("status"));
log.info("리스펀스 결과 값 : {}", responseMap.get("RESULTCODE"));
if ("0000".equals(responseMap.get("res_cd"))) {
// 8729 : 기 취소된 거래
if ("0000".equals(responseMap.get("RESULTCODE"))) {
// 0000 : 취소성공
log.debug("0000");
message.put("setleStatus", responseMap.get("res_cd"));
message.put("setleMessage", responseMap.get("res_msg"));
message = refundCancelCashReceipt(setle, ordrSetleInnb, sopmalCd, receiptCancelAmt, refundModeTypeSales, updusrDvCd, updusr); // 현금영수증 취소
if (!"0000".equals(message.get("cashReceiptStatus"))) {
logDtlCn = "현금영수증 취소에 실패하였습니다.";
// throw new WnbtRestException("현금영수증 취소에 실패하였습니다."); // TODO : 현금영수증 취소 실패해도 트렌젝션 걸러야하는지 확인 필요
}
} else {
if ("8729".equals(responseMap.get("res_cd"))) { // 계좌이체 기 취소된 거래
logDtlCn = String.valueOf(responseMap.get("res_msg"));
// throw new WnbtRestException(logDtlCn);
} else if ("8332".equals(responseMap.get("res_cd"))) { // 이미 사용중지된 가상계좌 사용중지요청
logDtlCn = String.valueOf(responseMap.get("res_msg"));
throw new WnbtRestException(logDtlCn);
} else if ("8133".equals(responseMap.get("res_cd"))) { // 기취소된 신용카드 거래 취소요청
logDtlCn = String.valueOf(responseMap.get("res_msg"));
// throw new WnbtRestException(logDtlCn);
} else if ("8317".equals(responseMap.get("res_cd"))) { // 가상계좌 환불 불가상태
logDtlCn = String.valueOf(responseMap.get("res_msg"));
throw new WnbtRestException(logDtlCn);
} else if ("5002".equals(responseMap.get("res_cd"))) { // 취소 불가 상태 (에스크로일 경우 '구매확인' 이후 처리가 가능해서 5002 에러가 들어옴
if ("05".equals(setle.getSetleTyCd()) || "06".equals(setle.getSetleTyCd())) {
logDtlCn = String.valueOf(responseMap.get("res_msg") + "\n에스크로 결제의 경우, 배송 완료 후 수령자 이메일에 있는 '구매확인' 버튼을 눌러야 취소가 가능합니다.");
} else {
logDtlCn = String.valueOf(responseMap.get("res_msg"));
}
throw new WnbtRestException(logDtlCn);
message.put("setleStatus", responseMap.get("RESULTCODE"));
message.put("setleMessage", responseMap.get("ERRORMESSAGE"));
} else {
log.debug("1111");
message.put("setleStatus", responseMap.get("res_cd"));
message.put("setleMessage", responseMap.get("res_msg"));
message.put("setleStatus", responseMap.get("RESULTCODE"));
message.put("setleMessage", responseMap.get("ERRORMESSAGE"));
logDtlCn = "잘못된 요청입니다. 관리자에게 문의하세요.";
throw new WnbtRestException("잘못된 요청입니다. 관리자에게 문의하세요.");
}
@@ -1204,8 +1152,6 @@ public class BORtngudrefndService {
}
}
orderRefundAmtSum += cancelAmt;
// refundAmt -= cancelAmt; // 현재 환불 금액에서 취소금액 차감
refundAmt = refundAmt - cancelAmt > 0 ? refundAmt - cancelAmt : 0; // 현재 환불 금액에서 취소금액 차감

View File

@@ -644,7 +644,7 @@ public class PayController {
}
@Policy(AuthPolicy.RESTRICTED)
@RequestMapping(value="/selectKiwoomSample2")
@RequestMapping(value="/selectKiwoomApiSample")
public String selectKiwoonPay2(ModelMap model) throws Exception {
log.debug("selectKiwoonPay = {}");
return "sopmal/ordr/PayKiwoomPay2C";
@@ -710,9 +710,9 @@ public class PayController {
*/
@Policy(AuthPolicy.RESTRICTED)
@RequestMapping(value="/kiwoomPaySuccss")
public String confirmPaymentkiwoom(HttpServletRequest request, ModelMap model) throws Exception {
public String confirmPaymentKiwoom(HttpServletRequest request, ModelMap model) throws Exception {
System.out.println("콜백 수신 ::: "+request.getQueryString());
System.out.println("성공결과페이지 ::: "+request.getQueryString());
BOPayVO payVO = new BOPayVO();
@@ -722,15 +722,6 @@ public class PayController {
payVO.setPayMethod(request.getParameter("PAYMETHOD"));
Map<String, Object> message = new HashMap<>();
/*String sopmalCd = payVO.getSopmalCd();
try {
message = service.insertKcpPay(payVO);
} catch (Exception e) {
message = new HashMap<>() {{
put("response", "결제를 실패하였습니다.\n관리자에게 문의하시기 바랍니다.");
}};
}*/
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", payVO.getCode());
@@ -740,11 +731,66 @@ public class PayController {
message.put("response",jsonObject.toString());
model.addAttribute("message", message);
// responseHandler.handleResponse(
// sendToResrc.ofPost(RESRC.GCONEBO, "/gcone/ordr/pay/kcpPayProc", payVO),
// model,
// "message"
// );
return "sopmal/ordr/PayKiwoomSucsC";
}
/**
* 키움 결제취소 화면
* @return PayKiwoomModC.jsp
* @author 이경숙
*/
@Policy(AuthPolicy.RESTRICTED)
@RequestMapping(value="/selectKiwoomCancelSample")
public String selectKiwoomCancel(ModelMap model) throws Exception {
log.debug("selectKiwoomCancel = {}");
return "sopmal/ordr/PayKiwoomModC";
}
/**
* 키움 결제 연계처리 - 결체취소결과페이지
* @return PayKiwoomSucsC.jsp
* @author 이경숙
*/
@Policy(AuthPolicy.RESTRICTED)
@RequestMapping(value="/kiwoomPayCancel")
public String confirmCancelKiwoom(HttpServletRequest request, ModelMap model) throws Exception {
System.out.println("취소데이터 수신 ::: "+request.getQueryString());
Map<String, Object> setleCancelResultMessage = new HashMap<>();
Map<String, Object> responseMap = new HashMap<>();
BOPayVO payVO = new BOPayVO();
payVO.setSopmalCd("SK");
payVO.setOrderId(request.getParameter("ORDERNO"));
payVO.setCancelAmount(request.getParameter("AMOUNT"));
payVO.setPayMethod(request.getParameter("PAYMETHOD"));
payVO.setTno(request.getParameter("TRXID"));
payVO.setCancelReason(request.getParameter("CANCELREASON"));
payVO.setSetleTyCd("01");
payVO.setPgCmpnyNm("kiwoom");
log.debug("confirmCancelKiwoom step1 payVO :::> {}", payVO);
Map<String, Object> message = new HashMap<>();
setleCancelResultMessage = service.cancelKiwoomPay(payVO);
String responseStr = (String) setleCancelResultMessage.get("response");
JSONParser parser = new JSONParser();
JSONObject jsonObject = (JSONObject) parser.parse(responseStr);
jsonObject.put("orderId", payVO.getOrderId());
jsonObject.put("amount", payVO.getAmount());
jsonObject.put("payMethod", payVO.getPayMethod());
jsonObject.put("code", jsonObject.get("RESULTCODE"));
message.put("response",jsonObject.toString());
model.addAttribute("message", message);
return "sopmal/ordr/PayKiwoomSucsC";
}

View File

@@ -176,6 +176,7 @@
<input type="hidden" name="AMOUNT" value="${data.setle.wonSetleAmt}" /><%-- 결제금액 --%>
<input type="hidden" name="PRODUCTNAME" value="${data.setle.goodsNm}" /><%-- 상품명 --%>
<input type="hidden" name="USERID" value="${data.ordr.mbrId}" /> <%-- 고객 ID --%>
<input type="hidden" name="EMAIL" value="${data.ordr.ordrrEmail}" /> <%-- 고객 EMAIL --%>
<input type="hidden" name="DIRECTRESULTFLAG" value="Y" /> <%-- 키움페이 결제 완료 창 없이 HOMEURL로 바로 이동(Y/N) --%>
<input type="hidden" name="HOMEURL" value="" /> <%-- 결제 성공 후, 이동할 URL(결제 창에서 이동) --%>
<input type="hidden" name="FAILURL" value="" /> <%-- 결제실패 후, 확인버튼 입력 시 이동할 URL --%>

View File

@@ -0,0 +1,58 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="ui" uri="http://www.winbit.kr/ctl/ui"%>
<%@ taglib prefix="f" uri="/WEB-INF/tlds/f.tld"%>
<%--
Class Name : PayKiwoomModC.jsp
Description : 키움 결제취소창
Modification Information
수정일 수정자 수정내용
------- -------- ---------------------------
2026-04-07 이경숙 최초 생성
--%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>통합 API 샘플페이지</title>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<script type="text/javascript">
var pf;
function fnSubmit2() {
var fileName;
fileName = "/sopmal/pay/kiwoomPayCancel";
pf = document.frmConfirm;
pf.action = fileName;
pf.method = "post";
pf.submit();
}
</script>
</head>
<body>
<form name="frmConfirm">
ORDERNO : <input type="text" id="ORDERNO" name="ORDERNO"><br>
AUTHKEY : <input type="text" id="AUTHKEY" name="AUTHKEY" placeholder="상점관리자 고객지원>연동정보설정에 연동키 확인"><br>
상점아이디 : <input type="text" id="CPID" name="CPID" placeholder="키움페이에서 발급받은 테스트ID입력" value="CTS18056"><br>
PAYMETHOD : <input type="text" id="PAYMETHOD" name="PAYMETHOD" placeholder="매뉴얼에 있는 결제수단별 PAYMETHOD확인" value="CARD"><br>
AMOUNT : <input type="text" id="AMOUNT" name="AMOUNT" placeholder="1004" style="width:80%;"/> <br>
CANCELREQ : <input type="text" id="CANCELREQ" name="CANCELREQ" value="Y"> 취소요청을 하는 경우라면 Y값 전송<br>
TRXID : <input type="text" id="TRXID" name="TRXID" placeholder="키움페이 거래번호"><br>
CANCELREASON : <input type="text" id="CANCELREASON" name="CANCELREASON" placeholder="취소사유"><br>
TAXFREEAMT : <input type="text" id="TAXFREEAMT" name="TAXFREEAMT" value=""> (선택)복합과세 결제일 경우 사용, 비과세 취소금액<br>
<input name="btnSubmit" type="button" value="결제요청" onclick="fnSubmit2()" ><br>
</form>
</body>
</html>

View File

@@ -36,6 +36,12 @@
$('#responseAmount').text(jsonObject.amount);
$('#resCode').text(jsonObject.code);
//$('#resMessage').text(jsonObject.res_msg);
$('#ERRORMESSAGE').text(jsonObject.ERRORMESSAGE);
$('#DAOUTRX').text(jsonObject.TRXID);
$('#AMOUNT').text(jsonObject.AMOUNT);
$('#ORDERNO').text(jsonObject.orderId);
$('#CANCELDATE').text(jsonObject.CANCELDATE);
});
</script>
@@ -50,6 +56,11 @@
<p>금액 : <span id="responseAmount"></span></p>
<p>메세지 : <span id="resMessage"></span></p>
<p>결과코드 : <span id="resCode"></span><p>
<p>-----------------------------------------</p>
<p>ERRORMESSAGE : <span id="ERRORMESSAGE"></span><p>
<p>DAOUTRX : <span id="DAOUTRX"></span><p>
<p>AMOUNT : <span id="AMOUNT"></span><p>
<p>CANCELDATE : <span id="CANCELDATE"></span><p>
<input type="button" onclick="window.opener.kiwoom_Completepayment(); self.close();" value="확인"/>