/*********************************************************************
*   All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JEKK0341C350ETDA
*   ソースファイル名：JEKK0341C350ETDA.java
*   作成者          ：富士通
*   日付            ：2011年10月08日
*＜機能概要＞
*   機器提供サービス契約解約確定のDBアクセス部品クラス
*＜修正履歴＞
*   バージョン  修正日      修正者      修正内容
*   v1.00.00    2011/10/08  富士通      新規作成
*   v4.00.00    2012/01/15  FJ)寺園     ANK-1292-00-00
*   v5.00.00    2013/03/20  FJ)寺園     ANK-1429-00-00
*   v5.00.01    2013/03/29  FJ)竹内     ST4-2013-0000382)遡及解約対応・課金終了日更新処理修正
*   v5.00.02    2013/05/02  FJ)寺本     IT1-2013-0001110
*   v5.00.03    2013/07/03  FJ)寺本     KT1-2013-0000691
*   v5.00.04    2013/11/29  FJ)寺園     OM-2013-0004088
*   v5.00.05    2013/11/30  FJ)寺園     OM-2013-0004310
*   v6.00.00    2013/12/04  FJ)寺園     OM-2013-0004310（不備のため再リリース）
*   v6.00.01    2014/01/11  FJ)小島     OM-2014-0000083
*   v7.00.00    2014/03/12  FJ)小島     OM-2014-0000389
*   v8.00.00    2014/04/07  FJ)小島     OM-2014-0000389
*   v37.00.00   2018/04/25  FJ)藤本     ANK-3366-00-00 eo光設備卸対応
**********************************************************************/

package eo.ejb.common.db;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fujitsu.futurity.common.JCCWebAddTrnId;
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.constant.JKKStrConst;
import eo.common.util.JKKStringUtil;
import eo.common.util.JPCUtilCommon;
import eo.ejb.cbm.entity.KK0081ETMsg;
import eo.ejb.cbm.entity.KK0341ETMsg;
import eo.ejb.cbm.entity.KK0341LE;
import eo.ejb.cbm.entity.KK1681ETMsg;
import eo.ejb.cbm.entity.KK1681LE;
import eo.ejb.cbs.cbsmsg.EKK0341C350CBSMsg;
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 JEKK0341C350ETDA
{
	/** 異動予約詳細コード 機器解約 */
	private static final String DTLCD_KKDISSOLVE = "013";
	
	/** 異動予約状態コード 反映済 */
	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 KKTK_STAT_DISSOLVE = "910";
	
	/** スキーマID サービス契約 */
	private static final String SCHEMAID_KKTK_SVCKEI = "KK0341";
	
	/** スキーマID 異動予約 */
	private static final String SCHEMAID_IDORSV = "KK1681";

	/** プラン終了種別コード：プラン変更に伴う終了 */
	private static final String PLAN_END_SBT_CD_PLAN_CHANGE = "1";

	/** 年月日：初期値 */
	private static final String YMD_SHKV = "20991231";

	/**
	 * <p>
	 * 新しいJEKK0341C350ETDAを作成します。
	 * </p>
	 */
	public JEKK0341C350ETDA()
	{
	}

	/**
	 * <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(EKK0341C350CBSMsg.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(EKK0341C350CBSMsg.KKTK_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 (SCHEMAID_KKTK_SVCKEI.equals(hm.get(JKKejbRule0083001.TRGT_SCHEMA_ID)))
			{
				// 機器提供サービス契約に振舞う場合
				updateInfo = makeKK0341ETMsg(inCBSMsg, inContext);
				create(inCBSMsg, updateInfo);

				// 機器提供サービス契約に振舞った場合の個別出力項目の設定
				inCBSMsg.set(EKK0341C350CBSMsg.GENE_ADD_DTM, updateInfo.getString(KK0341ETMsg.GENE_ADD_DTM));
				inCBSMsg.set(EKK0341C350CBSMsg.KKTK_SVC_KEI_STAT, updateInfo.getString(KK0341ETMsg.KKTK_SVC_KEI_STAT));
				inCBSMsg.set(EKK0341C350CBSMsg.RSV_APLY_YMD, updateInfo.getString(KK0341ETMsg.RSV_APLY_YMD));
				
				// 遡及解約対応
				// 履歴レコードにおいて、時系列順にて日付が逆転してしまう課金終了日の更新処理を行う
				updRirekiKK0341(inCBSMsg, inContext, updateInfo.getString(KK0341ETMsg.PLAN_CHRG_ENDYMD));
			}
			if (SCHEMAID_IDORSV.equals(hm.get(JKKejbRule0083001.TRGT_SCHEMA_ID)))
			{
				// サービス終了年月日が運用日付と同日で異動予約に振舞う場合
				updateInfo = makeKK1681ETMsg(inCBSMsg, hm, DTLCD_KKDISSOLVE, 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 makeKK0341ETMsg(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		String kktkSvcKeiNo = inCBSMsg.getString(EKK0341C350CBSMsg.KKTK_SVC_KEI_NO);
		String geneAddDtm = (String)JKKModelCommon.getTransferGeneAddDtm(inCBSMsg, inContext);
		String opeDate = JKKModelCommon.getOpeDate(inCBSMsg);

		// 引継元となるカレントレコードを取得
		CAANMsg infoKK0341 = getCurKK0341(inCBSMsg);
		
		// 機器提供サービス契約番号に紐付く「異動予約詳細コード」が"機器解約"、
		// 「異動予約状態コード」が"予約手続中"の異動予約を取得
		CAANMsg infoKK1681 = getIdoRsv(kktkSvcKeiNo, DTLCD_KKDISSOLVE, STATCD_RSV_PROC);
		
		// 機器提供サービス契約のETメッセージ
		infoKK0341.set(KK0341ETMsg.KKTK_SVC_KEI_NO, kktkSvcKeiNo);
		infoKK0341.set(KK0341ETMsg.GENE_ADD_DTM, geneAddDtm);
		infoKK0341.set(KK0341ETMsg.KKTK_SVC_KEI_STAT, KKTK_STAT_DISSOLVE);
		infoKK0341.set(KK0341ETMsg.MSKM_DTL_NO, infoKK1681.getString(KK1681ETMsg.MSKM_DTL_NO));

		// 運用日 ＞ サービス終了年月日の場合
		if (JPCUtilCommon.isPastDate(inCBSMsg.getString(EKK0341C350CBSMsg.SVC_ENDYMD), opeDate, "1"))
		{
			// 運用日付を設定する
			infoKK0341.set(KK0341ETMsg.RSV_APLY_YMD, opeDate);
		}
		else
		{
			infoKK0341.set(KK0341ETMsg.RSV_APLY_YMD, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_ENDYMD));
		}
		infoKK0341.setNull(KK0341ETMsg.RSV_CL_YMD);
		infoKK0341.set(KK0341ETMsg.RSV_APLY_CD, RSVAPLY_DECIDED);
		infoKK0341.set(KK0341ETMsg.PLAN_ENDYMD, JKKModelCommon.getYmdDslFix(inCBSMsg, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_ENDYMD)));
		infoKK0341.set(KK0341ETMsg.PLAN_CHRG_ENDYMD, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_CHRG_ENDYMD));
		infoKK0341.set(KK0341ETMsg.PLAN_END_SBT_CD, inCBSMsg.getString(EKK0341C350CBSMsg.PLAN_END_SBT_CD));
		infoKK0341.set(KK0341ETMsg.SVC_ENDYMD, JKKModelCommon.getYmdDslFix(inCBSMsg, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_ENDYMD)));
		infoKK0341.set(KK0341ETMsg.SVC_CHRG_ENDYMD, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_CHRG_ENDYMD));
		infoKK0341.set(KK0341ETMsg.SVC_DSL_YMD, JKKModelCommon.getYmdDslFix(inCBSMsg, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_ENDYMD)));
		infoKK0341.set(KK0341ETMsg.SVC_DLRE_CD, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_DLRE_CD));
		infoKK0341.set(KK0341ETMsg.SVC_DLRE_MEMO, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_DLRE_MEMO));
		infoKK0341.set(KK0341ETMsg.ZANCHI_FLG, inCBSMsg.getString(EKK0341C350CBSMsg.ZANCHI_FLG));
		infoKK0341.setNull(KK0341ETMsg.SVC_DSL_TTDKI_FIN_FLG);
		infoKK0341.setNull(KK0341ETMsg.KAIHK_YMD);
		infoKK0341.setNull(KK0341ETMsg.SVC_DSL_CL_YMD);
		infoKK0341.set(KK0341ETMsg.PNLTY_HASSEI_CD, infoKK1681.getString(KK1681ETMsg.PNLTY_HASSEI_CD));
		infoKK0341.set(KK0341ETMsg.IDO_DIV, infoKK1681.getString(KK1681ETMsg.IDO_DIV));
		infoKK0341.set(KK0341ETMsg.TAKNKIKI_IDO_CD, inCBSMsg.getString(EKK0341C350CBSMsg.TAKNKIKI_IDO_CD));
		infoKK0341.set(KK0341ETMsg.KAISHU_KIKI_UM, inCBSMsg.getString(EKK0341C350CBSMsg.KAISHU_KIKI_UM));
		infoKK0341.set(KK0341ETMsg.ADD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		infoKK0341.set(KK0341ETMsg.ADD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		infoKK0341.set(KK0341ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		infoKK0341.set(KK0341ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		infoKK0341.set(KK0341ETMsg.MK_FLG, MK_FLG_VALID);
		
		// サービス課金開始年月日を取得する
		String svcChrgStaymd = getSvcChrgStaymd(inCBSMsg, inContext, infoKK0341);
		if (svcChrgStaymd != null)
		{
			infoKK0341.set(KK0341ETMsg.SVC_CHRG_STAYMD, svcChrgStaymd);
			infoKK0341.set(KK0341ETMsg.PLAN_CHRG_STAYMD, svcChrgStaymd);
		}
		return infoKK0341;
	}
	
	/**
	 * <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 kktkSvcKeiNo = inCBSMsg.getString(EKK0341C350CBSMsg.KKTK_SVC_KEI_NO);
		CAANMsg infoKK1681 = getIdoRsv(kktkSvcKeiNo, 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(EKK0341C350CBSMsg.SVC_ENDYMD), opeDate, "1"))
		{
			// 運用日付を設定する
			kk1681ETMsg.set(KK0341ETMsg.RSV_APLY_YMD, opeDate);
		} else {
			kk1681ETMsg.set(KK1681ETMsg.RSV_APLY_YMD , inCBSMsg.getString(EKK0341C350CBSMsg.SVC_ENDYMD));
		}

		if (STATCD_DONE.equals(ruleStatCd))
		{
			// 即時反映(異動予約状態コードが反映済)の場合、異動予約反映年月日を設定
			// 運用日 ＞ サービス終了年月日の場合
			if (JPCUtilCommon.isPastDate(inCBSMsg.getString(EKK0341C350CBSMsg.SVC_ENDYMD), opeDate, "1"))
			{
				// 運用日付を設定する
				kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_HANEI_YMD , opeDate);
			} else {
				kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_HANEI_YMD , inCBSMsg.getString(EKK0341C350CBSMsg.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(EKK0341C350CBSMsg.IDO_DIV, infoKK1681.getString(KK1681ETMsg.IDO_DIV));
		inCBSMsg.set(EKK0341C350CBSMsg.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(EKK0341C350CBSMsg.UPD_DTM, inETMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		inCBSMsg.set(EKK0341C350CBSMsg.UPD_OPEACNT, inETMsg.getString(JCMConstants.OPERATOR_ID_KEY));
	}

	/**
	 * <p>
	 * 機器提供サービス契約のカレントレコードを取得します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @return 機器提供サービス契約のカレントレコード
	 */
	private CAANMsg getCurKK0341(CAANMsg inCBSMsg)
	{
		// 機器提供サービス契約のカレントレコードを取得
		CAANMsg et = new CAANMsg(KK0341ETMsg.class.getName());
		et.set(KK0341ETMsg.KKTK_SVC_KEI_NO, inCBSMsg.getString(EKK0341C350CBSMsg.KKTK_SVC_KEI_NO));
		et.set(KK0341ETMsg.RSV_APLY_YMD, JKKModelCommon.getOpeDate(inCBSMsg));
		
		CAANMsg curKK0341 = new JKKejbKK0341DBABase().findByCurrent(et);

		return curKK0341;
	}

	/**
	 * <p>
	 * 下記項目を条件に異動予約を取得します。
	 * <br>・機器提供サービス契約番号
	 * <br>・異動予約詳細コード
	 * <br>・異動予約状態コード
	 * </p>
	 * @param kktkSvcKeiNo 検索する機器提供サービス契約番号
	 * @param idoRsvDtlCd 検索する異動予約詳細コード
	 * @param idoRsvStatCd 検索する異動予約状態コード
	 * @return 条件に該当する異動予約
	 *          条件に該当する異動予約がない場合、nullを返却
	 */
	private CAANMsg getIdoRsv(String kktkSvcKeiNo, String idoRsvDtlCd, String idoRsvStatCd)
	{
		// 条件を設定
		KK1681LE le = new KK1681LE();
		CAANMsg conditionETMsg = new CAANMsg(KK1681ETMsg.class.getName());
		conditionETMsg.set(KK1681ETMsg.KKTK_SVC_KEI_NO, kktkSvcKeiNo);
		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("解約確定対象の機器提供サービス契約に対する異動予約が存在しません。機器提供サービス契約番号:" + kktkSvcKeiNo);
		}

		return updTgKK1681Msg;
	}
	
	/**
	 * <p>
	 * 遡及解約対応・履歴レコード課金終了日更新処理
	 * 遡及解約により、解約(最新)レコードの課金終了日に対して、履歴レコードの課金終了日が未来日になってしまう場合に、
	 * 解約(最新)レコードの課金終了日と同日を履歴レコードの課金終了日に設定する。
	 * </p>
	 * @param inCBSMsg  処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @param planChrgEndymd 新規レコードのプラン課金終了年月日
	 */
	private void updRirekiKK0341(CAANMsg inCBSMsg, AgentDispatchContext inContext, String planChrgEndymd)
	{
		// プラン課金終了日が設定されている履歴レコードを取得する。
		// 条件：プラン終了種別コード＝"プラン変更に伴う終了"
		CAANMsg conInMsg = new CAANMsg(KK0341ETMsg.class.getName());
		conInMsg.set(KK0341ETMsg.KKTK_SVC_KEI_NO, inCBSMsg.getString(EKK0341C350CBSMsg.KKTK_SVC_KEI_NO));
		conInMsg.set(KK0341ETMsg.PLAN_END_SBT_CD, PLAN_END_SBT_CD_PLAN_CHANGE);
		conInMsg.set(KK0341ETMsg.MK_FLG, MK_FLG_VALID);
		CAANMsg[] conRetMsg = null;
		try
		{
			conRetMsg = new KK0341LE().findByCondition(conInMsg);
		}
		catch (CAANException ce)
		{
			throw new CAANRuntimeException(ce);
		}
		// 取得できない場合は処理を終了する
		if (null == conRetMsg || conRetMsg.length == 0)
		{
			return;
		}

		// 当該サービスIFにて作成した解約(最新)レコードの世代登録年月日時分秒
		String geneAddDtm = inCBSMsg.getString(EKK0341C350CBSMsg.GENE_ADD_DTM);

		/* ----------------------------------------------------------------------------------------------------
		 * 履歴レコード.プラン課金終了年月日更新処理
		 * 条件：解約(最新)レコード.プラン課金終了年月日＜履歴レコード.プラン課金終了年月日
		 * ---------------------------------------------------------------------------------------------------- */
		for (CAANMsg retMsg : conRetMsg)
		{
			// 当該サービスIFにて作成した解約(最新)レコードは、更新対象外
			if (geneAddDtm.equals(retMsg.getString(KK0341ETMsg.GENE_ADD_DTM)))
			{
				continue;
			}

			// 履歴レコード.プラン課金終了年月日
			String workPlanChrgEndymd = retMsg.getString(KK0341ETMsg.PLAN_CHRG_ENDYMD);
			// 履歴レコード.プラン課金終了年月日が未設定または"20991231"の場合は処理しない
			if (null == workPlanChrgEndymd || "".equals(workPlanChrgEndymd) || YMD_SHKV.equals(workPlanChrgEndymd))
			{
				continue;
			}

			// 解約(最新)レコード.プラン課金終了年月日＜履歴レコード.プラン課金終了年月日の場合
			if (JPCUtilCommon.isFutureDate(workPlanChrgEndymd, planChrgEndymd, "0"))
			{
				retMsg.set(KK0341ETMsg.PLAN_CHRG_ENDYMD, planChrgEndymd);
				retMsg.set(KK0341ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
				retMsg.set(KK0341ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
			}
			else
			{
				continue;
			}

			JKKejbDBAUtil dbaUtil = new JKKejbDBAUtil(inCBSMsg);
			dbaUtil.update(retMsg);
		}
	}
	
	/**
	 * <p>
	 * 課金開始日取得
	 * </p>
	 * @param inCBSMsg  処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @param inETMsg 該当の機器提供サービス契約のETメッセージ
	 * @return 算出された課金開始日
	 */
	private String getSvcChrgStaymd(CAANMsg inCBSMsg, AgentDispatchContext inContext, CAANMsg inETMsg)
	{
		String svcChrgStaymd = null;
		String svcStaYmd = null;
		String chrgStaymd = null;
		String opeDate = JKKModelCommon.getOpeDate(inCBSMsg);
		// ANK-3366-00-00 ADD START
		CAANMsg kk0081MsgOya = null;
		// ANK-3366-00-00 ADD END
		
		// 対象の機器がサービス開始していない場合は処理しない。（サービス開始日がNULLである場合）
		if (null == inETMsg.getString(KK0341ETMsg.SVC_STA_YMD)
				|| "".equals(inETMsg.getString(KK0341ETMsg.SVC_STA_YMD)))
		{
			return null;
		}
		
		// レンタル機器（機器提供種別："02"）でない場合は処理しない
		if (!JKKModelConst.KKTK_SBT_CD_RENTAL.equals(inETMsg.getString(KK0341ETMsg.KKTK_SBT_CD)))
		{
			return null;
		}
		
		// 機器に紐づく親契約．サービス課金開始年月日 を取得する
		if (JKKModelConst.OYA_KEI_SKBT_CD_SVC_KEI_KAISEN_UCWK.equals(inETMsg.getString(KK0341ETMsg.OYA_KEI_SKBT_CD)))
		{
			// 該当の「サービス契約回線内訳」を使用している「サービス契約」を取得する
			CAANMsg[] kk0081MsgList = new JKKejbKK0081DBABase().getKK0081bySvcKeiKaisenUcwk(
					inETMsg.getString(KK0341ETMsg.SVC_KEI_KAISEN_UCWK_NO), null, opeDate, "1");
			
			for (CAANMsg kk0081Msg : kk0081MsgList)
			{
				// 「解約済」「キャンセル済」は対象外
				if (JKKModelConst.SVC_KEI_STAT_DSL_ZM.equals(kk0081Msg.getString(KK0081ETMsg.SVC_KEI_STAT)) ||
						JKKModelConst.SVC_KEI_STAT_CNCL_ZM.equals(kk0081Msg.getString(KK0081ETMsg.SVC_KEI_STAT)))
				{
					continue;
				}
				
				// 対象の契約がサービス開始していない（サービス開始日がNULL）の場合は、対象外
				if (null == kk0081Msg.getString(KK0081ETMsg.SVC_STA_YMD)
						|| "".equals(kk0081Msg.getString(KK0081ETMsg.SVC_STA_YMD)))
				{
					continue;
				}
				
				// 対象の機器が「Ｖ−ＯＮＵ」の場合
				if (JKKModelConst.KKTK_SVC_CD_V_ONU.equals(inETMsg.getString(KK0341ETMsg.KKTK_SVC_CD)))
				{
					// ＴＶの契約を対象とする
					if (JKKModelConst.SVC_CD_TV.equals(kk0081Msg.getString(KK0081ETMsg.SVC_CD)))
					{
						chrgStaymd = kk0081Msg.getString(KK0081ETMsg.SVC_CHRG_STAYMD);
					}
				}
				else 
				{
					// ＮＥＴ／ＴＥＬの契約を対象とする
					if (!(JKKModelConst.SVC_CD_NET.equals(kk0081Msg.getString(KK0081ETMsg.SVC_CD)) ||
							JKKModelConst.SVC_CD_TEL.equals(kk0081Msg.getString(KK0081ETMsg.SVC_CD))))
					{
						continue;
					}
					
					// 対象の機器が「Ｖ−ＯＮＵ」以外の場合、サービス開始年月日の早いものを取得する
					if (chrgStaymd == null || 
							JKKModelCommon.isPastDate(kk0081Msg.getString(KK0081ETMsg.SVC_STA_YMD), svcStaYmd, "0"))
					{
						svcStaYmd = kk0081Msg.getString(KK0081ETMsg.SVC_STA_YMD);
						chrgStaymd = kk0081Msg.getString(KK0081ETMsg.SVC_CHRG_STAYMD);
						// ANK-3366-00-00 ADD START
						kk0081MsgOya = kk0081Msg;
						// ANK-3366-00-00 ADD END
					}
				}
			}
		}
		else
		{
			// サービス契約のカレントレコードを取得
			CAANMsg et = new CAANMsg(KK0081ETMsg.class.getName());
			et.set(KK0081ETMsg.SVC_KEI_NO, inETMsg.getString(KK0341ETMsg.SVC_KEI_NO));
			et.set(KK0081ETMsg.RSV_APLY_YMD, JKKModelCommon.getOpeDate(inCBSMsg));
			
			CAANMsg curKK0081 = new JKKejbKK0081DBABase().findByCurrent(et);

			chrgStaymd = curKK0081.getString(KK0081ETMsg.SVC_CHRG_STAYMD);
		}
		
		if (chrgStaymd == null)
		{
			return null;
		}
		
		// ANK-3366-00-00 ADD START
		HashMap<String, Object> commonMsg = JCCWebAddTrnId.get(JCMConstants.ADD_TRN_ID_MESSAGE_COMMON_MAP);
		String serviceId = (String)commonMsg.get(JCMConstants.USECASE_ID_KEY);
		// 呼び出し元が卸先事業者解約（撤去解約）サービスの場合
		if (JKKStrConst.SERVICE_ID_ORSJGS_DSL.equals(serviceId))
		{
			if (kk0081MsgOya != null)
			{
				// 親サービス契約(eo光卸)解約時に設定する課金開始日を取得
				String chrgStaymdOrs = (String)JKKModelCommon.getChrgStaYmdEKK0081C260(inCBSMsg, kk0081MsgOya, inContext);
				// 遡及解約となる場合
				if (!JKKStringUtil.isNullBlank(chrgStaymdOrs))
				{
					chrgStaymd = chrgStaymdOrs;
				}
			}
		}
		// ANK-3366-00-00 ADD END
		
		// 機器に紐づく親契約．サービス課金開始年月日 <= 入力.サービス課金終了年月日でない場合は処理しない
		if (JKKModelCommon.isFutureDate(chrgStaymd, inCBSMsg.getString(EKK0341C350CBSMsg.SVC_CHRG_ENDYMD), "0"))
		{
			return null;
		}
		
		// 機器提供サービス契約.サービス課金開始年月日 > 入力.サービス課金終了年月日でない場合は処理しない
		if (!JKKModelCommon.isFutureDate(inETMsg.getString(KK0341ETMsg.SVC_CHRG_STAYMD), inCBSMsg.getString(EKK0341C350CBSMsg.SVC_CHRG_ENDYMD), "0"))
		{
			return null;
		}

		svcChrgStaymd = inETMsg.getString(KK0341ETMsg.SVC_STA_YMD);
		
		return svcChrgStaymd;
	}
}
