/*********************************************************************
*   All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JEKK2811C150ETDA
*   ソースファイル名：JEKK2811C150ETDA.java
*   作成者          ：富士通
*   日付            ：2013年11月14日
*＜機能概要＞
*   機器オプションサービス契約解約確定のDBアクセス部品クラス
*＜修正履歴＞
*   バージョン  修正日      修正者      修正内容
*   v7.00.00    2013/11/14  富士通      新規作成
*   v7.00.01    2013/12/24  FJ)大山     IT1-2013-0001729
*   v8.00.00	2014/05/12	FJ)宇野		OM-2014-0001440
*   v10.00.00	2014/09/02  FJ)中野     IT2-2014-0000289
*   v11.00.00	2015/01/06	FJ)阪口		OM-2014-0003832
*   v35.00.00	2017/12/06	FJ)岡村		OM-2017-0000287
**********************************************************************/

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.KK1681ETMsg;
import eo.ejb.cbm.entity.KK1681LE;
import eo.ejb.cbm.entity.KK2811ETMsg;
import eo.ejb.cbm.entity.KK2811LE;
import eo.ejb.cbs.cbsmsg.EKK2811C070CBSMsg;
import eo.ejb.cbs.cbsmsg.EKK2811C150CBSMsg;
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 JEKK2811C150ETDA
{
	/**
	 * <p>
	 * 新しいJEKK2811C150ETDAを作成します。
	 * </p>
	 */
	public JEKK2811C150ETDA()
	{
	}

	/**
	 * <p>
	 * 相関ルールにて振舞判定を行い、機器オプションサービス契約または異動予約にDBアクセスを行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 */
	public void execDBAccess(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		// 異動対象スキーマ判定相関ルール
		JKKejbKK2811ETDA kk2811Etda = new JKKejbKK2811ETDA();
		String svcEndYmd = inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD);
		List<HashMap<String, Object>> ruleList = kk2811Etda.execSokanOfIdoJdg(inCBSMsg, inContext, svcEndYmd);
		if (ruleList == null)
		{
			// 相関ルールチェックの結果が0件の場合はエラーとする
			inCBSMsg.set(EKK2811C150CBSMsg.KKOP_SVC_KEI_NO_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 (JKKejbKK2811ETDA.SCHEMAID_KKOPSVCKEI.equals(hm.get(JKKejbRule0083001.TRGT_SCHEMA_ID)))
			{
				// 機器オプションサービス契約に振舞う場合
				updateInfo = makeKK2811ETMsg(inCBSMsg, inContext);
				create(inCBSMsg, updateInfo);
	
				// 機器オプションサービス契約に振舞った場合の個別出力項目の設定
				inCBSMsg.set(EKK2811C150CBSMsg.GENE_ADD_DTM, updateInfo.getString(KK2811ETMsg.GENE_ADD_DTM));
				inCBSMsg.set(EKK2811C150CBSMsg.KKOP_SVC_KEI_STAT, updateInfo.getString(KK2811ETMsg.KKOP_SVC_KEI_STAT));
				inCBSMsg.set(EKK2811C150CBSMsg.RSV_APLY_YMD, updateInfo.getString(KK2811ETMsg.RSV_APLY_YMD));
				inCBSMsg.set(EKK2811C150CBSMsg.MSKM_DTL_NO, updateInfo.getString(KK2811ETMsg.MSKM_DTL_NO));
				inCBSMsg.set(EKK2811C150CBSMsg.RSV_APLY_CD, updateInfo.getString(KK2811ETMsg.RSV_APLY_CD));
				inCBSMsg.set(EKK2811C150CBSMsg.IDO_DIV, updateInfo.getString(KK2811ETMsg.IDO_DIV));
				inCBSMsg.set(EKK2811C150CBSMsg.ADD_DTM, updateInfo.getString(KK2811ETMsg.ADD_DTM));
				inCBSMsg.set(EKK2811C150CBSMsg.ADD_OPEACNT, updateInfo.getString(KK2811ETMsg.ADD_OPEACNT));
				inCBSMsg.set(EKK2811C150CBSMsg.MK_FLG, updateInfo.getString(KK2811ETMsg.MK_FLG));
				
				// 遡及解約対応
				// 履歴レコードにおいて、時系列順にて日付が逆転してしまう課金終了日の更新処理を行う
				updRirekiKK2811(inCBSMsg, inContext, updateInfo.getString(KK2811ETMsg.PLAN_CHRG_ENDYMD));
			}
			if (JKKejbKK2811ETDA.SCHEMAID_IDORSV.equals(hm.get(JKKejbRule0083001.TRGT_SCHEMA_ID)))
			{
				// サービス終了年月日が運用日付と同日で異動予約に振舞う場合
				updateInfo = makeKK1681ETMsg(inCBSMsg, hm, JKKModelConst.IDO_RSV_DTL_CD_KKOP_DSL, JKKModelConst.IDO_RSV_STAT_CD_RSV_TTDK_CHU);
				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 makeKK2811ETMsg(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		String kkopSvcKeiNo = inCBSMsg.getString(EKK2811C150CBSMsg.KKOP_SVC_KEI_NO);
		String geneAddDtm = (String)JKKModelCommon.getTransferGeneAddDtm(inCBSMsg, inContext);
		String opeDate = JKKModelCommon.getOpeDate(inCBSMsg);

		// 引継元となるカレントレコードを取得
		CAANMsg infoKK2811 = getCurKK2811(inCBSMsg);
		
		// OM-2014-0003832 ADD START
		// カレントレコードの機器オプションサービス契約ステータスを退避する
		String curKkopSvcKeiStat = infoKK2811.getString(KK2811ETMsg.KKOP_SVC_KEI_STAT);
		// OM-2014-0003832 ADD END
		
		// 機器オプションサービス契約番号に紐付く「異動予約詳細コード」が"機器オプション解約"、
		// 「異動予約状態コード」が"予約手続中"の異動予約を取得
		CAANMsg infoKK1681 = getIdoRsv(kkopSvcKeiNo, JKKModelConst.IDO_RSV_DTL_CD_KKOP_DSL, JKKModelConst.IDO_RSV_STAT_CD_RSV_TTDK_CHU);
		
		// 機器オプションサービス契約のETメッセージ
		// 機器オプションサービス契約番号
		infoKK2811.set(KK2811ETMsg.KKOP_SVC_KEI_NO, kkopSvcKeiNo);
		// 世代登録年月日時分秒
		infoKK2811.set(KK2811ETMsg.GENE_ADD_DTM, geneAddDtm);
		// 機器オプションサービス契約ステータス
		infoKK2811.set(KK2811ETMsg.KKOP_SVC_KEI_STAT, JKKModelConst.KKOP_SVC_KEI_STAT_DSL_ZM);
		// 申込明細番号
		infoKK2811.set(KK2811ETMsg.MSKM_DTL_NO, infoKK1681.getString(KK1681ETMsg.MSKM_DTL_NO));

		// 予約適用年月日
		// 運用日 ＞ サービス終了年月日の場合
		if (JPCUtilCommon.isPastDate(inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD), opeDate, "1"))
		{
			// 運用日付を設定する
			infoKK2811.set(KK2811ETMsg.RSV_APLY_YMD, opeDate);
		}
		else
		{
			infoKK2811.set(KK2811ETMsg.RSV_APLY_YMD, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD));
		}
		// 予約取消年月日
		infoKK2811.setNull(KK2811ETMsg.RSV_CL_YMD);
		// 予約適用コード
		infoKK2811.set(KK2811ETMsg.RSV_APLY_CD, JKKModelConst.RSV_APLY_CD_RSV_FIX);
		// サービス終了年月日
		infoKK2811.set(KK2811ETMsg.SVC_ENDYMD, JKKModelCommon.getYmdDslFix(inCBSMsg, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD)));
		
		// IT2-2014-0000289 ADD START
		String staYmd = infoKK2811.getString((KK2811ETMsg.SVC_STAYMD));
		// IT2-2014-0000289 ADD END
		// 相関ルールを実行し、サービス課金開始日を取得する
		JKKejbKK2811ETDA kk2811Etda = new JKKejbKK2811ETDA();
		String svcIfId = inCBSMsg.getString(EKK2811C070CBSMsg.TEMPLATEID);
		String idoDiv = inCBSMsg.getString(EKK2811C070CBSMsg.IDO_DIV);
		// IT2-2014-0000289 MOD START
		// String chrgStaYmd = kk2811Etda.getChrgStaYmd(inCBSMsg, inContext, kkopSvcKeiNo, idoDiv, null, opeDate, svcIfId);
		String chrgStaYmd = kk2811Etda.getChrgStaYmd(inCBSMsg, inContext, kkopSvcKeiNo, idoDiv, staYmd, opeDate, svcIfId);
		// IT2-2014-0000289 MOD END
		
		// サービス課金開始年月日
		if (!inCBSMsg.isNull(EKK2811C150CBSMsg.SVC_CHRG_STAYMD))
		{
			// 入力されている場合
			infoKK2811.set(KK2811ETMsg.SVC_CHRG_STAYMD, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_CHRG_STAYMD));
		}
		else
		{
			// OM-2017-0000287 ADD START
			// VA機能でない場合のみ処理実施
			if(!JKKModelConst.KKOP_SVC_CD_VA_ADPT.equals(infoKK2811.getString(KK2811ETMsg.KKOP_SVC_CD)))
			{
			// OM-2017-0000287 ADD END
				// OM-2014-0003832 MOD START
				// 未入力の場合
				if (!JKKModelConst.KKOP_SVC_KEI_STAT_CNC_ZM.equals(curKkopSvcKeiStat))
				{
					// 機器オプションサービス契約ステータスが「030：締結済」でなければ、相関ルールの実行結果を設定する
					infoKK2811.set(KK2811ETMsg.SVC_CHRG_STAYMD, chrgStaYmd);
				}
				// OM-2014-0003832 MOD END
			// OM-2017-0000287 ADD START
			}
			// OM-2017-0000287 ADD END
		}
		// サービス課金終了年月日
		infoKK2811.set(KK2811ETMsg.SVC_CHRG_ENDYMD, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_CHRG_ENDYMD));
		
		// プラン終了年月日
		if (inCBSMsg.isNull(EKK2811C150CBSMsg.PLAN_ENDYMD))
		{
			// 入力のプラン終了年月日が空白の場合「サービス終了年月日」
			infoKK2811.set(KK2811ETMsg.PLAN_ENDYMD, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD));
		}
		else
		{
			// 入力の「プラン終了年月日」
			infoKK2811.set(KK2811ETMsg.PLAN_ENDYMD, inCBSMsg.getString(EKK2811C150CBSMsg.PLAN_ENDYMD));
		}
		
		// プラン課金開始年月日
		if (!inCBSMsg.isNull(EKK2811C150CBSMsg.PLAN_CHRG_STAYMD))
		{
			// 入力されている場合
			infoKK2811.set(KK2811ETMsg.PLAN_CHRG_STAYMD, inCBSMsg.getString(EKK2811C150CBSMsg.PLAN_CHRG_STAYMD));
		}
		// OM-2017-0000287 ADD START
		else
		{
			// VA機能でない場合のみ処理実施
			if(!JKKModelConst.KKOP_SVC_CD_VA_ADPT.equals(infoKK2811.getString(KK2811ETMsg.KKOP_SVC_CD)))
			{
				// 未入力の場合
				if (!JKKModelConst.KKOP_SVC_KEI_STAT_CNC_ZM.equals(curKkopSvcKeiStat))
				{
					// 機器オプションサービス契約ステータスが「030：締結済」でなければ、相関ルールの実行結果を設定する
					infoKK2811.set(KK2811ETMsg.PLAN_CHRG_STAYMD, chrgStaYmd);
				}
			}
		}
		// OM-2017-0000287 ADD END
		
		// プラン課金開始年月日が未入力の場合カレント同項目
		
		// プラン課金終了年月日
		if (inCBSMsg.isNull(EKK2811C150CBSMsg.PLAN_CHRG_ENDYMD))
		{
			// 入力のプラン課金終了日が空白の場合「サービス課金終了年月日」
			infoKK2811.set(KK2811ETMsg.PLAN_CHRG_ENDYMD, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_CHRG_ENDYMD));
		}
		else
		{
			// 「プラン課金終了日」
			infoKK2811.set(KK2811ETMsg.PLAN_CHRG_ENDYMD, inCBSMsg.getString(EKK2811C150CBSMsg.PLAN_CHRG_ENDYMD));
		}

		// プラン終了種別コード
		infoKK2811.setNull(KK2811ETMsg.PLAN_END_SBT_CD);
		// サービス解約年月日
		infoKK2811.set(KK2811ETMsg.SVC_DSL_YMD, JKKModelCommon.getYmdDslFix(inCBSMsg, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD)));
		// サービス解約理由コード
		infoKK2811.set(KK2811ETMsg.SVC_DLRE_CD, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_DLRE_CD));
		// サービス解約理由メモ
		infoKK2811.set(KK2811ETMsg.SVC_DLRE_MEMO, inCBSMsg.getString(EKK2811C150CBSMsg.SVC_DLRE_MEMO));
		// サービス解約取消年月日
		infoKK2811.setNull(KK2811ETMsg.SVC_DSL_CL_YMD);
		// サービス解約手続完了フラグ
		infoKK2811.setNull(KK2811ETMsg.SVC_DSL_TTDKI_FIN_FLG);
		// 回復年月日
		infoKK2811.setNull(KK2811ETMsg.KAIHK_YMD);
		// 違約金発生コード
		infoKK2811.set(KK2811ETMsg.PNLTY_HASSEI_CD, infoKK1681.getString(KK1681ETMsg.PNLTY_HASSEI_CD));
		// 異動区分
		infoKK2811.set(KK2811ETMsg.IDO_DIV, infoKK1681.getString(KK1681ETMsg.IDO_DIV));
		
		infoKK2811.set(KK2811ETMsg.ADD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		infoKK2811.set(KK2811ETMsg.ADD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		infoKK2811.set(KK2811ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		infoKK2811.set(KK2811ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		infoKK2811.set(KK2811ETMsg.MK_FLG, JKKModelConst.MK_FLG_YK);
		
		return infoKK2811;
	}

	/**
	 * <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 kkopSvcKeiNo = inCBSMsg.getString(EKK2811C150CBSMsg.KKOP_SVC_KEI_NO);
		CAANMsg infoKK1681 = getIdoRsv(kkopSvcKeiNo, 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 (JKKModelCommon.isPastDate(inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD), opeDate, "1"))
		{
			// 運用日付を設定する
			kk1681ETMsg.set(KK2811ETMsg.RSV_APLY_YMD, opeDate);
		} else {
			kk1681ETMsg.set(KK1681ETMsg.RSV_APLY_YMD , inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD));
		}

		if (JKKModelConst.IDO_RSV_STAT_CD_HANEI_ZM.equals(ruleStatCd))
		{
			// 即時反映(異動予約状態コードが反映済)の場合、異動予約反映年月日を設定
			// 運用日 ＞ サービス終了年月日の場合
			if (JKKModelCommon.isPastDate(inCBSMsg.getString(EKK2811C150CBSMsg.SVC_ENDYMD), opeDate, "1"))
			{
				// 運用日付を設定する
				kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_HANEI_YMD , opeDate);
			} else {
				kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_HANEI_YMD , inCBSMsg.getString(EKK2811C150CBSMsg.SVC_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(EKK2811C150CBSMsg.IDO_DIV, infoKK1681.getString(KK1681ETMsg.IDO_DIV));
		inCBSMsg.set(EKK2811C150CBSMsg.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(EKK2811C150CBSMsg.UPD_DTM, inETMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		inCBSMsg.set(EKK2811C150CBSMsg.UPD_OPEACNT, inETMsg.getString(JCMConstants.OPERATOR_ID_KEY));
	}

	/**
	 * <p>
	 * 機器オプションサービス契約のカレントレコードを取得します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @return 機器オプションサービス契約のカレントレコード
	 */
	private CAANMsg getCurKK2811(CAANMsg inCBSMsg)
	{
		// 機器オプションサービス契約のカレントレコードを取得
		CAANMsg et = new CAANMsg(KK2811ETMsg.class.getName());
		et.set(KK2811ETMsg.KKOP_SVC_KEI_NO, inCBSMsg.getString(EKK2811C150CBSMsg.KKOP_SVC_KEI_NO));
		et.set(KK2811ETMsg.RSV_APLY_YMD, JKKModelCommon.getOpeDate(inCBSMsg));
		
		CAANMsg curKK2811 = new JKKejbKK2811DBABase().findByCurrent(et);

		return curKK2811;
	}

	/**
	 * <p>
	 * 下記項目を条件に最大の異動予約を取得します。
	 * <br>・機器オプションサービス契約番号
	 * <br>・異動予約詳細コード
	 * <br>・異動予約状態コード
	 * </p>
	 * @param KKOPSvcKeiNo 検索する機器オプションサービス契約番号
	 * @param idoRsvDtlCd 検索する異動予約詳細コード
	 * @param idoRsvStatCd 検索する異動予約状態コード
	 * @return 条件に該当する異動予約
	 *          条件に該当する異動予約がない場合、nullを返却
	 */
	private CAANMsg getIdoRsv(String kkopSvcKeiNo, String idoRsvDtlCd, String idoRsvStatCd)
	{
		// 条件を設定
		KK1681LE le = new KK1681LE();
		CAANMsg conditionETMsg = new CAANMsg(KK1681ETMsg.class.getName());
		conditionETMsg.set(KK1681ETMsg.KKOP_SVC_KEI_NO, kkopSvcKeiNo);
		conditionETMsg.set(KK1681ETMsg.IDO_RSV_DTL_CD, idoRsvDtlCd);
		conditionETMsg.set(KK1681ETMsg.IDO_RSV_STAT_CD, idoRsvStatCd);
		conditionETMsg.set(KK1681ETMsg.MK_FLG, JKKModelConst.MK_FLG_YK);
		
		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("解約確定対象の機器オプションサービス契約に対する異動予約が存在しません。機器オプションサービス契約番号:" + kkopSvcKeiNo);
		}

		return updTgKK1681Msg;
	}
	
	/**
	 * <p>
	 * 遡及解約対応・履歴レコード課金終了日更新処理
	 * 遡及解約により、解約(最新)レコードの課金終了日に対して、履歴レコードの課金終了日が未来日になってしまう場合に、
	 * 解約(最新)レコードの課金終了日と同日を履歴レコードの課金終了日に設定する。
	 * </p>
	 * @param inCBSMsg  処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @param planChrgEndymd 新規レコードのプラン課金終了年月日
	 */
	private void updRirekiKK2811(CAANMsg inCBSMsg, AgentDispatchContext inContext, String planChrgEndymd)
	{
		// プラン課金終了日が設定されている履歴レコードを取得する。
		// 条件：プラン終了種別コード＝"プラン変更に伴う終了"
		CAANMsg conInMsg = new CAANMsg(KK2811ETMsg.class.getName());
		conInMsg.set(KK2811ETMsg.KKOP_SVC_KEI_NO, inCBSMsg.getString(EKK2811C150CBSMsg.KKOP_SVC_KEI_NO));
		conInMsg.set(KK2811ETMsg.PLAN_END_SBT_CD, JKKModelConst.PLAN_END_SBT_CD_PLAN_CHANGE);
		conInMsg.set(KK2811ETMsg.MK_FLG, JKKModelConst.MK_FLG_YK);
		CAANMsg[] conRetMsg = null;
		try
		{
			conRetMsg = new KK2811LE().findByCondition(conInMsg);
		}
		catch (CAANException ce)
		{
			throw new CAANRuntimeException(ce);
		}
		// 取得できない場合は処理を終了する
		if (null == conRetMsg || conRetMsg.length == 0)
		{
			return;
		}

		// 当該サービスIFにて作成した解約(最新)レコードの世代登録年月日時分秒
		String geneAddDtm = inCBSMsg.getString(EKK2811C150CBSMsg.GENE_ADD_DTM);

		/* ----------------------------------------------------------------------------------------------------
		 * 履歴レコード.プラン課金終了年月日更新処理
		 * 条件：解約(最新)レコード.プラン課金終了年月日＜履歴レコード.プラン課金終了年月日
		 * ---------------------------------------------------------------------------------------------------- */
		for (CAANMsg retMsg : conRetMsg)
		{
			// 当該サービスIFにて作成した解約(最新)レコードは、更新対象外
			if (geneAddDtm.equals(retMsg.getString(KK2811ETMsg.GENE_ADD_DTM)))
			{
				continue;
			}

			// 履歴レコード.プラン課金終了年月日
			String workPlanChrgEndymd = retMsg.getString(KK2811ETMsg.PLAN_CHRG_ENDYMD);
			// 履歴レコード.プラン課金終了年月日が未設定または"20991231"の場合は処理しない
			if (null == workPlanChrgEndymd || "".equals(workPlanChrgEndymd) || JKKModelConst.DATE_MAX.equals(workPlanChrgEndymd))
			{
				continue;
			}

			// 解約(最新)レコード.プラン課金終了年月日＜履歴レコード.プラン課金終了年月日の場合
			if (JPCUtilCommon.isFutureDate(workPlanChrgEndymd, planChrgEndymd, "0"))
			{
				retMsg.set(KK2811ETMsg.PLAN_CHRG_ENDYMD, planChrgEndymd);
				retMsg.set(KK2811ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
				retMsg.set(KK2811ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
			}
			else
			{
				continue;
			}

			JKKejbDBAUtil dbaUtil = new JKKejbDBAUtil(inCBSMsg);
			dbaUtil.update(retMsg);
		}
	}
}
