Просмотр исходного кода

Merge branch 'develop' of http://112.172.147.34:4936/style24/STYLE24.git into develop

gagamel 5 лет назад
Родитель
Сommit
182fd12875

+ 128 - 27
style24.admin/src/main/java/com/style24/admin/biz/dao/TsaGoodsDao.java

@@ -3,14 +3,15 @@ package com.style24.admin.biz.dao;
 import java.util.Collection;
 
 import com.style24.core.support.annotation.ShopDs;
-import com.style24.persistence.domain.CodiGoods;
 import com.style24.persistence.domain.Color;
 import com.style24.persistence.domain.Goods;
 import com.style24.persistence.domain.GoodsCompose;
 import com.style24.persistence.domain.GoodsDesc;
+import com.style24.persistence.domain.GoodsEpSkip;
 import com.style24.persistence.domain.GoodsHst;
 import com.style24.persistence.domain.GoodsNotiInfo;
 import com.style24.persistence.domain.GoodsSearch;
+import com.style24.persistence.domain.GoodsTnmRes;
 import com.style24.persistence.domain.Itemkind;
 import com.style24.persistence.domain.NotiInfo;
 import com.style24.persistence.domain.Option;
@@ -270,16 +271,6 @@ public interface TsaGoodsDao {
 	 */
 	void saveGoodsNotiInfo(GoodsNotiInfo goodsNotiInfo);
 
-	/**
-	 * 코디 상품 목록 조회
-	 *
-	 * @param codiGoods
-	 * @return
-	 * @author eskim
-	 * @since 2020. 10. 26
-	 */
-	Collection<CodiGoods> getCodiGoodsList(CodiGoods codiGoods);
-
 	/**
 	 * 상품 기본 정보 수정
 	 *
@@ -334,22 +325,6 @@ public interface TsaGoodsDao {
 	 */
 	void saveStock(Option option);
 
-	/**
-	 * 코디상품 저장
-	 * @param codiGoods
-	 * @author eskim
-	 * @since 2020. 10. 28
-	 */
-	void saveCodiGoods(CodiGoods codiGoods);
-
-	/**
-	 * 코디상품 삭제
-	 * @param codiGoods
-	 * @author eskim
-	 * @since 2020. 10. 28
-	 */
-	void deleteCodiGoods(CodiGoods codiGoods);
-
 	/**
 	 * 상품 기본 정보 등록
 	 *
@@ -395,4 +370,130 @@ public interface TsaGoodsDao {
 	 */
 	void createGoodsSequence(Goods goods);
 
+	/**
+	 * 상품 타이틀 관리 목록 건수
+	 *
+	 * @param goodsSearch
+	 * @return
+	 * @author eskim
+	 * @since 2020. 10. 30
+	 */
+	int getGoodsTitleReserveCount(GoodsSearch goodsSearch);
+
+	/**
+	 * 상품 타이틀 관리 목록
+	 *
+	 * @param goodsSearch
+	 * @return
+	 * @author eskim
+	 * @since 2020. 10. 30
+	 */
+	Collection<GoodsTnmRes> getGoodsTitleReserveList(GoodsSearch goodsSearch);
+
+	/**
+	 * 상품 타이틀 조회(기간 체크용)
+	 *
+	 * @param goodsTnmRes
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	int getGoodsTnmDupChkCount(GoodsTnmRes goodsTnmRes);
+
+	/**
+	 * 상품 타이틀 예약 등록
+	 *
+	 * @param goodsTnmRes
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	void createGoodTnmRes(GoodsTnmRes goodsTnmRes);
+
+	/**
+	 * 상품 타이틀 수정
+	 *
+	 * @param goods
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	void updateGoodTnm(Goods goods);
+
+	/**
+	 * 상품 타이틀 예약건 초기화
+	 *
+	 * @param goods
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	void updateGoodTnmInit(Goods goods);
+
+	/**
+	 * 상품 타이틀 예약 삭제
+	 *
+	 * @param goodsTnmRes
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	void deleteGoodTnmRes(GoodsTnmRes goodsTnmRes);
+
+	/**
+	 * 상품 타이틀 초기값 조회
+	 *
+	 * @param goods
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	Goods getGoodTnmInit(Goods goods);
+
+	/**
+	 * 네이버 EP 제외 상품 목록 건수
+	 *
+	 * @param goodsSearch
+	 * @return Integer
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	int getGoodsEpSkipCount(GoodsSearch goodsSearch);
+
+	/**
+	 * 네이버 EP 제외 상품 목록
+	 *
+	 * @param goodsSearch
+	 * @return Collection<GoodsEpSkip>
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	Collection<GoodsEpSkip> getGoodsEpSkipList(GoodsSearch goodsSearch);
+
+	/**
+	 * 네이버 EP 제외 상품 조회(기간 체크용)
+	 *
+	 * @param GoodsEpSkip
+	 * @return Collection<GoodsEpSkip>
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	int getGoodsEpSkipDupChkCount(GoodsEpSkip GoodsEpSkip);
+
+	/**
+	 * 네이버 EP 제외 상품 예약 등록
+	 *
+	 * @param goodsEpSkip
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	void createGoodEpSkip(GoodsEpSkip goodsEpSkip);
+
+	/**
+	 * 네이버 EP 제외 상품 예약 삭제
+	 *
+	 * @param goodsEpSkip
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	void deleteGoodEpSkip(GoodsEpSkip goodsEpSkip);
+
 }

+ 184 - 42
style24.admin/src/main/java/com/style24/admin/biz/service/TsaGoodsService.java

@@ -16,16 +16,16 @@ import com.style24.admin.support.env.TsaConstants;
 import com.style24.admin.support.security.session.TsaSession;
 import com.style24.core.support.message.TscMessageByLocale;
 import com.style24.persistence.domain.Brand;
-import com.style24.persistence.domain.CodiGoods;
 import com.style24.persistence.domain.Color;
 import com.style24.persistence.domain.CommonCode;
 import com.style24.persistence.domain.Goods;
-import com.style24.persistence.domain.GoodsCategory;
 import com.style24.persistence.domain.GoodsCompose;
 import com.style24.persistence.domain.GoodsDesc;
+import com.style24.persistence.domain.GoodsEpSkip;
 import com.style24.persistence.domain.GoodsHst;
 import com.style24.persistence.domain.GoodsNotiInfo;
 import com.style24.persistence.domain.GoodsSearch;
+import com.style24.persistence.domain.GoodsTnmRes;
 import com.style24.persistence.domain.Itemkind;
 import com.style24.persistence.domain.NotiInfo;
 import com.style24.persistence.domain.Option;
@@ -36,6 +36,7 @@ import lombok.extern.slf4j.Slf4j;
 import com.gagaframework.excel.GagaExcelUtil;
 import com.gagaframework.excel.env.GagaExcelConstants;
 import com.gagaframework.web.parameter.GagaMap;
+import com.gagaframework.web.util.GagaDateUtil;
 import com.gagaframework.web.util.GagaFileUtil;
 import com.gagaframework.web.util.GagaStringUtil;
 
@@ -722,18 +723,6 @@ public class TsaGoodsService {
 //		}
 	}
 
-	/**
-	 * 코디 상품 목록 조회
-	 *
-	 * @param goods
-	 * @return
-	 * @author eskim
-	 * @since 2020. 10. 26
-	 */
-	public Collection<CodiGoods> getCodiGoodsList(CodiGoods codiGoods) {
-		return goodsDao.getCodiGoodsList(codiGoods);
-	}
-
 	/**
 	 * 상품 저장
 	 *
@@ -845,18 +834,6 @@ public class TsaGoodsService {
 		// 상품 정보고시 변경
 		this.saveGoodsNotiInfo(goods);
 
-		// 코디상품 변경
-		idx = 1;
-		Collection<CodiGoods> codiGoodsList = goods.getCodiGoodsListNew();
-		for (CodiGoods codiGoods : codiGoodsList) {
-			codiGoods.setDispOrd(idx);
-			codiGoods.setDelYn("N");
-			codiGoods.setRegNo(TsaSession.getInfo().getUserNo());
-			codiGoods.setUpdNo(TsaSession.getInfo().getUserNo());
-			goodsDao.saveCodiGoods(codiGoods); // 구성상품기본 저장
-
-			idx++;
-		}
 	}
 
 	/**
@@ -1057,22 +1034,6 @@ public class TsaGoodsService {
 		}
 	}
 
-	/**
-	 * 코드상품 삭제
-	 *
-	 * @param codiGoodsList
-	 * @author eskim
-	 * @since 2020. 10. 28
-	 */
-	@Transactional("shopTxnManager")
-	public void deleteCodiGoods(Collection<CodiGoods> codiGoodsList) {
-		for (CodiGoods codiGoods : codiGoodsList) {
-			codiGoods.setDelYn("Y");
-			codiGoods.setUpdNo(TsaSession.getInfo().getUserNo());
-			goodsDao.deleteCodiGoods(codiGoods);
-		}
-	}
-
 	/**
 	 * 딜상품 저장
 	 *
@@ -1274,4 +1235,185 @@ public class TsaGoodsService {
 		}
 		return goodsCd;
 	}
+
+	/**
+	 * 상품 타이틀 관리 목록 건수
+	 *
+	 * @param goodsSearch
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11 .02
+	 */
+	public int getGoodsTitleReserveCount(GoodsSearch goodsSearch) {
+		return goodsDao.getGoodsTitleReserveCount(goodsSearch);
+	}
+
+	/**
+	 * 상품 타이틀 관리 목록
+	 *
+	 * @param goodsSearch
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11 .02
+	 */
+	public Collection<GoodsTnmRes> getGoodsTitleReserveList(GoodsSearch goodsSearch) {
+		return goodsDao.getGoodsTitleReserveList(goodsSearch);
+	}
+
+	/**
+	 * 상품 타이틀 예약 등록
+	 *
+	 * @param goodsTnmRes
+	 * @author eskim
+	 * @since 2020. 11 .02
+	 */
+	@Transactional("shopTxnManager")
+	public void saveGoodsRsvtTnm(GoodsTnmRes goodsTnmRes) {
+		if (goodsTnmRes.getArrGoodsCd().length <= 0) {
+			throw new IllegalStateException(message.getMessage("FAIL_1001"));
+		}
+
+		goodsTnmRes.setGoodsTnm(GagaStringUtil.replace(GagaStringUtil.replace(goodsTnmRes.getGoodsTnm(), "&lt;", "<"), "&gt;", ">"));
+
+		for (String goodsCd : goodsTnmRes.getArrGoodsCd()) {
+
+			goodsTnmRes.setGoodsCd(goodsCd);
+			goodsTnmRes.setRegNo(TsaSession.getInfo().getUserNo());
+			goodsTnmRes.setUpdNo(TsaSession.getInfo().getUserNo());
+
+			if (goodsDao.getGoodsTnmDupChkCount(goodsTnmRes) > 0) {
+				throw new IllegalStateException("이미 등록된 상품 타이틀예약이 등록하려는 예약기간내에 존재합니다. \n(상품코드 : " + goodsCd + ")");
+			}
+
+			goodsDao.createGoodTnmRes(goodsTnmRes);
+
+			// 현재일자가 예약기간에 포함되어 있으면 바로 적용한다.
+			String toDaytime = GagaDateUtil.getTodayDateTime();
+			if (Long.parseLong(toDaytime) >= Long.parseLong(goodsTnmRes.getApplyStdt()) && Long.parseLong(toDaytime) <= Long.parseLong(goodsTnmRes.getApplyEddt())) {
+
+				// 이력생성 및 상품타이틀 수정
+				Goods goods = new Goods();
+				goods.setGoodsCd(goodsCd);
+				goods.setGoodsTnm(goodsTnmRes.getGoodsTnm());
+				goods.setRegNo(TsaSession.getInfo().getUserNo());
+				goods.setUpdNo(TsaSession.getInfo().getUserNo());
+
+				goodsDao.createGoodsHst(goods);
+				goodsDao.updateGoodTnm(goods);
+			}
+
+		}
+	}
+
+	/**
+	 * 상품 타이틀 예약 삭제
+	 *
+	 * @param goodsTnmRes
+	 * @author eskim
+	 * @since 2020. 11 .02
+	 */
+	@Transactional("shopTxnManager")
+	public void deleteGoodsRsvtTnm(GoodsTnmRes goodsTnmRes) {
+		if (goodsTnmRes.getArrGoodsCd().length <= 0) {
+			throw new IllegalStateException(message.getMessage("FAIL_1001"));
+		}
+
+		int idx = 0;
+		for (String goodsCd : goodsTnmRes.getArrGoodsCd()) {
+
+			// 상품 타이틀 예약 삭제
+			goodsTnmRes.setGoodsTnmResSq(goodsTnmRes.getArrGoodsTnmResSq()[idx]);
+			goodsDao.deleteGoodTnmRes(goodsTnmRes);
+
+			// 상품 타이틀 예약건 초기화
+			Goods goods = new Goods();
+			goods.setGoodsCd(goodsCd);
+			goods = goodsDao.getGoodTnmInit(goods);
+			goods.setRegNo(TsaSession.getInfo().getUserNo());
+			goods.setUpdNo(TsaSession.getInfo().getUserNo());
+
+			if (!StringUtils.isEmpty(goods.getGoodsTnm()) && !goods.getGoodsTnm().equals(goods.getGoodTnmInit())) {
+
+				// 상품이력 먼저 쌓기
+				goodsDao.createGoodsHst(goods);
+				// 정보수정
+				goods.setGoodsTnm(goods.getGoodTnmInit());
+				goodsDao.updateGoodTnm(goods);
+
+			}
+			idx++;
+		}
+	}
+
+	/**
+	 * 네이버 EP 제외 상품 목록 건수
+	 *
+	 * @param goodsSearch
+	 * @return int
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	public int getGoodsEpSkipCount(GoodsSearch goodsSearch) {
+		return goodsDao.getGoodsEpSkipCount(goodsSearch);
+	}
+
+	/**
+	 * 네이버 EP 제외 상품 목록
+	 *
+	 * @param goodsSearch
+	 * @return Collection<TsaGoodsEpSkip>
+	 * @author daehyoung
+	 * @since 2020. 11. 03
+	 */
+	public Collection<GoodsEpSkip> getGoodsEpSkipList(GoodsSearch goodsSearch) {
+		return goodsDao.getGoodsEpSkipList(goodsSearch);
+	}
+
+	/**
+	 * 네이버 EP 제외 상품 예약 등록
+	 *
+	 * @param goodsEpSkip
+	 * @return void
+	 * @author daehyoung
+	 * @since 2020. 11. 03
+	 */
+	@Transactional("shopTxnManager")
+	public void saveGoodsRsvtEpSkip(GoodsEpSkip goodsEpSkip) {
+		if (goodsEpSkip.getArrGoodsCd().length <= 0) {
+			throw new IllegalStateException(message.getMessage("FAIL_1001"));
+		}
+
+		for (String goodsCd : goodsEpSkip.getArrGoodsCd()) {
+
+			goodsEpSkip.setGoodsCd(goodsCd);
+			goodsEpSkip.setRegNo(TsaSession.getInfo().getUserNo());
+			goodsEpSkip.setUpdNo(TsaSession.getInfo().getUserNo());
+
+			if (goodsDao.getGoodsEpSkipDupChkCount(goodsEpSkip) > 0) {
+				throw new IllegalStateException("비노출예약이 중복된 상품이 존재합니다.<br/>(상품코드 : " + goodsCd + ")");
+			}
+			goodsDao.createGoodEpSkip(goodsEpSkip);
+		}
+	}
+
+	/**
+	 * 네이버 EP 제외 상품 예약 삭제
+	 *
+	 * @param goodsEpSkip
+	 * @return void
+	 * @author daehyoung
+	 * @since 2020. 11. 03
+	 */
+	@Transactional("shopTxnManager")
+	public void deleteGoodsEpSkip(GoodsEpSkip goodsEpSkip) {
+		if (goodsEpSkip.getArrGoodsCd().length <= 0) {
+			throw new IllegalStateException(message.getMessage("FAIL_1001"));
+		}
+		int idx = 0;
+		for (String goodsCd : goodsEpSkip.getArrGoodsCd()) {
+			goodsEpSkip.setGoodsEpSkipSq(goodsEpSkip.getArrGoodsEpSkipSq()[idx]);
+			goodsDao.deleteGoodEpSkip(goodsEpSkip);
+			idx++;
+		}
+	}
 }

+ 245 - 52
style24.admin/src/main/java/com/style24/admin/biz/web/TsaGoodsController.java

@@ -26,13 +26,14 @@ import com.style24.admin.support.controller.TsaBaseController;
 import com.style24.admin.support.security.session.TsaSession;
 import com.style24.core.support.message.TscMessageByLocale;
 import com.style24.persistence.TsaPageRequest;
-import com.style24.persistence.domain.CodiGoods;
 import com.style24.persistence.domain.Color;
 import com.style24.persistence.domain.Goods;
 import com.style24.persistence.domain.GoodsCompose;
+import com.style24.persistence.domain.GoodsEpSkip;
 import com.style24.persistence.domain.GoodsHst;
 import com.style24.persistence.domain.GoodsNotiInfo;
 import com.style24.persistence.domain.GoodsSearch;
+import com.style24.persistence.domain.GoodsTnmRes;
 import com.style24.persistence.domain.Itemkind;
 import com.style24.persistence.domain.NotiInfo;
 
@@ -516,6 +517,30 @@ public class TsaGoodsController extends TsaBaseController {
 		return super.ok("");
 	}
 
+	/**
+	 * 엑셀 업로드 상품 조회
+	 *
+	 * @param
+	 * @return GagaMap
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	@PostMapping("/excel/upload/goods/list")
+	@ResponseBody
+	public GagaMap getExcelUploadGoodsList() {
+		GagaMap result = new GagaMap();
+		GoodsSearch goodsSearch = new GoodsSearch();
+		goodsSearch.setSearchGb("EXCEL");
+		// 입점업체담당자는 업체코드 설정
+		if ("G001_B000".equals(TsaSession.getInfo().getRoleCd())) {
+			goodsSearch.setSupplyCompCd(TsaSession.getInfo().getSupplyCompCd());
+			goodsSearch.setMdId(Integer.toString(TsaSession.getInfo().getUserNo()));
+		}
+		goodsSearch.setRegNo(TsaSession.getInfo().getUserNo()); // 엑셀조회시 로그인 사용자의 엑셀 상품조회시 사용
+		result.set("goodsExcelList", goodsService.getGoodsList(goodsSearch));
+		return result;
+	}
+
 	/**
 	 * 상품 상세 화면
 	 *
@@ -661,25 +686,6 @@ public class TsaGoodsController extends TsaBaseController {
 		return goodsService.getGoodsDetailComposeList(goods);
 	}
 
-	/**
-	 * 코디 상품 목록 조회
-	 *
-	 * @param goods
-	 * @return
-	 * @author eskim
-	 * @since 2020. 10. 23
-	 */
-	@GetMapping("/detail/codi/list")
-	@ResponseBody
-	public Collection<CodiGoods> getGoodsDetailCodiList(Goods goods) {
-
-		CodiGoods codiGoods = new CodiGoods();
-		codiGoods.setGoodsCd(goods.getGoodsCd());
-
-		return goodsService.getCodiGoodsList(codiGoods);
-	}
-
-
 	/**
 	 * 상품 상세 저장
 	 *
@@ -706,7 +712,6 @@ public class TsaGoodsController extends TsaBaseController {
 
 		Collection<GoodsNotiInfo> notiList = null;
 		Collection<GoodsCompose> goodComposeList = null;
-		Collection<CodiGoods> codiGoodList = null;
 		ObjectMapper mapper = new ObjectMapper();
 		try {
 			if (goods.getNotiList() != null) {
@@ -716,14 +721,6 @@ public class TsaGoodsController extends TsaBaseController {
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
-		try {
-			if (goods.getCodiGoodsList() != null) {
-				codiGoodList = mapper.readValue(goods.getCodiGoodsList(), new TypeReference<Collection<CodiGoods>>() {
-				});
-			}
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
 		try {
 			if (goods.getGoodsComposeList() != null) {
 				goodComposeList = mapper.readValue(goods.getGoodsComposeList(), new TypeReference<Collection<GoodsCompose>>() {
@@ -735,27 +732,11 @@ public class TsaGoodsController extends TsaBaseController {
 
 		goods.setNotiListNew(notiList);
 		goods.setGoodsComposeListNew(goodComposeList);
-		goods.setCodiGoodsListNew(codiGoodList);
 
 		goodsService.saveGoodsDetail(goods);
 		return super.ok(message.getMessage("SUCC_0001"));
 	}
 
-	/**
-	 * 코디상품 삭제
-	 *
-	 * @param codiGoodsList
-	 * @author eskim
-	 * @since 2020. 10. 28
-	 */
-	@PostMapping("/codi/delete")
-	@ResponseBody
-	public GagaResponse deleteCodiGoods(@RequestBody Collection<CodiGoods> codiGoodsList) {
-
-		goodsService.deleteCodiGoods(codiGoodsList);
-		return super.ok(message.getMessage("SUCC_0003"));
-	}
-
 	/**
 	 * 세트상품구성 화면
 	 *
@@ -778,13 +759,12 @@ public class TsaGoodsController extends TsaBaseController {
 		// 시즌
 		mav.addObject("seasonList", rendererService.getAvailCommonCodeList("G006"));
 		// 스타일년도
-		mav.addObject("styleYearList", rendererService.getAvailCommonCodeList("G023"));
+		int toYear = Integer.parseInt(GagaDateUtil.getToday("yyyy")) - 4;
+		mav.addObject("styleYearList", rendererService.getYearList(toYear,0,5));
 		// 매입유형
 		mav.addObject("buyingTypeList", rendererService.getAvailCommonCodeList("G035"));
 		// 상품상태
-		// mav.addObject("goodsStatList",
-		// rendererService.getAvailCommonCodeList("G008"));
-		String[] exceptCds = {"00"};
+		String[] exceptCds = {"G008_00"};
 		mav.addObject("goodsStatList", rendererService.getCommonCodeList("G008", "Y", exceptCds));
 
 		mav.addObject("params", goods);
@@ -829,7 +809,8 @@ public class TsaGoodsController extends TsaBaseController {
 		// 시즌
 		mav.addObject("seasonList", rendererService.getAvailCommonCodeList("G006"));
 		// 스타일년도
-		mav.addObject("styleYearList", rendererService.getAvailCommonCodeList("G023"));
+		int toYear = Integer.parseInt(GagaDateUtil.getToday("yyyy")) - 4;
+		mav.addObject("styleYearList", rendererService.getYearList(toYear,0,5));
 		// 매입유형
 		mav.addObject("buyingTypeList", rendererService.getAvailCommonCodeList("G035"));
 		// 색상
@@ -966,17 +947,125 @@ public class TsaGoodsController extends TsaBaseController {
 	 *
 	 * @return
 	 * @author eskim
-	 * @since 2020. 10. 16
+	 * @since 2020. 10. 30
 	 */
 	@GetMapping("/title/reserve/form")
 	public ModelAndView titleReserveForm() {
 		ModelAndView mav = new ModelAndView();
 
+		// 사이트
+		mav.addObject("siteList", rendererService.getAvailCommonCodeList("G000"));
+		String supplyCompCd = "";
+		if ("G001_B000".equals(TsaSession.getInfo().getRoleCd())) {
+			supplyCompCd = TsaSession.getInfo().getSupplyCompCd();
+		}
+		// 공급업체
+		mav.addObject("supplyCompList", rendererService.getSupplyCompanyList(supplyCompCd));
+		// 상품상태
+		// mav.addObject("goodsStatList",
+		// rendererService.getAvailCommonCodeList("G008"));
+		String[] exceptCds = {"G008_00"};
+		mav.addObject("goodsStatList", rendererService.getCommonCodeList("G008", "Y", exceptCds));
+		// 정상이월
+		mav.addObject("formalGbList", rendererService.getAvailCommonCodeList("G009"));
+		// 시즌
+		mav.addObject("seasonList", rendererService.getAvailCommonCodeList("G006"));
+		// 스타일년도
+		int toYear = Integer.parseInt(GagaDateUtil.getToday("yyyy")) - 4;
+		mav.addObject("styleYearList", rendererService.getYearList(toYear,0,5));
+		// 사용여부
+		mav.addObject("useYnList", rendererService.getAvailCommonCodeList("G002"));
+		// 품목
+		mav.addObject("itemkindList", rendererService.getAllItemkindList());
+		// MD
+		mav.addObject("brandMdList", rendererService.getBrandMdList());
+
 		mav.setViewName("goods/GoodsTitleReserveForm");
 
 		return mav;
 	}
 
+	/**
+	 * 상품 타이틀 관리 조회
+	 *
+	 * @return
+	 * @author eskim
+	 * @since 2020. 10. 30
+	 */
+	@PostMapping("/title/reserve/list")
+	@ResponseBody
+	public GagaMap goodsTitleReserveList(@RequestBody GoodsSearch goodsSearch) {
+
+		GagaMap result = new GagaMap();
+
+		// 입점업체담당자는 업체코드 설정
+		if ("G001_B000".equals(TsaSession.getInfo().getRoleCd())) {
+			goodsSearch.setSupplyCompCd(TsaSession.getInfo().getSupplyCompCd());
+			goodsSearch.setMdId(Integer.toString(TsaSession.getInfo().getUserNo()));
+		}
+
+		// multi row 검색관련 처리
+		if (!StringUtils.isEmpty(goodsSearch.getCondition())) {
+			goodsSearch.setConditionList(goodsSearch.getCondition().replaceAll("\r", "").split("\n"));
+		}
+
+		goodsSearch.setRegNo(TsaSession.getInfo().getUserNo()); // 엑셀조회시 로그인 사용자의 엑셀 상품조회시 사용
+		goodsSearch.setPageable(new TsaPageRequest(goodsSearch.getPageNo() - 1, goodsSearch.getPageSize()));
+		goodsSearch.getPageable().setTotalCount(goodsService.getGoodsTitleReserveCount(goodsSearch));
+
+		result.set("pageing", goodsSearch);
+		result.set("goodsTnmList", goodsService.getGoodsTitleReserveList(goodsSearch));
+
+		return result;
+	}
+
+	/**
+	 * 상품등록 타이틀 예약등록 화면
+	 *
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	@GetMapping("/title/reserve/popup/form")
+	@ResponseBody
+	public ModelAndView goodsRsvtTnmListForm(GoodsTnmRes goodsTnmRes) {
+		ModelAndView mav = new ModelAndView();
+
+		mav.setViewName("goods/GoodsTitleReservePopupForm");
+		return mav;
+	}
+
+	/**
+	 * 상품 타이틀 예약 저장
+	 *
+	 * @param goodsTnmRes
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	@PostMapping("/title/reserve/save")
+	@ResponseBody
+	public GagaResponse saveGoodsRsvtTnm(@RequestBody GoodsTnmRes goodsTnmRes) {
+		goodsService.saveGoodsRsvtTnm(goodsTnmRes);
+		return super.ok(message.getMessage("SUCC_0001"));
+	}
+
+	/**
+	 * 상품 타이틀 예약 삭제
+	 *
+	 * @param goodsTnmRes
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 02
+	 */
+	@PostMapping("/title/reserve/delete")
+	@ResponseBody
+	public GagaResponse deleteGoodsRsvtTnm(@RequestBody GoodsTnmRes goodsTnmRes) {
+		goodsService.deleteGoodsRsvtTnm(goodsTnmRes);
+		return super.ok(message.getMessage("SUCC_0001"));
+	}
+
+
 	/**
 	 * 상품 동영상관리 화면
 	 *
@@ -998,17 +1087,121 @@ public class TsaGoodsController extends TsaBaseController {
 	 *
 	 * @return
 	 * @author eskim
-	 * @since 2020. 10. 16
+	 * @since 2020. 11. 03
 	 */
 	@GetMapping("/ep/skip/form")
 	public ModelAndView epSkipForm() {
 		ModelAndView mav = new ModelAndView();
 
+		String supplyCompCd = "";
+		if ("G001_B000".equals(TsaSession.getInfo().getRoleCd())) {
+			supplyCompCd = TsaSession.getInfo().getSupplyCompCd();
+		}
+		// 공급업체
+		mav.addObject("supplyCompList", rendererService.getSupplyCompanyList(supplyCompCd));
+		// 상품상태
+		String[] exceptCds = {"G001_00"};
+		mav.addObject("goodsStatList", rendererService.getCommonCodeList("G008", "Y", exceptCds));
+		// 정상이월
+		mav.addObject("formalGbList", rendererService.getAvailCommonCodeList("G009"));
+		// 시즌
+		mav.addObject("seasonList", rendererService.getAvailCommonCodeList("G006"));
+		// 년도
+		int toYear = Integer.parseInt(GagaDateUtil.getToday("yyyy")) - 4;
+		mav.addObject("styleYearList", rendererService.getYearList(toYear,0,5));
+		// 사용여부
+		mav.addObject("useYnList", rendererService.getAvailCommonCodeList("G002"));
+		// 품목
+		mav.addObject("itemkindList", rendererService.getAllItemkindList());
+		// MD
+		mav.addObject("brandMdList", rendererService.getBrandMdList());
+
 		mav.setViewName("goods/GoodsEpSkipForm");
 
 		return mav;
 	}
 
+	/**
+	 * 네이버 EP 제외 상품 조회
+	 *
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	@PostMapping("/ep/skip/list")
+	@ResponseBody
+	public GagaMap goodsEpSkipList(@RequestBody GoodsSearch goodsSearch) {
+
+		GagaMap result = new GagaMap();
+
+		// 입점업체담당자는 업체코드 설정
+		if ("B000".equals(TsaSession.getInfo().getRoleCd())) {
+			goodsSearch.setSupplyCompCd(TsaSession.getInfo().getSupplyCompCd());
+			goodsSearch.setMdId(Integer.toString(TsaSession.getInfo().getUserNo()));
+		}
+
+		// multi row 검색관련 처리
+		if (!StringUtils.isEmpty(goodsSearch.getCondition())) {
+			goodsSearch.setConditionList(goodsSearch.getCondition().replaceAll("\r", "").split("\n"));
+		}
+
+		goodsSearch.setRegNo(TsaSession.getInfo().getUserNo()); // 엑셀조회시 로그인 사용자의 엑셀 상품조회시 사용
+		goodsSearch.setPageable(new TsaPageRequest(goodsSearch.getPageNo() - 1, goodsSearch.getPageSize()));
+		goodsSearch.getPageable().setTotalCount(goodsService.getGoodsEpSkipCount(goodsSearch));
+
+		result.set("pageing", goodsSearch);
+		result.set("goodsEpSkipList", goodsService.getGoodsEpSkipList(goodsSearch));
+
+		return result;
+	}
+
+	/**
+	 * 네이버 EP 제외 상품 예약등록 화면
+	 *
+	 * @return
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	@GetMapping("/ep/skip/popup/form")
+	@ResponseBody
+	public ModelAndView goodsEpSkipPopupForm(GoodsEpSkip goodsEpSkip) {
+		ModelAndView mav = new ModelAndView();
+
+		mav.setViewName("goods/GoodsEpSkipPopupForm");
+		return mav;
+	}
+
+	/**
+	 * 네이버 EP 제외 상품 예약 저장
+	 *
+	 * @param goodsEpSkip
+	 * @return GagaResponse
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	@PostMapping("/rsvt/ep/skip/save")
+	@ResponseBody
+	public GagaResponse saveGoodsRsvtEpSkip(@RequestBody GoodsEpSkip goodsEpSkip) {
+		goodsService.saveGoodsRsvtEpSkip(goodsEpSkip);
+		return super.ok(message.getMessage("SUCC_0001"));
+	}
+
+	/**
+	 * 네이버 EP 제외 상품 예약 삭제
+	 *
+	 * @param goodsEpSkip
+	 * @return GagaResponse
+	 * @author eskim
+	 * @since 2020. 11. 03
+	 */
+	@PostMapping("/rsvt/ep/skip/delete")
+	@ResponseBody
+	public GagaResponse deleteGoodsEpSkip(@RequestBody GoodsEpSkip goodsEpSkip) {
+		goodsService.deleteGoodsEpSkip(goodsEpSkip);
+		return super.ok(message.getMessage("SUCC_0001"));
+	}
+
+
 	/**
 	 * 상품 재입고알림관리 화면
 	 *

+ 0 - 31
style24.admin/src/main/java/com/style24/persistence/domain/CodiGoods.java

@@ -1,31 +0,0 @@
-package com.style24.persistence.domain;
-
-import com.style24.persistence.TscBaseDomain;
-
-import lombok.Data;
-
-/**
- * 코드 상품 Domain
- * @author eskim
- * @since 2020. 10. 26
- */
-@SuppressWarnings("serial")
-@Data
-public class CodiGoods extends TscBaseDomain {
-
-	private String goodsCd;
-	private String codiGoodsCd;
-	private int dispOrd;
-	private String delYn;
-
-	private String goodsNm;
-	private int currPrice;
-	private String goodsStat;
-	private String formalGb;
-	private String imgType;
-	private String imgPath1;
-	private String imgPath6;
-	private String crud;
-
-}
-

+ 1 - 3
style24.admin/src/main/java/com/style24/persistence/domain/Goods.java

@@ -96,6 +96,7 @@ public class Goods extends TscBaseDomain {
 	private String imgPath6;
 	private String niClsfNm;
 	private String goodsTypeNm;
+	private String goodTnmInit;
 //
 //	private String goodsRegMsg;
 	private String procJob;
@@ -157,9 +158,6 @@ public class Goods extends TscBaseDomain {
 	private Collection<GoodsCompose> goodsComposeListNew; // 상품 구성상품
 	private String goodsComposeList; // 상품 구성상품
 
-	private Collection<CodiGoods> codiGoodsListNew; // 코디 상품
-	private String codiGoodsList; // 코디 상품
-
 	// Pagination
 	private TsaPageRequest pageable;
 	private int pageNo = 1;

+ 36 - 0
style24.admin/src/main/java/com/style24/persistence/domain/GoodsEpSkip.java

@@ -0,0 +1,36 @@
+package com.style24.persistence.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.style24.persistence.TscBaseDomain;
+
+import lombok.Data;
+
+/**
+ * EP제외상품 Domain
+ *
+ * @author eskim
+ * @since 2020. 11. 03
+ */
+@SuppressWarnings("serial")
+@Data
+public class GoodsEpSkip extends TscBaseDomain {
+
+	private Integer goodsEpSkipSq;
+	private String goodsCd;
+	private String applyStdt;
+	private String applyEddt;
+
+	private String goodsNm;
+	private String goodsNum;
+	private String supplyGoodsCd;
+	private String brandNm;
+	private String brandEnm;
+	private String goodsStat;
+
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private String[] arrGoodsCd;
+
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private int[] arrGoodsEpSkipSq;
+
+}

+ 37 - 0
style24.admin/src/main/java/com/style24/persistence/domain/GoodsTnmRes.java

@@ -0,0 +1,37 @@
+package com.style24.persistence.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.style24.persistence.TscBaseDomain;
+
+import lombok.Data;
+
+/**
+ * 상품타이틀예약 Domain
+ *
+ * @author eskim
+ * @since 2020. 10. 30
+ */
+@SuppressWarnings("serial")
+@Data
+public class GoodsTnmRes extends TscBaseDomain {
+
+	private int goodsTnmResSq;
+	private String goodsCd;
+	private String goodsTnm;
+	private String applyStdt;
+	private String applyEddt;
+	private String applycYn;
+
+	private String regGoodsTnm;
+	private String goodsNm;
+	private String supplyGoodsCd;
+	private String brandGrpNm;
+	private String goodsStat;
+
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private String[] arrGoodsCd;
+
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private int[] arrGoodsTnmResSq;
+
+}

+ 390 - 64
style24.admin/src/main/java/com/style24/persistence/mybatis/shop/TsaGoods.xml

@@ -242,7 +242,7 @@
 		        LEFT OUTER JOIN TB_GOODS_IMG GI ON G.GOODS_CD = GI.GOODS_CD
 		        WHERE 1=1
 		        <if test="searchGb == null or searchGb =='BASIC' or searchGb =='EXTEND' or searchGb =='MASTER'" >
-		        <include refid="getGoodsListContion_sql"/>
+		        <include refid="getGoodsListCondition_sql"/>
 		        </if>
 	</select>
 
@@ -351,17 +351,17 @@
 		        LEFT OUTER JOIN TB_GOODS_IMG GI ON G.GOODS_CD = GI.GOODS_CD
 		        WHERE 1=1
 		        <if test="searchGb == null or searchGb =='BASIC' or searchGb =='EXTEND' or searchGb =='MASTER'" >
-		        <include refid="getGoodsListContion_sql"/>
+		        <include refid="getGoodsListCondition_sql"/>
 		        ORDER BY G.REG_DT DESC, G.GOODS_CD
 		        </if>
 		        <if test="searchGb != null and searchGb =='EXCEL'">
 		        ORDER BY SD.TMP_DISP_ORD
 		        </if>
-		<include refid="getListPagingContion_sql"/>
+		<include refid="getListPagingCondition_sql"/>
 	</select>
 	
 	<!-- 상품 목록 조건 정보 -->
-	<sql id="getGoodsListContion_sql">
+	<sql id="getGoodsListCondition_sql">
 		        <if test='conditionList != null and conditionList.length>0'>
 		            <choose>
 		              <when test='search != null and search == "searchGoodsCd"'>
@@ -574,7 +574,7 @@
 	</sql>
 	
 	<!-- 목록 페이징 정보 -->
-	<sql id="getListPagingContion_sql">
+	<sql id="getListPagingCondition_sql">
 		<choose>
 		<when test="pageable != null">
 		    ) A
@@ -673,7 +673,7 @@
 		LEFT OUTER JOIN TB_GOODS_IMG GI ON G.GOODS_CD = GI.GOODS_CD
 		WHERE 1=1
 		<if test="searchGb == null or searchGb =='BASIC' or searchGb =='EXTEND' or searchGb =='MASTER'" >
-		<include refid="getGoodsListContion_sql"/>
+		<include refid="getGoodsListCondition_sql"/>
 		ORDER BY G.REG_DT DESC
 		</if>
 		<if test="searchGb == null or searchGb =='EXCEL'">
@@ -1140,31 +1140,6 @@
 		     , UPD_DT = NOW()
 	</update>
 	
-	<!-- 코디 상품 목록 조회  -->
-	<select id="getCodiGoodsList" parameterType="CodiGoods" resultType="CodiGoods">
-		/* TsaGoods.getCodiGoodsList */
-		SELECT A.GOODS_CD
-		     , A.CODI_GOODS_CD
-		     , A.DISP_ORD
-		     , A.DEL_YN
-		     , G.GOODS_NM
-		     , G.CURR_PRICE
-		     , G.GOODS_STAT
-		     , G.FORMAL_GB
-		     , GI.IMG_TYPE
-		     , GI.IMG_PATH1
-		     , GI.IMG_PATH6
-		     , FN_GET_USER_NM(A.UPD_NO) AS UPD_NM
-		     , A.UPD_NO
-		     , DATE_FORMAT(A.UPD_DT, '%Y%m%d%H%i%S') AS UPD_DT
-		FROM TB_CODI_GOODS A
-		INNER JOIN TB_GOODS G ON A.CODI_GOODS_CD = G.GOODS_CD
-		LEFT OUTER JOIN TB_GOODS_IMG GI ON A.CODI_GOODS_CD = GI.GOODS_CD
-		WHERE DEL_YN = 'N'
-		AND A.GOODS_CD = #{goodsCd}
-		ORDER BY A.DISP_ORD
-	</select>
-	
 	<!-- 상품 사이즈 조회 -->
 	<select id="getGoodsSizeList" parameterType="Goods" resultType="Option">
 		/* TsaGoods.getGoodsSizeList */
@@ -1551,53 +1526,404 @@
 		      </if>
 	</update>
 	
-	<!-- 코디상품 저장 -->
-	<insert id="saveCodiGoods" parameterType="CodiGoods">
-		/* TsaGoods.saveCodiGoods */
-		INSERT INTO TB_CODI_GOODS (
-		    GOODS_CD
-		  , CODI_GOODS_CD
-		  , DISP_ORD
-		  , DEL_YN
+	<!-- 상품코드 생성 -->
+	<insert id="createGoodsSequence" parameterType="Goods">
+		/* TsaGoods.createGoodsSequence */
+		<selectKey keyProperty="goodsSq" resultType="int" order="BEFORE">
+		SELECT GOODS_SQ FROM TB_GOODS_SEQUENCE
+		</selectKey>
+		INSERT INTO TB_GOODS_SEQUENCE (GOODS_SQ) VALUES (NULL)
+	</insert>
+
+	<!-- 상품 타이틀 예약관리 목록 건수 -->
+	<select id="getGoodsTitleReserveCount" parameterType="GoodsSearch" resultType="int">
+		/* TsaGoods.getGoodsTitleReserveCount */
+		SELECT COUNT(*) AS TOTCNT
+		FROM TB_GOODS G
+		INNER JOIN TB_BRAND B ON G.BRAND_CD = B.BRAND_CD
+		INNER JOIN TB_SUPPLY_COMPANY S ON G.SUPPLY_COMP_CD = S.SUPPLY_COMP_CD
+		INNER JOIN TB_GOODS_TNM_RES GR ON G.GOODS_CD = GR.GOODS_CD
+		<if test="searchGb == null or searchGb =='BASIC'" >
+		    <if test="applyStdt != null and applyStdt != ''">
+		                               AND GR.APPLY_EDDT >= DATE_FORMAT(#{applyStdt}, '%Y-%m-%d %H:%i:%S')
+		    </if>
+		    <if test="applyEddt != null and applyEddt != ''">
+		    <![CDATA[
+		                               AND GR.APPLY_STDT < DATE_FORMAT(DATE_ADD(#{applyEddt}, INTERVAL 1 DAY), '%Y-%m-%d %H:%i:%S')
+		    ]]>
+		    </if>
+		    <if test='beforSkipFlag != null and beforSkipFlag == "Y"'>
+		                               AND GR.APPLY_EDDT >= NOW() 
+		    </if>
+		</if>
+		<if test="searchGb != null and searchGb =='EXCEL'">
+		INNER JOIN (
+		            SELECT SEARCH_CD
+		                 , TMP_DISP_ORD
+		            FROM (
+		                  SELECT SEARCH_CD
+		                       , MIN(DISP_ORD) AS TMP_DISP_ORD
+		                  FROM TB_SEARCH_DATA
+		                  WHERE REG_NO = #{regNo}
+		                  GROUP BY SEARCH_CD) T
+		          ) SD
+		          ON ( (G.GOODS_CD LIKE CONCAT(SD.SEARCH_CD,'%')
+		               OR G.SUPPLY_GOODS_CD LIKE CONCAT(SD.SEARCH_CD,'%')) 
+		               <if test="mdId != null and mdId != ''">
+		               AND G.BRAND_CD IN (
+		                                  SELECT DISTINCT BRAND_CD
+		                                  FROM TB_BRAND_MD
+		                                  WHERE MD_ID = #{mdId}
+		                                  )
+		              </if>
+		           )
+		</if>
+		WHERE 1=1
+		<if test="searchGb == null or searchGb =='BASIC'" >
+		<include refid="getGoodsListCondition_sql"/>
+		</if>
+	</select>
+
+	<!-- 상품 타이틀 예약관리 목록 -->
+	<select id="getGoodsTitleReserveList" parameterType="GoodsSearch" resultType="GoodsTnmRes">
+		/* TsaGoods.getGoodsTitleReserveList */
+		SELECT Z.*
+		FROM (
+		    SELECT A.*, @rownum := @rownum + 1 AS RNUM FROM (
+		        SELECT
+		                G.GOODS_CD
+		              , B.BRAND_ENM
+		              , B.BRAND_GRP_NM
+		              , G.BRAND_CD
+		              , G.SUPPLY_COMP_CD
+		              , G.SUPPLY_GOODS_CD
+		              , G.GOODS_NM
+		              , G.GOODS_TNM
+		              , G.SELF_GOODS_YN
+		              , G.GOODS_STAT
+		              , GR.GOODS_TNM_RES_SQ
+		              , GR.GOODS_TNM AS REG_GOODS_TNM
+		              , DATE_FORMAT(GR.APPLY_STDT,'%Y%m%d%H%i%S') AS APPLY_STDT
+		              , DATE_FORMAT(GR.APPLY_EDDT,'%Y%m%d%H%i%S') AS APPLY_EDDT
+		              , GR.REG_NO
+		              , FN_GET_USER_NM(GR.REG_NO) AS REG_NM
+		              , DATE_FORMAT(GR.REG_DT,'%Y%m%d%H%i%S') AS REG_DT
+		        FROM TB_GOODS G
+		        JOIN ( SELECT @rownum := 0) R
+		        INNER JOIN TB_BRAND B ON G.BRAND_CD = B.BRAND_CD
+		        INNER JOIN TB_SUPPLY_COMPANY S ON G.SUPPLY_COMP_CD = S.SUPPLY_COMP_CD
+		        INNER JOIN TB_GOODS_TNM_RES GR ON G.GOODS_CD = GR.GOODS_CD
+		        <if test="searchGb == null or searchGb =='BASIC'" >
+		            <if test="applyStdt != null and applyStdt != ''">
+		                                       AND GR.APPLY_EDDT >= DATE_FORMAT(#{applyStdt}, '%Y-%m-%d %H:%i:%S')
+		            </if>
+		            <if test="applyEddt != null and applyEddt != ''">
+		            <![CDATA[
+		                                       AND GR.APPLY_STDT < DATE_FORMAT(DATE_ADD(#{applyEddt}, INTERVAL 1 DAY), '%Y-%m-%d %H:%i:%S')
+		            ]]>
+		            </if>
+		            <if test='beforSkipFlag != null and beforSkipFlag == "Y"'>
+		                                       AND GR.APPLY_EDDT >= NOW() 
+		            </if>
+		        </if>
+		        <if test="searchGb != null and searchGb =='EXCEL'">
+		        INNER JOIN (
+		                    SELECT SEARCH_CD
+		                         , TMP_DISP_ORD
+		                    FROM (
+		                          SELECT SEARCH_CD
+		                               , MIN(DISP_ORD) AS TMP_DISP_ORD
+		                          FROM TB_SEARCH_DATA
+		                          WHERE REG_NO = #{regNo}
+		                          GROUP BY SEARCH_CD) T
+		                  ) SD
+		                  ON ( (G.GOODS_CD LIKE CONCAT(SD.SEARCH_CD,'%')
+		                       OR G.SUPPLY_GOODS_CD LIKE CONCAT(SD.SEARCH_CD,'%')) 
+		                       <if test="mdId != null and mdId != ''">
+		                      AND G.BRAND_CD IN (
+		                                          SELECT DISTINCT BRAND_CD
+		                                          FROM TB_BRAND_MD
+		                                          WHERE MD_ID = #{mdId}
+		                                          )
+		                      </if>
+		                   )
+		        </if>
+		        WHERE 1=1
+		        <if test="searchGb == null or searchGb =='BASIC'" >
+		        <include refid="getGoodsListCondition_sql"/>
+		        ORDER BY  GR.APPLY_STDT DESC, GR.APPLY_EDDT DESC, G.GOODS_CD, GR.GOODS_TNM_RES_SQ
+		        </if>
+		        <if test="searchGb != null and searchGb =='EXCEL'">
+		        ORDER BY SD.TMP_DISP_ORD
+		        </if>
+		<include refid="getListPagingCondition_sql"/>
+	</select>
+
+	<!-- 상품 타이틀 예약조회(기간 체크용) -->
+	<select id="getGoodsTnmDupChkCount" parameterType="GoodsTnmRes" resultType="int">
+		/* TsaGoods.getGoodsTnmDupChkCount */
+		SELECT COUNTS(GOODS_CD)
+		FROM TB_GOODS_TNM_RES
+		WHERE 1=1
+		<![CDATA[
+		AND APPLY_STDT <= DATE_FORMAT(#{applyStdt}, '%Y%m%d%H%i%S')
+		]]>
+		AND APPLY_EDDT >= DATE_FORMAT(#{applyEddt},'%Y%m%d%H%i%S')
+		AND GOODS_CD = #{goodsCd}
+	</select>
+	
+	<!-- 상품 타이틀 예약 등록 -->
+	<insert id="createGoodTnmRes" parameterType="GoodsTnmRes">
+		/* TsaGoods.createGoodTnmRes */
+		INSERT INTO TB_GOODS_TNM_RES (
+		    GOODS_TNM_RES_SQ
+		  , GOODS_CD
+		  , GOODS_TNM
+		  , APPLY_STDT
+		  , APPLY_EDDT
 		  , REG_NO
 		  , REG_DT
 		  , UPD_NO
 		  , UPD_DT
-		) VALUES(
-		    #{goodsCd}
-		  , #{codiGoodsCd}
-		  , #{dispOrd}
-		  , #{delYn}
+		)
+		VALUES(
+		    NULL
+		  , #{goodsCd}
+		  , #{goodsTnm}
+		  , STR_TO_DATE(#{applyStdt},'%Y%m%d%H%i%S')
+		  , STR_TO_DATE(#{applyEddt},'%Y%m%d%H%i%S')
 		  , #{regNo}
 		  , NOW()
 		  , #{updNo}
 		  , NOW()
 		)
-		ON DUPLICATE KEY UPDATE 
-		      DISP_ORD = #{dispOrd}
-		    , DEL_YN = #{delYn} 
-		    , UPD_NO = #{updNo}
-		    , UPD_DT = NOW()
 	</insert>
 	
-	<!-- 코디상품 삭제 -->
-	<delete id="deleteCodiGoods" parameterType="CodiGoods">
-		/* TsaGoods.deleteCodiGoods */
-		UPDATE TB_CODI_GOODS SET
-		      DEL_YN = #{delYn} 
-		    , UPD_NO = #{updNo}
-		    , UPD_DT = NOW()
+	<!-- 상품 타이틀 수정 -->
+	<update id="updateGoodTnm" parameterType="Goods">
+		/* TsaGoods.updateGoodTnm */
+		UPDATE TB_GOODS
+		SET GOODS_TNM = #{goodsTnm}
+		  , UPD_NO = #{updNo} 
+		  , UPD_DT = NOW()
 		WHERE GOODS_CD = #{goodsCd}
-		AND CODI_GOODS_CD = #{codiGoodsCd}
+	</update >
+	
+	<!-- 상품 타이틀 예약 삭제 -->
+	<delete id="deleteGoodTnmRes" parameterType="GoodsTnmRes">
+		/* TsaGoods.deleteGoodTnmRes */
+		DELETE FROM TB_GOODS_TNM_RES 
+		WHERE GOODS_TNM_RES_SQ = #{goodsTnmResSq}
 	</delete>
+	
+	<!-- 상품 타이틀 예약건 초기화 -->
+	<update id="updateGoodTnmInit" parameterType="Goods">
+		/* TsaGoods.updateGoodTnmInit */
+		UPDATE TB_GOODS
+		SET UPD_NO = #{updNo} 
+		  , UPD_DT = NOW()
+		  , GOODS_TNM = (SELECT S.GOODS_TNM
+		                 FROM (
+		                       SELECT GT.GOODS_CD
+		                            , GT.GOODS_TNM
+		                            , RANK() OVER(PARTITION BY GT.GOODS_CD ORDER BY GT.GOODS_TNM_RES_SQ DESC) RANK 
+		                       FROM TB_GOODS_TNM_RES GT
+		                       WHERE GT.APPLYC_YN = 'N'
+		                       AND NOW() BETWEEN GT.APPLY_STDT AND GT.APPLY_EDDT
+		                       AND GT.GOODS_CD  = #{goodsCd}
+		                      ) S
+		                 WHERE S.RANK = 1
+		                 )
+		WHERE GOODS_CD = #{goodsCd}
+	</update >
+	
+	<!-- 상품 타이틀 예약건 초기화 조회 -->
+	<select id="getGoodTnmInit" parameterType="Goods"  resultType="Goods">
+		/* TsaGoods.getGoodTnmInit */
+		SELECT GOODS_CD
+		     , GOODS_TNM
+		     , (SELECT S.GOODS_TNM
+		        FROM (
+		              SELECT GT.GOODS_CD
+		                   , GT.GOODS_TNM
+		                   , RANK() OVER(PARTITION BY GT.GOODS_CD ORDER BY GT.GOODS_TNM_RES_SQ DESC) RANK 
+		              FROM TB_GOODS_TNM_RES GT
+		              WHERE GT.APPLYC_YN = 'N'
+		              AND NOW() BETWEEN GT.APPLY_STDT AND GT.APPLY_EDDT
+		              AND GT.GOODS_CD  = #{goodsCd}
+		             ) S
+		        WHERE S.RANK = 1
+		        ) AS GOOD_TNM_INIT
+		FROM TB_GOODS
+		WHERE GOODS_CD = #{goodsCd}
+	</select>
+	
+	<!-- 네이버 EP 제외 상품 목록 건수 -->
+	<select id="getGoodsEpSkipCount" parameterType="GoodsSearch" resultType="int">
+		/* TsaGoods.getGoodsEpSkipCount */
+		SELECT COUNT(*) AS TOTCNT
+		FROM TB_GOODS G
+		INNER JOIN TB_BRAND B ON G.BRAND_CD = B.BRAND_CD
+		INNER JOIN TB_SUPPLY_COMPANY S ON G.SUPPLY_COMP_CD = S.SUPPLY_COMP_CD
+		INNER JOIN TB_GOODS_EP_SKIP GE ON G.GOODS_CD = GE.GOODS_CD
+		<if test="searchGb == null or searchGb =='BASIC'" >
+		<if test="applyStdt != null and applyStdt != ''">
+		                               AND GE.APPLY_EDDT >= DATE_FORMAT(#{applyStdt}, '%Y-%m-%d %H:%i:%S')
+		</if>
+		<if test="applyEddt != null and applyEddt != ''">
+		<![CDATA[
+		                               AND GE.APPLY_STDT < DATE_FORMAT(DATE_ADD(#{applyEddt}, INTERVAL 1 DAY), '%Y-%m-%d %H:%i:%S')
+		]]>
+		</if>
+		<if test='beforSkipFlag != null and beforSkipFlag == "Y"'>
+		                               AND GE.APPLY_EDDT >= NOW() 
+		</if>
+		</if>
+		<if test="searchGb != null and searchGb =='EXCEL'">
+		INNER JOIN (
+		    SELECT SEARCH_CD
+		         , TMP_DISP_ORD
+		    FROM (
+		          SELECT SEARCH_CD
+		               , MIN(DISP_ORD) AS TMP_DISP_ORD
+		          FROM TB_SEARCH_DATA
+		          WHERE REG_NO = #{regNo}
+		          GROUP BY SEARCH_CD) T
+		  ) SD
+		  ON ( (G.GOODS_CD LIKE CONCAT(SD.SEARCH_CD,'%')
+		       OR G.SUPPLY_GOODS_CD LIKE CONCAT(SD.SEARCH_CD,'%')) 
+		       <if test="mdId != null and mdId != ''">
+		       AND G.BRAND_CD IN (
+		                          SELECT DISTINCT BRAND_CD
+		                          FROM TB_BRAND_MD
+		                          WHERE MD_ID = #{mdId}
+		                          )
+		      </if>
+		   )
+		</if>
+		WHERE 1=1
+		<if test="searchGb == null or searchGb =='BASIC'" >
+		<include refid="getGoodsListCondition_sql"/>
+		</if>
+	</select>
 
-	<!-- 상품코드 생성 -->
-	<insert id="createGoodsSequence" parameterType="Goods">
-		/* TsaGoods.createGoodsSequence */
-		<selectKey keyProperty="goodsSq" resultType="int" order="BEFORE">
-		SELECT GOODS_SQ FROM TB_GOODS_SEQUENCE
-		</selectKey>
-		INSERT INTO TB_GOODS_SEQUENCE (GOODS_SQ) VALUES (NULL) ;
+	<!-- 네이버 EP 제외 상품 목록 -->
+	<select id="getGoodsEpSkipList" parameterType="GoodsSearch" resultType="GoodsEpSkip">
+		/* TsaGoods.getGoodsEpSkipList */
+		SELECT Z.*
+		FROM (
+		    SELECT A.*, @rownum := @rownum + 1 AS RNUM FROM (
+		        SELECT
+		                G.GOODS_CD
+		              , B.BRAND_ENM
+		              , G.BRAND_CD
+		              , G.SUPPLY_COMP_CD
+		              , G.SUPPLY_GOODS_CD
+		              , G.GOODS_NM
+		              , G.GOODS_STAT
+		              , GE.GOODS_EP_SKIP_SQ
+		              , DATE_FORMAT(GE.APPLY_STDT,'%Y%m%d%H%i%S') AS APPLY_STDT
+		              , DATE_FORMAT(GE.APPLY_EDDT,'%Y%m%d%H%i%S') AS APPLY_EDDT
+		              , GE.REG_NO
+		              , FN_GET_USER_NM(GE.REG_NO) AS REG_NM
+		              , DATE_FORMAT(GE.REG_DT,'%Y%m%d%H%i%S') AS REG_DT
+		              , GE.UPD_NO
+		              , FN_GET_USER_NM(GE.UPD_NO) AS UPD_NM
+		              , DATE_FORMAT(GE.UPD_DT,'%Y%m%d%H%i%S') AS UPD_DT
+		        FROM TB_GOODS G
+		        JOIN ( SELECT @rownum := 0) R
+		        INNER JOIN TB_BRAND B ON G.BRAND_CD = B.BRAND_CD
+		        INNER JOIN TB_SUPPLY_COMPANY S ON G.SUPPLY_COMP_CD = S.SUPPLY_COMP_CD
+		        INNER JOIN TB_GOODS_EP_SKIP GE ON G.GOODS_CD = GE.GOODS_CD
+		        <if test="searchGb == null or searchGb =='BASIC'" >
+		            <if test="applyStdt != null and applyStdt != ''">
+		                                       AND GE.APPLY_EDDT >= DATE_FORMAT(#{applyStdt}, '%Y-%m-%d %H:%i:%S')
+		            </if>
+		            <if test="applyEddt != null and applyEddt != ''">
+		            <![CDATA[
+		                                       AND GE.APPLY_STDT < DATE_FORMAT(DATE_ADD(#{applyEddt}, INTERVAL 1 DAY), '%Y-%m-%d %H:%i:%S')
+		            ]]>
+		            </if>
+		            <if test='beforSkipFlag != null and beforSkipFlag == "Y"'>
+		                                       AND GE.APPLY_EDDT >= NOW() 
+		            </if>
+		        </if>
+		        <if test="searchGb != null and searchGb =='EXCEL'">
+		        INNER JOIN (
+		                    SELECT SEARCH_CD
+		                         , TMP_DISP_ORD
+		                    FROM (
+		                          SELECT SEARCH_CD
+		                               , MIN(DISP_ORD) AS TMP_DISP_ORD
+		                          FROM TB_SEARCH_DATA
+		                          WHERE REG_NO = #{regNo}
+		                          GROUP BY SEARCH_CD) T
+		                  ) SD
+		                  ON ( (G.GOODS_CD LIKE CONCAT(SD.SEARCH_CD,'%')
+		                       OR G.SUPPLY_GOODS_CD LIKE CONCAT(SD.SEARCH_CD,'%')) 
+		                       <if test="mdId != null and mdId != ''">
+		                      AND G.BRAND_CD IN (
+		                                          SELECT DISTINCT BRAND_CD
+		                                          FROM TB_BRAND_MD
+		                                          WHERE MD_ID = #{mdId}
+		                                          )
+		                      </if>
+		                   )
+		        </if>
+		        WHERE 1=1
+		        <if test="searchGb == null or searchGb =='BASIC'">
+		        <include refid="getGoodsListCondition_sql"/>
+		        ORDER BY GE.APPLY_STDT DESC, GE.APPLY_EDDT DESC, G.GOODS_CD, GE.GOODS_EP_SKIP_SQ
+		        </if>
+		         <if test="searchGb != null and searchGb =='EXCEL'">
+		        ORDER BY SD.TMP_DISP_ORD
+		        </if>
+		<include refid="getListPagingCondition_sql"/>
+	</select>
+
+	<!-- 네이버 EP 제외 상품 조회(기간 체크용) -->
+	<select id="getGoodsEpSkipDupChkCount" parameterType="GoodsEpSkip" resultType="int">
+		/* TsaGoods.getGoodsEpSkipDupChkCount */
+		SELECT COUNT(GOODS_CD)
+		FROM TB_GOODS_EP_SKIP
+		WHERE 1=1
+		<![CDATA[
+		AND APPLY_STDT <= DATE_FORMAT(#{applyStdt}, '%Y%m%d')
+		]]>
+		AND APPLY_EDDT >= DATE_FORMAT(#{applyEddt},'%Y%m%d%')
+		AND GOODS_CD = #{goodsCd}
+	</select>
+
+	<!-- 네이버 EP 제외 상품 예약 등록 -->
+	<insert id="createGoodEpSkip" parameterType="GoodsEpSkip">
+		/* TsaGoods.createGoodEpSkip */
+		INSERT INTO TB_GOODS_EP_SKIP (
+		GOODS_EP_SKIP_SQ
+		, GOODS_CD
+		, APPLY_STDT
+		, APPLY_EDDT
+		, REG_NO
+		, REG_DT
+		, UPD_NO
+		, UPD_DT
+		)
+		VALUES(
+		  NULL
+		, #{goodsCd}
+		, STR_TO_DATE(#{applyStdt},'%Y%m%d%H%i%S')
+		, STR_TO_DATE(#{applyEddt},'%Y%m%d%H%i%S')
+		, #{regNo}
+		, NOW()
+		, #{updNo}
+		, NOW()
+		)
 	</insert>
 
+	<!-- 네이버 EP 제외 상품 예약 삭제 -->
+	<delete id="deleteGoodEpSkip" parameterType="GoodsEpSkip">
+		/* TsaGoods.deleteGoodEpSkip */
+		DELETE FROM TB_GOODS_EP_SKIP
+		WHERE GOODS_EP_SKIP_SQ = #{goodsEpSkipSq}
+	</delete>
+	
 </mapper>

+ 4 - 146
style24.admin/src/main/webapp/WEB-INF/views/goods/GoodsDetailForm.html

@@ -33,7 +33,6 @@
 				<input type="hidden" id="niClsfNm" name="niClsfNm" />
 				<input type="hidden" id="uploadGoodsUrl" name="uploadGoodsUrl" th:value="${@environment.getProperty('upload.goods.view')}"/>
 				<input type="hidden" id="goodsType" name="goodsType" />
-				<input type="hidden" id="codiGoodsList" name="codiGoodsList" />
 				<input type="hidden" id="GoodsComposeList" name="GoodsComposeList" />
 				<table class="frmStyle">
 					<colgroup>
@@ -76,7 +75,7 @@
 							<li><a href="#goodstab2">옵션/재고정보</a></li>
 							<li><a href="#goodstab3">상품상세정보</a></li>
 							<li id="goodsNotiTab"><a href="#goodstab4">고시정보</a></li>
-							<li id="goodsCodiTab"><a href="#goodstab5">코디상품</a></li>
+							<li id="goodsCodiTab"><a href="#goodstab5">대표색상</a></li>
 							<li id="GoodsComposeTab" style="display:none;"><a href="#goodstab6">구성상품</a></li>
 							<li><a href="#goodstab7">변경이력</a></li>
 						</ul>
@@ -437,7 +436,7 @@
 						</li>
 						<!-- //TAB7 : 추가정보 -->
 						<!-- TAB5 : 이력정보 -->
-						<li class="tab" id="goodstab5">
+						<li class="tab" id="goodstab7">
 							<!-- TAB8 CONTENTS AREA -->
 							<div class="panelStyle">
 								<!-- 내용 삽입 -->
@@ -594,54 +593,11 @@
 		{headerName: "수정자", field: "updNm", width: 100, cellClass: 'text-center'}
 	];
 	
-	// specify the columns - 코디상품
-	var columnCodiGoodsDefs = [
-		{width: 40, minWidth: 40, cellClass: 'text-center', headerCheckboxSelection: true, checkboxSelection: true, filter: false},
-		{headerName: "정렬", field: "dispOrd", width: 70 ,hide: false, cellClass: 'text-center',  rowDrag: true },
-		{headerName: "CRUD", field: "crud", width: 75, minWidth: 75, hide: true},
-		//{headerName: 'No', width: 60, cellClass: 'text-center', valueGetter: function(params) { return params.node.rowIndex + 1 }},
-		{headerName: "이미지", field: "imgPath1", width: 100, height: 60, cellClass: 'text-center'
-			,cellRenderer: function(params) {
-				if (params.data.imgType == "G030_A"){
-					if(!gagajf.isNull(params.data.imgPath6)){
-						return '<img width="60" src="'+ params.data.imgPath6 + '" alt="" onerror="this.src=\'/image/no.gif\';"/>';
-					}else{
-						return '<img width="60" src="'+ params.value + '" alt="" onerror="this.src=\'/image/no.gif\';"/>';
-					}
-						
-				}else{
-					if(!gagajf.isNull(params.data.imgPath6)){
-						return '<img width="60" src="'+ uploadGoodsUrl+params.data.imgPath6 + '" alt=""  onerror="this.src=\'/image/no.gif\';"/>';
-					}else{
-						return '<img width="60" src="'+ uploadGoodsUrl+params.value + '" alt=""  onerror="this.src=\'/image/no.gif\';"/>';
-					}
-				}
-			}
-		},
-		{headerName: "상품코드", field: "codiGoodsCd" , width: 130, cellClass: 'text-center'},
-		{headerName: "상품명", field: "goodsNm" , width: 300, cellClass: 'text-left'},
-		{headerName: "판매가", field: "currPrice" , width: 100, cellClass: 'text-right'
-			,valueFormatter: function(params) { return Number(params.value).addComma();}
-		},
-		{headerName: "상품상태", field: "goodsStat" , width: 100, cellClass: 'text-center',
-			cellEditorParams: { values: gagaAgGrid.extractValues(goodsStatList) },
-			valueFormatter: function (params) { return gagaAgGrid.lookupValue(goodsStatList, params.value); },
-			valueParser: function (params) { return gagaAgGrid.lookupKey(goodsStatList, params.newValue); }
-		},
-		{headerName: "정상이월구분", field: "formalGb" , width: 100, cellClass: 'text-center',
-			cellEditorParams: { values: gagaAgGrid.extractValues(formalGbList) },
-			valueFormatter: function (params) { return gagaAgGrid.lookupValue(formalGbList, params.value); },
-			valueParser: function (params) { return gagaAgGrid.lookupKey(formalGbList, params.newValue); }
-		},
-		{headerName: "Master상품코드", field: "goodsCd", width: 150, cellClass: 'text-center', hide: true}
-		
-	];
+	
 
 	// Get GridOptions
 	var gridGoodsHstoryOptions = gagaAgGrid.getGridOptions(columnGoodsHstoryDefs);
 	gridGoodsHstoryOptions.enableBrowserTooltips = true;
-	var gridCodiGoodsOptions = gagaAgGrid.getGridOptions(columnCodiGoodsDefs);
-	gridCodiGoodsOptions.enableBrowserTooltips = true;
 	var gridGoodsComposeOptions = gagaAgGrid.getGridOptions(columnGoodsComposeDefs);
 	gridGoodsComposeOptions.enableBrowserTooltips = true;
 	// 드래그
@@ -650,11 +606,8 @@
 	//gridGoodsComposeOptions.rowDeselection = true;
 	//gridGoodsComposeOptions.enableMultiRowDragging = true;
 	//gridGoodsComposeOptions.rowSelection = 'multiple';
-	gridCodiGoodsOptions.suppressRowClickSelection = true;
-	gridCodiGoodsOptions.rowDragManaged = true;
 	
 	gridGoodsComposeOptions.rowHeight = 60; //이미지가 있을경우 높이 지정해야함.
-	gridCodiGoodsOptions.rowHeight = 60; //이미지가 있을경우 높이 지정해야함.
 	
 	//기준여부 표시
 	gridGoodsComposeOptions.getRowStyle = function(params) {
@@ -897,8 +850,7 @@
 			fnGoodsDetailSizeStockSearch(params);
 			//정보고시
 			fnGoodsDetailNotiInfoSearch(params);
-			//코디상품
-			fnGoodsDetailCodiSearch();
+			
 			
 			//구성상품
 			if ("G056_S" == result.goodsType || "G056_D" == result.goodsType){
@@ -945,11 +897,6 @@
 		gagaAgGrid.fetch("/goods/detail/hst/list?goodsCd=" + $('#goodsDetailForm input[name=goodsCd]').val() , gridGoodsHstoryOptions);
 	}
 	
-	//코디상품
-	var fnGoodsDetailCodiSearch = function() {
-		gagaAgGrid.fetch("/goods/detail/codi/list?goodsCd=" + $('#goodsDetailForm input[name=goodsCd]').val() , gridCodiGoodsOptions);
-	}
-	
 	//정보고시 콜백
 	var fnGoodsDetailNotiInfoSearchCallback = function(result) {
 		if (result == null) return;
@@ -1628,11 +1575,6 @@
 					$("#goodsDetailForm input[name=chDataYn]").val('N');
 				}
 				
-				// 코디 상품
-				var codiGoodsData = gagaAgGrid.getAllRowData(gridCodiGoodsOptions);
-				var jsonDataCodiGoods = JSON.stringify(codiGoodsData);
-				$('#goodsDetailForm input[name=codiGoodsList]').val(jsonDataCodiGoods);
-				
 				//구성상품
 				var allData = gagaAgGrid.getAllRowData(gridGoodsComposeOptions);
 				var jsonData = JSON.stringify(allData);
@@ -1898,89 +1840,6 @@
 		gridGoodsComposeOptions.api.refreshCells();
 	}
 	
-	// 코디상품 조회 팝업
-	var fnOpenCodiGoodsPopup = function() {
-		cfnOpenGoodsPopup('fnGoodsDetailCodiGoods');
-	}
-
-	// 코디상품 조회 팝업 - 상품추가
-	var fnGoodsDetailCodiGoods = function(goodsData) {
-		if (goodsData.length < 1) return;
-		
-		// 기존상품
-		var oldCodiGoodsList = gagaAgGrid.getAllRowData(gridCodiGoodsOptions);
-		var idx = oldCodiGoodsList.length+1; 
-		var goodsCd = $('#goodsDetailForm input[name=goodsCd]').val();
-		var isExist = false;
-		goodsData.forEach(function(goods){
-			isExist = false;
-
-			gridCodiGoodsOptions.api.forEachNode(function(rowNode, index) {
-
-				if (goods.goodsCd == rowNode.data.codiGoodsCd){
-					isExist = true;
-				}
-			});
-			
-			if (goods.goodsCd == goodsCd) {
-				isExist = true;
-			}
-			
-			if(!isExist){
-				
-				var data = { 
-						  goodsCd : goodsCd
-						, codiGoodsCd: goods.goodsCd
-						, dispOrd: idx
-						, delYn: 'N'
-						, goodsStat : goods.goodsStat
-						, goodsNm : goods.goodsNm
-						, currPrice : goods.currPrice
-						, formalGb : goods.formalGb
-						, imgType : goods.imgType
-						, imgPath1 : goods.imgPath1
-						, imgPath6 : goods.imgPath6
-						};
-				gridCodiGoodsOptions.api.updateRowData({add: [data], addIndex: idx});
-				
-				idx++;
-				$('#goodsDetailForm').find('.tabs .tabsNav li:eq(4) a').attr("style", "color:red;");
-			
-			}
-		});
-		gridGoodsComposeOptions.api.refreshCells();
-	}
-
-	// 코디 상품 삭제
-	$('#btnCodiGoodsDelete').on('click', function() {
-		var selectedData = gridCodiGoodsOptions.api.getSelectedRows();
-		if (selectedData.length == 0) {
-			mcxDialog.alert('선택된 행이 없습니다.');
-			return;
-		}
-
-		//화면에서 삭제
-		var removedData = gagaAgGrid.removeRowData(gridCodiGoodsOptions, false);
-		
-		if (removedData.length > 0) {
-
-			mcxDialog.confirm('삭제하시겠습니까?', {
-				cancelBtnText: "취소",
-				sureBtnText: "확인",
-				sureBtnClick: function(){
-					var deleteData = [];
-
-					$.each(removedData, function(idx, item) {
-						deleteData.push(item);
-					});
-
-					var jsonData = JSON.stringify(deleteData);
-					gagajf.ajaxJsonSubmit('/goods/codi/delete', jsonData);
-				}
-			});
-		}
-	});
-	
 	//엑셀 상품 조회
 	$('#btnGoodsDealSearchExcel').on('click', function() {
 		cfnExcelUploadPopup('goodsDetailExcelUpload', 'goodsDetailExcelUpload');
@@ -2009,7 +1868,6 @@
 	$(document).ready(function() {
 
 		gagaAgGrid.createGrid('gridGoodsHstoryList', gridGoodsHstoryOptions);
-		gagaAgGrid.createGrid('gridGoodsCodiList', gridCodiGoodsOptions);
 		gagaAgGrid.createGrid('gridGoodsComposeList', gridGoodsComposeOptions);
 
 		fnGoodsDeailSearch();

+ 411 - 0
style24.admin/src/main/webapp/WEB-INF/views/goods/GoodsEpSkipForm.html

@@ -0,0 +1,411 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : GoodsEpSkipForm.html
+ * @desc    : 네이버EP제외상품관리
+ *============================================================================
+ * PASTEL
+ * Copyright(C) 2019 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2020.11.03   eskim       최초 작성
+ *******************************************************************************
+ -->
+	<div id="main">
+		<!-- 메인타이틀 영역 -->
+		<div class="main-title">
+		</div>
+		<!-- //메인타이틀 영역 -->
+		<!-- 메뉴 설명 -->
+		<div class="infoBox menu-desc">
+		</div>
+		<form id="goodsEpSkipListForm" name="goodsEpSkipListForm" action="#" th:action="@{'/goods/ep/skip/list'}">
+		<input type="hidden" id="searchGb" name="searchGb" />
+		<input type="hidden" id="arrGoodsCd" name="arrGoodsCd" />
+ 		<!-- 패널 영역1 -->
+		<div class="panelStyle" >
+			<!-- TITLE -->
+			<div class="panelTitle">
+				<h3><i class="fa fa-info-circle"></i>아래 검색조건 중 하나를 꼭 입력해 주세요.</h3>
+			</div>
+			<!-- //TITLE -->
+			<div class="panelContent">
+				<table class="frmStyle">
+					<colgroup>
+						<col width="8%"/>
+						<col/>
+						<col width="8%"/>
+						<col width="25%"/>
+						<col width="8%"/>
+						<col width="20%"/>
+					</colgroup>
+					<tr>
+						<th>업체/브랜드</th>
+						<td>
+							<select name="supplyCompCd" id="supplyCompCd">
+								<option value="" th:if="${sessionInfo.roleCd} != 'B000'">[전체]</option>
+								<option th:if="${supplyCompList}" th:each="oneData, status : ${supplyCompList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+							</select>
+							<select name="brandCd" id="brandCd">
+								<option value="">[전체]</option>
+							</select>
+						</td>
+						<th>키워드</th>
+						<td>
+							<select name="search" id="search">
+								<option value="searchGoodsCd">상품코드</option>
+								<option value="searchGoodsNm">상품명</option>
+								<option value="searchGoodsNum">품번</option>
+								<option value="searchSupplyGoodsCd">업체상품코드</option>
+							</select>
+							<input type="text" class="w50p" name="condition" id="condition" maxlength="50"/>
+						</td>
+						<th>시즌/년도</th>
+						<td>
+							<select  name="styleYear" id="styleYear">
+								<option value="">[전체]</option>
+								<option th:if="${styleYearList}" th:each="oneData, status : ${styleYearList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+							</select>
+							<select  name="seasonCd" id="seasonCd">
+								<option value="">[전체]</option>
+								<option th:if="${seasonList}" th:each="oneData, status : ${seasonList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+							</select>
+						</td>
+					</tr>
+					<tr>
+						<th>비노출예약일</th>
+						<td colspan="5" id="sellTerms"></td>
+					</tr>
+				</table>
+				<ul class="panelBar">
+					<li class="center">
+						<button type="button" class="btn btn-gray btn-lg" id="btnInit" >초기화</button>
+						<button type="button" class="btn btn-info btn-lg" id="btnSearch" >조회</button>
+					</li>
+				</ul>	
+			</div>
+			<!-- //검색조건 영역 -->
+		</div>
+		<!-- 패널 영역1 -->
+		<div class="panelStyle">
+			<!-- 검색결과 영역 -->
+			<!-- 상단버튼 영역  -->
+			<ul class="panelBar">
+				<li class="left">
+					<button type="button" class="btn btn-default btn-lg" onclick="cfnDownloadSampleFile('SF003');">상품엑셀조회 양식 다운로드</button>
+					<button type="button" class="btn btn-base btn-lg" id="btnGoodsExcelUpLoad">엑셀조회</button>
+					<button type="button" class="btn btn-success  btn-lg" id="btnGoodsEpSkipSave">비노출예약등록</button>
+					<button type="button" class="btn btn-danger btn-lg" id="btnGoodsEpSkipDelete">비노출예약삭제</button>
+				</li>
+				<li class="right">
+					검색결과 : <strong><span id="gridRowTotalCount">0</span> 건</strong>&nbsp;
+					쪽번호 <span id="pgNo">0</span>/ <strong id="endPgNo">0</strong>&nbsp;&nbsp;
+					<select id="pageSize" name="pageSize">
+						<option value="50" selected="selected">50개씩 보기</option>
+						<option value="100">100개씩 보기</option>
+						<option value="500">500개씩 보기</option>
+						<option value="1000">1000개씩 보기</option>
+					</select>
+					<input type="hidden" name="pageNo" id="pageNo" value ="1"/>
+				</li>
+			</ul>
+			<!-- //상단버튼 영역  -->
+			<div id="gridList" style="width: 100%; height: 550px;" class="ag-theme-balham"></div>
+			<ul class="panelBar">
+				<li class="center">
+					<div class="tablePaging" id="goodsListPagination"></div>
+				</li>
+			</ul>
+			<!-- 검색결과 영역 -->
+		</div>
+		</form>
+		<!-- //패널 영역2 -->
+	</div>
+<script type="text/javascript" src="/ux/plugins/gaga/gaga.paging.js?v=2019072202"></script>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	var sessRoleCd = [[${sessionInfo.roleCd}]];
+	var goodsStatList = gagajf.convertToArray([[${goodsStatList}]]);
+	var formalGbList = gagajf.convertToArray([[${formalGbList}]]);
+	var columnDefs = [
+		{width: 40, minWidth: 40, cellClass: 'text-right', headerCheckboxSelection: true, checkboxSelection: true, filter: false},
+		{headerName: 'No', width: 60, cellClass: 'text-center',
+			valueGetter: function(params) { return cfnGridNumner('goodsEpSkipListForm',params.node.rowIndex, 'A');}
+		},
+		{headerName: "브랜드명", field: "brandEnm", width: 130, cellClass: 'text-center'},
+		{headerName: "상품코드", field: "goodsCd", width: 140, cellClass: 'text-center'},
+		{headerName: "상품명", field: "goodsNm", width: 180, cellClass: 'text-left'
+			,cellRenderer: function(params) {
+				return '<a href="javascript:void(0);">' + params.value + '</a>';
+			}
+		},
+		{headerName: "상품상태", field: "goodsStat" , width: 100, cellClass: 'text-center',
+			cellEditorParams: { values: gagaAgGrid.extractValues(goodsStatList) },
+			valueFormatter: function (params) { return gagaAgGrid.lookupValue(goodsStatList, params.value); },
+			valueParser: function (params) { return gagaAgGrid.lookupKey(goodsStatList, params.newValue); }
+		},
+		{headerName: "예약시작일", field: "applyStdt", width: 150, cellClass: 'text-center',
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD") : '';
+			}
+		},
+		{headerName: "예약종료일", field: "applyEddt", width: 150, cellClass: 'text-center',
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD") : '';
+			}
+		},
+		{headerName: "등록일시", field: "regDt", width: 150, cellClass: 'text-center',
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss") : '';
+			}
+		},
+		{headerName: "등록자", field: "regNm", width: 100, cellClass: 'text-center'},
+		{headerName: "수정일시", field: "updDt", width: 150, cellClass: 'text-center',
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss") : '';
+			}
+		},
+		{headerName: "수정자", field: "updNm", width: 100, cellClass: 'text-center'}
+	];
+	
+	// Get GridOptions
+	var gridOptions = gagaAgGrid.getGridOptions(columnDefs);
+
+	// 중복 선택 가능
+	gridOptions.rowSelection = 'multiple';
+	gridOptions.suppressRowClickSelection = true;
+
+	// Row Click
+	gridOptions.onCellClicked = function(event) {
+		var goodsCd = event.data.goodsCd;
+		if (event.colDef.field == "goodsNm"){
+			cfnOpenGoodsDetailPopup('U',goodsCd);
+		}else if (event.colDef.field == "goodsCd"){
+			
+		}
+	}
+
+	// 초기화 클릭시
+	$('#btnInit').on('click', function() {
+		fnInit();
+	});
+	
+	var fnInit = function(){
+		$('#goodsEpSkipListForm')[0].reset();
+		$("#goodsEpSkipListForm input[type=checkbox]").removeClass("checked");
+		$("#goodsEpSkipListForm input[type=checkbox]").parent("label").removeClass("checked");
+		$("#goodsEpSkipListForm input[type=radio][checked]").parent("label").addClass("checked");
+	}
+	
+	// 조회클릭시
+	$('#btnSearch').on('click', function() {
+		$("#goodsEpSkipListForm input[name=pageNo]").val('1');
+		fnGoodsEpSkipListSearch('BASIC');
+	});
+
+	// 조회
+	var fnGoodsEpSkipListSearch = function(gbn) {
+		
+		if (typeof(gbn) != 'undefined' &&  gbn == 'EXCEL'){
+			$("#goodsEpSkipListForm input[name=searchGb]").val("EXCEL");
+		}else{
+			$("#goodsEpSkipListForm input[name=searchGb]").val("BASIC");
+		}
+		
+		if(!fnConditionCheck()) return;
+		
+		gagaPaging.init('goodsEpSkipListForm', fnSearchCallBack, 'goodsListPagination', $('#goodsEpSkipListForm').find('#pageSize').val());
+		gagaPaging.load($("#goodsEpSkipListForm input[name=pageNo]").val());
+	}
+
+	// 조회 (등록 창 닫을 때)
+	var fnGoodsRsvtEpSkipListSearch = function(gbn) {
+
+		if (typeof(gbn) != 'undefined' &&  gbn == 'EXCEL'){
+			$("#goodsEpSkipListForm input[name=searchGb]").val("EXCEL");
+		}else{
+			$("#goodsEpSkipListForm input[name=searchGb]").val("BASIC");
+		}
+
+		gagaPaging.init('goodsEpSkipListForm', fnSearchCallBack, 'goodsListPagination', $('#goodsEpSkipListForm').find('#pageSize').val());
+		gagaPaging.load($("#goodsEpSkipListForm input[name=pageNo]").val());
+	}
+
+	//검색 조건 확인
+	var fnConditionCheck = function(){
+		var formId = '#goodsEpSkipListForm';
+		var form = document.goodsEpSkipListForm;
+
+		if($("#goodsEpSkipListForm input[name=searchGb]").val() == "EXCEL") return true;
+		
+		var searchFlag = false;
+		var cnt = 0;
+
+		for (i = 0; i < form.elements.length; i++ ) {
+			var el = form.elements[i];
+
+			if ($(el).prop("type") == "text" || ($(el).prop("type") == "select-one" && el.name != "search" && el.name != "pageSize")) {
+				if (!(el.value == null || el.value == "")) {
+					cnt++;
+				}
+			}
+		}
+			
+		if(cnt > 0) searchFlag = true;
+
+		if(searchFlag == false){
+			mcxDialog.alert("검색조건을 입력하세요.");
+			return false;
+		}
+		
+		var fromDate = $('#goodsEpSkipListForm input[name=stDate]').val();
+		var toDate = $('#goodsEpSkipListForm input[name=edDate]').val();
+		
+		if (!gagajf.isNull(fromDate) || !gagajf.isNull(toDate)) {
+			
+			if (gagajf.isNull(fromDate) || gagajf.isNull(toDate)) {
+				mcxDialog.alertC("등록일 조회시 시작일자와 종료일자를 입력하세요.", {
+					sureBtnText: "확인",
+					sureBtnClick: function(){
+						$('#goodsEpSkipListForm input[name=stDate]').focus();
+					}
+				});
+				return false;
+			}
+
+			if (fromDate > toDate) {
+				mcxDialog.alertC("노출기간 시작일자는 종료일자 보다 클 수 없습니다.", {
+					sureBtnText: "확인",
+					sureBtnClick: function(){
+						$('#goodsEpSkipListForm input[name=stDate]').focus();
+					}
+				});
+				return false;
+			} 
+		}
+
+		return true;
+	}
+	
+	var fnSearchCallBack = function(result){
+
+		$('#goodsEpSkipListForm').find('#gridRowTotalCount').html(result.pageing.pageable.totalCount.addComma());
+		$('#goodsEpSkipListForm').find('#pageNo').val(result.pageing.pageable.pageNo.addComma());
+		$('#goodsEpSkipListForm').find('#pgNo').html(result.pageing.pageable.pageNo.addComma());
+		$('#goodsEpSkipListForm').find('#endPgNo').html(result.pageing.pageable.totalPage.addComma());
+		gridOptions.api.setRowData(result.goodsEpSkipList);
+		gagaPaging.createPagination(result.pageing.pageable);
+	}
+	
+	//페이징 
+	$('#goodsEpSkipListForm select[name=pageSize]').on('change', function() {
+		$("#goodsEpSkipListForm input[name=pageNo]").val('1');
+		fnGoodsEpSkipListSearch($("#goodsEpSkipListForm input[name=searchGb]").val());
+	});
+	
+	//업체변경시
+	$('#goodsEpSkipListForm select[name=supplyCompCd]').on('change', function() {
+		var actionUrl = '/renderer/supplyCompany/brand/list/' + $(this).val();
+
+		if(sessRoleCd == "G001_B000"){
+			actionUrl = '/renderer/brand/AuthBrandlist';
+		}
+		$("#goodsEpSkipListForm select[name=brandCd] option:gt(0)").remove();
+
+		cfnCreateCombo(actionUrl, $('#goodsEpSkipListForm select[name=brandCd]'), "[전체]", "");
+	});
+	
+	//엑셀 상품 조회
+	$('#btnGoodsExcelUpLoad').on('click', function() {
+		cfnExcelUploadPopup('goodsEpSkipExcelUpload', 'goodsEpSkipExcelUpload');
+	});
+	
+	var goodsEpSkipExcelUpload = function(result){
+		var data = {procJob : result.procJob
+					,excelFileNm : result.excelFileNm
+					};
+		var jsonData = JSON.stringify(data);
+		gagajf.ajaxJsonSubmit('/goods/search/excelupload/save', jsonData, fngoodsEpSkipExcelUploadCallBack);
+	}
+	
+	var fngoodsEpSkipExcelUploadCallBack = function(result){
+		fnGoodsEpSkipListSearch("EXCEL");
+	}
+	
+	//예약등록
+	$('#btnGoodsEpSkipSave').click(function(e) {
+		var actionUrl = "/goods/ep/skip/popup/form";
+		cfnOpenModalPopup(actionUrl, 'popupGoodsEpSkip');
+	});
+	
+	//예약삭제
+	$('#btnGoodsEpSkipDelete').click(function(e) {
+		//상품선택여부 확인처리 추가
+		var selectedData = gridOptions.api.getSelectedRows();
+
+		if (selectedData.length == 0) {
+			mcxDialog.alert('선택된 행이 없습니다.');
+			return false;
+		}
+		
+		var arrGoodsCd = [];
+		var arrGoodsEpSkipSq = [];
+		var chkFlag = false;
+		$.each(selectedData, function(idx, item) {
+			
+			var toDateStr = new Date().format("YYYYMMDDHHmmss");
+			if (toDateStr > item.applyEddt){
+				chkFlag = true;
+				mcxDialog.alertC("종료된 네이버 EP 제외 상품은 삭제할 수 없습니다.",  {
+					sureBtnText: "확인",
+					sureBtnClick: function(){
+						$('#goodsRsvtEpSkipForm input[name=applyEdYMD]').focus();
+					}
+				});
+				return false;
+			}
+		
+			arrGoodsCd.push(item.goodsCd);
+			arrGoodsEpSkipSq.push(item.goodsEpSkipSq);
+		});
+
+		if (chkFlag){
+			return;
+		}
+		
+		mcxDialog.confirm('삭제하시겠습니까?', {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				var data = {arrGoodsCd : arrGoodsCd
+						,arrGoodsEpSkipSq : arrGoodsEpSkipSq
+							};
+			
+				var jsonData = JSON.stringify(data);
+				gagajf.ajaxJsonSubmit('/goods/rsvt/ep/skip/delete', jsonData, fnGoodsEpSkipResDeleteCallBack);
+			}
+		});
+	});
+	
+	var fnGoodsEpSkipResDeleteCallBack = function(){
+		//fnGoodsRsvtEpSkipListSearch($("#goodsEpSkipListForm input[name=searchGb]").val());
+	}
+	
+	$(document).ready(function() {
+
+		cfnCreateCalendar('#sellTerms', 'applyStdt', 'applyEddt', true, '예약일', 'X');
+		var chkBeforSkipFlag = '&nbsp;&nbsp;<label class="chkBox"><input type="checkbox" name="beforSkipFlag" value="Y" >이전데이터 제외</label>';
+		$("#goodsEpSkipListForm").find('#sellTerms').append(chkBeforSkipFlag);
+		
+		// Create a agGrid
+		gagaAgGrid.createGrid('gridList', gridOptions);
+
+	});
+
+/*]]>*/
+</script>
+ 	
+</html>

+ 265 - 0
style24.admin/src/main/webapp/WEB-INF/views/goods/GoodsEpSkipPopupForm.html

@@ -0,0 +1,265 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : GoodsEpSkipPopupForm.html
+ * @desc    : 네이버 EP 제외 상품 예약 화면
+ *============================================================================
+ * PASTEL
+ * Copyright(C) 2019 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2020.11.03   eskim       최초 작성
+ *******************************************************************************
+ -->	
+	<div class="modalPopup"  data-width="750" >
+		<div class="panelStyle">
+			<div class="panelTitle">
+				<h2>상품비노출예약</h2>
+				<button type="button" class="close" onclick="uifnPopupClose('popupGoodsEpSkip')"><i class="fa fa-times"></i></button>
+			</div>
+			<form id="goodsRsvtEpSkipForm" name="goodsRsvtEpSkipForm" >
+			<input type="hidden" id="goodsCd" name="goodsCd" />
+			<div class="panelContent">
+				<table class="frmStyle">
+					<colgroup>
+						<col style="width:10%;"/>
+						<col/>
+					</colgroup>
+					<tr>
+						<th>비노출예약일<em class="required" title="필수"></em></th>
+						<td>
+							<input name="applyStYMD" id="applyStYMD" type="text" class="w80 schDate" maxlength="10" required="required" data-valid-name="예약시작일" />
+							<input name="applyStdt" id="applyStdt" type="hidden" />
+							~
+							<input name="applyEdYMD" id="applyEdYMD" type="text" class="w80 schDate" maxlength="10" required="required" data-valid-name="예약 종료일" />
+							<input name="applyEddt" id="applyEddt" type="hidden" />
+						</td>
+					</tr>
+				</table>
+			</div>
+			<ul class="panelBar">
+				<li class="left">
+					<button type="button" class="btn btn-danger btn-lg" id="btnDeleteGoodsEpSkip">상품삭제</button>
+				</li>
+				<li class="right">
+					<button type="button" class="btn btn-base btn-lg" id="btnSearchExcel">엑셀조회</button>
+					<button type="button" class="btn btn-info btn-lg" id="btnSearchGoods">상품조회</button>
+				</li>
+			</ul>
+			<div id="gridGoodsRsvtEpSkipList" style="width: 100%; height: 500px;" class="ag-theme-balham"></div>
+			</form>
+			<ul class="panelBar">
+				<li class="right">
+					<button type="button" class="btnRight btn btn-base btn-lg" id=btnSaveGoodsRsvtTnm>저장</button>
+				</li>
+			</ul>
+		</div>
+	</div>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	var rsvtGoodsTnmColumnDefs = [
+		{width: 40, minWidth: 40, cellClass: 'text-center', headerCheckboxSelection: true, checkboxSelection: true, filter: false},
+		{headerName: 'No', width: 60, cellClass: 'text-center',valueGetter: function(params) { return params.node.rowIndex+1}},
+		{headerName: "브랜드명", field: "brandEnm", width: 140, cellClass: 'text-center'},
+		{headerName: "상품코드", field: "goodsCd", width: 140, cellClass: 'text-center'},
+		{headerName: "상품명", field: "goodsNm", width: 250, cellClass: 'text-left'}
+	];
+	
+	// Get GridOptions
+	var rsvtGoodsEpSkipGridOptions = gagaAgGrid.getGridOptions(rsvtGoodsTnmColumnDefs);
+
+	// 중복 선택 가능
+	rsvtGoodsEpSkipGridOptions.rowSelection = 'multiple';
+	rsvtGoodsEpSkipGridOptions.suppressRowClickSelection = true;
+
+	// 상품 조회 클릭 시
+	$('#btnSearchGoods').on('click', function() {
+		cfnOpenGoodsPopup('fnSearchGoods');
+	});
+
+	// 상품 조회 콜백함수
+	var fnSearchGoods = function(result) {
+		if (result.length < 1) return;
+		var oldData = gagaAgGrid.getAllRowData(rsvtGoodsEpSkipGridOptions);
+		$.each(result, function(idx, item) {
+			var isInvalid = false;
+			if (oldData != null && oldData.length != 0){
+				oldData.forEach(function(oneData){
+					if(oneData.goodsCd == item.goodsCd){
+						isInvalid = true;
+						return true;
+					}
+				});
+				if(isInvalid){
+					return isInvalid;
+				}
+			}
+			gagaAgGrid.addRowData(rsvtGoodsEpSkipGridOptions, {"goodsCd" : item.goodsCd, "goodsNm" : item.goodsNm, "brandEnm" : item.brandEnm});
+		});
+		uifnPopClose('popupGoods');
+		return;
+	};
+
+	// 저장 클릭 시
+	$('#btnSaveGoodsRsvtTnm').on('click', function() {
+		
+		var fromDate = $('#goodsRsvtEpSkipForm input[name=applyStYMD]').val();
+		var toDate = $('#goodsRsvtEpSkipForm input[name=applyEdYMD]').val();
+
+		if (gagajf.isNull(fromDate)) {
+			mcxDialog.alertC("예약  시작일자를 입력하세요.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtEpSkipForm input[name=applyStYMD]').focus();
+				}
+			});
+			return false;
+		}
+		
+		if (gagajf.isNull(toDate)) {
+			mcxDialog.alertC("예약  종료일자를 입력하세요.",  {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtEpSkipForm input[name=applyEdYMD]').focus();
+				}
+			});
+			return false;
+		}
+
+		if (fromDate > toDate) {
+			mcxDialog.alertC("예약 시작일자는 종료일자 보다 클 수 없습니다.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtEpSkipForm input[name=applyEdYMD]').focus();
+				}
+			});
+			return false;
+		} 
+		
+		var applyStdt = $('#goodsRsvtEpSkipForm input[name=applyStYMD]').val().replaceAll("-","");
+
+		var applyEddt = $('#goodsRsvtEpSkipForm input[name=applyEdYMD]').val().replaceAll("-","");
+		
+		$('#goodsRsvtEpSkipForm input[name=applyStdt]').val(applyStdt);
+		$('#goodsRsvtEpSkipForm input[name=applyEddt]').val(applyEddt);
+		
+		if ($('#goodsRsvtEpSkipForm input[name=applyStdt]').val() > $('#goodsRsvtEpSkipForm input[name=applyEddt]').val()) {
+			mcxDialog.alertC("예약 시작일자는 종료일자 보다 클 수 없습니다.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtEpSkipForm input[name=applyEdYMD]').focus();
+				}
+			});
+			return false;
+		}
+		
+		var toDateStr = new Date().format("YYYYMMDD");
+
+		if (toDateStr > applyStdt){
+			mcxDialog.alertC("예약 시작일시는 현재일시 보다 작을 수 없습니다.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtEpSkipForm input[name=applyStYMD]').focus();
+				}
+			});
+			return false;
+		}
+
+		if (toDateStr >= applyEddt){
+			mcxDialog.alertC("예약 종료일시는 현재일시 보다 작거나 같을 수 없습니다.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtEpSkipForm input[name=applyEdYMD]').focus();
+				}
+			});
+			return false;
+		}
+		
+		mcxDialog.confirm('저장하시겠습니까?', {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				var arrGoodsCd = [];
+				var allRowData = gagaAgGrid.getAllRowData(rsvtGoodsEpSkipGridOptions);
+				allRowData.forEach(function(item, index) {
+					arrGoodsCd.push(item.goodsCd);
+				});
+
+				var data = {applyStdt : $('#goodsRsvtEpSkipForm input[name=applyStdt]').val()
+						, applyEddt : $('#goodsRsvtEpSkipForm input[name=applyEddt]').val()
+						, arrGoodsCd : arrGoodsCd
+				};
+				
+				var jsonData = JSON.stringify(data);
+				gagajf.ajaxJsonSubmit('/goods/rsvt/ep/skip/save', jsonData, fnGoodsRsvtEpSkipListFormClose);
+			}
+		});
+	});
+
+	//엑셀 상품 조회
+	$('#btnSearchExcel').on('click', function() {
+		cfnExcelUploadPopup('goodsRsvtEpSkipExcelUpload', 'goodsRsvtEpSkipExcelUpload');
+	});
+
+	var goodsRsvtEpSkipExcelUpload = function(result){
+		var data = {procJob : result.procJob
+			,excelFileNm : result.excelFileNm
+		};
+		var jsonData = JSON.stringify(data);
+		gagajf.ajaxJsonSubmit('/goods/search/excelupload/save', jsonData, fnRsvtGoodsEpSkipExcelUploadCallBack);
+	}
+
+	var fnRsvtGoodsEpSkipExcelUploadCallBack = function(result){
+		gagajf.ajaxJsonSubmit('/goods/excel/upload/goods/list', '', fnExcelSearchCallBack);
+	}
+
+	var fnExcelSearchCallBack = function(result){
+		if (result.goodsExcelList.length < 1) return;
+		var oldData = gagaAgGrid.getAllRowData(rsvtGoodsEpSkipGridOptions);
+		$.each(result.goodsExcelList, function(idx, item) {
+			var isInvalid = false;
+			if (oldData != null && oldData.length != 0){
+				oldData.forEach(function(oneData){
+					if(oneData.goodsCd == item.goodsCd){
+						isInvalid = true;
+						return true;
+					}
+				});
+				if(isInvalid){
+					return isInvalid;
+				}
+			}
+			gagaAgGrid.addRowData(rsvtGoodsEpSkipGridOptions, {"goodsCd" : item.goodsCd, "goodsNm" : item.goodsNm, "brandEnm" : item.brandEnm});
+		});
+		return;
+	}
+	
+	// 조회상품 삭제
+	$('#btnDeleteGoodsEpSkip').on('click', function() {
+		var selectedData = rsvtGoodsEpSkipGridOptions.api.getSelectedRows();
+		if (selectedData.length == 0) {
+			mcxDialog.alert('선택된 행이 없습니다.');
+			return;
+		}
+
+		//화면에서 삭제
+		var removedData = gagaAgGrid.removeRowData(rsvtGoodsEpSkipGridOptions, false);
+	});
+	
+	//창종료
+	var fnGoodsRsvtEpSkipListFormClose = function(){
+		uifnPopClose('popupGoodsEpSkip');
+		fnGoodsEpSkipResDeleteCallBack();
+	}
+
+	$(document).ready(function() {
+		// Create a agGrid
+		gagaAgGrid.createGrid('gridGoodsRsvtEpSkipList', rsvtGoodsEpSkipGridOptions);
+	});
+
+/*]]>*/
+</script>
+</html>

+ 3 - 1
style24.admin/src/main/webapp/WEB-INF/views/goods/GoodsPopupListForm.html

@@ -184,7 +184,8 @@
 					<button type="button" class="btn btn-info btn-lg" id="btnPopupGoodsSearch" >조회</button>
 				</li>
 			</ul>
-			</form>
+		</div>	
+			
 			<ul class="panelBar">
 				<li>검색 결과 : <em><span id="gridRowTotalCount">0</span></em>개가 검색되었습니다.
 				<input type="hidden" name="pageNo" id="pageNo" value ="1"/>
@@ -210,6 +211,7 @@
 					<button type="button" class="btnRight btn btn-base btn-lg" id="btnPopupGoodsApply">적용</button>
 				</li>
 			</ul>
+			</form>
 			<!-- //버튼 배치 영역 -->
 		</div>
 	</div>

+ 514 - 0
style24.admin/src/main/webapp/WEB-INF/views/goods/GoodsSetForm.html

@@ -0,0 +1,514 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : GoodsSetForm.html
+ * @desc    : 세트상품 구성 관리
+ *============================================================================
+ * SISUN
+ * Copyright(C) 2019 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2020.05.26   eskim       최초 작성
+ *******************************************************************************
+ -->	
+	<ul class="popup modal" data-width="1100" >
+		<li class="mdPopTitle">
+			<strong>세트 상품 구성</strong>
+			<button type="button" class="close" onclick="fnGoodsSetFormClose()"><i class="fa fa-times"></i></button>
+		</li>
+		<li class="mdPopContent" style="height:610px; overflow-y: auto;">
+			<ul class="notice">
+				<li>구성상품 등록시 기본값&nbsp;
+					<!-- 아이콘 툴팁 -->
+					<div class="iconTooltip">
+						<i class="fa fa-info" aria-hidden="true"></i>
+						<span class="left" style="width:400px; text-align:left;">
+						<!-- class="left" 또는 class="right" -->
+							- 상품상태 : 정보부족<br/>
+							- TAG가 : 구성상품의 TAG가 합<br/>
+							- 정상가 : 구성상품의 정상가 합<br/>
+							- 판매가 : 구성상품 판매가 입력값의 합<br/>
+							- 브랜드코드 : 구성상품의 기준여부 'Y'상품의 브랜드코드<br/>
+							- 품목코드 : 구성상품의 기준여부 'Y'상품의 품목코드<br/>
+							- 포인트 : 구성상품의 기준여부 'Y'상품의 브랜드 포인트<br/>
+							- 기본배송비 : 구성상품의 기준여부 'Y'상품의 브랜드 기본배송비<br/>
+							- 무료배송비기준 : 구성상품의 기준여부 'Y'상품의 브랜드 무료배송비기준<br/>
+							- 외부몰 판매가 : 구성상품 판매가 입력값의 합<br/>
+							- 상품이미지 : 상품상세에서 이미지 경로 등록 처리
+						</span>
+					</div>
+					<!-- //아이콘 툴팁 --> 
+				</li>
+			</ul>
+			<form id="goodsSetForm" name="goodsSetForm" th:method="post">
+			<input type="hidden" id="extendGoodsList" name="extendGoodsList" />
+			<table class="frmStyle">
+				<colgroup>
+					<col width="10%"/>
+					<col/>
+					<col width="10%"/>
+					<col width="23%"/>
+					<col width="10%"/>
+					<col width="23%"/>
+				</colgroup>
+				<tr>
+					<th>상품명<i class="star"></i></th>
+					<td><input type="text" id="goodsNm" name="goodsNm" maxlength="60"/></td>
+					<th>자사노출여부<i class="star"></i></th>
+					<td><label><input type="radio" name="selfMallYn" id="selfMallYnY" value="Y" checked/>Y</label>
+						<label><input type="radio" name="selfMallYn" id="selfMallYnN" value="N"/>N</label>
+					</td>
+					<th>성별<i class="star"></i></th>
+					<td><select  name="sexGb" id="sexGb">
+							<option value="">[전체]</option>
+							<option th:if="${sexGbList}" th:each="oneData, status : ${sexGbList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+						</select>
+					</td>
+				</tr>
+				<tr>
+					<th>년도/시즌<i class="star"></i></th>
+					<td colspan="3">
+						<select  name="styleYear" id="styleYear">
+							<option value="">[전체]</option>
+							<option th:if="${styleYearList}" th:each="oneData, status : ${styleYearList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+						</select>
+						<select  name="seasonCd" id="seasonCd">
+							<option value="">[전체]</option>
+							<option th:if="${seasonList}" th:each="oneData, status : ${seasonList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+						</select>
+					</td>
+					<th>원산지<i class="star"></i></th>
+					<td><input type="text" class="w100" id="makeNm" name="makeNm" maxlength="20" /></td>
+				</tr>
+				<tr>
+					<th>색상<i class="star"></i></th>
+					<td colspan="3">
+						<select name="colorCd" id="colorCd">
+						</select>
+					</td>
+					<th>제조년월일<i class="star"></i></th>
+					<td><input type="text" class="w100" id="makeYmd" name="makeYmd" maxlength="8" data-valid-type="date"/></td>
+					<!-- <th>매입유형<i class="star"></i></th>
+					<td colspan="3">
+						<select  name="buyingType" id="buyingType">
+							<option value="">[선택]</option>
+							<option th:if="${buyingTypeList}" th:each="oneData, status : ${buyingTypeList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+						</select>
+					</td> -->
+				</tr>
+			</table>
+			<div class="padT15 padB15">
+				<button type="button" class="btn btn-danger btn-lg" onclick="fnGoodsSetDeleteRow();">행삭제</button>
+				<button type="button" class="btn btnRight  btn-base btn-lg" onclick="fnOpenGoodsSetPopup();">구상상품추가</button>
+			</div>
+			<div id="gridGoodsSetList" style="height: 390px;" class="ag-theme-balham lh60"></div>
+		</form>	
+		</li>
+		<li class="mdPopBtnB padT15">
+			<th:block th:if="${sessionInfo.roleCd == '0000' OR sessionInfo.roleCd == 'A000' OR sessionInfo.roleCd == 'A101' OR sessionInfo.roleCd == 'A100' OR sessionInfo.roleCd == 'A001'}">
+			<button type="button" class="btn btnRight btn-success btn-lg" id="btnGoodsSetSave">저장</button>
+			</th:block>
+		</li>
+	</ul>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	var useYnList = cfnConvertToArray([[${useYnList}]]);
+	var goodsStatList = cfnConvertToArray([[${goodsStatList}]]);
+	// specify the columns
+	var columnGoodsSetDefs = [
+		{headerName: "정렬", field: "dispOrd", width: 70 ,hide: false, cellClass: 'text-center',  rowDrag: true },
+		{width: 40, minWidth: 40, cellClass: 'text-center', headerCheckboxSelection: true, checkboxSelection: true, filter: false},
+		//{headerName: 'No', width: 60, cellClass: 'text-center', valueGetter: function(params) { return params.node.rowIndex + 1 }},
+		{headerName: "이미지", field: "imgPath1", width: 100, height: 60, cellClass: 'text-center'
+			,cellRenderer: function(params) {
+				if (params.data.imgType == "A"){
+					if(!gagajf.isNull(params.data.imgPath6)){
+						return '<img width="60" src="'+ uploadGoodsUrl+params.data.imgPath6.replace("/1000/","/100/") + '" alt=""  onerror="this.src=\'/image/no.gif\';"/>';
+					}else{
+						return '<img width="60" src="'+ uploadGoodsUrl+params.value.replace("/1000/","/100/") + '" alt=""  onerror="this.src=\'/image/no.gif\';"/>';
+					}	
+				}else{
+					if(!gagajf.isNull(params.data.imgPath6)){
+						return '<img width="60" src="'+ params.data.imgPath1 + '" alt="" onerror="this.src=\'/image/no.gif\';"/>';
+					}else{
+						return '<img width="60" src="'+ params.value + '" alt="" onerror="this.src=\'/image/no.gif\';"/>';
+					}
+					
+				}
+			}
+		},
+		{headerName: "구성상품코드", field: "extendGoodsCd" , width: 130, cellClass: 'text-center'},
+		{headerName: "구성상품명", field: "goodsNm" , width: 130, cellClass: 'text-left'},
+		//{headerName: "순서", field: "dispOrd" , width: 100, cellClass: 'text-center',editable: true, required: true},
+		{headerName: "수량", field: "qty" , width: 80, cellClass: 'text-right',editable: true, required: true},
+		{headerName: "상품판매가", field: "extendCurrPrice" , width: 120, cellClass: 'text-right',editable: true, required: true,
+			cellEditor: 'textCellEditor',
+			cellEditorParams: { maxlength: 14, validType: 'numeric'}
+		},
+		/* {headerName: "임직원판매가", field: "extendStaffCurrPrice" , width: 120, cellClass: 'text-right',editable: true, required: true,
+			cellEditor: 'textCellEditor',
+			cellEditorParams: { maxlength: 14, validType: 'numeric'}
+		}, */
+		{headerName: "기준여부(품목/전시카테)", field: "baseYn" , width: 160, cellClass: 'text-center',editable: true, required: true,
+			cellEditor: 'agRichSelectCellEditor',
+			cellEditorParams: { values: gagaAgGrid.extractValues(useYnList) },
+			valueFormatter: function (params) { return gagaAgGrid.lookupValue(useYnList, params.value); },
+			valueParser: function (params) { return gagaAgGrid.lookupKey(useYnList, params.newValue); }
+		},
+		{headerName: "상품상태", field: "goodsStat" , width: 100, cellClass: 'text-center',
+			cellEditorParams: { values: gagaAgGrid.extractValues(goodsStatList) },
+			valueFormatter: function (params) { return gagaAgGrid.lookupValue(goodsStatList, params.value); },
+			valueParser: function (params) { return gagaAgGrid.lookupKey(goodsStatList, params.newValue); }
+		},
+		{headerName: "자사/입점구분", field: "selfGoodsYn" , width: 100, cellClass: 'text-center'}
+		/* {headerName: "등록일자", field: "regDt", width: 150, cellClass: 'text-center' ,
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmm").format("YYYY-MM-DD HH:mm") : '';
+			}
+		},
+		{headerName: "등록자", field: "regId", width: 100, cellClass: 'text-center'},
+		{headerName: "수정일자", field: "regDt", width: 150, cellClass: 'text-center' ,
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmm").format("YYYY-MM-DD HH:mm") : '';
+			}
+		},
+		{headerName: "수정자", field: "regId", width: 100, cellClass: 'text-center'} */
+	];
+
+	// Get GridOptions
+	var gridGoodsSetOptions = gagaAgGrid.getGridOptions(columnGoodsSetDefs);
+	gridGoodsSetOptions.rowSelection = 'multiple';
+	gridGoodsSetOptions.suppressRowClickSelection = true;
+	
+	// 드래그
+	gridGoodsSetOptions.rowDragManaged = true;
+	gridGoodsSetOptions.rowHeight = 60; //이미지가 있을경우 높이 지정해야함.
+ 	
+	//기준여부 표시
+	gridGoodsSetOptions.getRowStyle = function(params) {
+		if ("Y" == params.data.baseYn) {
+			return { background: '#1ab394' };
+		}
+	}
+	
+	// Row 
+	gridGoodsSetOptions.onCellValueChanged = function(event) {
+		var rowIdx = null;
+		var isChangColor = true;
+		if (event.colDef.field == "baseYn"){
+			if (event.data.baseYn == "Y"){
+				rowIdx = event.rowIndex;
+				
+				//다른 기준여부 'Y'가 존재하는지 확인
+				gridGoodsSetOptions.api.forEachNode(function(rowNode, index) {
+					if (rowNode.data.baseYn == "Y" && index != rowIdx){
+						event.data.baseYn = event.oldValue;
+						gridGoodsSetOptions.api.updateRowData({update: [event.data]});
+						isChangColor = false;
+						return;
+					}
+				});
+				
+				if (!isChangColor){ 
+					mcxDialog.alert('다른 구성상품에 기준여부가 선택되어 있습니다.');
+					return;
+				}
+				
+				//기준상품의 색상 정보 읽어오기
+				var goodsCd = event.data.extendGoodsCd;
+				$("#goodsSetForm select[name=colorCd] option:gt(0)").remove();
+				cfnCreateCombo("/renderer/goods/brand/color/list/" + goodsCd, $('#goodsSetForm select[name=colorCd]'), "[선택]");
+			}	
+		}
+	}
+	
+	//창종료
+	var fnGoodsSetFormClose = function(){
+		uifnPopupClose('popupGoodsSet');
+	}
+	
+	$(document).ready(function() {
+		gagaAgGrid.createGrid('gridGoodsSetList', gridGoodsSetOptions);
+	});
+	
+	//상품조회 팝업
+	var fnOpenGoodsSetPopup = function() {
+		cfnOpenGoodsPopup('fnCreateGoodsSet');
+	}
+
+	// 상품추가
+	var fnCreateGoodsSet = function(goodsData) {
+		if (goodsData.length < 1) return;
+		
+		// 기존상품
+		var oldGoodsSetList = gagaAgGrid.getAllRowData(gridGoodsSetOptions);
+		var idx = oldGoodsSetList.length+1; 
+		
+		var isExist = false;
+		goodsData.forEach(function(goods){
+			isExist = false;
+
+			gridGoodsSetOptions.api.forEachNode(function(rowNode, index) {
+				if (goods.goodsCd == rowNode.data.extendGoodsCd){
+					isExist = true;
+				}
+			});
+
+			if (goods.goodsType != 'N'){
+				isExist = true;
+			}
+			
+			if(!isExist){
+				
+				var data = { 
+						  extendGoodsCd: goods.goodsCd
+						, goodsType: 'S'
+						, dispOrd: idx
+						, qty: 1
+						, extendCurrPrice: goods.currPrice
+						, extendStaffCurrPrice: goods.currPrice
+						, baseYn: 'N'
+						, goodsStat : goods.goodsStat
+						, useYn: 'Y'
+						, goodsNm : goods.goodsNm
+						, selfGoodsYn : goods.selfGoodsYn
+						, imgType : goods.imgType
+						, imgPath1 : goods.imgPath1
+						, imgPath6 : goods.imgPath6
+						};
+				//그리드 마지막에 추가해야함
+				gridGoodsSetOptions.api.updateRowData({add: [data], addIndex: idx});
+				gridGoodsSetOptions.api.refreshCells();
+				idx++;
+			
+			}
+		});
+	}
+	
+	// 저장클릭시
+	$('#btnGoodsSetSave').on('click', function() {
+
+		if(!fnGoodsSetConditionCheck()) return;
+		
+		mcxDialog.confirm('세트상품을 등록 하시겠습니까?',  {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				var extendGoodsList = gagaAgGrid.getAllRowData(gridGoodsSetOptions);
+				$("#goodsSetForm input[name=extendGoodsList]").val(JSON.stringify(extendGoodsList));
+				gagajf.ajaxFormSubmit("/goods/set/save", "#goodsSetForm", fnGoodsSetFormClose);
+			}
+		});
+	});
+
+	//저장 조건 확인
+	var fnGoodsSetConditionCheck = function(){
+		var optCheck = false;
+		
+		if(gagajf.isNull($("#goodsSetForm input[name=goodsNm]").val())){
+			mcxDialog.alertC('상품명을 입력해 주세요.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm input[name=goodsNm]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		if(gagajf.isNull($("#goodsSetForm select[name=colorCd]").val())){
+			mcxDialog.alertC('색상을 입력해 주세요.<br/>기준여부를 선택하시면<br/>해당브랜드의 색상을 노출합니다.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm select[name=colorCd]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		if (gagajf.isNull($("#goodsSetForm input[name=selfMallYn]").val())){
+			mcxDialog.alertC('자사노출여부를 선택해 주세요.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm input[name=selfMallYn]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		if(gagajf.isNull($("#goodsSetForm select[name=styleYear]").val())){
+			mcxDialog.alertC('년도을 선택해 주세요.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm select[name=styleYear]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		if(gagajf.isNull($("#goodsSetForm select[name=seasonCd]").val())){
+			mcxDialog.alertC('시즌을 선택해주세요.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm select[name=seasonCd]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		if(gagajf.isNull($("#goodsSetForm select[name=sexGb]").val())){
+			mcxDialog.alertC('성별을 선택해주세요.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm select[name=sexGb]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		if(gagajf.isNull($("#goodsSetForm input[name=makeNm]").val())){
+			mcxDialog.alertC('원산지를 입력해 주세요.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm input[name=makeNm]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		var makeYmd = $("#goodsSetForm input[name=makeYmd]").val();
+		
+		if(gagajf.isNull(makeYmd)){
+			mcxDialog.alertC('제조년월일를 입력해 주세요.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm input[name=makeYmd]").focus();
+				}
+			});	
+			return;
+		}
+		
+		if(makeYmd.length < 8){
+			mcxDialog.alertC('제조년월일를 바르게 주세요.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm input[name=makeYmd]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		if(isNaN(Date.parse(makeYmd.substr(0, 4) +'-'+ makeYmd.substr(4, 2) +'-'+ makeYmd.substr(6, 2)))){
+			mcxDialog.alertC('날짜형식이 아닙니다.', {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsSetForm input[name=makeYmd]").focus();
+				}
+			});	
+			return false;
+		}
+		
+		var allData = gagaAgGrid.getAllRowData(gridGoodsSetOptions);
+		// Validation
+		if (!gagaAgGrid.validation(gridGoodsSetOptions, allData))
+			return false;
+		
+		var comSupplyCompCd = '';
+		var comSelfGoodsYn = '';
+		//기준여부 Y  존재하는지 확인
+		var checkBaseYn = false;
+		optCheck = false;
+		$.each(allData, function(index, item) {
+			if (index == 0){
+				comSelfGoodsYn = item.selfGoodsYn;
+				comSupplyCompCd = item.supplyCompCd;
+			}
+			
+			if (item.baseYn == "Y"){
+				checkBaseYn = true;
+			}
+			
+			if(item.goodsStat != "90"){
+				optCheck = true;
+				mcxDialog.alertC("상품상태를 확인해 주세요.", {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						gridGoodsSetOptions.api.setFocusedCell(index, "goodsStat", null);
+					}
+				});	
+				return false;
+			}
+			
+			if(Number(item.qty)  ==  0){
+				optCheck = true;
+				mcxDialog.alertC("수량을 입력해 주세요.", {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						gridGoodsSetOptions.api.setFocusedCell(index, "qty", null);
+					}
+				});	
+				return false;
+			}
+			
+			if (comSelfGoodsYn != item.selfGoodsYn){
+				optCheck = true;
+				mcxDialog.alertC("구상상품중 자사/입점상품 구분값이 다릅니다.\n확인해 주세요", {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						gridGoodsSetOptions.api.setFocusedCell(index, "goodsCd", null);
+					}
+				});	
+				return false;
+			}else{
+				if (comSelfGoodsYn == "N" && (comSupplyCompCd != item.supplyCompCd)){
+					optCheck = true;
+					mcxDialog.alertC("구상상품중 입점은 같은 업체 상품만 가능합니다.\n확인해 주세요", {
+						sureBtnText: "확인",
+						sureBtnClick: function() {
+							gridGoodsSetOptions.api.setFocusedCell(index, "goodsCd", null);
+						}
+					});	
+					return false;
+				}
+			}
+			
+			
+		});
+		
+		if(optCheck) {
+			return false;
+		}
+		
+		if (!checkBaseYn){
+			mcxDialog.alert('구성상품중 기준여부를 선택해 주세요.');
+			return false;
+		}
+		
+		return true;
+	}
+	
+	//상품삭제
+	var fnGoodsSetDeleteRow = function() {
+		var selectedData = gagaAgGrid.selectedRowData(gridGoodsSetOptions);
+		
+		if (selectedData.length == 0) {
+			mcxDialog.alert('선택된 행이 없습니다.');
+			return;
+		}
+		
+		var iTotalCnt = 0;
+		var iCnt = 0;
+		$.each(selectedData, function(index, item) {	
+			iTotalCnt ++;
+			if (item.crud == "C"){
+				gridGoodsSetOptions.api.updateRowData({remove: [item]});	
+				iCnt ++;
+			}
+		});
+	}
+	
+/*]]>*/
+</script>
+</html>

+ 438 - 0
style24.admin/src/main/webapp/WEB-INF/views/goods/GoodsTitleReserveForm.html

@@ -0,0 +1,438 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : GoodsTitleReserveForm.html
+ * @desc    : 상품 타이틀 예약관리
+ *============================================================================
+ * PASTEL
+ * Copyright(C) 2020 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2020.10.30   eskim       최초 작성
+ *******************************************************************************
+ -->
+	<div id="main">
+		<!-- 메인타이틀 영역 -->
+		<div class="main-title">
+		</div>
+		<!-- //메인타이틀 영역 -->
+		<!-- 메뉴 설명 -->
+		<div class="infoBox menu-desc">
+		</div>
+		<form id="goodsTnmListForm" name="goodsTnmListForm" action="#" th:action="@{'/goods/title/reserve/list'}">
+		<input type="hidden" id="searchGb" name="searchGb" />
+		<input type="hidden" id="arrGoodsCd" name="arrGoodsCd" />
+ 		<!-- 패널 영역1 -->
+		<div class="panelStyle" >
+			<!-- TITLE -->
+			<div class="panelTitle">
+				<h3><i class="fa fa-info-circle"></i>아래 검색조건 중 하나를 꼭 입력해 주세요.</h3>
+			</div>
+			<!-- //TITLE -->
+			<div class="panelContent">
+				<table class="frmStyle">
+					<colgroup>
+						<col width="8%"/>
+						<col width="10%"/>
+						<col width="8%"/>
+						<col width="10%"/>
+						<col width="8%"/>
+						<col width="20%"/>
+						<col width="8%"/>
+						<col/>
+					</colgroup>
+					<tr>
+						<th>업체/브랜드</th>
+						<td colspan="5">
+							<select name="supplyCompCd" id="supplyCompCd">
+								<option value="" th:if="${sessionInfo.roleCd} != 'G001_B000'">[전체]</option>
+								<option th:if="${supplyCompList}" th:each="oneData, status : ${supplyCompList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+							</select>
+							<span id="multiBrand"></span>
+						</td>
+						<th rowspan="2">키워드</th>
+						<td rowspan="2">
+							<select name="search" id="search">
+								<option value="searchGoodsCd">상품코드</option>
+								<option value="searchGoodsNum">품번</option>
+								<option value="searchSupplyGoodsCd">업체상품코드</option>
+							</select>
+							<textarea class="textareaR2 w50p" name="condition" id="condition"></textarea>
+						</td>
+					</tr>
+					<tr>
+						<th>상품명</th>
+						<td>
+							<input type="text" class="w200" name="goodsTnm11" id="goodsTnm111" maxlength="50"/>
+						</td>
+						<th>예약타이틀</th>
+						<td>
+							<input type="text" class="w200" name="goodsTnm" id="goodsTnm" maxlength="50"/>
+						</td>
+						<th>시즌/년도</th>
+						<td>
+							<select  name="styleYear" id="styleYear">
+								<option value="">[전체]</option>
+								<option th:if="${styleYearList}" th:each="oneData, status : ${styleYearList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+							</select>
+							<select  name="seasonCd" id="seasonCd">
+								<option value="">[전체]</option>
+								<option th:if="${seasonList}" th:each="oneData, status : ${seasonList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+							</select>
+						</td>
+					</tr>
+					<tr>
+						<th>예약일</th>
+						<td colspan="7" id="sellTerms"></td>
+					</tr>
+				</table>
+				<ul class="panelBar">
+					<li class="center">
+						<button type="button" class="btn btn-gray btn-lg" id="btnInit" >초기화</button>
+						<button type="button" class="btn btn-info btn-lg" id="btnSearch" >조회</button>
+					</li>
+				</ul>	
+			</div>
+			<!-- //검색조건 영역 -->
+		</div>
+		<!-- 패널 영역1 -->
+		<div class="panelStyle">
+			<!-- 검색결과 영역 -->
+			<!-- 상단버튼 영역  -->
+			<ul class="panelBar">
+				<li>
+					<button type="button" class="btn btn-default btn-lg" onclick="cfnDownloadSampleFile('SF003');">상품엑셀조회 양식 다운로드</button>
+					<button type="button" class="btn btn-base btn-lg" id="btnGoodsExcelUpLoad">엑셀조회</button>
+					<button type="button" class="btn btn-success  btn-lg" id="btnGoodsTnmResSave">예약등록</button>
+					<button type="button" class="btn btn-danger btn-lg" id="btnGoodsTnmResDelete">예약삭제</button>
+				</li>
+				<li class="right">
+					검색결과 : <strong><span id="gridRowTotalCount">0</span> 건</strong>&nbsp;
+					
+					쪽번호 <span id="pgNo">0</span>/ <strong id="endPgNo">0</strong>&nbsp;&nbsp;
+					<select id="pageSize" name="pageSize">
+						<option value="50" selected="selected">50개씩 보기</option>
+						<option value="100">100개씩 보기</option>
+						<option value="500">500개씩 보기</option>
+						<option value="1000">1000개씩 보기</option>
+					</select>
+					<input type="hidden" name="pageNo" id="pageNo" value ="1"/>
+				</li>
+			</ul>
+			<!-- //상단버튼 영역  -->
+			<div id="gridList" style="width: 100%; height: 550px;" class="ag-theme-balham"></div>
+			<ul class="panelBar">
+				<li class="center">
+					<div class="tablePaging" id="goodsListPagination"></div>
+				</li>
+			</ul>
+			<!-- 검색결과 영역 -->
+		</div>
+		</form>
+		<!-- //패널 영역2 -->
+	</div>
+<script type="text/javascript" src="/ux/plugins/gaga/gaga.paging.js?v=2019072202"></script>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	var sessRoleCd = [[${sessionInfo.roleCd}]];
+	var goodsStatList = gagajf.convertToArray([[${goodsStatList}]]);
+	var formalGbList = gagajf.convertToArray([[${formalGbList}]]);
+
+	var columnDefs = [
+		{width: 40, minWidth: 40, cellClass: 'text-right', headerCheckboxSelection: true, checkboxSelection: true, filter: false},
+		{headerName: 'No', width: 60, cellClass: 'text-center',
+			valueGetter: function(params) { return cfnGridNumner('goodsTnmListForm',params.node.rowIndex, 'A');}
+		},
+		{headerName: "브랜드명", field: "brandGrpNm", width: 130, cellClass: 'text-center'},
+		{headerName: "상품코드", field: "goodsCd", width: 140, cellClass: 'text-center'},
+		{headerName: "상품명", field: "goodsNm", width: 180, cellClass: 'text-left'
+			,cellRenderer: function(params) {
+				return '<a href="javascript:void(0);">' + params.value + '</a>';
+			}
+		},
+		{headerName: "상품타이틀", field: "goodsTnm", width: 200, cellClass: 'text-left'},
+		{headerName: "예약상품타이틀", field: "regGoodsTnm", width: 200, cellClass: 'text-left'},
+		{headerName: "예약시작일시", field: "applyStdt", width: 150, cellClass: 'text-center',
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss") : '';
+			}
+		},
+		{headerName: "예약종료일시", field: "applyEddt", width: 150, cellClass: 'text-center',
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss") : '';
+			}
+		},
+		{headerName: "상품상태", field: "goodsStat" , width: 100, cellClass: 'text-center',
+			cellEditorParams: { values: gagaAgGrid.extractValues(goodsStatList) },
+			valueFormatter: function (params) { return gagaAgGrid.lookupValue(goodsStatList, params.value); },
+			valueParser: function (params) { return gagaAgGrid.lookupKey(goodsStatList, params.newValue); }
+		},
+		{headerName: "등록일시", field: "regDt", width: 150, cellClass: 'text-center',
+			cellRenderer: function(params) {
+				return !gagajf.isNull(params.value) ? params.value.toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss") : '';
+			}
+		},
+		{headerName: "등록자", field: "regNm", width: 100, cellClass: 'text-center'},
+		{headerName: "상품타이틀예약순번", field: "goodsTnmResSq", hide: true}
+	];
+	
+	// Get GridOptions
+	var gridOptions = gagaAgGrid.getGridOptions(columnDefs);
+
+	// 중복 선택 가능
+	gridOptions.rowSelection = 'multiple';
+	gridOptions.suppressRowClickSelection = true;
+	//gridOptions.rowHeight = 60; //이미지가 있을경우 높이 지정해야함.
+
+	// Row Click
+	gridOptions.onCellClicked = function(event) {
+		var goodsCd = event.data.goodsCd;
+		if (event.colDef.field == "goodsNm"){
+			cfnOpenGoodsDetailPopup('U',goodsCd);
+		}else if (event.colDef.field == "goodsCd"){
+			
+		}
+	}
+
+	// 초기화 클릭시
+	$('#btnInit').on('click', function() {
+		fnInit();
+	});
+	
+	var fnInit = function(){
+		$("#goodsTnmListForm input[name=siteCd]").prop("disabled", true);
+		$("#goodsTnmListForm input[name=siteCd]").addClass("formControl");
+		
+		$('#goodsTnmListForm')[0].reset();
+		//$("#goodsTnmListForm input[type=radio]").removeClass("checked");
+		$("#goodsTnmListForm input[type=checkbox]").removeClass("checked");
+		//$("#goodsTnmListForm input[type=radio]").parent("label").removeClass("checked");
+		$("#goodsTnmListForm input[type=checkbox]").parent("label").removeClass("checked");
+		$("#goodsTnmListForm input[type=radio][checked]").parent("label").addClass("checked");
+		$("#multiBrand").empty();
+	}
+	
+	// 조회클릭시
+	$('#btnSearch').on('click', function() {
+		$("#goodsTnmListForm input[name=pageNo]").val('1');
+		fnGoodsTnmListSearch('BASIC');
+	});
+
+	// 조회
+	var fnGoodsTnmListSearch = function(gbn) {
+		
+		if (typeof(gbn) != 'undefined' &&  gbn == 'EXCEL'){
+			$("#goodsTnmListForm input[name=searchGb]").val("EXCEL");
+		}else{
+			$("#goodsTnmListForm input[name=searchGb]").val("BASIC");
+		}
+		
+		if(!fnConditionCheck()) return;
+		
+		gagaPaging.init('goodsTnmListForm', fnSearchCallBack, 'goodsListPagination', $('#goodsTnmListForm').find('#pageSize').val());
+		gagaPaging.load($("#goodsTnmListForm input[name=pageNo]").val());
+	}
+
+	// 조회 (등록 창 닫을 때)
+	var fnGoodsRsvtTnmListSearch = function(gbn) {
+
+		if (typeof(gbn) != 'undefined' &&  gbn == 'EXCEL'){
+			$("#goodsTnmListForm input[name=searchGb]").val("EXCEL");
+		}else{
+			$("#goodsTnmListForm input[name=searchGb]").val("BASIC");
+		}
+
+		gagaPaging.init('goodsTnmListForm', fnSearchCallBack, 'goodsListPagination', $('#goodsTnmListForm').find('#pageSize').val());
+		gagaPaging.load($("#goodsTnmListForm input[name=pageNo]").val());
+	}
+
+	//검색 조건 확인
+	var fnConditionCheck = function(){
+		var formId = '#goodsTnmListForm';
+		var form = document.goodsTnmListForm;
+
+		if($("#goodsTnmListForm input[name=searchGb]").val() == "EXCEL") return true;
+		
+		var searchFlag = false;
+		var cnt = 0;
+
+		/* if( !gagajf.isNull($("#goodsTnmListForm select[name=supplyCompCd]").val())
+				|| !gagajf.isNull($("#goodsTnmListForm input[name=condition]").val())
+				|| (!gagajf.isNull($("#goodsTnmListForm input[name=stDate]").val()) && !gagajf.isNull($("#goodsTnmListForm input[name=edDate]").val()))
+			){
+			searchFlag = true;
+		}else{ */
+			for (i = 0; i < form.elements.length; i++ ) {
+				var el = form.elements[i];
+				if ($(el).prop("type") == "text" || $(el).prop("type") == "textarea" || ($(el).prop("type") == "select-one" && el.name != "search" && el.name != "pageSize")) {
+					if (!(el.value == null || el.value == "")) {
+						cnt++;
+					}
+				}
+			}
+			
+			if(cnt > 0) searchFlag = true;
+			
+		/* } */
+		
+		if(searchFlag == false){
+			mcxDialog.alert("검색조건을 입력하세요.");
+			return false;
+		}
+		
+		var fromDate = $('#goodsTnmListForm input[name=stDate]').val();
+		var toDate = $('#goodsTnmListForm input[name=edDate]').val();
+		
+		if (!gagajf.isNull(fromDate) || !gagajf.isNull(toDate)) {
+			
+			if (gagajf.isNull(fromDate) || gagajf.isNull(toDate)) {
+				mcxDialog.alertC("등록일 조회시 시작일자와 종료일자를 입력하세요.", {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						$('#goodsTnmListForm input[name=stDate]').focus();
+					}
+				});
+				return false;
+			}
+
+			if (fromDate > toDate) {
+				mcxDialog.alert("노출기간 시작일자는 종료일자 보다 클 수 없습니다.", {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						$('#goodsTnmListForm input[name=stDate]').focus();
+					}
+				});
+				return false;
+			} 
+		}
+
+		return true;
+	}
+	
+	var fnSearchCallBack = function(result){
+
+		$('#goodsTnmListForm').find('#gridRowTotalCount').html(result.pageing.pageable.totalCount.addComma());
+		$('#goodsTnmListForm').find('#pageNo').val(result.pageing.pageable.pageNo.addComma());
+		$('#goodsTnmListForm').find('#pgNo').html(result.pageing.pageable.pageNo.addComma());
+		$('#goodsTnmListForm').find('#endPgNo').html(result.pageing.pageable.totalPage.addComma());
+		gridOptions.api.setRowData(result.goodsTnmList);
+		gagaPaging.createPagination(result.pageing.pageable);
+	}
+	
+	//페이징 
+	$('#goodsTnmListForm select[name=pageSize]').on('change', function() {
+		$("#goodsTnmListForm input[name=pageNo]").val('1');
+		fnGoodsTnmListSearch($("#goodsTnmListForm input[name=searchGb]").val());
+	});
+	
+	//업체변경시
+	$('#goodsTnmListForm select[name=supplyCompCd]').on('change', function() {
+		var actionUrl = '/renderer/supplyCompany/brand/list/' + $(this).val();
+
+		if(sessRoleCd == "G001_B000"){
+			actionUrl = '/renderer/brand/AuthBrandlist';
+		}
+		cfnCreateMultiCombo(actionUrl,"multiBrand",  "[전체]",null, 'Y');
+	});
+	
+	//엑셀 상품 조회
+	$('#btnGoodsExcelUpLoad').on('click', function() {
+		cfnExcelUploadPopup('goodsTnmExcelUpload', 'goodsTnmExcelUpload');
+	});
+	
+	var goodsTnmExcelUpload = function(result){
+		var data = {procJob : result.procJob
+					,excelFileNm : result.excelFileNm
+					};
+		var jsonData = JSON.stringify(data);
+		gagajf.ajaxJsonSubmit('/goods/search/excelupload/save', jsonData, fnGoodsTnmExcelUploadCallBack);
+	}
+	
+	var fnGoodsTnmExcelUploadCallBack = function(result){
+		fnGoodsTnmListSearch("EXCEL");
+	}
+	
+	//예약등록 팝업
+	$('#btnGoodsTnmResSave').click(function(e) {
+		var actionUrl = "/goods/title/reserve/popup/form";
+		cfnOpenModalPopup(actionUrl, 'popupGoodsTitleReserve'); 
+	});
+	
+	//예약삭제
+	$('#btnGoodsTnmResDelete').click(function(e) {
+		//상품선택여부 확인처리 추가
+		var selectedData = gridOptions.api.getSelectedRows();
+
+		if (selectedData.length == 0) {
+			mcxDialog.alert('선택된 행이 없습니다.');
+			return false;
+		}
+		
+		var arrGoodsCd = [];
+		var arrGoodsTnmResSq = [];
+		var chkFlag = false;
+		//selectedData = gagaAgGrid.getAllRowData(gridOptions);
+		$.each(selectedData, function(idx, item) {
+			
+			if (gagajf.isNull(item.goodsTnmResSq) || item.goodsTnmResSq == "0"){
+				chkFlag = true;
+				mcxDialog.alert(item.goodsCd +"상품은 상품타이틀이 예약된 상품이 아닙니다.");
+				return false;
+			}
+			
+			var toDateStr = new Date().format("YYYYMMDDHHmmss");
+			if (toDateStr > item.applyEddt){
+				chkFlag = true;
+				mcxDialog.alertC("종료된 예약 상품은 삭제할 수 없습니다.", {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						$('#goodsRsvtTnmForm input[name=applyEdYMD]').focus();
+					}
+				});
+				return false;
+			}
+		
+			arrGoodsCd.push(item.goodsCd);
+			arrGoodsTnmResSq.push(item.goodsTnmResSq);
+		});
+
+		if (chkFlag){
+			return;
+		}
+		
+		mcxDialog.confirm('삭제하시겠습니까?',  {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				var data = {arrGoodsCd : arrGoodsCd
+						,arrGoodsTnmResSq : arrGoodsTnmResSq
+			};
+			
+			var jsonData = JSON.stringify(data);
+			gagajf.ajaxJsonSubmit('/goods/title/reserve/delete', jsonData, fnGoodsTnmResDeleteCollBack);
+			}
+		});
+	});
+	
+	var fnGoodsTnmResDeleteCollBack = function(){
+		//fnGoodsRsvtTnmListSearch($("#goodsTnmListForm input[name=searchGb]").val());
+	}
+	
+	$(document).ready(function() {
+
+		cfnCreateCalendar('#sellTerms', 'applyStdt', 'applyEddt', true, '예약일', 'X');
+		var chkBeforSkipFlag = '&nbsp;&nbsp;<label class="chkBox"><input type="checkbox" name="beforSkipFlag" value="Y" >이전데이터 제외</label>';
+		$("#goodsTnmListForm").find('#sellTerms').append(chkBeforSkipFlag);
+		
+		// Create a agGrid
+		gagaAgGrid.createGrid('gridList', gridOptions);
+
+	});
+
+/*]]>*/
+</script>
+ 	
+</html>

+ 305 - 0
style24.admin/src/main/webapp/WEB-INF/views/goods/GoodsTitleReservePopupForm.html

@@ -0,0 +1,305 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : GoodsTitleReservePopupForm.html
+ * @desc    : 상품등록 타이틀 예약등록 화면
+ *============================================================================
+ * PASTEL
+ * Copyright(C) 2019 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2020.11.02   eskim       최초 작성
+ *******************************************************************************
+ -->	
+	<div class="modalPopup" data-width="850" >
+		<div class="panelStyle">
+			<div class="panelTitle">
+				<h2>상품타이틀예약</h2>
+				<button type="button" class="close" onclick="uifnPopupClose('popupGoodsTitleReserve')"><i class="fa fa-times"></i></button>
+			</div>
+			<form id="goodsRsvtTnmForm" name="goodsRsvtTnmForm" >
+			<div class="panelContent">
+				<table class="frmStyle">
+					<colgroup>
+						<col style="width:10%;"/>
+						<col/>
+					</colgroup>
+					<tr>
+						<th>상품타이틀<em class="required" title="필수"></em></th>
+						<td><input type="text" class="w100p" id="goodsTnm" name="goodsTnm"  maxlength="50" /></td>
+					</tr>
+					<tr>
+						<th>예약일시<em class="required" title="필수"></em></th>
+						<td>
+							<input name="applyStYMD" id="applyStYMD" type="text" class="w80 schDate" maxlength="10" required="required" data-valid-name="예약시작일" />
+							<select name="applyStHH" id="applyStHH" required="required" data-valid-name="예약 시작시간">
+								<th:block th:each="num, index  : ${#numbers.sequence(0,23)}">
+								<option  th:value="${#numbers.formatInteger(num,2)}" th:text="|${#numbers.formatInteger(num,2)}시|" >시간</option>
+								</th:block>
+							</select>
+							<input name="applyStdt" id="applyStdt" type="hidden" />
+							~
+							<input name="applyEdYMD" id="applyEdYMD" type="text" class="w80 schDate" maxlength="10" required="required" data-valid-name="예약 종료일" />
+							<select name="applyEdHH" id="applyEdHH" required="required" data-valid-name="예약 종료시간">
+								<th:block th:each="num: ${#numbers.sequence(0,23)}">
+								<option  th:value="${#numbers.formatInteger(num,2)}"  th:text="|${#numbers.formatInteger(num,2)}시|" th:selected="${#numbers.formatInteger(num,2)}==23 ? 'true'">시간</option>
+								</th:block>
+							</select>
+							<input name="applyEddt" id="applyEddt" type="hidden" />
+						</td>
+					</tr>
+				</table>
+			</div>
+			<ul class="panelBar">
+				<li class="left">
+					<button type="button" class="btn btn-danger btn-lg" id="btnDeleteGoodsRsvtTnm">상품삭제</button>
+				</li>
+				<li class="right">
+					<button type="button" class="btn btn-base btn-lg" id="btnSearchExcel">엑셀조회</button>
+					<button type="button" class="btn btn-info btn-lg" id="btnSearchGoods">상품조회</button>
+				</li>
+			</ul>
+			<div id="gridGoodsRsvtTnmList" style="width: 100%; height: 400px;" class="ag-theme-balham"></div>
+			<ul class="panelBar">
+				<li class="right">
+					<button type="button" class="btnRight btn btn-base btn-lg" id="btnSaveGoodsRsvtTnm">적용</button>
+				</li>
+			</ul>
+			</form>	
+		</div>
+	</div>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	
+	var rsvtGoodsTnmColumnDefs = [
+		{width: 40, minWidth: 40, cellClass: 'text-center', headerCheckboxSelection: true, checkboxSelection: true, filter: false},
+		{headerName: 'No', width: 50, cellClass: 'text-center',valueGetter: function(params) { return params.node.rowIndex+1}},
+		{headerName: "상품코드", field: "goodsCd", width: 140, cellClass: 'text-center'},
+		{headerName: "상품명", field: "goodsNm", width: 330, cellClass: 'text-left'},
+		{headerName: "현재상품타이틀", field: "goodsTnm", width: 250, cellClass: 'text-left'}
+	];
+	
+	// Get GridOptions
+	var rsvtGoodsTnmGridOptions = gagaAgGrid.getGridOptions(rsvtGoodsTnmColumnDefs);
+	rsvtGoodsTnmGridOptions.enableBrowserTooltips = true;
+	
+	// 중복 선택 가능
+	rsvtGoodsTnmGridOptions.rowSelection = 'multiple';
+	rsvtGoodsTnmGridOptions.suppressRowClickSelection = true;
+	//rsvtGoodsTnmGridOptions.rowHeight = 60; //이미지가 있을경우 높이 지정해야함.
+
+	// 상품 조회 클릭 시
+	$('#btnSearchGoods').on('click', function() {
+		cfnOpenGoodsPopup('fnSearchGoods');
+	});
+
+	// 상품 조회 콜백함수
+	var fnSearchGoods = function(result) {
+		if (result.length < 1) return;
+		var oldData = gagaAgGrid.getAllRowData(rsvtGoodsTnmGridOptions);
+		$.each(result, function(idx, item) {
+			var isInvalid = false;
+			if (oldData != null && oldData.length != 0){
+				oldData.forEach(function(oneData){
+					if(oneData.goodsCd == item.goodsCd){
+						isInvalid = true;
+						return true;
+					}
+				});
+				if(isInvalid){
+					return isInvalid;
+				}
+			}
+			gagaAgGrid.addRowData(rsvtGoodsTnmGridOptions, {"goodsCd" : item.goodsCd, "goodsNm" : item.goodsNm, "goodsTnm" : item.goodsTnm});
+		});
+		uifnPopupClose('popupGoods');
+		return false;
+	};
+
+	// 저장 클릭 시
+	$('#btnSaveGoodsRsvtTnm').on('click', function() {
+
+		var allRowData = gagaAgGrid.getAllRowData(rsvtGoodsTnmGridOptions);
+
+		if(allRowData.length == 0){
+			mcxDialog.alertC("상품을 조회한 후 추가해주세요.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+				}
+			});
+			return;
+		}
+
+		if(gagajf.isNull($("#goodsRsvtTnmForm input[name=goodsTnm]").val())) {
+			mcxDialog.alertC("상품 타이틀을 입력하세요.",{
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$("#goodsRsvtTnmForm input[name=goodsTnm]").focus();
+				}
+			});
+			return false;
+		}
+
+		var fromDate = $('#goodsRsvtTnmForm input[name=applyStYMD]').val();
+		var toDate = $('#goodsRsvtTnmForm input[name=applyEdYMD]').val();
+
+		if (gagajf.isNull(fromDate)) {
+			mcxDialog.alertC("예약  시작일자를 입력하세요.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtTnmForm input[name=applyStYMD]').focus();
+				}
+			});
+			return false;
+		}
+
+		if (gagajf.isNull(toDate)) {
+			mcxDialog.alertC("예약  종료일자를 입력하세요.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtTnmForm input[name=applyEdYMD]').focus();
+				}
+			});
+			return false;
+		}
+
+		if (fromDate > toDate) {
+			mcxDialog.alertC("예약 시작일자는 종료일자 보다 클 수 없습니다.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtTnmForm input[name=applyEdYMD]').focus();
+				}
+			});
+			return false;
+		}
+
+		var applyStdt = $('#goodsRsvtTnmForm input[name=applyStYMD]').val().replaceAll("-","") +
+		$('#goodsRsvtTnmForm select[name=applyStHH]').val() + "0000";
+
+		var applyEddt = $('#goodsRsvtTnmForm input[name=applyEdYMD]').val().replaceAll("-","") +
+		$('#goodsRsvtTnmForm select[name=applyEdHH]').val() +"5959";
+
+		$('#goodsRsvtTnmForm input[name=applyStdt]').val(applyStdt);
+		$('#goodsRsvtTnmForm input[name=applyEddt]').val(applyEddt);
+
+		if ($('#goodsRsvtTnmForm input[name=applyStdt]').val() > $('#goodsRsvtTnmForm input[name=applyEddt]').val()) {
+			mcxDialog.alertC("예약 시작일자는 종료일자 보다 클 수 없습니다.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtTnmForm input[name=applyEdYMD]').focus();
+				}
+			});
+			return false;
+		}
+
+		var toDateStr = new Date().format("YYYYMMDDHHmmss");
+
+		if (toDateStr >= applyStdt){
+			mcxDialog.alertC("예약 시작일시는 현재일시 보다 작거나 같을 수 없습니다.",  {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtTnmForm input[name=applyStYMD]').focus();
+				}
+			});
+			return false;
+		}
+
+		if (toDateStr >= applyEddt){
+			mcxDialog.alertC("예약 종료일시는 현재일시 보다 작거나 같을 수 없습니다.", {
+				sureBtnText: "확인",
+				sureBtnClick: function() {
+					$('#goodsRsvtTnmForm input[name=applyEdYMD]').focus();
+				}
+			});
+			return false;
+		}
+
+		mcxDialog.confirm('저장하시겠습니까?',  {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				var arrGoodsCd = [];
+				allRowData.forEach(function(item, index) {
+					arrGoodsCd.push(item.goodsCd);
+				});
+
+				var data = {goodsTnm : $('#goodsRsvtTnmForm input[name=goodsTnm]').val()
+							, applyStdt : $('#goodsRsvtTnmForm input[name=applyStdt]').val()
+							, applyEddt : $('#goodsRsvtTnmForm input[name=applyEddt]').val()
+							, arrGoodsCd : arrGoodsCd
+				};
+
+				var jsonData = JSON.stringify(data);
+				gagajf.ajaxJsonSubmit('/goods/title/reserve/save', jsonData, fnGoodsRsvtTnmListFormClose);
+
+			}
+		});
+	});
+
+	// 조회상품 삭제
+	$('#btnDeleteGoodsRsvtTnm').on('click', function() {
+		var selectedData = rsvtGoodsTnmGridOptions.api.getSelectedRows();
+		if (selectedData.length == 0) {
+			mcxDialog.alert('선택된 행이 없습니다.');
+			return;
+		}
+
+		//화면에서 삭제
+		var removedData = gagaAgGrid.removeRowData(rsvtGoodsTnmGridOptions, false);
+	});
+	
+	//엑셀 상품 조회
+	$('#btnSearchExcel').on('click', function() {
+		cfnExcelUploadPopup('goodsRsvtTnmExcelUpload', 'goodsRsvtTnmExcelUpload');
+	});
+
+	var goodsRsvtTnmExcelUpload = function(result){
+		var data = {procJob : result.procJob
+			,excelFileNm : result.excelFileNm
+		};
+		var jsonData = JSON.stringify(data);
+		gagajf.ajaxJsonSubmit('/goods/search/excelupload/save', jsonData, fnRsvtGoodsTnmExcelUploadCallBack);
+	}
+
+	var fnRsvtGoodsTnmExcelUploadCallBack = function(result){
+		gagajf.ajaxJsonSubmit('/goods/excel/upload/goods/list', '', fnExcelSearchCallBack);
+	}
+
+	var fnExcelSearchCallBack = function(result){
+		if (result.goodsExcelList.length < 1) return;
+		var oldData = gagaAgGrid.getAllRowData(rsvtGoodsTnmGridOptions);
+		$.each(result.goodsExcelList, function(idx, item) {
+			var isInvalid = false;
+			if (oldData != null && oldData.length != 0){
+				oldData.forEach(function(oneData){
+					if(oneData.goodsCd == item.goodsCd){
+						isInvalid = true;
+						return true;
+					}
+				});
+				if(isInvalid){
+					return isInvalid;
+				}
+			}
+			gagaAgGrid.addRowData(rsvtGoodsTnmGridOptions, {"goodsCd" : item.goodsCd, "goodsNm" : item.goodsNm, "goodsTnm" : item.goodsTnm});
+		});
+		return;
+	}
+
+	//창종료
+	var fnGoodsRsvtTnmListFormClose = function(){
+		uifnPopupClose('popupGoodsTitleReserve');
+		fnGoodsTnmResDeleteCollBack();
+	}
+
+	$(document).ready(function() {
+		// Create a agGrid
+		gagaAgGrid.createGrid('gridGoodsRsvtTnmList', rsvtGoodsTnmGridOptions);
+	});
+
+/*]]>*/
+</script>
+</html>