package cokr.xit.fims.sndb.service.bean;

import java.io.IOException;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import cokr.xit.fims.cmmn.CmmnUtil;
import cokr.xit.fims.cmmn.CrdnSttsHstry;
import cokr.xit.fims.cmmn.service.bean.CrdnSttsHstryBean;
import cokr.xit.fims.crdn.Crdn;
import cokr.xit.fims.epst.EpostQuery;
import cokr.xit.fims.epst.dao.EpostDlvrRsltMapper;
import cokr.xit.fims.levy.Levy;
import cokr.xit.fims.levy.dao.LevyMapper;
import cokr.xit.fims.nxrp.A03;
import cokr.xit.fims.nxrp.NisIndivQuery;
import cokr.xit.fims.nxrp.service.bean.NisIndivBean;
import cokr.xit.fims.sndb.SndbQuery;
import cokr.xit.fims.sndb.SndngDtl;
import cokr.xit.fims.sndb.dao.SndngDtlMapper;
import cokr.xit.fims.sndb.dao.SvbtcMapper;
import cokr.xit.foundation.component.AbstractBean;
import cokr.xit.foundation.data.DataObject;

/**발송 상세 정보 관리 Bean
 *
 * <p>상세 설명:
 *
 * <pre>
 * ============ 변경 이력 ============
 * 2023-12-27	JoJH 최초 작성
 * ================================
 * </pre>
 */
@Component("sndngDtlBean")
public class SndngDtlBean extends AbstractBean {
	/** 발송 상세 정보 DAO */
	@Resource(name = "sndngDtlMapper")
	private SndngDtlMapper sndngDtlMapper;
	/** 공시송달 대장 정보 DAO */
	@Resource(name = "svbtcMapper")
	private SvbtcMapper svbtcMapper;
	/** 전자우편 배달 결과 정보 DAO */
	@Resource(name = "epostDlvrRsltMapper")
	private EpostDlvrRsltMapper epostDlvrRsltMapper;
	/** 부과 대장 정보 DAO */
	@Resource(name = "levyMapper")
	private LevyMapper levyMapper;
	/** 단속 상태 이력 정보 Bean */
	@Resource(name = "crdnSttsHstryBean")
	private CrdnSttsHstryBean crdnSttsHstryBean;
	/** 과태료 대장 단속 정보 등록 정보 Bean */
	@Resource(name = "nisIndivBean")
	private NisIndivBean nisIndivBean;

	/**지정한 조건에 따라 발송 상세 목록을 조회하여 반환한다.
	 * @param req 발송 상세 조회 조건
	 * @return 발송 상세 목록
	 */
	public List<DataObject> getSndngDtlList(SndbQuery req) {
		// 삭제 여부 확인
		if (req.getDelYn() == null) {
			req.setDelYn("N");
		}
		// 정렬 확인
		if (req.getOrderBy() == null) {
			if (req.getBy() == null) {
				req.setOrderBy("REG_DT");
			} else {
				req.setOrderBy(CmmnUtil.convertCamelCaseToSnakeCase(req.getBy()));
			}
		}

		return sndngDtlMapper.selectSndngDtlList(req);
	}

	/**지정한 조건에 따라 발송 상세 객체들을 반환한다.
	 * @param req 발송 상세 조회 조건
	 * @return 발송 상세 객체 목록
	 */
	public List<DataObject> getSndngDtls(SndbQuery req) {
		// 삭제 여부 확인
		if (req.getDelYn() == null) {
			req.setDelYn("N");
		}
		if (req.getOrderBy() == null) {
			req.setOrderBy("SNDNG_DTL_ID");
		}

		return sndngDtlMapper.selectSndngDtls(req);
	}

	/**발송 ID에 따라 발송 상세 ID를 반환한다.
	 * @param req 발송 상세 조회 조건
	 * @return 발송 상세 객체 목록
	 */
	public List<DataObject> getSndngTrgtDtlIds(SndbQuery req) {
		return sndngDtlMapper.selectSndngTrgtDtlIds(req);
	}

	/**발송 상세 정보를 세외수입 과태료대장 단속 정보를 등록한다.
	 * @param sndngDtl 발송 상세
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String setNxrpIndivA01List(SndngDtl sndngDtl) {
		// 발송 상세 상태 코드(SNDNG_DTL_STTS_CD) 가 처리전(00)인 자료만 처리
		if (!"00".equals(sndngDtl.getSndngDtlSttsCd()))
			throw new RuntimeException("연계처리할 수 없는 발송정보 입니다.");

		NisIndivQuery nisIndivQuery = new NisIndivQuery();
		nisIndivQuery.setCrdnId(sndngDtl.getCrdnId());
		nisIndivQuery.setSndngDtlId(sndngDtl.getSndngDtlId());

		nisIndivQuery.setSndngYmd(sndngDtl.getSndngYmd());

		SndngDtl uptSndngDtl = nisIndivBean.registerNisIndivA01(nisIndivQuery);
		if (uptSndngDtl != null) {
			uptSndngDtl.setSndngDtlId(sndngDtl.getSndngDtlId());			// 발송 상세 ID
			int affected = sndngDtlMapper.updateSndngDtlSttsCd(uptSndngDtl);
			if (affected == 1)
				return "[S] 작업이 정상 처리 되었습니다.";
			else
				throw new RuntimeException("세외수입 과태료대장 연계 정보를 단속 대장에 수정하지 못했습니다.");
		} else
			throw new RuntimeException("세외수입 과태료대장 연계 작업중 오류가 발생했습니다.");
	}

	/**발송 상세 정보를 세외수입 과태료대장 상세 조회 정보를 조회하여 발송 상세 정보를 수정한다.
	 * @param sndngDtl 발송 상세
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String getNxrpIndivA03List(SndngDtl sndngDtl) {
		// 발송 상세 상태 코드(SNDNG_DTL_STTS_CD) 가 세외수입부과(01)인 자료만 처리
		if ("01".equals(sndngDtl.getSndngDtlSttsCd())) {
			NisIndivQuery nisIndivQuery = new NisIndivQuery();
			nisIndivQuery.setCrdnId(sndngDtl.getCrdnId());
			nisIndivQuery.setSndngDtlId(sndngDtl.getSndngDtlId());

			String a03Msg = nisIndivBean.createNisIndivA03(nisIndivQuery);
			try {
				ObjectMapper mapper = new ObjectMapper();
				JsonNode linkRst = mapper.readTree(a03Msg);

				// 개별시스템 연계결과코드(linkRstCd) - 000:정상, 100:검증오류(연계관리키 중복), 101:검증오류(등록 시 자료 null, 길이체크), 900:필수값누락
				if (linkRst.get("linkRstCd").asText().equals("000")) {
					// resVo1
					JsonNode resVo1 = linkRst.findValue("resVo1");

					// 이 설정을 통해 JSON의 모든 데이터를 파싱하는 것이 아닌 내가 필요로 하는 데이터, 즉 내가 필드로 선언한 데이터들만 파싱할 수 있다.
					mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
					A03 a03 = mapper.readValue(resVo1.toString(), A03.class);

					// 발송 대장(TB_SNDNG) - 발송 상세 수정
					SndngDtl uptSndngDtl = new SndngDtl();

					uptSndngDtl.setSndngDtlId(sndngDtl.getSndngDtlId());				// 발송 상세 ID
					if (toInt(sndngDtl.getSndngDtlSttsCd()) >= 3) {
						uptSndngDtl.setSndngDtlSttsCd(sndngDtl.getSndngDtlSttsCd());
                	} else {
                		uptSndngDtl.setSndngDtlSttsCd("02");							// 발송 상태 코드(FIM050) 02:가상계좌취득
                	}
					if ("01".equals(a03.getPyrSeCd())) {
						uptSndngDtl.setRcpnBrdt(a03.getPyrNo().substring(0, 6));		// 수령인 생년월일
					}
					uptSndngDtl.setRcpnNm(a03.getPyrNm());								// 수령인 명
					uptSndngDtl.setRcpnAddr(a03.getPyrAddr());							// 수령인 주소
					uptSndngDtl.setRcpnDtlAddr("");										// 수령인 상세 주소
					uptSndngDtl.setRcpnZip(a03.getPyrZip());							// 수령인 우편번호
					uptSndngDtl.setFyr(a03.getRsveItem1().substring(11, 15));			// 회계연도
					uptSndngDtl.setLevyNo(a03.getRsveItem1().substring(23, 29));		// 부과 번호
					uptSndngDtl.setLevyYmd(a03.getOpnSbmsnTermBgngYmd());				// 부과 일자
					uptSndngDtl.setDudtYmd(a03.getOpnSbmsnTermEndYmd());				// 납기 일자
					uptSndngDtl.setFfnlgAmt(toInt(a03.getFinScrgAmt()));		// 과태료 금액
					uptSndngDtl.setPcptax(toInt(a03.getFinScrgAmt()) - toInt(a03.getBfRdtAmt()));    // 본세
					uptSndngDtl.setAdamt(0);											// 가산금
					uptSndngDtl.setLastAmt(toInt(a03.getFinScrgAmt()) - toInt(a03.getBfRdtAmt()));   // 최종 금액
					uptSndngDtl.setDudtAftrAmt(0);										// 납기 후 금액
					uptSndngDtl.setTaxNo(a03.getRsveItem1());							// 납세 번호
					uptSndngDtl.setEpayno(a03.getEpayNo());								// 전자납부번호
					uptSndngDtl.setBankNm(a03.getVtlacBankNm1());						// 은행 명
					uptSndngDtl.setVrActno(a03.getVrActno1());							// 가상 계좌번호
					uptSndngDtl.setBankNm2(a03.getVtlacBankNm2());						// 은행 명2
					uptSndngDtl.setVrActno2(a03.getVrActno2());							// 가상 계좌번호2
					uptSndngDtl.setBankNm3(a03.getVtlacBankNm3());						// 은행 명3
					uptSndngDtl.setVrActno3(a03.getVrActno3());							// 가상 계좌번호3
					uptSndngDtl.setBankNm4(a03.getVtlacBankNm4());						// 은행 명4
					uptSndngDtl.setVrActno4(a03.getVrActno4());							// 가상 계좌번호4
					uptSndngDtl.setBankNm5(a03.getVtlacBankNm5());						// 은행 명5
					uptSndngDtl.setVrActno5(a03.getVrActno5());							// 가상 계좌번호5
					uptSndngDtl.setBankNm6(a03.getVtlacBankNm6());						// 은행 명6
					uptSndngDtl.setVrActno6(a03.getVrActno6());							// 가상 계좌번호6
					uptSndngDtl.setBankNm7(a03.getVtlacBankNm7());						// 은행 명7
					uptSndngDtl.setVrActno7(a03.getVrActno7());							// 가상 계좌번호7
					uptSndngDtl.setBankNm8(a03.getVtlacBankNm8());						// 은행 명8
					uptSndngDtl.setVrActno8(a03.getVrActno8());							// 가상 계좌번호8
					uptSndngDtl.setBankNm9(a03.getVtlacBankNm9());						// 은행 명9
					uptSndngDtl.setVrActno9(a03.getVrActno9());							// 가상 계좌번호9
					uptSndngDtl.setBankNm10(a03.getVtlacBankNm10());					// 은행 명10
					uptSndngDtl.setVrActno10(a03.getVrActno10());						// 가상 계좌번호10
					uptSndngDtl.setBankNm11(a03.getVtlacBankNm11());					// 은행 명11
					uptSndngDtl.setVrActno11(a03.getVrActno11());						// 가상 계좌번호11
					uptSndngDtl.setBankNm12(a03.getVtlacBankNm12());					// 은행 명12
					uptSndngDtl.setVrActno12(a03.getVrActno12());						// 가상 계좌번호12
					uptSndngDtl.setBankNm13(a03.getVtlacBankNm13());					// 은행 명13
					uptSndngDtl.setVrActno13(a03.getVrActno13());						// 가상 계좌번호13
					uptSndngDtl.setBankNm14(a03.getVtlacBankNm14());					// 은행 명14
					uptSndngDtl.setVrActno14(a03.getVrActno14());						// 가상 계좌번호14
					uptSndngDtl.setBankNm15(a03.getVtlacBankNm15());					// 은행 명15
					uptSndngDtl.setVrActno15(a03.getVrActno15());						// 가상 계좌번호15
					uptSndngDtl.setBankNm16(a03.getVtlacBankNm16());					// 은행 명16
					uptSndngDtl.setVrActno16(a03.getVrActno16());						// 가상 계좌번호16
					uptSndngDtl.setBankNm17(a03.getVtlacBankNm17());					// 은행 명17
					uptSndngDtl.setVrActno17(a03.getVrActno17());						// 가상 계좌번호17
					uptSndngDtl.setBankNm18(a03.getVtlacBankNm18());					// 은행 명18
					uptSndngDtl.setVrActno18(a03.getVrActno18());						// 가상 계좌번호18
					uptSndngDtl.setBankNm19(a03.getVtlacBankNm19());					// 은행 명19
					uptSndngDtl.setVrActno19(a03.getVrActno19());						// 가상 계좌번호19
					uptSndngDtl.setBankNm20(a03.getVtlacBankNm20());					// 은행 명20
					uptSndngDtl.setVrActno20(a03.getVrActno20());						// 가상 계좌번호20

					int affected = sndngDtlMapper.updateSndngDtlNxrpA03(uptSndngDtl);
					if (affected != 1)
						throw new RuntimeException("세외수입 연계 정보를 발송 상세에 수정하지 못했습니다.");

					// 단속, 부과 대장 조회
					DataObject crdnLevyInfo = sndngDtlMapper.selectCrdnLevy(sndngDtl.getCrdnId());

					// 단속 대장 수정
					Crdn crdn = new Crdn();
					crdn.setCrdnId(crdnLevyInfo.string("CRDN_ID"));				// 단속 ID
					crdn.setNxrpAcbKey(a03.getFinScrgAcbKey());					// 세외수입 대장 키

					affected = sndngDtlMapper.updateCrdnNxrpAcbKey(crdn);
					if (affected != 1) {
						throw new RuntimeException("단속 대장에 세외수입 대장키 수정에 실패하였습니다.");
					}

					// 부과 대장에 등록 및 수정
					Levy levy = new Levy();
					levy.setSggCd(crdnLevyInfo.string("SGG_CD"));				// 시군구 코드
					levy.setTaskSeCd(crdnLevyInfo.string("TASK_SE_CD"));		// 업무 구분 코드
					levy.setCrdnId(crdnLevyInfo.string("CRDN_ID"));				// 단속 ID
					levy.setInstCd(a03.getSgbCd());								// 기관 코드
					levy.setDeptCd(a03.getDptCd());								// 부서 코드
					levy.setSpclBizCd(a03.getSpacBizCd());						// 특별회계 사업 코드
				    levy.setFyr(a03.getRsveItem1().substring(11, 15));			// 회계연도
				    levy.setAcntgSeCd(a03.getActSeCd());						// 회계 구분 코드
				    levy.setTxitmCd(a03.getRprsTxmCd());						// 세목 코드
				    levy.setOperItemCd(a03.getOperItemCd());					// 운영 항목 코드
				    levy.setLevyNo(a03.getRsveItem1().substring(23, 29));		// 부과 번호
				    levy.setIspySn(a03.getRsveItem1().substring(29, 31));		// 분납 번호
                    levy.setLevySeCd("02");                                     // 부과 구분 코드 FIM040
                    levy.setUntySeCd("02");                                     // 통합 구분 코드 FIM072
                    levy.setRdctSeCd("01");                                     // 감경 구분 코드 FIM046 - 01 감경
				    levy.setLevyYmd(a03.getOpnSbmsnTermBgngYmd());				// 부과 일자
				    levy.setFrstDudtYmd(a03.getOpnSbmsnTermEndYmd());			// 최초 납기 일자
				    levy.setDudtYmd(a03.getOpnSbmsnTermEndYmd());				// 납기 일자
				    levy.setFfnlgAmt(toInt(a03.getFinScrgAmt()));	            // 과태료 금액
					levy.setLevyPcptax(toInt(a03.getFinScrgAmt()) - toInt(a03.getBfRdtAmt()));	// 부과 본세
                    levy.setLevyAdamt(0);                                       // 부과 가산금
                    levy.setIspyInt(0);                                         // 분납 이자
                    levy.setRcvmtPcptax(0);										// 수납 본세
                    levy.setRcvmtAdamt(0);										// 수납 가산금
                    levy.setRdamtPcptax(0);                                     // 감액 본세
                    levy.setRdamtAdamt(0);										// 감액 가산금
                    levy.setLastAmt(toInt(a03.getFinScrgAmt()) - toInt(a03.getBfRdtAmt()));       // 최종 금액
                    levy.setDudtAftrAmt(0);										// 납기 후 금액
//					levy.setTxtnThing(a03.getVhrno());							// 과세 물건 -> 값이 넘어오지 않는다.. 차세대 연계 확인 요청이 필요하다.
					levy.setTxtnThing(crdnLevyInfo.string("VHRNO"));			// 과세 물건
					levy.setMngItem1(a03.getMngItemCn1());						// 관리 아이템1
					levy.setMngItem2(a03.getMngItemCn2());						// 관리 아이템2
					levy.setMngItem3(a03.getMngItemCn3());						// 관리 아이템3
					levy.setMngItem4(a03.getMngItemCn4());						// 관리 아이템4
					levy.setMngItem5(a03.getMngItemCn5());						// 관리 아이템5
					levy.setMngItem6(a03.getMngItemCn6());						// 관리 아이템6
					levy.setEpayno(a03.getEpayNo());							// 전자납부번호
					levy.setBankNm(a03.getVtlacBankNm1());						// 은행 명
					levy.setVrActno(a03.getVrActno1());							// 가상 계좌번호
					levy.setBankNm2(a03.getVtlacBankNm2());						// 은행 명2
					levy.setVrActno2(a03.getVrActno2());						// 가상 계좌번호2
					levy.setBankNm3(a03.getVtlacBankNm3());						// 은행 명3
					levy.setVrActno3(a03.getVrActno3());						// 가상 계좌번호3
					levy.setBankNm4(a03.getVtlacBankNm4());						// 은행 명4
					levy.setVrActno4(a03.getVrActno4());						// 가상 계좌번호4
					levy.setBankNm5(a03.getVtlacBankNm5());						// 은행 명5
					levy.setVrActno5(a03.getVrActno5());						// 가상 계좌번호5
					levy.setBankNm6(a03.getVtlacBankNm6());						// 은행 명6
					levy.setVrActno6(a03.getVrActno6());						// 가상 계좌번호6
					levy.setBankNm7(a03.getVtlacBankNm7());						// 은행 명7
					levy.setVrActno7(a03.getVrActno7());						// 가상 계좌번호7
					levy.setBankNm8(a03.getVtlacBankNm8());						// 은행 명8
					levy.setVrActno8(a03.getVrActno8());						// 가상 계좌번호8
					levy.setBankNm9(a03.getVtlacBankNm9());						// 은행 명9
					levy.setVrActno9(a03.getVrActno9());						// 가상 계좌번호9
					levy.setBankNm10(a03.getVtlacBankNm10());					// 은행 명10
					levy.setVrActno10(a03.getVrActno10());						// 가상 계좌번호10
					levy.setBankNm11(a03.getVtlacBankNm11());					// 은행 명11
					levy.setVrActno11(a03.getVrActno11());						// 가상 계좌번호11
					levy.setBankNm12(a03.getVtlacBankNm12());					// 은행 명12
					levy.setVrActno12(a03.getVrActno12());						// 가상 계좌번호12
					levy.setBankNm13(a03.getVtlacBankNm13());					// 은행 명13
					levy.setVrActno13(a03.getVrActno13());						// 가상 계좌번호13
					levy.setBankNm14(a03.getVtlacBankNm14());					// 은행 명14
					levy.setVrActno14(a03.getVrActno14());						// 가상 계좌번호14
					levy.setBankNm15(a03.getVtlacBankNm15());					// 은행 명15
					levy.setVrActno15(a03.getVrActno15());						// 가상 계좌번호15
					levy.setBankNm16(a03.getVtlacBankNm16());					// 은행 명16
					levy.setVrActno16(a03.getVrActno16());						// 가상 계좌번호16
					levy.setBankNm17(a03.getVtlacBankNm17());					// 은행 명17
					levy.setVrActno17(a03.getVrActno17());						// 가상 계좌번호17
					levy.setBankNm18(a03.getVtlacBankNm18());					// 은행 명18
					levy.setVrActno18(a03.getVrActno18());						// 가상 계좌번호18
					levy.setBankNm19(a03.getVtlacBankNm19());					// 은행 명19
					levy.setVrActno19(a03.getVrActno19());						// 가상 계좌번호19
					levy.setBankNm20(a03.getVtlacBankNm20());					// 은행 명20
					levy.setVrActno20(a03.getVrActno20());						// 가상 계좌번호20

					if (isEmpty(crdnLevyInfo.get("LEVY_ID"))) {			// 부과 ID가 없다면
						// 부과(TB_LEVY) 대장을 등록한다.
						affected = levyMapper.insertLevy(levy);
						if (affected != 1)
							throw new RuntimeException("부과대장 등록에 실패하였습니다.");

						// 단속상태이력(TB_CRDN_STTS_HSTRY)
						CrdnSttsHstry crdnSttsHstry = new CrdnSttsHstry();
						crdnSttsHstry.setCrdnId(crdnLevyInfo.string("CRDN_ID"));					// 단속 ID
						crdnSttsHstry.setBfrSttsCd(crdnLevyInfo.string("CRDN_STTS_CD"));			// 이전 단속 상태 코드
						crdnSttsHstry.setBfrSttsChgDt(crdnLevyInfo.string("CRDN_STTS_CHG_DT"));		// 이전 단속 상태 변경 일시
						crdnSttsHstry.setCrdnSttsCd("23");											// 단속 상태 코드(FIM010) - 23:감경부과

						boolean rtnScs = false;													// DB 처리 결과
						if (toInt(crdnLevyInfo.get("CRDN_STTS_CD")) >= 1 && toInt(crdnLevyInfo.get("CRDN_STTS_CD")) <= 22 ) {
							// 단속 상태 이력(TB_CRDN_STTS_HSTRY) 대장에 등록하고, 단속(TB_CRDN) 대장을 수정한다.
							rtnScs = crdnSttsHstryBean.createHstryUpdateCrdnSttsCd(crdnSttsHstry);
							if (!rtnScs)
								throw new RuntimeException("감경부과 등록 중 단속 대장의 단속상태 변경에 실패하였습니다.");
						} else {
							// 단속상태이력(TB_CRDN_STTS_HSTRY) 대장을 등록한다.
							rtnScs = crdnSttsHstryBean.create(crdnSttsHstry);
							if (!rtnScs)
								throw new RuntimeException("감경부과 등록 중 단속 대장의 단속상태 변경에 실패하였습니다.");
						}
					} else {
						levy.setLevyId(crdnLevyInfo.string("LEVY_ID"));

						// 부과(TB_LEVY) 대장을 수정한다.
						affected = levyMapper.updateLevy(levy);
						if (affected != 1)
							throw new RuntimeException("부과대장 수정에 실패하였습니다.");
					}

					// 수납 정보 확인하여 발송(TB_SNDNG) - 발송 상태 코드(SNDNG_DTL_STTS_CD) 수정
					if (resVo1.get("rcvmtSeNm").asText().equals("수납")) {
						uptSndngDtl.setSndngDtlSttsCd("09");					// 발송 상세 상태 코드(FIM050) 09:수납
						uptSndngDtl.setSndngRcvmtCd("1");						// 발송 수납 코드(FIM051) 1:수납

						// 발송(TB_SNDNG) 대장을 수정한다.
						affected = sndngDtlMapper.updateSndngDtlSttsCd(uptSndngDtl);
						if (affected != 1)
							throw new RuntimeException("세외수입 연계 정보를 발송 상세에 수정하지 못했습니다.");
					}
				}
			} catch (IOException e) {
				throw new RuntimeException("세외수입 과태료대장 연계 작업중 오류가 발생하였습니다.");
			}
		}

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**지정한 조건에 따라 반송 목록을 조회하여 반환한다.
	 * @param req 발송 대장 조회 조건
	 * @return 반송 목록
	 */
	public List<DataObject> getSndbkList(SndbQuery req) {
		return sndngDtlMapper.selectSndbkList(req);
	}

	/**지정한 발송 상세 ID의 미배달 정보를 반환한다.<br />
	 * @param sndngDtlId 발송 상세 ID
	 * @return 발송상세 미배달 정보
	 */
	public DataObject getSndbkInfo(SndbQuery req) {
		return "create".equals(req.getCallPurpose()) ?
			sndngDtlMapper.selectSndngDtlInfo(req) :
			sndngDtlMapper.selectSndbkInfo(req);
	}

	/**발송 상세 목록의 반송 정보를 등록한다.
	 * @param sndngDtl 발송 상세
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String createSndbkList(SndbQuery req) {
		List<DataObject> sndngDtlList = sndngDtlMapper.selectSndngTrgtDtlIds(req);
		if (isEmpty(sndngDtlList))
			return "[F] 작업 중 대상 자료가 존재하지 않습니다.";

		// 반송 정보를 등록한다.
		for (int i = 0; i < sndngDtlList.size(); i++) {
			// 반송 내역 조회
			DataObject sndbkInfo = sndngDtlMapper.selectSndbkInfo(new SndbQuery().setSndngDtlId(sndngDtlList.get(i).string("SNDNG_DTL_ID")));

			// 반송 등록이 가능한지 확인.
			if (!("03,05".contains(sndbkInfo.string("SNDNG_DTL_STTS_CD"))))
				return "[F] 반송 등록 대상자료가 아닙니다.";
			// 등기 번호가 있는지 확인
			if (sndbkInfo.string("RG_NO").equals(""))
				return "[F] 등기번호가 존재하지 않습니다.";
			// 등기 번호가 13자리인지 확인
			if (sndbkInfo.string("RG_NO").length() != 13)
				return "[F] 등기번호 자릿수(13)가 맞지 않습니다.";

			// 전자우편 배달 결과 조회
			EpostQuery epostQuery = new EpostQuery();
			epostQuery.setConKey(sndbkInfo.string("CON_KEY"));
			epostQuery.setRegino(sndbkInfo.string("RG_NO"));

			DataObject epostDlvrRsltInfo = epostDlvrRsltMapper.selectEpostDlvrRsltInfo(epostQuery);
			// 조회 건수 확인
			if (epostDlvrRsltInfo == null)
				return "[F] 반송 자료가 존재하지 않습니다.";

			// 발송 상세(TB_SNDNG_DTL) 대장에 반송 정보를 등록한다.
			SndngDtl sndngDtl = new SndngDtl();
			if (epostDlvrRsltInfo.string("DELIVRSLTCD").equals("1")) {
				sndngDtl.setSndngDtlId(sndbkInfo.string("SNDNG_DTL_ID"));
				sndngDtl.setDlvrYmd(epostDlvrRsltInfo.string("DELIVYMD"));				// 배달일자
				sndngDtl.setDlvrTm(epostDlvrRsltInfo.string("DELIVHHMI"));				// 배달시간
				sndngDtl.setRcpnNm(epostDlvrRsltInfo.string("SUBRECPRSNNM"));			// 수령인 명
				sndngDtl.setRcpnRelNm(epostDlvrRsltInfo.string("RELRECPRSNCDNM"));		// 수령인 관계 명
				sndngDtl.setSndngDtlSttsCd("04");										// 발송 상세 상태 코드 FIM050 - 04:발송확인
				sndngDtl.setBfrSndngDtlSttsCd(sndbkInfo.string("SNDNG_DTL_STTS_CD"));	// 전 발송 상세 상태 코드
			} else {
				sndngDtl.setSndngDtlId(sndbkInfo.string("SNDNG_DTL_ID"));
				sndngDtl.setDlvrYmd(epostDlvrRsltInfo.string("DELIVYMD"));				// 배달일자
				sndngDtl.setDlvrTm(epostDlvrRsltInfo.string("DELIVHHMI"));				// 배달시간
				sndngDtl.setUndlvrRsnCd(epostDlvrRsltInfo.string("NONDELIVREASNCD"));	// 미배달 사유 코드
				sndngDtl.setUndlvrRsnNm(epostDlvrRsltInfo.string("NONDELIVREASNCDNM"));	// 미배달 사유 명
				sndngDtl.setSndngDtlSttsCd("05");										// 발송 상세 상태 코드 FIM050 - 05:반송
				sndngDtl.setBfrSndngDtlSttsCd(sndbkInfo.string("SNDNG_DTL_STTS_CD"));	// 전 발송 상세 상태 코드
			}

			// 발송상세(TB_SNDNG_DTL)에 반송 정보를 등록한다.
			String rtnMsg = createSndbk(sndngDtl);
			// 메시지 확인
			if (!rtnMsg.contains("[S]")) {
				throw new RuntimeException(rtnMsg);
			}
		}

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**발송 상세의 반송 정보를 등록한다.
	 * @param sndngDtl 발송 상세
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String createSndbk(SndngDtl sndngDtl) {
		// 발송상세(TB_SNDNG_DTL)에 반송 정보를 등록한다.
		int rtnNocs = sndngDtlMapper.createSndbk(sndngDtl);
		if (rtnNocs < 1)
			throw new RuntimeException("발송상세의 반송 정보 등록에 실패하였습니다.");

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**발송 상세의 반송 정보를 수정한다.
	 * @param sndngDtl 발송 상세
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String updateSndbk(SndngDtl sndngDtl) {
		// 발송상세(TB_SNDNG_DTL)에 반송 정보를 등록한다.
		int rtnNocs = sndngDtlMapper.updateSndbk(sndngDtl);
		if (rtnNocs != 1)
			throw new RuntimeException("발송상세의 반송 정보 수정에 실패하였습니다.");

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**발송 상세의 반송 정보를 삭제 한다.
	 * @param sndngDtl 발송 상세
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String removeSndbk(SndngDtl sndngDtl) {
        // 반송 내역 조회
		SndbQuery req = new SndbQuery();
		req.setSndngDtlId(sndngDtl.getSndngDtlId());
		req.setDelYn("N");

        DataObject sndbkInfo = sndngDtlMapper.selectSndbkInfo(req);

        // 반송 삭제가 가능한지 확인
		if (sndbkInfo == null)
			return "[F] 작업 중 대상 자료가 존재하지 않습니다.";

		sndngDtl.setDlvrYmd(sndbkInfo.string("BFR_DLVR_YMD"));
		sndngDtl.setDlvrTm(sndbkInfo.string("BFR_DLVR_TM"));
		sndngDtl.setSndngDtlSttsCd(sndbkInfo.string("BFR_SNDNG_DTL_STTS_CD"));

		// 발송 상세(TB_SNDNG_DTL) 대장에 반송 정보를 삭제한다.
		int rtnNocs = sndngDtlMapper.deleteSndbk(sndngDtl);
		if (rtnNocs < 1)
			throw new RuntimeException("발송상세의 반송 정보 삭제에 실패하였습니다.");

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**공시송달ID 조건에 따라 발송상세 대장의 총 건수를 조회한다.
	 * @param req 발송 대장 조회 조건
	 * @return 계고장 발송 대상 목록
	 */
	public int selectTnocsSndngDtlSvbtc(String svbtcId) {
		return sndngDtlMapper.selectTnocsSndngDtlSvbtc(svbtcId);
	}

	/**발송 상세 대장의 공시송달 정보를 삭제한다.
	 * @param sndngDtl 발송 상세
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String removeSndngDtlSvbtc(SndngDtl sndngDtl) {
		// 발송 상세(TB_SNDNG_DTL) 대장에 공시송달 정보를 삭제한다.
		int rtnNocs = sndngDtlMapper.deleteSndngDtlSvbtc(sndngDtl);
		if (rtnNocs != 1)
			throw new RuntimeException("발송상세의 공시송달 정보 삭제에 실패하였습니다.");

		return "[S] 작업이 정상 처리 되었습니다.";
	}
}