Kaynağa Gözat

Merge branch 'style' into 계좌환불등록문ì자

yujung 4 yıl önce
ebeveyn
işleme
af04a596cb

+ 21 - 3
src/main/java/com/style24/core/biz/dao/TscNaverPayDao.java

@@ -1,12 +1,11 @@
 package com.style24.core.biz.dao;
 
+import java.util.Collection;
+
 import com.style24.core.support.annotation.ShopDs;
-import com.style24.persistence.domain.GiftCard;
 import com.style24.persistence.domain.Order;
 import com.style24.persistence.domain.Payment;
 
-import java.util.Collection;
-
 /**
  * 네이버페이 Dao
  *
@@ -155,4 +154,23 @@ public interface TscNaverPayDao {
 	 * @since  2021. 07. 21
 	 */
 	Order getOrderDetailInfoFromOrdDtlNo(Order param);
+
+	/**
+	 * 네이버페이 주문형 반품/교환 보류 여부 수정
+	 * 
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 10. 05
+	 */
+	int updateNaverPayChangeHold(Order order);
+
+	/**
+	 * 네이버페이 주문형 발송지연 대상 조회
+	 * 
+	 * @return Collection<Order>
+	 * @author card007
+	 * @since 2021. 10. 12
+	 */
+	Collection<Order> getNaverPayDelayTargetList();
 }

+ 642 - 100
src/main/java/com/style24/core/biz/service/TscNaverPayService.java

@@ -26,13 +26,16 @@ import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
 
 import com.gagaframework.web.parameter.GagaMap;
+import com.google.gson.Gson;
 import com.nhncorp.psinfra.toolkit.SimpleCryptLib;
 import com.style24.core.biz.checkout.MallServiceLocator;
 import com.style24.core.biz.checkout.MallServiceSOAP11BindingStub;
 import com.style24.core.biz.checkout.base.AccessCredentialsType;
 import com.style24.core.biz.checkout.base.ChangedProductOrderInfo;
 import com.style24.core.biz.checkout.base.ClaimRequestReasonType;
+import com.style24.core.biz.checkout.base.DelayedDispatchReasonType;
 import com.style24.core.biz.checkout.base.DeliveryMethodType;
+import com.style24.core.biz.checkout.base.HoldbackClassType;
 import com.style24.core.biz.checkout.base.HoldbackStatusType;
 import com.style24.core.biz.checkout.base.ProductOrderChangeType;
 import com.style24.core.biz.checkout.base.ProductOrderInfo;
@@ -45,6 +48,8 @@ import com.style24.core.biz.checkout.mall.ApproveReturnApplicationRequest;
 import com.style24.core.biz.checkout.mall.ApproveReturnApplicationResponse;
 import com.style24.core.biz.checkout.mall.CancelSaleRequest;
 import com.style24.core.biz.checkout.mall.CancelSaleResponse;
+import com.style24.core.biz.checkout.mall.DelayProductOrderRequest;
+import com.style24.core.biz.checkout.mall.DelayProductOrderResponse;
 import com.style24.core.biz.checkout.mall.GetChangedProductOrderListRequest;
 import com.style24.core.biz.checkout.mall.GetChangedProductOrderListResponse;
 import com.style24.core.biz.checkout.mall.GetProductOrderInfoListRequest;
@@ -57,12 +62,18 @@ import com.style24.core.biz.checkout.mall.RejectExchangeRequest;
 import com.style24.core.biz.checkout.mall.RejectExchangeResponse;
 import com.style24.core.biz.checkout.mall.RejectReturnRequest;
 import com.style24.core.biz.checkout.mall.RejectReturnResponse;
+import com.style24.core.biz.checkout.mall.ReleaseExchangeHoldRequest;
+import com.style24.core.biz.checkout.mall.ReleaseExchangeHoldResponse;
 import com.style24.core.biz.checkout.mall.ReleaseReturnHoldRequest;
 import com.style24.core.biz.checkout.mall.ReleaseReturnHoldResponse;
 import com.style24.core.biz.checkout.mall.RequestReturnRequest;
 import com.style24.core.biz.checkout.mall.RequestReturnResponse;
 import com.style24.core.biz.checkout.mall.ShipProductOrderRequest;
 import com.style24.core.biz.checkout.mall.ShipProductOrderResponse;
+import com.style24.core.biz.checkout.mall.WithholdExchangeRequest;
+import com.style24.core.biz.checkout.mall.WithholdExchangeResponse;
+import com.style24.core.biz.checkout.mall.WithholdReturnRequest;
+import com.style24.core.biz.checkout.mall.WithholdReturnResponse;
 import com.style24.core.biz.dao.TscNaverPayDao;
 import com.style24.core.biz.dao.TscOrderChangeDao;
 import com.style24.core.biz.dao.TscOrderDao;
@@ -429,13 +440,13 @@ public class TscNaverPayService {
 
 		// 로컬의 경우 별도 기간을 설정해서 사용
 		if("locd".equals(env.getProperty("spring.profiles.active"))) {
-			stdt				= "20210727000000";			// 조회기간 시작
-			eddt				= "20210727235959";			// 조회기간 끝
+			stdt				= "20211014000000";			// 조회기간 시작
+			eddt				= "20211014235959";			// 조회기간 끝
 
 			log.info("stdt : eddt ---> " + stdt + " : " + eddt);
 		}
 
-		// 조회기간 Date 타입 설정
+		// 조회기간 Date 타입 설정getReviewGoodsOptionList
 		Date tmp1				= new SimpleDateFormat("yyyyMMddHHmmss").parse(stdt, new ParsePosition(0));
 		Date tmp2				= new SimpleDateFormat("yyyyMMddHHmmss").parse(eddt, new ParsePosition(0));
 
@@ -844,8 +855,9 @@ public class TscNaverPayService {
 	}
 
 	@Transactional("shopTxnManager")
-	public String sendNaverPayDeliveryStartOrder(Order param, String statGb, Integer userNo) {
+	public GagaMap sendNaverPayDeliveryStartOrder(Order param, String statGb, Integer userNo) {
 		//for(Order param : params) {
+		GagaMap result = new GagaMap();
 			if ("SHIPPING".equals(statGb)) {
 				Order order = naverPayDao.getOrderDetailInfoFromOrdDtlNo(param);
 
@@ -931,21 +943,30 @@ public class TscNaverPayService {
 
 								orderDao.createNaverPayErrorLog(fail);
 
-								return "FAIL";
+								result.setString("status", "FAIL");
+								result.setString("message", shipProductOrderResponse.getError().getMessage());
+								return result;
 							} catch(Exception e) {
 								e.printStackTrace();
-								return "FAIL";
+
+								result.setString("status", "FAIL");
+								result.setString("message", e.getMessage());
+								return result;
 							}
 						}
 					} catch (Exception e) {
 						e.printStackTrace();
-						return "FAIL";
+
+						result.setString("status", "FAIL");
+						result.setString("message", e.getMessage());
+						return result;
 					}
 				}
 			}
 		//}
 
-		return "SUCCESS";
+		result.setString("status", "SUCCESS");
+		return result;
 	}
 
 	/**
@@ -1245,6 +1266,9 @@ public class TscNaverPayService {
 				}
 			}
 
+			// 핸드폰번호 하이픈 처리
+			change.setHypenRecipPhone();
+
 			// 배송지 정보 (네이버페이 주문형 배송지는 회수지와 동일 적용 (배송지 주소 작성란 없음))
 			change.setChgerNm(change.getRecipNm());
 			change.setChgerPhnno(change.getRecipPhnno());
@@ -1281,7 +1305,7 @@ public class TscNaverPayService {
 				cancelReq.setDelvFeeCd(item.getDelvFeeCd());											// 출고처코드
 				cancelReq.setSupplyCompCd(item.getSupplyCompCd());										// 공급업체코드
 				cancelReq.setChgQty(item.getOrdQty());													// 교환수량 (네이버페이주문형은 수량부분 취/반/교 없음. 전체수량.)
-				cancelReq.setOrdChgOpt(item.getOptCd2());												// 교환옵션 (네이버페이주문형은 교환 옵션이 존재하지 않음. 메모를 보고 수정해야함)
+				cancelReq.setOrdChgOpt(item.getOptCd());												// 교환옵션 (네이버페이주문형은 교환 옵션이 존재하지 않음. 메모를 보고 수정해야함)
 				cancelReq.setExcDelvFee(addDelvFee / 2);												// 교환 배송비 (교환배송비는 반품배송비 * 2로 송부되므로 교환/반품 배송비 절반씩 배분)
 				cancelReq.setRtnDelvFee(addDelvFee / 2);												// 반품배송비  (교환배송비는 반품배송비 * 2로 송부되므로 교환/반품 배송비 절반씩 배분)
 
@@ -1307,6 +1331,19 @@ public class TscNaverPayService {
 			change.setWdTargetYn("N");
 			log.info("CHECK CHG_MEMO :::: {}", change.getChgMemo());
 
+			// 보류 상태
+			String holdbackStatus = "";
+			if (orderInfo.getExchangeInfo().getHoldbackStatus() != null) {
+				holdbackStatus = orderInfo.getExchangeInfo().getHoldbackStatus().getValue();
+			}
+
+			log.info("holdbackStatus >>> {}", holdbackStatus);
+			if ("HOLDBACK".equals(holdbackStatus)) {
+				change.setNpayChangeHoldYn("Y");
+			} else {
+				change.setNpayChangeHoldYn("N");
+			}
+
 			GagaMap result = orderChangeService.exchReq(change);
 
 			// 추가배송비 결제 이력 있으면 TB_PAYMENT 넣고 deliveryFee에 PAY_SQ UPDATE
@@ -1336,6 +1373,15 @@ public class TscNaverPayService {
 				}
 			}
 
+			// 교환 보류 처리
+			if (!"HOLDBACK".equals(holdbackStatus)) {
+				order.setHoldCode(TscConstants.nPayExchangeHoldCode.ETC.value());
+				order.setHoldReason("교환 옵션 변경 대기중");
+				order.setRegNo(userNo);
+				order.setUpdNo(userNo);
+				this.nPayExchangeHold(order);
+			}
+
 			log.info("NAPAY_ORD_NO 교환 접수 성공 :::: {}", order.getNpayOrdDtlNo());
 		}
 
@@ -1418,6 +1464,7 @@ public class TscNaverPayService {
 					}
 				}
 
+				change.setHypenChgerPhone();
 				change.setOrdNo(order.getOrdNo());
 				change.setCustNo(custNo);
 				change.setOrdNm(ordNm);
@@ -1494,6 +1541,19 @@ public class TscNaverPayService {
 					change.setChgReason(TscConstants.OrderReturnReason.NOT_DELV_ALL.value());
 				}
 
+				// 보류 상태
+				String holdbackStatus = "";
+				if (orderInfo.getReturnInfo().getHoldbackStatus() != null) {
+					holdbackStatus = orderInfo.getReturnInfo().getHoldbackStatus().getValue();
+				}
+
+				log.info("holdbackStatus >>> {}", holdbackStatus);
+				if ("HOLDBACK".equals(holdbackStatus)) {
+					change.setNpayChangeHoldYn("Y");
+				} else {
+					change.setNpayChangeHoldYn("N");
+				}
+
 				GagaMap map = returnReq(change);
 			}
 		} catch(Exception e) {
@@ -1523,34 +1583,35 @@ public class TscNaverPayService {
 		GagaMap result = orderRefundService.cnclRtnRefundAmt(returnReqList);
 
 		// 4. 주문변경 기본정보 설정
-		result.set("ordNo", orderChange.getOrdNo());					// 주문번호
-		result.setInt("custNo", orderChange.getCustNo());				// 고객번호
-		result.set("regNo", orderChange.getRegNo());
-		result.set("updNo", orderChange.getUpdNo());
-		result.set("pgGb", orderChange.getPgGb());
-		// result.set("ordChgSq", orderChange.getOrdChgSq());			// 주문변경번호
-		result.set("chgReason", orderChange.getChgReason());			// 변경사유
-		result.set("chgMemo", orderChange.getChgMemo());				// 변경메모
-
-		result.set("accountNo", orderChange.getAccountNo());			// 환불계좌번호
-		result.set("accountNm", orderChange.getAccountNm());			// 환불계좌예금주명
-		result.set("bankCd", orderChange.getBankCd());					// 환불계좌은행코드
-
-		result.setString("allLastCanYn", allLastCanYn);					// 전체 마지막 취소 여부
-		result.set("isCustomer", orderChange.getIsCustomer());			// 변경사유 (고객, 회사)
-		result.set("wdTargetYn", orderChange.getWdTargetYn());			// 회수지시 요청 여부
-		result.set("wdGb", orderChange.getWdGb());						// 회수방법
-		result.set("wdInvoiceNo", orderChange.getWdInvoiceNo());		// 회수송장번호
+		result.set("ordNo"				, orderChange.getOrdNo());					// 주문번호
+		result.set("custNo"				, orderChange.getCustNo());					// 고객번호
+		result.set("regNo"				, orderChange.getRegNo());
+		result.set("updNo"				, orderChange.getUpdNo());
+		result.set("pgGb"				, orderChange.getPgGb());
+		// result.set("ordChgSq"			, orderChange.getOrdChgSq());			// 주문변경번호
+		result.set("chgReason"			, orderChange.getChgReason());			// 변경사유
+		result.set("chgMemo"			, orderChange.getChgMemo());			// 변경메모
+
+		result.set("accountNo"			, orderChange.getAccountNo());			// 환불계좌번호
+		result.set("accountNm"			, orderChange.getAccountNm());			// 환불계좌예금주명
+		result.set("bankCd"				, orderChange.getBankCd());				// 환불계좌은행코드
+
+		result.set("allLastCanYn"		, allLastCanYn);						// 전체 마지막 취소 여부
+		result.set("isCustomer"			, orderChange.getIsCustomer());			// 변경사유 (고객, 회사)
+		result.set("wdTargetYn"			, orderChange.getWdTargetYn());			// 회수지시 요청 여부
+		result.set("wdGb"				, orderChange.getWdGb());				// 회수방법
+		result.set("wdInvoiceNo"		, orderChange.getWdInvoiceNo());		// 회수송장번호
+		result.set("npayChangeHoldYn"	, orderChange.getNpayChangeHoldYn());	// 네이버페이 주문형 반품/교환 보류 여부 설정
 
 		// 5. 주문변경 회수지정보 추가
-		result.set("chgerNm", orderChange.getChgerNm());				// 변경자명
-		result.set("chgerEmail", orderChange.getChgerEmail());			// 변경자이메일주소
-		result.set("chgerZipcode", orderChange.getChgerZipcode());		// 회수지우편번호
-		result.set("chgerBaseAddr", orderChange.getChgerBaseAddr());	// 회수지기본주소
-		result.set("chgerDtlAddr", orderChange.getChgerDtlAddr());		// 회수지상세주소
-		result.set("chgerPhnno", orderChange.getChgerPhnno());			// 변경자핸드폰번호
-		result.set("chgerTelno", orderChange.getChgerTelno());			// 변경자전화번호
-		result.set("chgerRtnMemo", orderChange.getChgerRtnMemo());		// 반품메모
+		result.set("chgerNm"			, orderChange.getChgerNm());			// 변경자명
+		result.set("chgerEmail"			, orderChange.getChgerEmail());			// 변경자이메일주소
+		result.set("chgerZipcode"		, orderChange.getChgerZipcode());		// 회수지우편번호
+		result.set("chgerBaseAddr"		, orderChange.getChgerBaseAddr());		// 회수지기본주소
+		result.set("chgerDtlAddr"		, orderChange.getChgerDtlAddr());		// 회수지상세주소
+		result.set("chgerPhnno"			, orderChange.getChgerPhnno());			// 변경자핸드폰번호
+		result.set("chgerTelno"			, orderChange.getChgerTelno());			// 변경자전화번호
+		result.set("chgerRtnMemo"		, orderChange.getChgerRtnMemo());		// 반품메모
 
 		// 6. 주문변경 DB 등록 (TB_ORDER_CHANGE, TB_ORDER_CHANGE_DETAIL, TB_REFUND)
 		GagaMap map = orderChangeService.returnRequest(result);
@@ -1566,7 +1627,8 @@ public class TscNaverPayService {
 	 * @since  2021. 06. 28
 	 */
 	@Transactional("shopTxnManager")
-	public String sendNaverPayExchangeReDelivery(Order param, int userNo) throws Exception {
+	public GagaMap sendNaverPayExchangeReDelivery(Order param, int userNo) throws Exception {
+		GagaMap result = new GagaMap();
 		Order order = naverPayDao.getOrderDetailInfoFromOrdDtlNo(param);
 
 		Security.addProvider(new BouncyCastleProvider());
@@ -1644,15 +1706,21 @@ public class TscNaverPayService {
 
 					orderDao.createNaverPayErrorLog(fail);
 
-					return "FAIL";
+					result.setString("status", "FAIL");
+					result.setString("message", reDeliveryExchangeResponse.getError().getMessage());
+					return result;
 				} catch(Exception e) {
 					e.printStackTrace();
-					return "FAIL";
+					
+					result.setString("status", "FAIL");
+					result.setString("message", e.getMessage());
+					return result;
 				}
 			}
 		}
 
-		return "SUCCESS";
+		result.setString("status", "SUCCESS");
+		return result;
 	}
 
 	/**
@@ -2015,65 +2083,16 @@ public class TscNaverPayService {
 					}
 				}
 
-				if ((returnPayType != null && !returnPayType.equals("")) && (returnHoldStatus.toString() != null && !returnHoldStatus.equals(""))) {
+				// if ((returnPayType != null && !returnPayType.equals("")) && (returnHoldStatus.toString() != null && !returnHoldStatus.equals(""))) {
 					// 보류중이고 환불금 차감 형식이 아니면 보류해제 처리
-					if ("HOLDBACK".equals(returnHoldStatus.toString()) && !passRfdDelPayType.equals(returnPayType)) {
-						//서명생성
-						generateSignature("ReleaseReturnHold", env.getProperty("naverPay.secret.key"));
-						log.info("ReleaseReturnHold(반품 보류해제 네이버로 송신) :: timeStamp === " + timeStamp);
-
-						//인증정보
-						accessCredentialsType.setAccessLicense(env.getProperty("naverPay.access.license"));
-						accessCredentialsType.setSignature(signature);
-						accessCredentialsType.setTimestamp(timeStamp);
-
-						releaseReturnHoldRequest = new ReleaseReturnHoldRequest();
-						releaseReturnHoldRequest.setAccessCredentials(accessCredentialsType);
-						releaseReturnHoldRequest.setRequestID("");
-						releaseReturnHoldRequest.setDetailLevel("Full");
-						releaseReturnHoldRequest.setVersion(env.getProperty("naverPay.version"));
-						releaseReturnHoldRequest.setProductOrderID(change.getNpayOrdDtlNo());
-
-						releaseReturnHoldResponse = stub.releaseReturnHold(releaseReturnHoldRequest);
-
-						if (releaseReturnHoldResponse.getResponseType() != null) {
-							resultStr = releaseReturnHoldResponse.getResponseType().toUpperCase();
-						}
-
-						if ("SUCCESS".equals(resultStr)) {
-							log.info("보류해제 성공 네이버상품주문번호 ===> " + change.getNpayOrdDtlNo());
-							log.info("보류해제 성공 반품배송비결제방법 ===> " + returnPayType);
-						} else {
-							log.info("보류해제 에러");
-							log.info("네이버상품주문번호 ===> " + change.getNpayOrdDtlNo());
-							log.info("반품배송비 결제방법 >>>> " + returnPayType);
-							log.info("Code : " + releaseReturnHoldResponse.getError().getCode());
-							log.info("Message : " + releaseReturnHoldResponse.getError().getMessage());
-							log.info("Detail : " + releaseReturnHoldResponse.getError().getDetail());
-
-							try {
-								Order fail = new Order();
-								fail.setErrorReason("반품 보류 해제 데이터 송부 에러");
-								fail.setOrdNo(change.getOrdNo());
-								fail.setNpayOrdDtlNo(change.getNpayOrdDtlNo());
-								fail.setOptCd("sendNaverPayReturnComplete");
-								fail.setResultCd(releaseReturnHoldResponse.getError().getCode());
-								fail.setResultMsg(releaseReturnHoldResponse.getError().getMessage());
-								fail.setMallCd(env.getProperty("naverPay.shop.id"));
-								fail.setAccessLicense(env.getProperty("naverPay.access.license"));
-								fail.setSecretKey(env.getProperty("naverPay.secret.key"));
-								fail.setRegNo(userNo);
-
-								orderDao.createNaverPayErrorLog(fail);
-
-								return "FAIL";
-							} catch (Exception e) {
-								e.printStackTrace();
-								return "FAIL";
-							}
-						}
-					}
+					// if ("HOLDBACK".equals(returnHoldStatus.toString()) && !passRfdDelPayType.equals(returnPayType)) {
+				
+				// 2021.10.08 card007 보류중이면 보류해제 처리로 변경
+				if (returnHoldStatus.toString() != null && "HOLDBACK".equals(returnHoldStatus.toString())) {
+					param.setRegNo(userNo);
+					this.nPayReleaseReturnHold(param);
 				}
+				// }
 			}
 			//}
 
@@ -2255,6 +2274,7 @@ public class TscNaverPayService {
 				param.setMallCd(env.getProperty("naverPay.shop.id"));
 
 				generateSignature("PlaceProductOrder", param.getSecretKey());
+				log.info("PlaceProductOrder(배송준비중 주문 정보 조회) :: timeStamp === " + timeStamp);
 
 				byte[] encryptKey = SimpleCryptLib.generateKey(timeStamp, param.getSecretKey());
 
@@ -2473,7 +2493,7 @@ public class TscNaverPayService {
 		try {
 			// TSIT 서버에서만 SSL 미적용.
 			String protocol = "";
-			if ("tsit".equals(env.getProperty("spring.profiles.active"))) {
+			if ("tsit".equals(env.getProperty("spring.profiles.active")) || "locd".equals(env.getProperty("spring.profiles.active"))) {
 				protocol = "http:";
 			} else {
 				protocol = "https:";
@@ -2481,7 +2501,6 @@ public class TscNaverPayService {
 			log.info("SEND SCM URL ::::: {}", protocol + env.getProperty("domain.scm") + urlQueryString);
 			URL url = new URL(protocol + env.getProperty("domain.scm") + urlQueryString);
 			HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();
-
 			urlCon.setUseCaches(false);
 			urlCon.setDoOutput(true);
 			urlCon.setRequestMethod("GET");
@@ -2500,7 +2519,20 @@ public class TscNaverPayService {
 				log.info("NAVERPAY RESULT MESSAGE ::::: " + out.toString("UTF-8"));
 
 				if (!"SUCCESS".equals(out.toString("UTF-8"))) {
-					throw new IllegalStateException("네이버페이 송부 실패");
+					Gson gson = new Gson();
+					GagaMap rtn = new GagaMap();
+
+					try {
+						rtn = gson.fromJson(out.toString("UTF-8"), GagaMap.class);
+					} catch (Exception e) {
+						return "네이버페이 송부 실패";
+					}
+
+					log.info("status >>> {}", rtn.getString("status"));
+					log.info("message >>> {}", rtn.getString("message"));
+					if (!"SUCCESS".equals(rtn.getString("status"))) {
+						return rtn.getString("message");
+					}
 				}
 			} catch (Exception e) {
 				e.printStackTrace();
@@ -2508,7 +2540,7 @@ public class TscNaverPayService {
 
 			urlCon.disconnect();
 		} catch (Exception e) {
-			return "FAIL";
+			return "네이버페이 송부 실패";
 		}
 
 		return "SUCCESS";
@@ -2517,4 +2549,514 @@ public class TscNaverPayService {
 	public Order getOrderDetailInfoFromOrdDtlNo(Order param) {
 		return naverPayDao.getOrderDetailInfoFromOrdDtlNo(param);
 	}
+
+	/**
+	 * 네이버페이 주문형 교환보류 요청
+	 * 
+	 * @param OrderChange
+	 * @return int
+	 * @author card007
+	 * @since 2021. 10. 05
+	 */
+	@Transactional("shopTxnManager")
+	public int nPayExchangeHold(Order order) {
+		Order info 				= naverPayDao.getOrderDetailInfoFromOrdDtlNo(order);
+		String holdCode			= order.getHoldCode();
+		String holdReason		= order.getHoldReason();
+		Integer regNo			= order.getRegNo();
+		String npayOrdDtlNo 	= info.getNpayOrdDtlNo();
+		String pgGb 			= info.getPgGb();
+		Integer ordNo 			= info.getOrdNo();
+
+		try {
+			Security.addProvider(new BouncyCastleProvider());
+			AccessCredentialsType accessCredentialsType = new AccessCredentialsType();
+			MallServiceLocator MSL = new MallServiceLocator(env.getProperty("naverPay.port.address"));
+			MallServiceSOAP11BindingStub stub = (MallServiceSOAP11BindingStub)MSL.getMallServiceSOAP11Port();
+
+			WithholdExchangeRequest withholdExchangeRequest = new WithholdExchangeRequest();
+			WithholdExchangeResponse withholdExchangeResponse = new WithholdExchangeResponse();
+
+			if (order != null && TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb)) {
+				// 서명생성
+				generateSignature("WithholdExchange", env.getProperty("naverPay.secret.key"));
+				log.info("WithholdExchange(교환보류 네이버로 송신) :: timeStamp === " + timeStamp);
+
+				//인증정보
+				accessCredentialsType.setAccessLicense(env.getProperty("naverPay.access.license"));
+				accessCredentialsType.setSignature(signature);
+				accessCredentialsType.setTimestamp(timeStamp);
+
+				withholdExchangeRequest.setAccessCredentials(accessCredentialsType);
+				withholdExchangeRequest.setDetailLevel("Full");
+				withholdExchangeRequest.setVersion(env.getProperty("naverPay.version"));
+				withholdExchangeRequest.setRequestID("");
+				withholdExchangeRequest.setProductOrderID(npayOrdDtlNo);											// 상품 주문 번호
+
+				// 교환 보류 타입 코드
+				if (TscConstants.nPayExchangeHoldCode.EXCHANGE_DELIVERYFEE.value().equals(holdCode)) {
+					withholdExchangeRequest.setExchangeHoldCode(HoldbackClassType.EXCHANGE_DELIVERYFEE);			// 교환 배송비 청구
+				} else if (TscConstants.nPayExchangeHoldCode.EXCHANGE_EXTRAFEE.value().equals(holdCode)) {
+					withholdExchangeRequest.setExchangeHoldCode(HoldbackClassType.EXCHANGE_EXTRAFEE);				// 기타 교환 비용 청구
+				} else if (TscConstants.nPayExchangeHoldCode.EXCHANGE_PRODUCT_READY.value().equals(holdCode)) {
+					withholdExchangeRequest.setExchangeHoldCode(HoldbackClassType.EXCHANGE_PRODUCT_READY);			// 교환 상품 준비 중
+				} else if (TscConstants.nPayExchangeHoldCode.EXCHANGE_PRODUCT_NOT_DELIVERED.value().equals(holdCode)) {
+					withholdExchangeRequest.setExchangeHoldCode(HoldbackClassType.EXCHANGE_PRODUCT_NOT_DELIVERED);	// 교환 상품 미입고
+				} else if (TscConstants.nPayExchangeHoldCode.EXCHANGE_HOLDBACK.value().equals(holdCode)) {
+					withholdExchangeRequest.setExchangeHoldCode(HoldbackClassType.EXCHANGE_HOLDBACK);				// 교환 구매 확정 보류
+				} else {
+					withholdExchangeRequest.setExchangeHoldCode(HoldbackClassType.ETC);								// 기타 사유
+				}
+
+				withholdExchangeRequest.setExchangeHoldDetailContent(holdReason);									// 교환 보류 상세 사유
+				// withholdExchangeRequest.setEtcFeeDemandAmount(0);													// 기타 교환 비용
+
+
+				withholdExchangeResponse = stub.withholdExchange(withholdExchangeRequest);
+
+				String resultStr = "";
+				if (withholdExchangeResponse.getResponseType() != null) {
+					resultStr = withholdExchangeResponse.getResponseType().toUpperCase();
+				}
+
+				if ("SUCCESS".equals(resultStr)) {
+					log.info("교환보류 성공 주문번호===>" + ordNo);
+					log.info("교환보류 성공 네이버상품주문번호===>" + npayOrdDtlNo);
+				} else {
+					log.info("교환보류 에러");
+					log.info("주문번호 ===>" + ordNo);
+					log.info("네이버상품주문번호 ===> " + npayOrdDtlNo);
+					log.info("Code : " + withholdExchangeResponse.getError().getCode());
+					log.info("Message : " + withholdExchangeResponse.getError().getMessage());
+					log.info("Detail : " + withholdExchangeResponse.getError().getDetail());
+
+					Order fail = new Order();
+					fail.setErrorReason("교환보류 데이터 송부 에러");
+					fail.setOrdNo(ordNo);
+					fail.setNpayOrdDtlNo(npayOrdDtlNo);
+					fail.setOptCd("WithholdExchange");
+					fail.setResultCd(withholdExchangeResponse.getError().getCode());
+					fail.setResultMsg(withholdExchangeResponse.getError().getMessage());
+					fail.setMallCd(env.getProperty("naverPay.shop.id"));
+					fail.setAccessLicense(env.getProperty("naverPay.access.license"));
+					fail.setSecretKey(env.getProperty("naverPay.secret.key"));
+					fail.setRegNo(regNo);
+
+					orderDao.createNaverPayErrorLog(fail);
+
+					return 0;
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			return 0;
+		}
+
+		return 1;
+	}
+
+	/**
+	 * 네이버페이 주문형 교환보류 해제 요청
+	 *
+	 * @param OrderChange
+	 * @return int
+	 * @author card007
+	 * @since 2021. 10. 05
+	 */
+	@Transactional("shopTxnManager")
+	public int nPayReleaseExchangeHold(Order order) {
+		Order info 				= naverPayDao.getOrderDetailInfoFromOrdDtlNo(order);
+		String npayOrdDtlNo 	= info.getNpayOrdDtlNo();
+		String pgGb 			= info.getPgGb();
+		Integer ordNo 			= info.getOrdNo();
+		Integer regNo			= order.getRegNo();
+
+		try {
+			Security.addProvider(new BouncyCastleProvider());
+			AccessCredentialsType accessCredentialsType = new AccessCredentialsType();
+			MallServiceLocator MSL = new MallServiceLocator(env.getProperty("naverPay.port.address"));
+			MallServiceSOAP11BindingStub stub = (MallServiceSOAP11BindingStub)MSL.getMallServiceSOAP11Port();
+
+			ReleaseExchangeHoldRequest releaseExchangeHoldRequest = new ReleaseExchangeHoldRequest();
+			ReleaseExchangeHoldResponse releaseExchangeHoldResponse = new ReleaseExchangeHoldResponse();
+
+			if (order != null && TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb)) {
+				// 서명생성
+				generateSignature("ReleaseExchangeHold", env.getProperty("naverPay.secret.key"));
+				log.info("ReleaseExchangeHold(교환보류 해제 네이버로 송신) :: timeStamp === " + timeStamp);
+
+				//인증정보
+				accessCredentialsType.setAccessLicense(env.getProperty("naverPay.access.license"));
+				accessCredentialsType.setSignature(signature);
+				accessCredentialsType.setTimestamp(timeStamp);
+
+				releaseExchangeHoldRequest.setAccessCredentials(accessCredentialsType);
+				releaseExchangeHoldRequest.setDetailLevel("Full");
+				releaseExchangeHoldRequest.setVersion(env.getProperty("naverPay.version"));
+				releaseExchangeHoldRequest.setRequestID("");
+				releaseExchangeHoldRequest.setProductOrderID(npayOrdDtlNo);					// 상품 주문 번호
+
+				releaseExchangeHoldResponse = stub.releaseExchangeHold(releaseExchangeHoldRequest);
+
+				String resultStr = "";
+				if (releaseExchangeHoldResponse.getResponseType() != null) {
+					resultStr = releaseExchangeHoldResponse.getResponseType().toUpperCase();
+				}
+
+				if ("SUCCESS".equals(resultStr)) {
+					log.info("교환보류 해제 성공 주문번호===>" + ordNo);
+					log.info("교환보류 해제 성공 네이버상품주문번호===>" + npayOrdDtlNo);
+				} else {
+					log.info("교환보류 해제 에러");
+					log.info("주문번호 ===>" + ordNo);
+					log.info("네이버상품주문번호 ===> " + npayOrdDtlNo);
+					log.info("Code : " + releaseExchangeHoldResponse.getError().getCode());
+					log.info("Message : " + releaseExchangeHoldResponse.getError().getMessage());
+					log.info("Detail : " + releaseExchangeHoldResponse.getError().getDetail());
+
+					Order fail = new Order();
+					fail.setErrorReason("교환보류 해제 데이터 송부 에러");
+					fail.setOrdNo(ordNo);
+					fail.setNpayOrdDtlNo(npayOrdDtlNo);
+					fail.setOptCd("ReleaseExchangeHold");
+					fail.setResultCd(releaseExchangeHoldResponse.getError().getCode());
+					fail.setResultMsg(releaseExchangeHoldResponse.getError().getMessage());
+					fail.setMallCd(env.getProperty("naverPay.shop.id"));
+					fail.setAccessLicense(env.getProperty("naverPay.access.license"));
+					fail.setSecretKey(env.getProperty("naverPay.secret.key"));
+					fail.setRegNo(regNo);
+
+					orderDao.createNaverPayErrorLog(fail);
+
+					return 0;
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			return 0;
+		}
+
+		return 1;
+	}
+
+	/**
+	 * 네이버페이 주문형 반품보류 요청
+	 *
+	 * @param OrderChange
+	 * @return int
+	 * @author card007
+	 * @since 2021. 10. 05
+	 */
+	@Transactional("shopTxnManager")
+	public int nPayReturnHold(Order order) {
+		Order info 				= naverPayDao.getOrderDetailInfoFromOrdDtlNo(order);
+		String npayOrdDtlNo 	= info.getNpayOrdDtlNo();
+		String pgGb 			= info.getPgGb();
+		String holdCode			= order.getHoldCode();
+		Integer ordNo 			= info.getOrdNo();
+		Integer regNo			= order.getRegNo();
+
+		try {
+			Security.addProvider(new BouncyCastleProvider());
+			AccessCredentialsType accessCredentialsType = new AccessCredentialsType();
+			MallServiceLocator MSL = new MallServiceLocator(env.getProperty("naverPay.port.address"));
+			MallServiceSOAP11BindingStub stub = (MallServiceSOAP11BindingStub)MSL.getMallServiceSOAP11Port();
+
+			WithholdReturnRequest withholdReturnRequest = new WithholdReturnRequest();
+			WithholdReturnResponse withholdReturnResponse = new WithholdReturnResponse();
+
+			if (order != null && TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb)) {
+				// 서명생성
+				generateSignature("WithholdReturn", env.getProperty("naverPay.secret.key"));
+				log.info("WithholdReturn(교환보류 네이버로 송신) :: timeStamp === " + timeStamp);
+
+				//인증정보
+				accessCredentialsType.setAccessLicense(env.getProperty("naverPay.access.license"));
+				accessCredentialsType.setSignature(signature);
+				accessCredentialsType.setTimestamp(timeStamp);
+
+				withholdReturnRequest.setAccessCredentials(accessCredentialsType);
+				withholdReturnRequest.setDetailLevel("Full");
+				withholdReturnRequest.setVersion(env.getProperty("naverPay.version"));
+				withholdReturnRequest.setRequestID("");
+				withholdReturnRequest.setProductOrderID(npayOrdDtlNo);												// 상품 주문 번호
+
+				// 교환 보류 타입 코드
+				if (TscConstants.nPayReturnHoldCode.RETURN_DELIVERYFEE.value().equals(holdCode)) {
+					withholdReturnRequest.setReturnHoldCode(HoldbackClassType.RETURN_DELIVERYFEE);					// 반품 배송비 청구
+				} else if (TscConstants.nPayReturnHoldCode.EXTRAFEEE.value().equals(holdCode)) {
+					withholdReturnRequest.setReturnHoldCode(HoldbackClassType.EXTRAFEEE);							// 기타 반품 비용 청구
+				} else if (TscConstants.nPayReturnHoldCode.RETURN_DELIVERYFEE_AND_EXTRAFEEE.value().equals(holdCode)) {
+					withholdReturnRequest.setReturnHoldCode(HoldbackClassType.RETURN_DELIVERYFEE_AND_EXTRAFEEE);	// 반품 배송비 및 기타 반품 비용 청구
+				} else if (TscConstants.nPayReturnHoldCode.RETURN_PRODUCT_NOT_DELIVERED.value().equals(holdCode)) {
+					withholdReturnRequest.setReturnHoldCode(HoldbackClassType.RETURN_PRODUCT_NOT_DELIVERED);		// 반품 상품 미입고
+				} else {
+					withholdReturnRequest.setReturnHoldCode(HoldbackClassType.ETC);									// 기타 사유
+				}
+
+				withholdReturnRequest.setReturnHoldDetailContent(order.getHoldReason());							// 반품 보류 상세 사유
+				// withholdReturnRequest.setEtcFeeDemandAmount(0);														// 기타 반품 비용
+
+
+				withholdReturnResponse = stub.withholdReturn(withholdReturnRequest);
+
+				String resultStr = "";
+				if (withholdReturnResponse.getResponseType() != null) {
+					resultStr = withholdReturnResponse.getResponseType().toUpperCase();
+				}
+
+				if ("SUCCESS".equals(resultStr)) {
+					log.info("반품보류 성공 주문번호===>" + ordNo);
+					log.info("반품보류 성공 네이버상품주문번호===>" + npayOrdDtlNo);
+				} else {
+					log.info("반품보류 에러");
+					log.info("주문번호 ===>" + ordNo);
+					log.info("네이버상품주문번호 ===> " + npayOrdDtlNo);
+					log.info("Code : " + withholdReturnResponse.getError().getCode());
+					log.info("Message : " + withholdReturnResponse.getError().getMessage());
+					log.info("Detail : " + withholdReturnResponse.getError().getDetail());
+
+					Order fail = new Order();
+					fail.setErrorReason("반품보류 데이터 송부 에러");
+					fail.setOrdNo(ordNo);
+					fail.setNpayOrdDtlNo(npayOrdDtlNo);
+					fail.setOptCd("WithholdReturn");
+					fail.setResultCd(withholdReturnResponse.getError().getCode());
+					fail.setResultMsg(withholdReturnResponse.getError().getMessage());
+					fail.setMallCd(env.getProperty("naverPay.shop.id"));
+					fail.setAccessLicense(env.getProperty("naverPay.access.license"));
+					fail.setSecretKey(env.getProperty("naverPay.secret.key"));
+					fail.setRegNo(regNo);
+
+					orderDao.createNaverPayErrorLog(fail);
+
+					return 0;
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			return 0;
+		}
+
+		return 1;
+	}
+
+	/**
+	 * 네이버페이 주문형 반품보류 해제 요청
+	 *
+	 * @param OrderChange
+	 * @return int
+	 * @author card007
+	 * @since 2021. 10. 08
+	 */
+	@Transactional("shopTxnManager")
+	public int nPayReleaseReturnHold(Order order) {
+		Order info 				= naverPayDao.getOrderDetailInfoFromOrdDtlNo(order);
+		String npayOrdDtlNo 	= info.getNpayOrdDtlNo();
+		String pgGb 			= info.getPgGb();
+		Integer ordNo 			= info.getOrdNo();
+		Integer regNo			= order.getRegNo();
+
+		try {
+			Security.addProvider(new BouncyCastleProvider());
+			AccessCredentialsType accessCredentialsType = new AccessCredentialsType();
+			MallServiceLocator MSL = new MallServiceLocator(env.getProperty("naverPay.port.address"));
+			MallServiceSOAP11BindingStub stub = (MallServiceSOAP11BindingStub)MSL.getMallServiceSOAP11Port();
+
+			ReleaseReturnHoldRequest releaseReturnHoldRequest = new ReleaseReturnHoldRequest();
+			ReleaseReturnHoldResponse releaseReturnHoldResponse = new ReleaseReturnHoldResponse();
+
+			if (order != null && TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb)) {
+				// 서명생성
+				generateSignature("ReleaseReturnHold", env.getProperty("naverPay.secret.key"));
+				log.info("ReleaseReturnHold(반품보류 해제 네이버로 송신) :: timeStamp === " + timeStamp);
+
+				//인증정보
+				accessCredentialsType.setAccessLicense(env.getProperty("naverPay.access.license"));
+				accessCredentialsType.setSignature(signature);
+				accessCredentialsType.setTimestamp(timeStamp);
+
+				releaseReturnHoldRequest.setAccessCredentials(accessCredentialsType);
+				releaseReturnHoldRequest.setDetailLevel("Full");
+				releaseReturnHoldRequest.setVersion(env.getProperty("naverPay.version"));
+				releaseReturnHoldRequest.setRequestID("");
+				releaseReturnHoldRequest.setProductOrderID(npayOrdDtlNo);					// 상품 주문 번호
+
+				releaseReturnHoldResponse = stub.releaseReturnHold(releaseReturnHoldRequest);
+
+				String resultStr = "";
+				if (releaseReturnHoldResponse.getResponseType() != null) {
+					resultStr = releaseReturnHoldResponse.getResponseType().toUpperCase();
+				}
+
+				if ("SUCCESS".equals(resultStr)) {
+					log.info("반품보류 해제 성공 주문번호===>" + ordNo);
+					log.info("반품보류 해제 성공 네이버상품주문번호===>" + npayOrdDtlNo);
+				} else {
+					log.info("반품보류 해제 에러");
+					log.info("주문번호 ===>" + ordNo);
+					log.info("네이버상품주문번호 ===> " + npayOrdDtlNo);
+					log.info("Code : " + releaseReturnHoldResponse.getError().getCode());
+					log.info("Message : " + releaseReturnHoldResponse.getError().getMessage());
+					log.info("Detail : " + releaseReturnHoldResponse.getError().getDetail());
+
+					Order fail = new Order();
+					fail.setErrorReason("반품보류 해제 데이터 송부 에러");
+					fail.setOrdNo(ordNo);
+					fail.setNpayOrdDtlNo(npayOrdDtlNo);
+					fail.setOptCd("ReleaseReturnHold");
+					fail.setResultCd(releaseReturnHoldResponse.getError().getCode());
+					fail.setResultMsg(releaseReturnHoldResponse.getError().getMessage());
+					fail.setMallCd(env.getProperty("naverPay.shop.id"));
+					fail.setAccessLicense(env.getProperty("naverPay.access.license"));
+					fail.setSecretKey(env.getProperty("naverPay.secret.key"));
+					fail.setRegNo(regNo);
+
+					orderDao.createNaverPayErrorLog(fail);
+
+					return 0;
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			return 0;
+		}
+
+		return 1;
+	}
+
+	/**
+	 * 네이버페이 주문형 반품/교환 보류 여부 수정
+	 * 
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 10. 05
+	 */
+	public int updateNaverPayChangeHold(Order order) {
+		return naverPayDao.updateNaverPayChangeHold(order);
+	}
+
+	/**
+	 * 네이버페이 주문형 발송지연 대상 조회
+	 *
+	 * @return Collection<Order>
+	 * @author card007
+	 * @since 2021. 10. 12
+	 */
+	public Collection<Order> getNaverPayDelayTargetList() {
+		return naverPayDao.getNaverPayDelayTargetList();
+	}
+
+	/**
+	 * 네이버페이 주문형 발송 지연 처리
+	 *
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 10. 12
+	 */
+	@Transactional("shopTxnManager")
+	public int nPayDelayProductOrder(Order order) {
+		Integer ordNo 			= order.getOrdNo();
+		String npayOrdDtlNo 	= order.getNpayOrdDtlNo();
+		String pgGb 			= order.getPgGb();
+		String reasonCd			= order.getReasonCd();
+		Integer regNo			= order.getRegNo();
+
+		try {
+			Security.addProvider(new BouncyCastleProvider());
+			AccessCredentialsType accessCredentialsType = new AccessCredentialsType();
+			MallServiceLocator MSL = new MallServiceLocator(env.getProperty("naverPay.port.address"));
+			MallServiceSOAP11BindingStub stub = (MallServiceSOAP11BindingStub)MSL.getMallServiceSOAP11Port();
+
+			DelayProductOrderRequest delayProductOrderRequest = new DelayProductOrderRequest();
+			DelayProductOrderResponse delayProductOrderResponse = new DelayProductOrderResponse();
+
+			if (order != null && TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb)) {
+				// 서명생성
+				generateSignature("DelayProductOrder", env.getProperty("naverPay.secret.key"));
+				log.info("DelayProductOrder(발송 지연 네이버로 송신) :: timeStamp === " + timeStamp);
+
+				//인증정보
+				accessCredentialsType.setAccessLicense(env.getProperty("naverPay.access.license"));
+				accessCredentialsType.setSignature(signature);
+				accessCredentialsType.setTimestamp(timeStamp);
+
+				delayProductOrderRequest.setAccessCredentials(accessCredentialsType);
+				delayProductOrderRequest.setDetailLevel("Full");
+				delayProductOrderRequest.setVersion(env.getProperty("naverPay.version"));
+				delayProductOrderRequest.setRequestID("");
+				delayProductOrderRequest.setProductOrderID(npayOrdDtlNo);												// 상품 주문 번호
+
+				// 발송 기한 설정
+				Calendar dispatchDate = Calendar.getInstance();
+				Date tmp;
+				if(StringUtils.isNotBlank(order.getDelvResDt())) {
+					tmp = new SimpleDateFormat("yyyyMMddHHmmss").parse(order.getDelvResDt(), new ParsePosition(0));
+				} else {
+					tmp = new Date();
+				}
+
+				dispatchDate.setTime(tmp);
+				delayProductOrderRequest.setDispatchDueDate(dispatchDate);												// 발송 기한
+
+				// 발송 지연 사유 코드 설정
+				if (TscConstants.nPayDelayReasonCode.PRODUCT_PREPARE.value().equals(reasonCd)) {
+					delayProductOrderRequest.setDispatchDelayReasonCode(DelayedDispatchReasonType.PRODUCT_PREPARE);		// 상품 준비 중
+				} else if (TscConstants.nPayDelayReasonCode.CUSTOMER_REQUEST.value().equals(reasonCd)) {
+					delayProductOrderRequest.setDispatchDelayReasonCode(DelayedDispatchReasonType.CUSTOMER_REQUEST);	// 고객 요청
+				} else if (TscConstants.nPayDelayReasonCode.CUSTOM_BUILD.value().equals(reasonCd)) {
+					delayProductOrderRequest.setDispatchDelayReasonCode(DelayedDispatchReasonType.CUSTOM_BUILD);		// 주문 제작
+				} else if (TscConstants.nPayDelayReasonCode.RESERVED_DISPATCH.value().equals(reasonCd)) {
+					delayProductOrderRequest.setDispatchDelayReasonCode(DelayedDispatchReasonType.RESERVED_DISPATCH);	// 예약 발송
+				} else {
+					delayProductOrderRequest.setDispatchDelayReasonCode(DelayedDispatchReasonType.ETC);					// 기타
+				}
+
+				// delayProductOrderRequest.setDispatchDelayDetailReason();												// 발송 지연 상세 사유
+
+				delayProductOrderResponse = stub.delayProductOrder(delayProductOrderRequest);
+
+				String resultStr = "";
+				if (delayProductOrderResponse.getResponseType() != null) {
+					resultStr = delayProductOrderResponse.getResponseType().toUpperCase();
+				}
+
+				if ("SUCCESS".equals(resultStr)) {
+					log.info("발송 지연 처리 성공 주문번호===>" + ordNo);
+					log.info("발송 지연 처리 성공 네이버상품주문번호===>" + npayOrdDtlNo);
+				} else {
+					log.info("발송 지연 처리 에러");
+					log.info("주문번호 ===>" + ordNo);
+					log.info("네이버상품주문번호 ===> " + npayOrdDtlNo);
+					log.info("Code : " + delayProductOrderResponse.getError().getCode());
+					log.info("Message : " + delayProductOrderResponse.getError().getMessage());
+					log.info("Detail : " + delayProductOrderResponse.getError().getDetail());
+
+					Order fail = new Order();
+					fail.setErrorReason("발송 지연 처리 데이터 송부 에러");
+					fail.setOrdNo(ordNo);
+					fail.setNpayOrdDtlNo(npayOrdDtlNo);
+					fail.setOptCd("DelayProductOrder");
+					fail.setResultCd(delayProductOrderResponse.getError().getCode());
+					fail.setResultMsg(delayProductOrderResponse.getError().getMessage());
+					fail.setMallCd(env.getProperty("naverPay.shop.id"));
+					fail.setAccessLicense(env.getProperty("naverPay.access.license"));
+					fail.setSecretKey(env.getProperty("naverPay.secret.key"));
+					fail.setRegNo(regNo);
+
+					orderDao.createNaverPayErrorLog(fail);
+
+					return 0;
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			return 0;
+		}
+
+		return 1;
+	}
+
 }

+ 113 - 51
src/main/java/com/style24/core/biz/service/TscOrderChangeService.java

@@ -2,9 +2,11 @@ package com.style24.core.biz.service;
 
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -180,6 +182,7 @@ public class TscOrderChangeService {
 		String batchYn			= map.getString("batchYn");										// 배치여부
 		String pgStat			= map.getString("pgStat");										// PG점프
 		int depositAmt			= map.getInt("depositAmt");										// PG점프 입금액
+		String delvDesc			= map.getString("delvDesc");									// 배송메모 (취소위치확인용)
 		int regNo				= userNo;														// 등록자번호
 		int updNo				= userNo;														// 수정자번호
 
@@ -691,27 +694,7 @@ public class TscOrderChangeService {
 			}
 		}
 
-		// 7. WMS 취소 처리
-		List<Order> wmsList = new ArrayList<>();
-		for (Order cancelOrderRefund : cancelOrderRefundList) {
-			int ordDtlNo = cancelOrderRefund.getOrdDtlNo();
-			int chgQty = cancelOrderRefund.getOrdCanChgQty();
-
-			Order wms = new Order();
-			wms.setOrdNo(ordNo);
-			wms.setOrdDtlNo(ordDtlNo);
-			wms.setChgQty(chgQty);
-
-			if (chgQty > 0) {
-				wmsList.add(wms);
-			}
-		}
-
-		if (wmsList.size() > 0) {
-			wmsService.updateWmsCancel(wmsList);
-		}
-
-		// 8. PG 취소 처리
+		// 7. PG 취소 처리
 		for (Payment pg : pgList) {
 			
 			// 2021.09.02 (PAY_STAT = 'G016_30' AND PG_TID IS NULL AND PG_GB <> 'ISTYLE') 체크 후 없으면 제휴몰로 판단 로직
@@ -721,7 +704,10 @@ public class TscOrderChangeService {
 			
 			// 네이버페이주문형, 외부몰주문, PG점프, 100%상품권 결제는 PG점프 처리
 			if (TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb) || TscConstants.PayMeans.EXTMALL.value().equals(payMeans) || "Y".equals(pgStat) || pg.getPartCancelAmt() == 0) {
-				pg.setPayAmt(-pg.getPartCancelAmt());
+				// 2021.10.15 card007 PG점프는 추후 데이터 구분을 위해 pgTid, pgTradeNo 없앰
+				pg.setPayAmt(pg.getPartCancelAmt() * -1);
+				pg.setPgTid("");
+				pg.setPgTradeNo("");
 				orderDao.insertPaymentCancel(pg);
 			} else if (TscConstants.PgGb.KCP.value().equals(pgGb) || TscConstants.PgGb.PAYCO.value().equals(pgGb)) {
 				log.info("modType ::: {}", modType);
@@ -747,7 +733,7 @@ public class TscOrderChangeService {
 				kakaoPayService.cancelKakaoPayment(pg);
 			}
 
-			// 9. 환불정보 수정
+			// 8. 환불정보 수정
 			Order refundOrder = new Order();
 			refundOrder.setOrdNo(ordNo);
 			refundOrder.setPaySq(pg.getPaySq());
@@ -757,11 +743,40 @@ public class TscOrderChangeService {
 			orderChangeDao.updateRefundInfo(refundOrder);
 		}
 
-		// 10. 현금영수증 취소 처리
+		// 9. 현금영수증 취소 처리
 		for (GiftCard cashReceipts : cashReceiptsList) {
 			kcpService.kcpCashReceiptCancel(cashReceipts);
 		}
 
+		// 10. WMS 취소 처리
+		// 2021.10.14 card007 트랜잭션 처리 안되는듯 하여 PG처리 후 WMS처리 하는걸로 변경
+		StringBuilder sb = new StringBuilder();
+		sb.append(env.getProperty("server.site.name"));
+		sb.append(" / ");
+		sb.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+		sb.append(" / ");
+		sb.append(delvDesc);
+
+		List<Order> wmsList = new ArrayList<>();
+		for (Order cancelOrderRefund : cancelOrderRefundList) {
+			int ordDtlNo = cancelOrderRefund.getOrdDtlNo();
+			int chgQty = cancelOrderRefund.getOrdCanChgQty();
+
+			Order wms = new Order();
+			wms.setOrdNo(ordNo);
+			wms.setOrdDtlNo(ordDtlNo);
+			wms.setChgQty(chgQty);
+			wms.setDelvDesc(sb.toString());
+
+			if (chgQty > 0) {
+				wmsList.add(wms);
+			}
+		}
+
+		if (wmsList.size() > 0) {
+			wmsService.updateWmsCancel(wmsList);
+		}
+
 		return map;
 	}
 
@@ -811,6 +826,12 @@ public class TscOrderChangeService {
 		int orgOrdChgSq						= map.getInt("orgOrdChgSq");									// 반품TO반품 기존 주문변경일련번호
 		int orgAddPayCost					= map.getInt("orgAddPayCost");									// 반품TO반품 기존 추가배송비
 		String wdTargetYn					= map.getString("wdTargetYn");									// 회수요청대상
+		String npayChangeHoldYn				= "";															// 네이버페이 주문형 반품/교환 보류 여부
+
+		// 네이버페이 주문형 반품/교환 보류 여부 설정
+		if (TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb)) {
+			npayChangeHoldYn 				= map.getString("npayChangeHoldYn");
+		}
 
 		// 3. 주문변경정보, 주문정보, 환불정보 (배송정책코드 별)
 		for (Order obj : cancelDelvRefundList) {
@@ -889,6 +910,7 @@ public class TscOrderChangeService {
 				orderChange.setShipCompCd(shipCompCd);
 				orderChange.setAddPayCost(addDelvFee);
 				orderChange.setAddPayAmt(0);
+				orderChange.setNpayChangeHoldYn(npayChangeHoldYn);
 				orderChange.setRegNo(regNo);
 				orderChange.setUpdNo(updNo);
 
@@ -1046,7 +1068,11 @@ public class TscOrderChangeService {
 
 			mav.setInt("orgAddPayCost", payAmt);
 
-			if(pg != null && TscConstants.PgGb.NAVER_ORDER.value().equals(pg.getPgGb())) {
+			Payment pay = new Payment();
+			pay.setOrdChgSq(ordChgSq);
+			pay.setOrdNo(ordNo);
+			pay = orderChangeDao.getPaymentInfo(pay);
+			if(pay != null && TscConstants.PgGb.NAVER_ORDER.value().equals(pay.getPgGb())) {
 				Collection<Order> dtlList = naverPayDao.getOrderDetailInfoFromOrdChgSq(order);
 				for(Order dtl : dtlList) {
 					if("scm".equals(env.getProperty("server.site.name"))) {
@@ -1131,9 +1157,14 @@ public class TscOrderChangeService {
 		payment = orderChangeDao.getPaymentInfo(payment);
 
 		// 네이버페이는 추가 결제 금액이 있어도 취소접수로 변경
+		String npayChangeHoldYn = "";
 		if(StringUtils.isNotBlank(excReq.getPgGb()) && TscConstants.PgGb.NAVER_ORDER.value().equals(excReq.getPgGb())) {
-			// 2021.08.18 card007 네이버페이 주문형 반품신청의 경우 반품접수승인대기로 변경
+			// 2021.08.18 card007 네이버페이 주문형 교환신청의 경우 교환접수승인대기로 변경
 			orderChangeStat = TscConstants.OrderChangeStat.EXCHANGE_APPROVE_WAIT.value();
+			npayChangeHoldYn = excReq.getNpayChangeHoldYn();
+
+			// 핸드폰번호 하이픈 처리
+			excReq.setHypenRecipPhone();
 		}
 		
 		// 제휴몰 주문은 추가 결제 금액이 있어도 반품접수로 처리
@@ -1252,6 +1283,7 @@ public class TscOrderChangeService {
 				orderChange.setAddPayCost(addPayCost);
 				orderChange.setAddPayAmt(excReq.getAddPayAmt());
 				orderChange.setWdBfSendYn(wdBfSendYn);
+				orderChange.setNpayChangeHoldYn(npayChangeHoldYn);
 				orderChange.setRegNo(regNo);
 				orderChange.setUpdNo(updNo);
 
@@ -1658,7 +1690,10 @@ public class TscOrderChangeService {
 			result.set("status", GagaResponseStatus.SUCCESS.getCode());
 
 			// 6. 네이버페이 주문시 네이버페이 교환 반려 송부
-			if(TscConstants.PgGb.NAVER_ORDER.value().equals(pg.getPgGb())) {
+			Payment pay = new Payment();
+			pay.setOrdNo(ordNo);
+			pay = orderChangeDao.getPaymentInfo(pay);
+			if(TscConstants.PgGb.NAVER_ORDER.value().equals(pay.getPgGb())) {
 				// 반품 반려 정보 조회
 				Order order = new Order();
 				order.setOrdChgSq(ordChgSq);
@@ -1748,6 +1783,13 @@ public class TscOrderChangeService {
 				orderChangeDao.createOrderChangeDetailHst(orderChangeDetailHst);
 
 				preOrdDtlNo = ordDtlNo;
+
+				// 네이버페이 주문형 교환승인 시 교환보류해제 처리
+				Order nPayReleaseExchangeHold = new Order();
+				nPayReleaseExchangeHold.setOrdDtlNo(ordDtlNo);
+				nPayReleaseExchangeHold.setRegNo(regNo);
+				nPayReleaseExchangeHold.setUpdNo(updNo);
+				naverPayService.nPayReleaseExchangeHold(nPayReleaseExchangeHold);
 			}
 
 			// 4. TB_ORDER_DETAIL_ITEM 변경옵션 UPDATE
@@ -1915,6 +1957,7 @@ public class TscOrderChangeService {
 				result.setString("cashAuthNo"	, refundPreInfo.getString("cashAuthNo"));	// 현금영수증 승인번호
 				result.setString("pgStat"		, pgStat);									// PG점프
 				result.setInt("depositAmt"		, orderChange.getDepositAmt());				// PG점프 입금액
+				result.setString("delvDesc"		, "BOS 취소승인");							// 배송메모 (취소위치확인용)
 
 				// 부분취소 처리
 				result = partialCancel(result, userNo);
@@ -2220,24 +2263,7 @@ public class TscOrderChangeService {
 		
 		orderChangeDao.updateOrderDetailItemForAllCancel(orderDetail);
 		
-		// 10. WMS 취소 처리
-		List<Order> wmsList = new ArrayList<>();
-		if(orderChange.getOrdDtlNoArr() != null && orderChange.getOrdDtlNoArr().length > 0) {
-			for (int i = 0; i < orderChange.getOrdDtlNoArr().length; i++) {
-				Order wms = new Order();
-				wms.setOrdNo(ordNo);
-				wms.setOrdDtlNo(orderChange.getOrdDtlNoArr()[i]);
-				wms.setChgQty(orderChange.getCnclRtnReqQtyArr()[i]);
-
-				wmsList.add(wms);
-			}
-
-			if(wmsList.size() > 0) {
-				wmsService.updateWmsCancel(wmsList);
-			}
-		}
-		
-		// 11. 배송비 취소 처리
+		// 10. 배송비 취소 처리
 		OrderChange deliveryFee = new OrderChange();
 		deliveryFee.setOrdNo(ordNo);
 		deliveryFee.setOrdChgSq(ordChgSq);
@@ -2245,7 +2271,7 @@ public class TscOrderChangeService {
 		deliveryFee.setUpdNo(updNo);
 		orderChangeDao.createDeliveryFeeForAllCancel(deliveryFee);
 
-		// 12. PG 연동
+		// 11. PG 연동
 		Payment pg = new Payment();
 		pg.setOrdNo(ordNo);
 		pg.setOrdChgSq(ordChgSq);
@@ -2270,7 +2296,10 @@ public class TscOrderChangeService {
 		// PG처리
 		if (TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb) || TscConstants.PayMeans.EXTMALL.value().equals(payMeans) || "Y".equals(pgStat) || refundAmt == 0) {
 			// 상품권 100%, 제휴몰, PG점프처리, 네이버페이주문은 PG점프 처리
+			// 2021.10.15 card007 PG점프는 추후 데이터 구분을 위해 pgTid, pgTradeNo 없앰
 			pg.setPayAmt(pg.getPayAmt() * -1);
+			pg.setPgTid("");
+			pg.setPgTradeNo("");
 			orderDao.insertPaymentCancel(pg);
 		} else if (TscConstants.PgGb.KCP.value().equals(pgGb) || TscConstants.PgGb.PAYCO.value().equals(pgGb)) {
 			pg.setModType(modType);
@@ -2292,12 +2321,12 @@ public class TscOrderChangeService {
 			kakaoPayService.cancelKakaoPayment(pg);
 		}
 
-		// 11. 환불금액 정보 수정
+		// 12. 환불금액 정보 수정
 		refundOrder.setPaySq(pg.getPaySq());
 
 		orderChangeDao.updateRefundInfo(refundOrder);
 
-		// 12. 보증보험 취소 처리 (무통장입금 전 전체취소 시 처리)
+		// 13. 보증보험 취소 처리 (무통장입금 전 전체취소 시 처리)
 		if (TscConstants.OrderChangeStat.PAYMENT_BEFORE_CANCEL.value().equals(chgStat)) {
 			Order guarantee = new Order();
 			guarantee.setOrdNo(ordNo);
@@ -2305,7 +2334,7 @@ public class TscOrderChangeService {
 			orderService.uSafeGuaranteePayedBeforeCancel(guarantee);
 		}
 
-		// 13. 상품권 현금영수증 취소 처리
+		// 14. 상품권 현금영수증 취소 처리
 		GiftCard giftCardCashReceipts = orderDao.getGiftCardReceiptInfo(ordNo);
 
 		if (giftCardCashReceipts != null && StringUtils.isNotBlank(giftCardCashReceipts.getTradeNo())) {
@@ -2314,6 +2343,29 @@ public class TscOrderChangeService {
 
 			kcpService.kcpCashReceiptCancel(giftCardCashReceipts);
 		}
+
+		// 15. WMS 취소 처리
+		// 2021.10.14 card007 트랜잭션 처리 안되는듯 하여 PG처리 후 WMS처리 하는걸로 변경
+		StringBuilder sb = new StringBuilder();
+		sb.append(env.getProperty("server.site.name"));
+		sb.append(" / ");
+		sb.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+		List<Order> wmsList = new ArrayList<>();
+		if(orderChange.getOrdDtlNoArr() != null && orderChange.getOrdDtlNoArr().length > 0) {
+			for (int i = 0; i < orderChange.getOrdDtlNoArr().length; i++) {
+				Order wms = new Order();
+				wms.setOrdNo(ordNo);
+				wms.setOrdDtlNo(orderChange.getOrdDtlNoArr()[i]);
+				wms.setChgQty(orderChange.getCnclRtnReqQtyArr()[i]);
+				wms.setDelvDesc(sb.toString());
+
+				wmsList.add(wms);
+			}
+
+			if(wmsList.size() > 0) {
+				wmsService.updateWmsCancel(wmsList);
+			}
+		}
 		
 		return ordChgSq;
 	}
@@ -2373,6 +2425,7 @@ public class TscOrderChangeService {
 			result.setString("cashAuthNo", refundPreInfo.getString("cashAuthNo"));	// 현금영수증 승인번호
 			result.setString("pgStat", "N");										// PG점프
 			result.setString("batchYn", orderChange.getBatchYn());
+			result.setString("delvDesc", "FRONT, SCM, BATCH, 네이버페이주문형 취소");	// 배송메모 (취소위치확인용)
 
 			// 부분취소 처리
 			result = partialCancel(result, userNo);
@@ -3190,10 +3243,13 @@ public class TscOrderChangeService {
 			if (orderDao.getExtmallOrderChk(pg) > 0) {
 				payMeans = TscConstants.PayMeans.EXTMALL.value();
 			}
-						
+
 			// 상품권 100%, 제휴몰, PG점프처리, 네이버페이주문은 PG점프 처리
 			if (TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb) || TscConstants.PayMeans.EXTMALL.value().equals(payMeans) || "Y".equals(pgStat) || refundAmt == 0) {
-				pg.setPayAmt(pg.getPayAmt() * -1);
+				// 2021.10.15 card007 PG점프는 추후 데이터 구분을 위해 pgTid, pgTradeNo 없앰
+				pg.setPayAmt(pg.getPartCancelAmt() * -1);
+				pg.setPgTid("");
+				pg.setPgTradeNo("");
 				orderDao.insertPaymentCancel(pg);
 			}
 			// KCP 및 PAYCO 결제 취소 처리
@@ -4180,7 +4236,10 @@ public class TscOrderChangeService {
 
 		// 상품권 100%, 제휴몰, PG점프처리, 네이버페이주문은 PG점프 처리
 		if (TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb) || TscConstants.PayMeans.EXTMALL.value().equals(payMeans) || "Y".equals(pgStat) || refundAmt == 0) {
+			// 2021.10.15 card007 PG점프는 추후 데이터 구분을 위해 pgTid, pgTradeNo 없앰
 			pg.setPayAmt(pg.getPayAmt() * -1);
+			pg.setPgTid("");
+			pg.setPgTradeNo("");
 			orderDao.insertPaymentCancel(pg);
 		}
 		// KCP 및 PAYCO 결제 취소 처리
@@ -4500,7 +4559,10 @@ public class TscOrderChangeService {
 		// 상품권으로만 결제 시 PG점프
 		if (TscConstants.PgGb.NAVER_ORDER.value().equals(pgGb) || TscConstants.PayMeans.EXTMALL.value().equals(payMeans) || "Y".equals(pgStat) || refundAmt == 0) {
 			// 상품권 100%, 제휴몰, PG점프처리, 네이버페이주문은 PG점프 처리
+			// 2021.10.15 card007 PG점프는 추후 데이터 구분을 위해 pgTid, pgTradeNo 없앰
 			pg.setPayAmt(pg.getPayAmt() * -1);
+			pg.setPgTid("");
+			pg.setPgTradeNo("");
 			orderDao.insertPaymentCancel(pg);
 		} else if (TscConstants.PgGb.KCP.value().equals(pgGb) || TscConstants.PgGb.PAYCO.value().equals(pgGb)) {
 			pg.setModType(modType);

+ 101 - 51
src/main/java/com/style24/core/biz/service/TscOrderService.java

@@ -2544,7 +2544,7 @@ public class TscOrderService {
 	 * @author xodud1202
 	 * @since 2021. 04. 21
 	 */
-	public void updateSellerDelvStart(Collection<Order> params, Collection<OrderChange> cancelDataList, int userNo) {
+	public String updateSellerDelvStart(Collection<Order> params, Collection<OrderChange> cancelDataList, int userNo) {
 		// 배송중 주문 목록 (알림톡 송부 위함)
 		List<Order> delvStartList = new ArrayList<Order>();
 
@@ -2552,6 +2552,10 @@ public class TscOrderService {
 		List<Order> delvStartDtlList = new ArrayList<Order>();
 
 		int exchangeDelvFailCnt = 0;
+		int cnt = 0;
+		int idx = 0;
+		List<Integer> ordNoList = new ArrayList<>();
+		List<String> messageList = new ArrayList<>();
 
 		try {
 			// 결품 취소 후 수량이 남은 경우 배송중처리
@@ -2571,80 +2575,99 @@ public class TscOrderService {
 	
 				// 결품 취소 후 수량이 남은 경우 배송중 변경 처리
 				if (temp) {
-	
 					// 변경번호 ORD_CHG_SQ 로 출고대상목록 조회 후 한번에 출고되는지 체크
 					// 한번에 출고되지 않으면 결제완료로 변경
 					if (param.getOrdQty() - param.getCnclRtnQty() - param.getCancelQty() > 0) {
-	
-						// 주문 상세 (TB_ORDER_DETAIL) 배송중으로 변경
-						param.setOrdDtlStat(TscConstants.OrderDetailStat.SHIPPING.value());
-						param.setRegNo(userNo);
-						param.setUpdNo(userNo);
-						orderDao.changedOrdDtlStatDelvStart(param);
-	
-						// 주문 상품 상세 (TB_ORDER_DETAIL_ITEM) 배송중으로 변경
-						scmDao.updateOrderDetailItemStat(param);
-	
-						// 주문 상세 송장번호 등록
-						scmDao.createOrderDetailInvoice(param);
-	
-						// 주문 변경 이력 저장
-						orderDao.createOrderDetailHst(param);
-	
-						// 주문 상세 아이템 이력 저장
-						// 2021.08.06 card007 TB_ORDER_DETAIL_ITEM_HST.ORD_DTL_STAT G013 -> G720으로 변경
-						// 뒷로직에서 G013으로 사용하는지 확인 후 안쓰면 하기 G013으로 변경 로직 제거 필요
-						String ordDtlStat = param.getOrdDtlStat();
-						param.setOrdDtlStat(TscConstants.OrdDtlItemStat.SALE_SHIPPING.value());
-						orderDao.createOrderDetailItemHstFromDtlNo(param);
-						param.setOrdDtlStat(ordDtlStat);
-	
+						GagaMap map = new GagaMap();
 						Order tmp = naverPayDao.getOrderDetailInfoFromOrdDtlNo(param);
+						String result = "SUCESS";
 						if(TscConstants.PgGb.NAVER_ORDER.value().equals(tmp.getPgGb())) {
 							if ("E".equals(tmp.getOrdExchGb())) {
 								// 네이버페이 교환 배송중 데이터 송부
 								if("scm".equals(env.getProperty("server.site.name"))) {
-									naverPayService.sendNaverPayExchangeReDelivery(param, userNo);    // 교환재배송
+									map = naverPayService.sendNaverPayExchangeReDelivery(param, userNo);    // 교환재배송
+									result = map.getString("status");
 								} else {
 									// naverPayService.sendNaverPayExchangeReDelivery(change, userNo);    // 교환재배송
 									String addUrl = "/naverpay/send/exchange/delivery?ordDtlNo=" + param.getOrdDtlNo() + "&userNo=" + userNo;
-									naverPayService.sendScmServerForNaverpay(addUrl);						// 교환재배송
+									result = naverPayService.sendScmServerForNaverpay(addUrl);						// 교환재배송
+
+									if (!"SUCCESS".equals(result)) {
+										map.setString("message", result);
+									}
 								}
 							} else if ("O".equals(tmp.getOrdExchGb())) {
 								// 네이버페이 원주문 배송중 데이터 송부
 								if("scm".equals(env.getProperty("server.site.name"))) {
-									naverPayService.sendNaverPayDeliveryStartOrder(tmp, "SHIPPING", userNo);    // 배송중
+									map = naverPayService.sendNaverPayDeliveryStartOrder(tmp, "SHIPPING", userNo);    // 배송중
+									result = map.getString("status");
 								} else {
 									// naverPayService.sendNaverPayDeliveryStartOrder(tmp, "SHIPPING", userNo);    // 배송중
 									String addUrl = "/naverpay/send/order/delivery/start?ordDtlNo=" + param.getOrdDtlNo() + "&userNo=" + userNo;
-									naverPayService.sendScmServerForNaverpay(addUrl);						// 배송중
+									result = naverPayService.sendScmServerForNaverpay(addUrl);						// 배송중
+									
+									if (!"SUCCESS".equals(result)) {
+										map.setString("message", result);
+									}
 								}
 							}
 						}
-	
-						boolean isOther = true;
-						for (Order delv : delvStartList) {
-							if (delv.getOrdNo().equals(param.getOrdNo())) {
-								delv.setGoodsCnt(String.valueOf(Integer.parseInt(delv.getGoodsCnt()) + 1));
-								isOther = false;
+
+						if ("SUCCESS".equals(result)) {
+							// 주문 상세 (TB_ORDER_DETAIL) 배송중으로 변경
+							param.setOrdDtlStat(TscConstants.OrderDetailStat.SHIPPING.value());
+							param.setRegNo(userNo);
+							param.setUpdNo(userNo);
+							orderDao.changedOrdDtlStatDelvStart(param);
+
+							// 주문 상품 상세 (TB_ORDER_DETAIL_ITEM) 배송중으로 변경
+							scmDao.updateOrderDetailItemStat(param);
+
+							// 주문 상세 송장번호 등록
+							scmDao.createOrderDetailInvoice(param);
+
+							// 주문 변경 이력 저장
+							orderDao.createOrderDetailHst(param);
+
+							// 주문 상세 아이템 이력 저장
+							// 2021.08.06 card007 TB_ORDER_DETAIL_ITEM_HST.ORD_DTL_STAT G013 -> G720으로 변경
+							// 뒷로직에서 G013으로 사용하는지 확인 후 안쓰면 하기 G013으로 변경 로직 제거 필요
+							String ordDtlStat = param.getOrdDtlStat();
+							param.setOrdDtlStat(TscConstants.OrdDtlItemStat.SALE_SHIPPING.value());
+							orderDao.createOrderDetailItemHstFromDtlNo(param);
+							param.setOrdDtlStat(ordDtlStat);
+
+							boolean isOther = true;
+							for (Order delv : delvStartList) {
+								if (delv.getOrdNo().equals(param.getOrdNo())) {
+									delv.setGoodsCnt(String.valueOf(Integer.parseInt(delv.getGoodsCnt()) + 1));
+									isOther = false;
+								}
 							}
-						}
-	
-						if (isOther) {
-							Order delv = new Order();
-							delv.setOrdNo(param.getOrdNo());
-							delv.setOrdNm(param.getOrdNm());
-							delv.setGoodsNm(param.getGoodsNm());
-							delv.setOrdPhnno(param.getOrdPhnno());
-							delv.setCustNo(param.getCustNo());
-							delv.setOrdDtlNo(param.getOrdDtlNo());
-							delv.setGoodsCnt("0");		// 첫 상품은 외 0건
-	
-							delvStartList.add(delv);
-							if("O".equals(tmp.getOrdExchGb())) {
-								delvStartDtlList.add(delv);
+
+							if (isOther) {
+								Order delv = new Order();
+								delv.setOrdNo(param.getOrdNo());
+								delv.setOrdNm(param.getOrdNm());
+								delv.setGoodsNm(param.getGoodsNm());
+								delv.setOrdPhnno(param.getOrdPhnno());
+								delv.setCustNo(param.getCustNo());
+								delv.setOrdDtlNo(param.getOrdDtlNo());
+								delv.setGoodsCnt("0");        // 첫 상품은 외 0건
+
+								delvStartList.add(delv);
+								if ("O".equals(tmp.getOrdExchGb())) {
+									delvStartDtlList.add(delv);
+								}
 							}
+
+							cnt++;
+						} else {
+							ordNoList.add(param.getOrdNo());
+							messageList.add(map.getString("message"));
 						}
+
+						idx++;
 					}
 				}
 				// 2021.07.22 교환상품 출고예외등록
@@ -2687,6 +2710,33 @@ public class TscOrderService {
 			// 카카오 발송 에러시에는 그냥 진행되어야함
 			e.printStackTrace();
 		}
+
+		// alert 처리
+		String alert;
+		if (cnt == idx) {
+			alert = message.getMessage("SUCC_0004");
+		} else {
+			StringBuilder sb = new StringBuilder();
+			sb.append("총 ");
+			sb.append(idx);
+			sb.append("건 중 ");
+			sb.append(cnt);
+			sb.append("건 처리되었습니다.<br/>");
+			sb.append("(");
+			for (int i=0; i < ordNoList.size(); i++) {
+				sb.append(ordNoList.get(i));
+				sb.append(" : ");
+				sb.append(messageList.get(i));
+				if (i < ordNoList.size() - 1) {
+					sb.append("<br/>");
+				}
+			}
+			sb.append(")");
+
+			alert = sb.toString();
+		}
+
+		return alert;
 	}
 
 	/**

+ 7 - 3
src/main/java/com/style24/core/biz/service/TscWmsService.java

@@ -136,8 +136,8 @@ public class TscWmsService {
 	 */
 	@Transactional("wmsTxnManager")
 	public void updateWmsCancel(Collection<Order> ordCancelList) {
-		// 주문번호, 주문상세번호, 변경수량 
-		// ordNo, ordDtlNo , chgQty
+		// 주문번호, 주문상세번호, 변경수량, 취소메모
+		// ordNo, ordDtlNo , chgQty, delvDesc
 		// 세트상품 취소 
 		// 오픈시점 이전 출고data 취소시 --주문상세번호 없음. productNo, skuCode 로 비교 
 		// 사은품 취소 
@@ -146,6 +146,7 @@ public class TscWmsService {
 		for (Order cData : ordCancelList) {
 
 			vOrdNo = cData.getOrdNo();
+			String delvDesc = cData.getDelvDesc();
 
 			//1. 주문TB 조회  PRODUCT_NO, SKU_CODE 및  세트상품일경우 포함됨.
 			WmsDelivery inData = new WmsDelivery();
@@ -159,9 +160,12 @@ public class TscWmsService {
 
 			//2. WMS_IF (TB_IF_DELIVERYORDERITEM) 주문상세 취소 업데이트 
 			for (WmsDelivery uData : ordDtlList) {
+				uData.setExceptionDesc(delvDesc);
+
 				if ("Y".equals(chkYn)) {
-					uData.setOrdDtlNo(null);
+					//uData.setOrdDtlNo(null);
 				}
+
 				wmsDao.updateWmsIfDeliveryOrderItemCancel(uData);
 				wmsDao.updateWmsTbIfDelifixQty(uData);
 			}

+ 57 - 0
src/main/java/com/style24/core/support/env/TscConstants.java

@@ -1169,4 +1169,61 @@ public class TscConstants {
 		}
 	}
 
+	// 네이버페이 주문형 교환보류 코드
+	public enum nPayExchangeHoldCode {
+		EXCHANGE_DELIVERYFEE("EXCHANGE_DELIVERYFEE"),						// 교환 배송비 청구
+		EXCHANGE_EXTRAFEE("EXCHANGE_EXTRAFEE"),								// 기타 교환 비용 청구
+		EXCHANGE_PRODUCT_READY("EXCHANGE_PRODUCT_READY"),					// 교환 상품 준비 중
+		EXCHANGE_PRODUCT_NOT_DELIVERED("EXCHANGE_PRODUCT_NOT_DELIVERED"),	// 교환 상품 미입고
+		EXCHANGE_HOLDBACK("EXCHANGE_HOLDBACK"),								// 교환 구매 확정 보류
+		ETC("ETC");															// 기타 사유
+
+		private String value;
+
+		private nPayExchangeHoldCode(String value) {
+			this.value = value;
+		}
+
+		public String value() {
+			return value;
+		}
+	}
+
+	// 네이버페이 주문형 반품보류 코드
+	public enum nPayReturnHoldCode {
+		RETURN_DELIVERYFEE("RETURN_DELIVERYFEE"),								// 반품 배송비 청구
+		EXTRAFEEE("EXTRAFEEE"),													// 기타 반품 비용 청구
+		RETURN_DELIVERYFEE_AND_EXTRAFEEE("RETURN_DELIVERYFEE_AND_EXTRAFEEE"),	// 반품 배송비 및 기타 반품 비용 청구
+		RETURN_PRODUCT_NOT_DELIVERED("RETURN_PRODUCT_NOT_DELIVERED"),			// 반품 상품 미입고
+		ETC("ETC");																// 기타 사유
+
+		private String value;
+
+		private nPayReturnHoldCode(String value) {
+			this.value = value;
+		}
+
+		public String value() {
+			return value;
+		}
+	}
+
+	// 네이버페이 주문형 발송지연 사유 코드
+	public enum nPayDelayReasonCode {
+		PRODUCT_PREPARE("PRODUCT_PREPARE"),		// 상품 준비 중
+		CUSTOMER_REQUEST("CUSTOMER_REQUEST"),	// 고객 요청
+		CUSTOM_BUILD("CUSTOM_BUILD"),			// 주문 제작
+		RESERVED_DISPATCH("RESERVED_DISPATCH"),	// 예약 발송
+		ETC("ETC");								// 기타
+
+		private String value;
+
+		private nPayDelayReasonCode(String value) {
+			this.value = value;
+		}
+
+		public String value() {
+			return value;
+		}
+	}
 }

+ 4 - 1
src/main/java/com/style24/persistence/domain/Order.java

@@ -265,6 +265,7 @@ public class Order extends TscBaseDomain {
 	private String chgerRtnMemo;					// 변경자반품메모
 	private String wdInvoiceNo;						// 회수송장번호
 	private int chgItemCnt;							// 변경이력카운트 (AS-IS 데이타 구분)
+	private String npayChangeHoldYn;				// 네이버페이 반품/교환 보류 여부
 
 	private String supplyCompNm;					// 공급업체명
 	private String brandKnm;						// 브랜드명(한글)
@@ -689,7 +690,7 @@ public class Order extends TscBaseDomain {
 
 	// 휴대폰 번호 대쉬 붙이기
 	public void setHypenRecipPhone() {
-		if (StringUtils.isNotBlank(this.cellPhnno)) {
+		if (StringUtils.isNotBlank(this.recipPhnno)) {
 			if (this.recipPhnno.length() > 10) {
 				this.recipPhnno = this.recipPhnno.substring(0, 3) + "-" + this.recipPhnno.substring(3, 7) + "-" + this.recipPhnno.substring(7, 11);
 			} else {
@@ -781,6 +782,8 @@ public class Order extends TscBaseDomain {
 	private int addDeliveryFee;	
 	private String wdBfSendYn;
 	private String canRequestCancelYn;
+	private String holdCode;
+	private String holdReason;
 	
 	// 2021.06.17 스윗트래커 정보 조회
 	private String timeTrans;

+ 24 - 0
src/main/java/com/style24/persistence/domain/OrderChange.java

@@ -3,6 +3,8 @@ package com.style24.persistence.domain;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.lang3.StringUtils;
+
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.style24.core.support.session.TscSession;
 import com.style24.core.support.util.CryptoUtils;
@@ -57,6 +59,7 @@ public class OrderChange extends TscBaseDomain {
 	private String shipCompCd;
 	private String shipCompNm;
 	private String wdBfSendYn;
+	private String npayChangeHoldYn;
 
 	private int chgQty;
 	private String chgStat;
@@ -278,4 +281,25 @@ public class OrderChange extends TscBaseDomain {
 	public String getMaskingOrderPhnno() {
 		return TscSession.getAttribute("maskingYn").equals("Y") ? MaskingUtils.phoneNo(getOrdPhnno()) : getOrdPhnno();
 	}
+
+	// 휴대폰 번호 대쉬 붙이기
+	public void setHypenRecipPhone() {
+		if (StringUtils.isNotBlank(this.recipPhnno) && !this.recipPhnno.contains("-")) {
+			if (this.recipPhnno.length() > 10) {
+				this.recipPhnno = this.recipPhnno.substring(0, 3) + "-" + this.recipPhnno.substring(3, 7) + "-" + this.recipPhnno.substring(7, 11);
+			} else {
+				this.recipPhnno = this.recipPhnno.substring(0, 3) + "-" + this.recipPhnno.substring(3, 6) + "-" + this.recipPhnno.substring(6, 10);
+			}
+		}
+	}
+
+	public void setHypenChgerPhone() {
+		if (StringUtils.isNotBlank(this.chgerPhnno) && !this.chgerPhnno.contains("-")) {
+			if (this.chgerPhnno.length() > 10) {
+				this.chgerPhnno = this.chgerPhnno.substring(0, 3) + "-" + this.chgerPhnno.substring(3, 7) + "-" + this.chgerPhnno.substring(7, 11);
+			} else {
+				this.chgerPhnno = this.chgerPhnno.substring(0, 3) + "-" + this.chgerPhnno.substring(3, 6) + "-" + this.chgerPhnno.substring(6, 10);
+			}
+		}
+	}
 }

+ 1 - 0
src/main/java/com/style24/persistence/domain/WmsDelivery.java

@@ -59,4 +59,5 @@ public class WmsDelivery extends TscBaseDomain {
 	private String IfDate;
 	private int encloseFee;
 	private int CodFee;
+	private String ExceptionDesc;
 }

+ 60 - 11
src/main/java/com/style24/persistence/mybatis/shop/TscNaverPay.xml

@@ -338,17 +338,17 @@
 	<select id="getOrderDetailInfoFromOrdDtlNo" parameterType="Order" resultType="Order">
 		/* TsbNaverPay.getOrderDetailInfoFromOrdDtlNo : 주문 상세 번호를 통해 주문 정보 조회 */
 		SELECT O.CUST_NO
-			 , P.PG_GB
-			 , OD.ORD_NO
-			 , OD.ORD_DTL_NO
-			 , OD.NPAY_ORD_DTL_NO
-			 , OD.ORD_EXCH_GB
-			 , OD.INVOICE_NO
-			 , OD.SHIP_COMP_CD
-			 , OD.INVOICE_SEND_YN
-			 , SC.NAVER_PAY_SHIP_COMP_CD
-			 , DATE_FORMAT(OD.DELV_STDT,'%Y%m%d%H%i%S') AS DELV_STDT
-			 , DATE_FORMAT(OD.DELV_EDDT,'%Y%m%d%H%i%S') AS DELV_EDDT
+		     , P.PG_GB
+		     , OD.ORD_NO
+		     , OD.ORD_DTL_NO
+		     , OD.NPAY_ORD_DTL_NO
+		     , OD.ORD_EXCH_GB
+		     , OD.INVOICE_NO
+		     , OD.SHIP_COMP_CD
+		     , OD.INVOICE_SEND_YN
+		     , SC.NAVER_PAY_SHIP_COMP_CD
+		     , DATE_FORMAT(OD.DELV_STDT,'%Y%m%d%H%i%S') AS DELV_STDT
+		     , DATE_FORMAT(OD.DELV_EDDT,'%Y%m%d%H%i%S') AS DELV_EDDT
 		FROM   TB_ORDER O
 		INNER  JOIN TB_ORDER_DETAIL OD
 		ON     O.ORD_NO = OD.ORD_NO
@@ -359,6 +359,55 @@
 		LEFT   OUTER JOIN TB_SHIP_COMPANY SC
 		ON     OD.SHIP_COMP_CD = SC.SHIP_COMP_CD
 		WHERE  1=1
+		<choose>
+			<when test="npayOrdDtlNo != null and npayOrdDtlNo != ''">
+		AND    OD.NPAY_ORD_DTL_NO = #{npayOrdDtlNo}
+			</when>
+			<otherwise>
 		AND    OD.ORD_DTL_NO = #{ordDtlNo}
+			</otherwise>
+		</choose>
+		LIMIT 1
+	</select>
+
+	<!-- 네이버페이 주문형 반품/교환 보류 여부 수정 -->
+	<update id="updateNaverPayChangeHold" parameterType="OrderChange">
+		/* TscNaverPay.updateNaverPayChangeHold */
+		UPDATE TB_ORDER_CHANGE
+		   SET NPAY_CHANGE_HOLD_YN = #{npayChangeHoldYn}
+		     , UPD_NO = #{updNo}
+		     , UPD_DT = NOW()
+		 WHERE ORD_CHG_SQ = #{ordChgSq}
+	</update>
+	
+	<!-- 네이버페이 주문형 발송지연 대상 조회 -->
+	<select id="getNaverPayDelayTargetList" resultType="Order">
+		/* TscNaverPay.getNaverPayDelayTargetList */
+		SELECT O.ORD_NO
+		     , OD.NPAY_ORD_DTL_NO
+		     , P.PG_GB
+		     , CASE WHEN OD.MAKE_GOODS_YN = 'Y' THEN CONCAT(FN_GET_BIZDATE(DATE_FORMAT(NOW(),'%Y%m%d'), 10), '235959')
+		            WHEN GRS.GOODS_CD IS NOT NULL THEN DATE_FORMAT(GRS.DELV_RES_DT ,'%Y%m%d%H%i%S')
+		            ELSE CONCAT(FN_GET_BIZDATE(DATE_FORMAT(NOW(),'%Y%m%d'), 3), '235959')
+		       END AS DELV_RES_DT
+		     , CASE WHEN OD.MAKE_GOODS_YN = 'Y' THEN 'CUSTOM_BUILD'
+		            WHEN GRS.GOODS_CD IS NOT NULL THEN 'RESERVED_DISPATCH'
+		            ELSE 'PRODUCT_PREPARE'
+			   END AS REASON_CD
+		  FROM TB_ORDER O
+		 INNER JOIN TB_ORDER_DETAIL OD
+		    ON O.ORD_NO = OD.ORD_NO
+		 INNER JOIN TB_PAYMENT P
+		    ON O.ORD_NO = P.ORD_NO
+		   AND P.PAY_STAT = 'G016_30'
+		   AND P.PAY_GB = 'O'
+		   AND P.PG_GB = 'NAVER_ORDER'
+		  LEFT OUTER JOIN TB_GOODS_RES_SELL GRS
+		    ON OD.GOODS_CD = GRS.GOODS_CD
+		   AND GRS.USE_YN = 'Y'
+		   AND GRS.DELV_RES_DT > NOW()
+		 WHERE OD.ORD_DTL_STAT IN ('G013_20', 'G013_30', 'G013_35', 'G013_40')
+		--   AND FN_GET_BIZDAYS(DATE_FORMAT(O.ORD_DT,'%Y%m%d'), DATE_FORMAT(NOW(),'%Y%m%d')) > 3
+		   AND GRS.GOODS_CD IS NOT NULL
 	</select>
 </mapper>

+ 10 - 7
src/main/java/com/style24/persistence/mybatis/shop/TscOrder.xml

@@ -2839,13 +2839,16 @@
 	<!-- 쿠폰정보 조회 -->
 	<select id="getCouponInfo" parameterType="Order" resultType="int">
 		/* order.getCouponInfo */
-		SELECT COUNT(CUST_CPN_SQ) AS CNT
-		  FROM TB_CUST_COUPON
-		 WHERE CUST_NO = #{custNo}
-		   AND NOW() BETWEEN AVAIL_STDT AND AVAIL_EDDT
-		   AND USED_DT IS NULL
+		SELECT COUNT(CC.CUST_CPN_SQ) AS CNT
+		  FROM TB_CUST_COUPON CC
+		 INNER JOIN TB_COUPON C
+		    ON CC.CPN_ID = C.CPN_ID
+		   AND C.CPN_STAT = 'G232_11'
+		 WHERE CC.CUST_NO = #{custNo}
+		   AND NOW() BETWEEN CC.AVAIL_STDT AND CC.AVAIL_EDDT
+		   AND CC.USED_DT IS NULL
 		<if test='expiredSoon == "Y"'>
-		   AND TIMESTAMPDIFF(SECOND, CURRENT_DATE, AVAIL_EDDT) BETWEEN 0 AND 604800
+		   AND TIMESTAMPDIFF(SECOND, CURRENT_DATE, CC.AVAIL_EDDT) BETWEEN 0 AND 604800
 		</if>
 	</select>
 
@@ -5617,7 +5620,7 @@
 				AND    ODEI.REASON_CD IN ('재고부족')
 				AND    ODE.COMPLTED_YN = 'N'
 				UNION  ALL
-				SELECT OREI.ORDER_DTL_NO 
+				SELECT OREI.ORDER_DTL_NO AS ORD_DTL_NO
 				     , OREI.REASON_CD
 				     , OREI.EXCEPTION_QTY
 				FROM   TB_ORDER_RECALL_EXCEPTION ORE

+ 5 - 2
src/main/java/com/style24/persistence/mybatis/shop/TscOrderChange.xml

@@ -462,6 +462,7 @@
 		     , CASE WHEN OC.WD_SHIP_STATE = '12' AND WD_REASON_CD IN ('14', '16', '18', '21', '25') THEN 'Y'
 		            ELSE 'N'
 		        END                                    AS CAN_REQUEST_CANCEL_YN
+		     , OC.NPAY_CHANGE_HOLD_YN
 		  FROM TB_ORDER_CHANGE_DETAIL OCD
 		 INNER JOIN TB_ORDER_CHANGE OC
 		    ON OC.ORD_CHG_SQ = OCD.ORD_CHG_SQ
@@ -687,6 +688,7 @@
 		     , WD_INVOICE_NO
 		     , SHIP_COMP_CD
 		     , WD_BF_SEND_YN
+		     , NPAY_CHANGE_HOLD_YN
 		     , REG_NO
 		     , REG_DT
 		     , UPD_NO
@@ -710,6 +712,7 @@
 		     , #{wdInvoiceNo}
 		     , #{shipCompCd}
 		     , IFNULL(NULLIF(#{wdBfSendYn}, ''), 'N')
+		     , #{npayChangeHoldYn}
 		     , #{regNo}
 		     , NOW()
 		     , #{updNo}
@@ -1363,7 +1366,7 @@
 		SELECT OD.ORD_DTL_NO
 		     , OD.ORD_NO
 		     , OD.ORD_EXCH_GB
-		     , OCD.CHG_STAT
+		     , OD.ORD_DTL_STAT
 		     , OD.ORG_ORD_DTL_NO
 		     , OD.SUPPLY_COMP_CD
 		     , OD.GOODS_CD
@@ -1433,7 +1436,7 @@
 		     , NOW()
 		  FROM TB_ORDER_DETAIL OD
 		 INNER JOIN TB_ORDER_CHANGE_DETAIL OCD
-		    ON OD.ORD_DTL_NO = OCD.ORD_DTL_NO
+		    ON OD.ORD_DTL_NO = OCD.CHG_ORD_DTL_NO
 		 WHERE 1 = 1
 		   AND OCD.ORD_CHG_SQ = #{ordChgSq}
 		   AND OD.ORD_NO = #{ordNo}

+ 4 - 11
src/main/java/com/style24/persistence/mybatis/wms/TscWmsDelivery.xml

@@ -79,7 +79,7 @@
 			 WHERE A.DeliveryOrderNo = B.DeliveryOrderNo 
 			   AND A.OrderNo  = #{ordNo} 
 			   AND B.OrderDtlNo IS NULL
-   	    
+			   AND B.GiftYn = 'N'
 		 ]]>      
    </select>
       
@@ -91,7 +91,7 @@
 			, StatusCd    = '60'
 			, IsCancel    = 1
 			WHERE OrderNo = #{ordNo}
-			  AND StatusCd !='60'		
+			  AND StatusCd !='60'
 	</update>
 	
 	      
@@ -103,18 +103,11 @@
 			, IsCancel = CASE WHEN (Qty - Cqty) = #{itemQty} THEN 1    ELSE IsCancel END 
 			, Cqty     = CASE WHEN (SELECT COUNT(*) FROM istyle24_Wmsif.dbo.TB_IF_RecallExceptionItem B WHERE B.OrderDtlNo = #{ordDtlNo} AND B.ProductNo = #{productNo} AND B.SKUCode = #{optCd}   AND B.ReasonCode IN ('08','10') ) > 0 THEN Cqty ELSE  Cqty + #{itemQty} END
 			, DateLastModified = GETDATE()
-			, ExceptionDesc = 'istyle취소'
+			, ExceptionDesc = #{ExceptionDesc}
 			WHERE 1=1
-			  <if test='ordDtlNo != null and ordDtlNo != ""'>
 			  AND OrderDtlNo = #{ordDtlNo}
 			  AND ProductNo  = #{productNo}
-			  AND SKUCode    = #{optCd}  	
-			  </if>
-			  <if test='ordDtlNo == null or ordDtlNo == ""'>
-			  AND ProductNo  = #{productNo}
-			  AND SKUCode    = #{optCd}  	
-			  </if>	
-			  AND (GiftYn != 'Y' OR GiftYn IS NULL) 
+			  AND SKUCode    = #{optCd}
 	</update>
 	
 	<!-- WMS 전체취소 여부 -->