이호영 이호영 1 days ago
토쓰진행중
@f1f3da2e2551e951356bcae28c88aac1ae6a55bb
 
src/main/java/itn/let/mjo/pay/service/MjonPayTossService.java (added)
+++ src/main/java/itn/let/mjo/pay/service/MjonPayTossService.java
@@ -0,0 +1,23 @@
+package itn.let.mjo.pay.service;
+
+import itn.com.cmm.LoginVO;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+public interface MjonPayTossService {
+	Map<String, Object> processTossConfirm(String paymentKey, String orderId, String amount, LoginVO loginVO) throws Exception;
+
+//	public int selectBLineMberCnt(String mberId) throws Exception;
+//
+//	public int insertPrePayInfo(MjonPrePayVO mjonPrePayVO) throws Exception;
+//
+//	public List<MjonPrePayVO> selectPrePayList(MjonPrePayVO mjonPrePayVO) throws Exception;
+//
+//	public int deletePrePayInfo(MjonPrePayVO mjonPrePayVO) throws Exception;
+//
+//	public MjonPrePayVO selectPrePayInfo(MjonPrePayVO mjonPrePayVO) throws Exception;
+//
+//	public int updatePrePayModify(MjonPrePayVO mjonPrePayVO) throws Exception;
+}
src/main/java/itn/let/mjo/pay/service/MjonPayVO.java
--- src/main/java/itn/let/mjo/pay/service/MjonPayVO.java
+++ src/main/java/itn/let/mjo/pay/service/MjonPayVO.java
@@ -246,6 +246,6 @@
 	private String managerNm;			// 담당자명
 	private String prePaymentYn;		// 선불결제여부 N:후불제고객
 	private String dept;				// 회원종류 p:개인 c:기업
-	
-	
+
+
 }
 
src/main/java/itn/let/mjo/pay/service/impl/MjonPayTossServiceImpl.java (added)
+++ src/main/java/itn/let/mjo/pay/service/impl/MjonPayTossServiceImpl.java
@@ -0,0 +1,232 @@
+package itn.let.mjo.pay.service.impl;
+
+import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import itn.com.cmm.LoginVO;
+import itn.let.mjo.pay.service.MjonPayTossService;
+
+import javax.annotation.Resource;
+import java.io.*;
+import java.util.Map;
+
+import itn.let.mjo.pay.service.MjonPayVO;
+import itn.let.uat.uia.service.impl.MberManageDAO;
+import itn.let.uss.umt.service.MberManageVO;
+import org.springframework.stereotype.Service;
+
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Base64;
+import java.util.HashMap;
+
+import org.json.JSONObject;
+
+@Service("mjonPayTossService")
+public class MjonPayTossServiceImpl extends EgovAbstractServiceImpl implements MjonPayTossService {
+
+	@Resource(name="mjonPrePayDAO")
+	private MjonPrePayDAO mjonPrePayDAO;
+
+	@Resource(name="mjonPayDAO")
+	private MjonPayDAO mjonPayDAO;
+
+	/** mberManageDAO */
+	@Resource(name="mberManageDAO")
+	private MberManageDAO mberManageDAO;
+
+	/**
+	 * 토스페이먼츠 결제 승인 및 내역 저장
+	 * @param paymentKey 토스 결제 고유 키
+	 * @param orderId 상점 주문번호 (MOID)
+	 * @param amount 결제 금액
+	 * @param loginVO 로그인 사용자 정보
+	 * @return 처리 결과 Map
+	 */
+	@Override
+	public Map<String, Object> processTossConfirm(String paymentKey, String orderId, String amount, LoginVO loginVO) throws Exception {
+
+		// 1. 토스 승인 API 호출 설정
+		String secretKey = "test_gsk_GjLJoQ1aVZ5nzl22xOql3w6KYe2R:"; // 시크릿 키 (뒤에 콜론 필수)
+		String encodedKey = Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8));
+
+		URL url = new URL("https://api.tosspayments.com/v1/payments/confirm");
+		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+		connection.setRequestMethod("POST");
+		connection.setRequestProperty("Authorization", "Basic " + encodedKey);
+		connection.setRequestProperty("Content-Type", "application/json");
+		connection.setDoOutput(true);
+
+		// API 요청 바디 생성 (JSON 형식)
+		String jsonBody = String.format("{\"paymentKey\":\"%s\",\"orderId\":\"%s\",\"amount\":%s}",
+				paymentKey, orderId, amount);
+
+		try (OutputStream os = connection.getOutputStream()) {
+			os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
+		}
+
+		// 2. 응답 수신 처리
+		int responseCode = connection.getResponseCode();
+		InputStream responseStream = (responseCode == 200) ? connection.getInputStream() : connection.getErrorStream();
+
+		StringBuilder resBuilder = new StringBuilder();
+		try (BufferedReader reader = new BufferedReader(new InputStreamReader(responseStream, StandardCharsets.UTF_8))) {
+			String line;
+			while ((line = reader.readLine()) != null) {
+				resBuilder.append(line);
+			}
+		}
+
+		if (responseCode != 200) {
+			throw new Exception("토스 결제 승인 실패: " + resBuilder.toString());
+		}
+
+		// 3. 응답 데이터 파싱 및 mj_pg 테이블 매핑
+		JSONObject resObj = new JSONObject(resBuilder.toString());
+		String method = resObj.getString("method"); // 결제수단 (카드, 가상계좌 등)
+
+		// 회원 정보 상세 조회 (연락처 등 매핑용)
+		MberManageVO mberManageVO = mberManageDAO.selectMber(loginVO.getId());
+
+		// 기존 쿼리의 parameterClass인 VO 객체 생성 및 값 세팅
+		MjonPayVO payVO = new MjonPayVO();
+
+		// [공통 정보 세팅]
+		payVO.setMoid(orderId);                             // #moid# (idgen으로 생성된 PK)
+		payVO.setPgCode("TOSS");                            // #pgCode#
+		payVO.setTid(resObj.getString("paymentKey"));       // #tid#
+		payVO.setAmt(String.valueOf(resObj.getLong("totalAmount"))); // #amt#
+		payVO.setGoodsName(resObj.getString("orderName"));  // #goodsName#
+		payVO.setMid(resObj.optString("mId"));              // #mid# (상점ID 추가)
+
+		// 고객 정보 매핑 (연락처/이메일 누락 방지)
+		payVO.setUserId(loginVO.getId());                   // #userId#
+		payVO.setEmail(mberManageVO.getMberEmailAdres());   // #email#
+		payVO.setPhone(mberManageVO.getMoblphonNo());       // #phone#
+		payVO.setMobile(mberManageVO.getMoblphonNo());      // #mobile#
+		payVO.setBuyerName(loginVO.getName());              // #buyerName#
+
+		payVO.setResultCode("0000");                        // #resultCode#
+		payVO.setResultMsg("정상처리 되었습니다.");               // #resultMsg#
+		payVO.setAfterPayYn("N");                           // #afterPayYn# (선불 고정)
+
+		// CASH(공급가액) 계산: 부가세 제외 금액
+		long totalAmt = resObj.getLong("totalAmount");
+		long cashAmount = resObj.optLong("suppliedAmount", Math.round(totalAmt / 1.1));
+		payVO.setCash(Double.parseDouble(String.valueOf(cashAmount))); // #cash#
+
+		// 4. 결제 수단별 상세 분기 처리
+		if ("가상계좌".equals(method)) {
+			JSONObject vAccount = resObj.getJSONObject("virtualAccount");
+			String bankCode = vAccount.getString("bankCode");
+
+			payVO.setPayMethod("VBANK");          // #payMethod#
+			payVO.setPgStatus("0");               // #pgStatus# (0: 입금 대기)
+			payVO.setVbankNum(vAccount.getString("accountNumber")); // #vbankNum#
+			payVO.setVbankCode(vAccount.getString("bankCode"));     // #vbankCode#
+
+			// --- 은행 코드 -> 한글명 변환 ---
+			String bankName = "";
+			switch (bankCode) {
+				case "20": bankName = "우리은행"; break;
+				case "88": bankName = "신한은행"; break;
+				case "11": bankName = "농협"; break;
+				case "04": bankName = "국민은행"; break;
+				case "03": bankName = "기업은행"; break;
+				case "81": bankName = "하나은행"; break;
+				case "07": bankName = "수협"; break;
+				case "31": bankName = "대구은행"; break;
+				case "32": bankName = "부산은행"; break;
+				case "34": bankName = "광주은행"; break;
+				case "37": bankName = "전북은행"; break;
+				case "39": bankName = "경남은행"; break;
+				case "71": bankName = "우체국"; break;
+				case "23": bankName = "SC제일"; break;
+				case "45": bankName = "새마을금고"; break;
+				case "48": bankName = "신협"; break;
+				case "02": bankName = "산업은행"; break;
+				case "90": bankName = "카카오뱅크"; break;
+				case "92": bankName = "토스뱅크"; break;
+				case "89": bankName = "케이뱅크"; break;
+				default: bankName = "기타은행(" + bankCode + ")"; break;
+			}
+			payVO.setVbankName(bankName);
+
+			// 입금 기한 가공 (YYYYMMDD 형식)
+			String dueDate = vAccount.getString("dueDate").substring(0, 10).replace("-", "");
+			payVO.setVbankExpDate(dueDate);      // #vbankExpDate#
+
+		} else if ("카드".equals(method)) {
+			JSONObject card = resObj.getJSONObject("card");
+			payVO.setPayMethod("CARD");           // #payMethod#
+			payVO.setPgStatus("1");               // #pgStatus# (1: 결제 완료)String issuerCode = card.getString("issuerCode");
+			String issuerCode = card.getString("issuerCode");
+			payVO.setCardCode(issuerCode);        // #cardCode#
+
+
+			// --- 카드사 코드 -> 한글명 변환 시작 ---
+			String cardName = "";
+			switch (issuerCode) {
+				case "36": cardName = "씨티"; break;
+				case "31": cardName = "삼성"; break;
+				case "61": cardName = "현대"; break;
+				case "11": cardName = "농협"; break;
+				case "91": cardName = "카카오뱅크"; break;
+				case "26": cardName = "비씨"; break;
+				case "21": cardName = "하나"; break;
+				case "41": cardName = "신한"; break;
+				case "51": cardName = "롯데"; break;
+				case "15": cardName = "우리"; break;
+				case "01": cardName = "외환"; break;
+				case "12": cardName = "수협"; break;
+				case "46": cardName = "광주"; break;
+				case "33": cardName = "전북"; break;
+				case "62": cardName = "제주"; break;
+				case "35": cardName = "KDB산업"; break;
+				default: cardName = "기타카드(" + issuerCode + ")"; break;
+			}
+			payVO.setCardName(cardName); // #cardName#에 한글명 세팅
+
+		} else if ("간편결제".equals(method)) {
+			JSONObject easyPay = resObj.getJSONObject("easyPay");
+			String provider = easyPay.getString("provider");
+
+			payVO.setPayMethod("SPAY");           // #payMethod#
+			payVO.setPgStatus("1");
+			payVO.setSpayMethod("M");             // #spayMethod#
+			payVO.setCardName(provider);          // #cardName#
+
+			// 기존 SPAY_DIV 코드 매핑 + 토스페이(TOS) 추가
+			if ("카카오페이".equals(provider)) {
+				payVO.setSpayDiv("KKO");
+			} else if ("네이버페이".equals(provider)) {
+				payVO.setSpayDiv("NAV");
+			} else if ("토스페이".equals(provider)) {
+				payVO.setSpayDiv("TOS"); // 요청하신 토스페이 코드 추가
+			}
+		}
+
+		// 5. DB INSERT 실행
+		mjonPayDAO.insertMjPg(payVO);
+
+		// 컨트롤러 응답용 결과 Map 구성
+		Map<String, Object> result = new HashMap<>();
+		result.put("PG_STATUS", payVO.getPgStatus());
+		result.put("MOID", payVO.getMoid());
+		result.put("VBANK_NUM", payVO.getVbankNum());
+		result.put("VBANK_NAME", payVO.getVbankName());
+		result.put("VBANK_EXP_DATE", payVO.getVbankExpDate());
+		result.put("AMT", payVO.getAmt());
+
+		return result;
+	}
+
+	/**
+	 * 입금 대기 중인 가상계좌 조회 (PayView용)
+	 */
+/*	@Override
+	public Map<String, Object> selectWaitingVBank(String userId) throws Exception {
+		return mjonPayDAO.selectWaitingVBank(userId);
+	}*/
+}
 
src/main/java/itn/let/mjo/pay/web/MjonPayTossController.java (added)
+++ src/main/java/itn/let/mjo/pay/web/MjonPayTossController.java
@@ -0,0 +1,130 @@
+package itn.let.mjo.pay.web;
+
+import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
+import itn.com.cmm.LoginVO;
+import itn.let.mjo.mjocommon.MjonCommon;
+import itn.let.mjo.msgcampain.service.MjonCandidateService;
+import itn.let.mjo.pay.service.MjonPayService;
+import itn.let.mjo.pay.service.MjonPayTossService;
+import itn.let.mjo.payva.service.VacsVactService;
+import itn.let.sym.grd.service.MberGrdService;
+import itn.let.sym.site.service.EgovSiteManagerService;
+import itn.let.uss.umt.service.EgovMberManageService;
+import itn.let.uss.umt.service.EgovUserManageService;
+import itn.let.utl.user.service.MjonNoticeSendUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+@Controller
+public class MjonPayTossController {
+	private static final Logger LOGGER = LoggerFactory.getLogger(MjonPayController.class);
+	
+	@Resource(name = "mjonPayService")
+    private MjonPayService mjonPayService;
+	
+	@Resource(name = "mberManageService")
+	private EgovMberManageService mberManageService;
+	
+	@Resource(name = "mjonCandidateService")
+    private MjonCandidateService mjonCandidateService;
+	
+	//전용계좌 서비스
+	@Resource(name = "vacsVactService")
+	private VacsVactService vacsVactService;
+	
+    /** userManageService */
+	@Resource(name = "userManageService")
+	private EgovUserManageService userManageService;
+	
+	/** 사이트 설정 */ 
+	@Resource(name = "egovSiteManagerService")
+	EgovSiteManagerService egovSiteManagerService;	
+
+	/** 알림전송 Util */
+	@Resource(name = "mjonNoticeSendUtil")
+	private MjonNoticeSendUtil mjonNoticeSendUtil;    
+
+	@Resource(name="MjonCommon")
+	private MjonCommon mjonCommon;
+	
+	@Resource(name = "mberGrdService")
+	MberGrdService mberGrdService;
+	@Resource(name = "mjonPayTossService")
+    MjonPayTossService mjonPayTossService;
+	
+	/** KG 모빌리언스 설정 */
+	// CARD
+	@Value("#{globalSettings['Globals.pay.kgm.card.cnSvcid']}")
+	private String globalCnSvcid;
+	@Value("#{globalSettings['Globals.pay.kgm.card.payMode']}")
+	private String globalCnPayMode;
+
+	// BANK
+	@Value("#{globalSettings['Globals.pay.kgm.bank.raSvcid']}")
+	private String globalRaSvcid;
+	@Value("#{globalSettings['Globals.pay.kgm.bank.payMode']}")
+	private String globalRaPayMode;
+	
+	// MOBILE
+	@Value("#{globalSettings['Globals.pay.kgm.mobile.mcSvcid']}")
+	private String globalMcSvcid;
+	@Value("#{globalSettings['Globals.pay.kgm.mobile.payMode']}")
+	private String globalMcPayMode;	
+
+	@RequestMapping(value = "/web/member/pay/tossSuccess.do")
+	public String tossSuccess(HttpServletRequest request
+			, RedirectAttributes redirectAttributes) throws Exception {
+
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated() ? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser() : null;
+		if(loginVO == null) return "redirect:/web/user/login/login.do";
+
+		// 파라미터 수신
+		String paymentKey = request.getParameter("paymentKey");
+		String orderId = request.getParameter("orderId");
+		String amount = request.getParameter("amount");
+
+		try {
+			// 비즈니스 로직 호출
+			Map<String, Object> result = mjonPayTossService.processTossConfirm(paymentKey, orderId, amount, loginVO);
+
+			// 가상계좌일 경우 화면에 띄울 데이터 전달
+			if ("0".equals(result.get("PG_STATUS"))) {
+				redirectAttributes.addFlashAttribute("vbankInfo", result);
+				redirectAttributes.addFlashAttribute("isVbankIssued", "Y");
+				return "redirect:/web/member/pay/PayView.do"; // 결제뷰로 이동
+			}
+
+			return "redirect:/web/member/pay/PayList.do"; // 일반 결제는 리스트로 이동
+
+		} catch (Exception e) {
+			redirectAttributes.addFlashAttribute("message", e.getMessage());
+			return "redirect:/web/member/pay/tossFail.do";
+		}
+	}
+
+
+	@RequestMapping(value = "/web/member/pay/tossFail.do")
+	public String tossFail(HttpServletRequest request, RedirectAttributes redirectAttributes) throws Exception {
+
+		String code = request.getParameter("code");
+		String message = request.getParameter("message");
+
+		// 로그 기록
+		LOGGER.error("결제 실패 원인: [{}] {}", code, message);
+
+		// 다시 결제 화면으로 보낼 때 실패 메시지를 전달
+		// FlashAttribute는 리다이렉트 후 한 번만 유지되는 데이터입니다.
+		redirectAttributes.addFlashAttribute("payErrorMsg", message);
+		redirectAttributes.addFlashAttribute("payErrorCode", code);
+
+		return "redirect:/web/member/pay/PayView.do";
+	}
+}
src/main/java/itn/let/mjo/pay/web/MjonPayV2Controller.java
--- src/main/java/itn/let/mjo/pay/web/MjonPayV2Controller.java
+++ src/main/java/itn/let/mjo/pay/web/MjonPayV2Controller.java
@@ -1,22 +1,26 @@
 package itn.let.mjo.pay.web;
 
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-import java.util.Random;
+import java.util.*;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
 import org.springframework.ui.ModelMap;
 import org.springframework.web.bind.annotation.ModelAttribute;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -1877,5 +1881,6 @@
 		
 		return rtnVal;
    	}
-   	
+
+
 }
src/main/webapp/WEB-INF/jsp/web/pay/PayView.jsp
--- src/main/webapp/WEB-INF/jsp/web/pay/PayView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/pay/PayView.jsp
@@ -21,6 +21,16 @@
 	let paymentMethodWidget;
 
 	$(document).ready(function(){
+
+		// 서버에서 보낸 payErrorMsg가 있는지 확인
+		var errorMsg = "${payErrorMsg}";
+
+		if (errorMsg && errorMsg !== "") {
+			// 사용자에게 익숙한 alert 띄우기
+			alert("결제에 실패하였습니다.\n사유: " + errorMsg);
+		}
+
+
 		setPriceMake();
 		// 다음 결제시 결제수단 SELECT (필요 시 유지)
 		// getNextPayMethod();
@@ -92,15 +102,24 @@
 			alert("최소 충전금액 5천원 이상 선택해주세요.");
 			return false;
 		}
+		// const paymentMethodsWidget = paymentWidget.renderPaymentMethods();
+		// const selectedPaymentMethod = paymentMethodsWidget.getSelectedPaymentMethod();
+		// console.log('paymentMethodsWidget : ', paymentMethodsWidget);
+		// console.log('selectedPaymentMethod : ', selectedPaymentMethod);
 
 		// 토스페이먼츠 결제창 바로 호출
 		paymentWidget.requestPayment({
 			orderId: 'ORDER_' + new Date().getTime(), // 고유한 상점 주문번호 생성
 			orderName: '문자온 충전 ' + lastPrice + '원',
 			successUrl: window.location.origin + '/web/member/pay/tossSuccess.do', // 결제 성공 시 이동할 URL (백엔드 컨트롤러 생성 필요)
+			// paymentType=NORMAL
+			// &orderId=ORDER_1778047452906
+			// &paymentKey=tmunj2026050615041659Zv9
+			// &amount=55000
 			failUrl: window.location.origin + '/web/member/pay/tossFail.do',       // 결제 실패 시 이동할 URL (백엔드 컨트롤러 생성 필요)
-			customerEmail: 'hoyoung.lee@gmail.com', // 필요시 로그인한 사용자의 이메일 매핑
-			customerName: '이호영'                  // 필요시 로그인한 사용자의 이름 매핑
+			customerEmail: $('#mberEmailAdres').val(), // 필요시 로그인한 사용자의 이메일 매핑
+			customerName: $('#mberNm').val(),   // 필요시 로그인한 사용자의 이름 매핑
+			customerMobilePhone: $('#moblphonNo').val()
 		}).catch(function (error) {
 			if (error.code === 'USER_CANCEL') {
 				alert('결제를 취소하셨습니다.');
@@ -159,6 +178,9 @@
 	<input type="hidden" id="payMethod" name="payMethod" />
 	<input type="hidden" id="accMsg" name="accMsg" />
 	<input type="hidden" id="sendCnt" name="sendCnt" value="<c:out value='${resultMsgInfo.sendCnt}'/>" />
+	<input type="hidden" id="mberEmailAdres" value="<c:out value='${mberManageVO.mberEmailAdres}'/>" />
+	<input type="hidden" id="moblphonNo" value="<c:out value='${mberManageVO.moblphonNo}'/>" />
+	<input type="hidden" id="mberNm" value="<c:out value='${mberManageVO.mberNm}'/>" />
      <!-- content 영역 -->
         <div class="inner">
             <!-- send top -->
Add a comment
List