/*********************************************************************
 *   All Rights reserved,Copyright (c) K-Opticom
 **********************************************************************
 *＜プログラム内容＞
 *  システム名      ：eo顧客基幹システム
 *  モジュール名    ：JEKK0351C250ETDA
 *  ソースファイル名：JEKK0351C250ETDA.java
 *  作成者          ：富士通
 *  日付            ：2011年10月19日
 *＜機能概要＞
 *  オプションサービス契約解約確定のDBアクセス部品クラス
 *＜修正履歴＞
 *  バージョン  修正日      修正者      修正内容
 *  v1.00.00    2011/10/19  富士通      新規作成
 *  v4.00.00    2013/01/15  FJ)寺園     ANK-1292-00-00
 *  v4.00.01    2013/03/29  FJ)竹内     ST4-2013-0000382)遡及解約対応・課金終了日更新処理修正
 *  v4.00.02    2013/04/02  FJ)寺園     ST2-2013-0001542
 *  v4.00.03    2013/05/02  FJ)寺本     IT1-2013-0001110
 *  v5.00.00    2013/07/03  FJ）沖田    KT1-2013-0000691
 *  v5.00.01    2013/07/09  FJ）沖田    IT2-2013-0000593
 *  v4.00.04    2013/07/14  FJ）竹内    LT-2013-0000391
 *  v5.00.00    2013/11/29  FJ)寺園     OM-2013-0004088
 *  v7.00.00    2014/02/20  FJ)寺園     OM-2014-0000553
 *  v8.00.00    2014/06/11  FJ)小島     OM-2014-0002105
 *
 **********************************************************************/

package eo.ejb.common.db;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fujitsu.futurity.common.JCMConstants;
import com.fujitsu.futurity.model.base.CAANException;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.base.CAANRuntimeException;
import com.fujitsu.futurity.model.ejb.common.StatusCodes;
import com.fujitsu.futurity.model.ejb.common.fw.AgentDispatchContext;

import eo.common.util.JPCUtilCommon;
import eo.ejb.cbm.entity.KK0081ETMsg;
import eo.ejb.cbm.entity.KK0161ETMsg;
import eo.ejb.cbm.entity.KK0351ETMsg;
import eo.ejb.cbm.entity.KK1681ETMsg;
import eo.ejb.cbm.entity.KK1681LE;
import eo.ejb.cbs.cbsmsg.EKK0351C250CBSMsg;
import eo.ejb.cbs.mainproc.JKKejbIdoRsvUtil;
import eo.ejb.common.JKKModelCommon;
import eo.ejb.common.JKKModelConst;
import eo.ejb.common.rule.JKKejbRule0083001;

/**
 * <p>
 * オプションサービス契約解約確定のDBアクセス部品クラスです。
 * </p>
 * @author 富士通
 */
public class JEKK0351C250ETDA
{
	/** 異動予約詳細コード オプション解約 */
	private static final String DTLCD_OPDISSOLVE = "016";
	
	/** 異動予約状態コード 反映済 */
	private static final String STATCD_DONE = "01";
	
	/** 異動予約状態コード 予約手続中 */
	private static final String STATCD_RSV_PROC = "03";
	
	/** 無効フラグ 有効 */
	private static final String MK_FLG_VALID = "0";
	
	/** 予約適用コード 予約確定 */
	private static final String RSVAPLY_DECIDED = "2";
	
	/** オプションサービス契約ステータス 解約済 */
	private static final String OP_STAT_DISSOLVE = "910";

	/** オプションサービス契約ステータス 締結済 */
	private static final String OP_STAT_TEIKETUZUMI = "030";
	
	/** 親契約識別コード(サービス契約内訳) */
	private static final String OYA_KEI_SKBT_CD_SVC_KEI_UCWK = "03";

	/** スキーマID オプションサービス契約 */
	private static final String SCHEMAID_OP_SVCKEI = "KK0351";
	
	/** スキーマID 異動予約 */
	private static final String SCHEMAID_IDORSV = "KK1681";

	/** 料金グループコード  ｅｏ光テレビ（Ｋ−ＣＡＴ）*/
	private static final String PRC_GRP_CD_TV_K_CAT = "11";
	
	/** 料金グループコード  ｅｏ光テレビ（再送信）*/
	private static final String PRC_GRP_CD_TV_RESEND = "13";
	
	/** カレント引継値 */
	private static final String CURRENT_VALUE = "CURRENT";

	/** 設定種類Key名 */
	private static final String KEY_SET_TYPE = "KEY_SET_TYPE";

	/** サービス課金開始年月日Key名 */
	private static final String KEY_SVC_CHRG_STA_YMD = "KEY_SVC_CHRG_STA_YMD";
	
	/** 設定種類保持用 */
	private String setType = null;
	
	/** プラン終了種別コード：プラン変更に伴う終了 */
	private static final String PLAN_END_SBT_CD_PLAN_CHANGE = "1";
	
	/** 年月日：初期値 */
	private static final String YMD_SHKV = "20991231";

	/**
	 * <p>
	 * 新しいJEKK0351C250ETDAを作成します。
	 * </p>
	 */
	public JEKK0351C250ETDA()
	{
	}

	/**
	 * <p>
	 * 相関ルールにて振舞判定を行い、オプションサービス契約または異動予約にDBアクセスを行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 */
	public void execDBAccess(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		// 相関ルールにて振舞うスキーマを判定
		JKKejbRule0083001 rule0083 = new JKKejbRule0083001(inCBSMsg);
		rule0083.setSvc_if_id(inCBSMsg.getString(JCMConstants.TEMPLATE_ID_KEY));
		
		String baseDate = inCBSMsg.getString(EKK0351C250CBSMsg.SVC_ENDYMD);
		String opeDate = JKKModelCommon.getOpeDate(inCBSMsg);
		
		rule0083.setBase_date(baseDate);
		rule0083.setOpe_date(opeDate);
		
		List<HashMap<String, Object>> ruleList = rule0083.referRuleEngine();
		
		if (ruleList == null)
		{
			// 相関ルールチェックの結果が0件の場合はエラーとする
			inCBSMsg.set(EKK0351C250CBSMsg.IDO_DIV_ERR, "EA");
			inCBSMsg.set(JCMConstants.STATUS_INT_KEY, StatusCodes.TEMPLATE_CORRELATION_ERR);
			return;
		}
		
		// 相関ルールチェック結果を格納
		new JKKejbIdoRsvUtil().setOnlyIdoRsvFlg(inCBSMsg, inContext, ruleList);
		
		CAANMsg updateInfo = null;
		
		for (HashMap<String, Object> hm : ruleList)
		{
			if (SCHEMAID_OP_SVCKEI.equals(hm.get(JKKejbRule0083001.TRGT_SCHEMA_ID)))
			{
				// オプションサービス契約に振舞う場合
				updateInfo = makeKK0351ETMsg(inCBSMsg, inContext);

				// 設定種類がカレント以外でサービス課金開始年月日が未設定の場合
				if (updateInfo == null)
				{
					return;
				}

				create(inCBSMsg, updateInfo);

				// オプションサービス契約に振舞った場合の個別出力項目の設定
				inCBSMsg.set(EKK0351C250CBSMsg.GENE_ADD_DTM, updateInfo.getString(KK0351ETMsg.GENE_ADD_DTM));
				inCBSMsg.set(EKK0351C250CBSMsg.OP_SVC_KEI_STAT, updateInfo.getString(KK0351ETMsg.OP_SVC_KEI_STAT));
				inCBSMsg.set(EKK0351C250CBSMsg.RSV_APLY_YMD, updateInfo.getString(KK0351ETMsg.RSV_APLY_YMD));
				inCBSMsg.set(EKK0351C250CBSMsg.SVCTK_BUT_DEL_TRN_JSSI_DTM, updateInfo.getString(KK0351ETMsg.SVCTK_BUT_DEL_TRN_JSSI_DTM));

				// 対象の「オプションサービス契約」の親「サービス契約」を取得する。
				CAANMsg kk0081Msg = new JKKejbKK0081DBABase().getKK0081byOpSvcKei(updateInfo, opeDate);

				// テレビオプション(親「サービス契約」のサービスコードが"テレビサービス")の場合、遡及解約は行なわない
				if (!JKKModelConst.SVC_CD_TV.equals(kk0081Msg.getString(KK0081ETMsg.SVC_CD)))
				{
					// 遡及解約対応
					// 履歴レコードにおいて、時系列順にて日付が逆転してしまう課金終了日の更新処理を行う
					updRirekiKK0351(inCBSMsg, inContext, updateInfo,
							updateInfo.getString(KK0351ETMsg.PLAN_CHRG_ENDYMD),
							updateInfo.getString(KK0351ETMsg.SVC_CHRG_ENDYMD));
				}
			}
			if (SCHEMAID_IDORSV.equals(hm.get(JKKejbRule0083001.TRGT_SCHEMA_ID)))
			{
				// 異動予約に振舞う場合
				updateInfo = makeKK1681ETMsg(inCBSMsg, hm, DTLCD_OPDISSOLVE, STATCD_RSV_PROC);
				update(inCBSMsg, updateInfo);
			}
		}

		// 出力項目の設定
		setOutputItem(inCBSMsg, updateInfo);
	}
	
	/**
	 * <p>
	 * DBの登録を行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @param inETMsg 登録対象DBのメッセージキャリア(ETメッセージ)
	 */
	private void create(CAANMsg inCBSMsg, CAANMsg inETMsg)
	{
		JKKejbDBAUtil dba = new JKKejbDBAUtil(inCBSMsg);
		
		// レコード登録
		dba.create(inETMsg);
	}

	/**
	 * <p>
	 * DBの更新を行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @param inETMsg 更新対象DBのメッセージキャリア(ETメッセージ)
	 */
	private void update(CAANMsg inCBSMsg, CAANMsg inETMsg)
	{
		JKKejbDBAUtil dba = new JKKejbDBAUtil(inCBSMsg);
		
		// レコード更新
		dba.update(inETMsg);
	}
	
	/**
	 * <p>
	 * オプションサービス契約に設定するETメッセージを作成します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @return サービス契約に設定する内容が設定されたETメッセージ
	 */
	private CAANMsg makeKK0351ETMsg(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		String opSvcKeiNo = inCBSMsg.getString(EKK0351C250CBSMsg.OP_SVC_KEI_NO);
		String geneAddDtm = (String)JKKModelCommon.getTransferGeneAddDtm(inCBSMsg, inContext);
		String opeDate = JKKModelCommon.getOpeDate(inCBSMsg);
		
		// 引継元となるカレントレコードを取得
		CAANMsg infoKK0351 = getCurKK0351(inCBSMsg);

		// オプションサービス契約ステータスを取得する
		String opSvcKeiStat = infoKK0351.getString(KK0351ETMsg.OP_SVC_KEI_STAT);
		// サービス課金開始年月日を取得する
		HashMap<String, String> svcChrgYmd = (HashMap<String, String>)JKKModelCommon.getChrgStaYmdEKK0351C250(inCBSMsg, inContext);
		// 設定種類をここで保持しておく
		setType = svcChrgYmd.get(KEY_SET_TYPE);

		if (setType == null || 
				(!CURRENT_VALUE.equals(setType) && !OP_STAT_TEIKETUZUMI.equals(opSvcKeiStat) && (svcChrgYmd == null || svcChrgYmd.get(KEY_SVC_CHRG_STA_YMD) == null)))
		{
			// 関連制約エラーのステータスを設定
			inCBSMsg.set(EKK0351C250CBSMsg.OP_SVC_KEI_NO_ERR, "EC");
			inCBSMsg.set(EKK0351C250CBSMsg.STATUS, StatusCodes.RELATION_ERR);
			return null;
		}

		// オプションサービス契約番号に紐付く「異動予約詳細コード」が"機器解約"、
		// 「異動予約状態コード」が"予約手続中"の異動予約を取得
		CAANMsg infoKK1681 = getIdoRsv(opSvcKeiNo, DTLCD_OPDISSOLVE, STATCD_RSV_PROC);
		
		// オプションサービス契約のETメッセージ
		infoKK0351.set(KK0351ETMsg.OP_SVC_KEI_NO, opSvcKeiNo);
		infoKK0351.set(KK0351ETMsg.GENE_ADD_DTM, geneAddDtm);
		infoKK0351.set(KK0351ETMsg.OP_SVC_KEI_STAT, OP_STAT_DISSOLVE);
		infoKK0351.set(KK0351ETMsg.MSKM_DTL_NO, infoKK1681.getString(KK1681ETMsg.MSKM_DTL_NO));

		// 運用日 ＞ サービス終了年月日の場合
		if (JPCUtilCommon.isPastDate(inCBSMsg.getString(EKK0351C250CBSMsg.SVC_ENDYMD), opeDate, "1"))
		{
			infoKK0351.set(KK0351ETMsg.RSV_APLY_YMD, opeDate);
		}
		else 
		{
			infoKK0351.set(KK0351ETMsg.RSV_APLY_YMD, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_ENDYMD));
		}
		infoKK0351.setNull(KK0351ETMsg.RSV_CL_YMD);
		infoKK0351.set(KK0351ETMsg.RSV_APLY_CD, RSVAPLY_DECIDED);
		//プラン終了年月日
		String svcEndYmd = (String) JKKModelCommon.getYmdDslFix(inCBSMsg, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_ENDYMD));
		infoKK0351.set(KK0351ETMsg.PLAN_ENDYMD, svcEndYmd);
		
		// オプションサービス契約ステータスが締結済の場合はカレント引継
		if (!OP_STAT_TEIKETUZUMI.equals(opSvcKeiStat)){
			infoKK0351.set(KK0351ETMsg.PLAN_CHRG_STAYMD, svcChrgYmd.get(KEY_SVC_CHRG_STA_YMD));
		}
		
		// プラン課金終了年月日
		infoKK0351.set(KK0351ETMsg.PLAN_CHRG_ENDYMD, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_CHRG_ENDYMD));
		
		// オプションサービス契約ステータスが締結済の場合はカレント引継
		if (!OP_STAT_TEIKETUZUMI.equals(opSvcKeiStat)){
			infoKK0351.set(KK0351ETMsg.SVC_CHRG_STAYMD, svcChrgYmd.get(KEY_SVC_CHRG_STA_YMD));
		}
		
		infoKK0351.set(KK0351ETMsg.PLAN_END_SBT_CD, inCBSMsg.getString(EKK0351C250CBSMsg.PLAN_END_SBT_CD));
		// サービス終了年月日
		infoKK0351.set(KK0351ETMsg.SVC_ENDYMD, svcEndYmd);
		// サービス課金終了年月日
		infoKK0351.set(KK0351ETMsg.SVC_CHRG_ENDYMD, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_CHRG_ENDYMD));
		// サービス解約年月日
		infoKK0351.set(KK0351ETMsg.SVC_DSL_YMD, svcEndYmd);
		infoKK0351.set(KK0351ETMsg.SVC_DLRE_CD, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_DLRE_CD));
		infoKK0351.set(KK0351ETMsg.SVC_DLRE_MEMO, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_DLRE_MEMO));
		infoKK0351.set(KK0351ETMsg.DSL_TNT_USER_ID, inCBSMsg.getString(EKK0351C250CBSMsg.DSL_TNT_USER_ID));
		infoKK0351.setNull(KK0351ETMsg.SVC_DSL_TTDKI_FIN_FLG);
		infoKK0351.setNull(KK0351ETMsg.KAIHK_YMD);
		infoKK0351.setNull(KK0351ETMsg.SVC_DSL_CL_YMD);
		infoKK0351.set(KK0351ETMsg.PNLTY_HASSEI_CD, infoKK1681.getString(KK1681ETMsg.PNLTY_HASSEI_CD));
		infoKK0351.set(KK0351ETMsg.IDO_DIV, infoKK1681.getString(KK1681ETMsg.IDO_DIV));
		
		if (JKKModelCommon.isChkSvctkButDelTrnJssiDtmKK0351(inCBSMsg, inContext, opSvcKeiNo, inCBSMsg.getString(EKK0351C250CBSMsg.IDO_DIV)))
		{
			// サービス提供物消去処理実施年月日時分秒
			infoKK0351.set(KK0351ETMsg.SVCTK_BUT_DEL_TRN_JSSI_DTM, JKKModelCommon.getOpeDateTimeStamp(inCBSMsg));
		}
		
		infoKK0351.set(KK0351ETMsg.ADD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		infoKK0351.set(KK0351ETMsg.ADD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		infoKK0351.set(KK0351ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		infoKK0351.set(KK0351ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		infoKK0351.setNull(KK0351ETMsg.DEL_DTM);
		infoKK0351.setNull(KK0351ETMsg.DEL_OPEACNT);
		infoKK0351.set(KK0351ETMsg.MK_FLG, MK_FLG_VALID);

		return infoKK0351;
	}

	/**
	 * <p>
	 * 異動予約に設定するETメッセージを作成します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param ruleMap 相関ルールチェック結果のマップクラス
	 * @param idoRsvDtlCd 検索する異動予約詳細コード
	 * @param idoRsvStatCd 検索する異動予約状態コード
	 * @return 異動予約に設定する内容が設定されたETメッセージ
	 */
	private CAANMsg makeKK1681ETMsg(CAANMsg inCBSMsg, Map<String, Object> ruleMap
										, String idoRsvDtlCd, String idoRsvStatCd)
	{
		// 異動予約番号を取得
		String opSvcKeiNo = inCBSMsg.getString(EKK0351C250CBSMsg.OP_SVC_KEI_NO);
		CAANMsg infoKK1681 = getIdoRsv(opSvcKeiNo, idoRsvDtlCd, idoRsvStatCd);
		
		String ruleStatCd = (String)ruleMap.get(JKKejbRule0083001.IDO_RSV_STAT_CD);
		
		// 異動予約のETメッセージ
		CAANMsg kk1681ETMsg = new CAANMsg(KK1681ETMsg.class.getName());
		kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_NO, infoKK1681.getString(KK1681ETMsg.IDO_RSV_NO));
		String opeDate = JKKModelCommon.getOpeDate(inCBSMsg);

		// 運用日 ＞ サービス終了年月日の場合
		if (JPCUtilCommon.isPastDate(inCBSMsg.getString(EKK0351C250CBSMsg.SVC_ENDYMD), opeDate, "1"))
		{
			kk1681ETMsg.set(KK0351ETMsg.RSV_APLY_YMD, opeDate);
		}
		else 
		{
			kk1681ETMsg.set(KK0351ETMsg.RSV_APLY_YMD, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_ENDYMD));
		}

		if (STATCD_DONE.equals(ruleStatCd))
		{
			// 即時反映(異動予約状態コードが反映済)の場合、異動予約反映年月日を設定
			// 運用日 ＞ サービス終了年月日の場合
			if (JPCUtilCommon.isPastDate(inCBSMsg.getString(EKK0351C250CBSMsg.SVC_ENDYMD), opeDate, "1"))
			{
				kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_HANEI_YMD, opeDate);
			}
			else 
			{
				kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_HANEI_YMD, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_ENDYMD));
			}
		}
		else
		{
			// 料金グループが「ｅｏ光テレビ（Ｋ−ＣＡＴ）」か「ｅｏ光テレビ（再送信）」判定処理
			if(isChkPrcGrpCdTv(inCBSMsg))
			{
				// サービス課金終了年月日
				kk1681ETMsg.set(KK1681ETMsg.SVC_CHRG_ENDYMD, inCBSMsg.getString(EKK0351C250CBSMsg.SVC_CHRG_ENDYMD));
			}
		}
		
		kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_STAT_CD, ruleMap.get(JKKejbRule0083001.IDO_RSV_STAT_CD));
		kk1681ETMsg.set(KK1681ETMsg.UPD_DTM , inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		kk1681ETMsg.set(KK1681ETMsg.UPD_OPEACNT , inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));

		// 申込明細番号を出力に設定
		inCBSMsg.set(EKK0351C250CBSMsg.MSKM_DTL_NO, infoKK1681.getString(KK1681ETMsg.MSKM_DTL_NO));
		
		return kk1681ETMsg;
	}
	
	/**
	 * <p>
	 * CBSメッセージの出力項目に値を設定します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @param inETMsg DBに設定した内容を持っているETメッセージ
	 */
	private void setOutputItem(CAANMsg inCBSMsg, CAANMsg inETMsg)
	{
		inCBSMsg.set(EKK0351C250CBSMsg.ADD_DTM, inETMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		inCBSMsg.set(EKK0351C250CBSMsg.ADD_OPEACNT, inETMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		inCBSMsg.set(EKK0351C250CBSMsg.UPD_DTM, inETMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		inCBSMsg.set(EKK0351C250CBSMsg.UPD_OPEACNT, inETMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		inCBSMsg.set(EKK0351C250CBSMsg.MK_FLG, MK_FLG_VALID);
	}

	/**
	 * <p>
	 * オプションサービス契約のカレントレコードを取得します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @return オプションサービス契約のカレントレコード
	 */
	private CAANMsg getCurKK0351(CAANMsg inCBSMsg)
	{
		// オプションサービス契約のカレントレコードを取得
		CAANMsg et = new CAANMsg(KK0351ETMsg.class.getName());
		et.set(KK0351ETMsg.OP_SVC_KEI_NO, inCBSMsg.getString(EKK0351C250CBSMsg.OP_SVC_KEI_NO));
		et.set(KK0351ETMsg.RSV_APLY_YMD, JKKModelCommon.getOpeDate(inCBSMsg));
		
		CAANMsg curKK0351 = new JKKejbKK0351DBABase().findByCurrent(et);

		return curKK0351;
	}

	/**
	 * <p>
	 * 下記項目を条件に異動予約を取得します。
	 * <br>・オプションサービス契約番号
	 * <br>・異動予約詳細コード
	 * <br>・異動予約状態コード
	 * </p>
	 * @param opSvcKeiNo 検索するオプションサービス契約番号
	 * @param idoRsvDtlCd 検索する異動予約詳細コード
	 * @param idoRsvStatCd 検索する異動予約状態コード
	 * @return 条件に該当する異動予約
	 *          条件に該当する異動予約がない場合、nullを返却
	 */
	private CAANMsg getIdoRsv(String opSvcKeiNo, String idoRsvDtlCd, String idoRsvStatCd)
	{
		// 条件を設定
		KK1681LE le = new KK1681LE();
		CAANMsg conditionETMsg = new CAANMsg(KK1681ETMsg.class.getName());
		conditionETMsg.set(KK1681ETMsg.OP_SVC_KEI_NO, opSvcKeiNo);
		conditionETMsg.set(KK1681ETMsg.IDO_RSV_DTL_CD, idoRsvDtlCd);
		conditionETMsg.set(KK1681ETMsg.IDO_RSV_STAT_CD, idoRsvStatCd);
		conditionETMsg.set(KK1681ETMsg.MK_FLG, MK_FLG_VALID);
		
		CAANMsg[] kk1681MsgList = null;

		try
		{
			kk1681MsgList = le.findByCondition(conditionETMsg);
		}
		catch (CAANException ce)
		{
			// エラーが発生した場合、nullを返却
			return null;
		}

		/* ----------------------------------------------------------------------------------------------------
		 * 複数の「異動予約」(異動予約詳細コード＝"解約")が存在する場合、
		 * 異動区分、申込明細番号などを入力項目(必須)として、更新対象の「異動予約」を特定する必要があるが、
		 * 現時点では、入力値が存在しないため、異動予約番号が最大の「異動予約」を更新対象とする。
		 * ---------------------------------------------------------------------------------------------------- */
		// 更新対象「異動予約」
		CAANMsg updTgKK1681Msg = null;
		// 更新対象「異動予約」の異動予約番号
		String updTgIdoRsvNo = null;

		for (CAANMsg kk1681Msg : kk1681MsgList)
		{
			String idoRsvNo = kk1681Msg.getString(KK1681ETMsg.IDO_RSV_NO);
			if (updTgIdoRsvNo == null || updTgIdoRsvNo.compareTo(idoRsvNo) < 0)
			{
				updTgIdoRsvNo = idoRsvNo;
				updTgKK1681Msg = kk1681Msg;
			}
		}
		if (updTgKK1681Msg == null)
		{
			throw new CAANRuntimeException("解約確定対象のオプションサービス契約に対する異動予約が存在しません。オプションサービス契約番号:" + opSvcKeiNo);
		}

		return updTgKK1681Msg;
	}
	
	/**
	 * <p>
	 * 料金グループが「ｅｏ光テレビ（Ｋ−ＣＡＴ）」か「ｅｏ光テレビ（再送信）」判定処理
	 * </p>
	 * @param inCBSMsg 入力パラメータのCBSMsg
	 * @return 「ｅｏ光テレビ（Ｋ−ＣＡＴ）」か「ｅｏ光テレビ（再送信）」の場合true
	 */
	private boolean isChkPrcGrpCdTv(CAANMsg inCBSMsg)
	{
		// 運用日付
		String opeDate = JKKModelCommon.getOpeDate(inCBSMsg);
		// オプションサービス契約番号
		String opSvcKeiNo = inCBSMsg.getString(EKK0351C250CBSMsg.OP_SVC_KEI_NO);

		// 内部スキーマメッセージを作成(オプションサービス契約)
		CAANMsg inMsgKK0351 = new CAANMsg(KK0351ETMsg.class.getName());

		// パラメータ設定
		inMsgKK0351.set(KK0351ETMsg.OP_SVC_KEI_NO, opSvcKeiNo);
		inMsgKK0351.set(KK0351ETMsg.RSV_APLY_YMD, opeDate);

		// オプションサービス契約のカレントレコードを取得する。
		CAANMsg curMsgKK0351 = new JKKejbKK0351DBABase().findByCurrent(inMsgKK0351);
		
		if(null == curMsgKK0351)
		{
			return false;
		}

		// サービス契約番号
		String svcKeiNo = curMsgKK0351.getString(KK0351ETMsg.SVC_KEI_NO);

		// サービス契約番号が取得でない場合
		if (null == svcKeiNo || "".equals(svcKeiNo))
		{
			// サービス契約内訳メッセージ生成
			CAANMsg inMsgKK0161 = new CAANMsg(KK0161ETMsg.class.getName());

			// サービス契約番号
			String svcKeiUcwkNo = curMsgKK0351.getString(KK0351ETMsg.SVC_KEI_UCWK_NO);

			// サービス契約内訳設定
			inMsgKK0161.set(KK0161ETMsg.SVC_KEI_UCWK_NO, svcKeiUcwkNo);
			inMsgKK0161.set(KK0161ETMsg.RSV_APLY_YMD, opeDate);

			// サービス契約内訳カレント検索を行う
			CAANMsg curMsgKK0161 = new JKKejbKK0161DBABase().findByCurrent(inMsgKK0161);

			if(null == curMsgKK0161)
			{
				return false;
			}

			svcKeiNo = curMsgKK0161.getString(KK0161ETMsg.SVC_KEI_NO);

		}

		// サービス契約メッセージ生成
		CAANMsg inMsgKK0081 = new CAANMsg(KK0081ETMsg.class.getName());

		// サービス契約設定
		inMsgKK0081.set(KK0081ETMsg.SVC_KEI_NO, svcKeiNo);
		inMsgKK0081.set(KK0081ETMsg.RSV_APLY_YMD, opeDate);

		// サービス契約カレント検索を行う
		CAANMsg curMsgKK0081 = new JKKejbKK0081DBABase().findByCurrent(inMsgKK0081);

		if(null == curMsgKK0081)
		{
			return false;
		}

		// 料金グループコード
		String prcGrpCd = curMsgKK0081.getString(KK0081ETMsg.PRC_GRP_CD);

		// 料金グループコードが「ｅｏ光テレビ（Ｋ−ＣＡＴ）」か「ｅｏ光テレビ（再送信）」の場合
		if (PRC_GRP_CD_TV_K_CAT.equals(prcGrpCd) || PRC_GRP_CD_TV_RESEND.equals(prcGrpCd))
		{
			return true;
		}

		return false;
	}

	/**
	 * <p>
	 * 遡及解約対応・履歴レコード課金終了日更新処理
	 * 遡及解約により、解約(最新)レコードの課金終了日に対して、履歴レコードの課金終了日が未来日になってしまう場合に、
	 * 解約(最新)レコードの課金終了日と同日を履歴レコードの課金終了日に設定する。
	 * </p>
	 * @param inCBSMsg  処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @param updateInfo 解約(最新)レコードのメッセージキャリア
	 * @param planChrgEndymd 新規レコードのプラン課金終了年月日
	 * @param svcChrgEndymd 新規レコードのサービス課金終了年月日
	 */
	private void updRirekiKK0351(CAANMsg inCBSMsg, AgentDispatchContext inContext, CAANMsg updateInfo, String planChrgEndymd, String svcChrgEndymd)
	{
		// 同一「サービス契約」配下の「オプションサービス契約」で、プラン課金終了日が設定されている履歴レコードを取得する。
		// 条件：プラン終了種別コード＝"プラン変更に伴う終了"、オプションサービスコード＝解約対象オプション
		CAANMsg[] conRetMsg = getPlanEndRirekiKK0351(updateInfo);
		// 取得できない場合は処理を終了する
		if (null == conRetMsg || conRetMsg.length == 0)
		{
			return;
		}
		
		// 当該サービスIFにて作成した解約(最新)レコードのサービス契約内訳番号、世代登録年月日時分秒
		String opSvcKeiNo = inCBSMsg.getString(EKK0351C250CBSMsg.OP_SVC_KEI_NO);
		String geneAddDtm = inCBSMsg.getString(EKK0351C250CBSMsg.GENE_ADD_DTM);

		/* ----------------------------------------------------------------------------------------------------
		 * 履歴レコード.プラン課金終了年月日更新処理
		 * 条件：解約(最新)レコード.プラン課金終了年月日＜履歴レコード.プラン課金終了年月日
		 * ---------------------------------------------------------------------------------------------------- */
		for (CAANMsg retMsg : conRetMsg)
		{
			// 当該サービスIFにて作成した解約(最新)レコードは、更新対象外
			if (opSvcKeiNo.equals(retMsg.getString(KK0351ETMsg.OP_SVC_KEI_NO)) && 
					geneAddDtm.equals(retMsg.getString(KK0351ETMsg.GENE_ADD_DTM)))
			{
				continue;
			}

			// 履歴レコード.プラン課金終了年月日
			String workPlanChrgEndymd = retMsg.getString(KK0351ETMsg.PLAN_CHRG_ENDYMD);
			// 履歴レコード.プラン課金終了年月日が未設定または"20991231"または解約(最新)レコード.サービス課金終了年月日が未設定の場合は処理しない
			if (!(null == workPlanChrgEndymd || "".equals(workPlanChrgEndymd) || YMD_SHKV.equals(workPlanChrgEndymd) || null == svcChrgEndymd)
					&& JPCUtilCommon.isFutureDate(workPlanChrgEndymd, planChrgEndymd, "0"))
			{
				// 解約(最新)レコード.プラン課金終了年月日＜履歴レコード.プラン課金終了年月日の場合
				retMsg.set(KK0351ETMsg.PLAN_CHRG_ENDYMD, planChrgEndymd);
				
				/* ----------------------------------------------------------------------------------------------------
				 * 履歴レコード.サービス課金終了年月日更新処理
				 * 条件：解約(最新)レコード.サービス課金終了年月日＜履歴レコード.サービス課金終了年月日
				 * ※同一「サービス契約」配下で、サービス課金終了年月日が解約対象の当該「オプションサービス契約」より未来日になる場合
				 * ---------------------------------------------------------------------------------------------------- */
				// 履歴レコード.サービス課金終了年月日
				String workSvcChrgEndymd = retMsg.getString(KK0351ETMsg.SVC_CHRG_ENDYMD);
				// 履歴レコード.サービス課金終了年月日が未設定または"20991231"の場合は処理しない
				if (!(null == workSvcChrgEndymd || "".equals(workSvcChrgEndymd) || YMD_SHKV.equals(workSvcChrgEndymd))
						&& JPCUtilCommon.isFutureDate(workSvcChrgEndymd, svcChrgEndymd, "0"))
				{
					// 解約(最新)レコード.サービス課金終了年月日＜履歴レコード.サービス課金終了年月日の場合
					retMsg.set(KK0351ETMsg.SVC_CHRG_ENDYMD, svcChrgEndymd);
				}
				
				retMsg.set(KK0351ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
				retMsg.set(KK0351ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
			}
			else
			{
				continue;
			}

			JKKejbDBAUtil dbaUtil = new JKKejbDBAUtil(inCBSMsg);
			dbaUtil.update(retMsg);
		}
	}

	/**
	 * <p>
	 * 遡及解約対応・プラン終了履歴レコード抽出処理
	 * </p>
	 * @param updateInfo 解約(最新)レコードのメッセージキャリア
	 */
	private CAANMsg[] getPlanEndRirekiKK0351(CAANMsg updateInfo)
	{
		// 解約(最新)レコード.オプションサービスコード
		String opSvcCd = updateInfo.getString(KK0351ETMsg.OP_SVC_CD);
		// 解約(最新)レコード.サービス契約番号
		String svcKeiNo = updateInfo.getString(KK0351ETMsg.SVC_KEI_NO);
		// 解約(最新)レコード.サービス契約内訳番号
		String svcKeiUcwkNo = updateInfo.getString(KK0351ETMsg.SVC_KEI_UCWK_NO);
		// 解約(最新)レコード.親契約識別コード
		String oyaKeiSkbtCd = updateInfo.getString(KK0351ETMsg.OYA_KEI_SKBT_CD);

		if (OYA_KEI_SKBT_CD_SVC_KEI_UCWK.equals(oyaKeiSkbtCd)) 
		{
			// サービス契約内訳のカレントレコードを取得
			CAANMsg infoKK0161 = getCurKK0161(updateInfo, svcKeiUcwkNo);
			svcKeiNo = infoKK0161.getString(KK0161ETMsg.SVC_KEI_NO);
		}
		
		// 運用日付
		String opeDate = JKKModelCommon.getOpeDate(updateInfo);
		// 個別検索条件マップ
		HashMap<String, String[]> searchJknMap = new HashMap<String, String[]>();
		// 追加検索条件：オプションサービス契約.オプションサービスコード
		String [] opSvcCdList = {opSvcCd};
		searchJknMap.put(KK0351ETMsg.OP_SVC_CD, opSvcCdList);
		// 追加検索条件：オプションサービス契約.プラン終了種別コード：プラン変更に伴う終了 
		String [] planEndSbtCdList = {PLAN_END_SBT_CD_PLAN_CHANGE};
		searchJknMap.put(KK0351ETMsg.PLAN_END_SBT_CD, planEndSbtCdList);
		
		// 同一「サービス契約」配下の「オプションサービス契約」履歴を取得する
		JKKejbKK0351DBABase kk0351Dba = new JKKejbKK0351DBABase();
		CAANMsg[] kk0351MsgList = kk0351Dba.getKK0351bySvcKeiRireki(svcKeiNo, searchJknMap, opeDate, "3");
		
		return kk0351MsgList;
	}

	/**
	 * <p>
	 * サービス契約内訳のカレントレコードを取得します。
	 * </p>
	 * @param updateInfo 処理対象のメッセージキャリア(CBSメッセージ)
	 * @return サービス契約内訳のカレントレコード
	 */
	private CAANMsg getCurKK0161(CAANMsg updateInfo, String svcKeiUcwkNo)
	{
		// サービス契約内訳のカレントレコードを取得
		CAANMsg et = new CAANMsg(KK0161ETMsg.class.getName());
		et.set(KK0161ETMsg.SVC_KEI_UCWK_NO, svcKeiUcwkNo);
		et.set(KK0161ETMsg.RSV_APLY_YMD, JKKModelCommon.getOpeDate(updateInfo));
		
		CAANMsg curKK0161 = new JKKejbKK0161DBABase().findByCurrent(et);

		return curKK0161;
	}
}
