package jp.mosp.payroll.base;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import jp.mosp.common.bean.OdsBean;
import jp.mosp.common.common.MospException;
import jp.mosp.common.common.MospUtility;
import jp.mosp.common.common.PoiUtility;
import jp.mosp.common.dao.CmCodeDao;
import jp.mosp.common.dao.MosPConfDao;
import jp.mosp.common.dto.CmCodeDto;
import jp.mosp.common.dto.MosPConfDto;
import jp.mosp.common.utils.DateUtil;
import jp.mosp.human.dao.MKojinDao;
import jp.mosp.human.dto.MKojinDto;
import jp.mosp.kintai.common.dao.MSyozokuDao;
import jp.mosp.kintai.common.dao.MYakusyokuDao;
import jp.mosp.kintai.common.dto.MKihonDto;
import jp.mosp.kintai.common.dto.MSyozokuDto;
import jp.mosp.kintai.common.dto.MYakusyokuDto;
import jp.mosp.legal.LegalConst;
import jp.mosp.legal.LegalUtility;
import jp.mosp.payroll.bonus.dao.PdBonAllowanceDao;
import jp.mosp.payroll.bonus.dao.PdBonDeductionDao;
import jp.mosp.payroll.bonus.dao.PdBonSumDao;
import jp.mosp.payroll.bonus.dao.PhBounsDao;
import jp.mosp.payroll.bonus.dto.PhBounsDto;
import jp.mosp.payroll.dao.CdAdjustmentDao;
import jp.mosp.payroll.dao.CdSocInsuranceDao;
import jp.mosp.payroll.dao.CmIncomeTaxDao;
import jp.mosp.payroll.dao.CmMidwayEnterDao;
import jp.mosp.payroll.dao.CmSocInsuranceDao;
import jp.mosp.payroll.dao.MKihonPayrollDao;
import jp.mosp.payroll.dao.PdPayAllowanceDao;
import jp.mosp.payroll.dao.PdPayDeductionDao;
import jp.mosp.payroll.dao.PdPaySumDao;
import jp.mosp.payroll.dao.PdPayTimeDao;
import jp.mosp.payroll.dao.PhPaymentDao;
import jp.mosp.payroll.dao.PtCurrentDao;
import jp.mosp.payroll.dto.CdAdjustmentDto;
import jp.mosp.payroll.dto.CmCompanyDto;
import jp.mosp.payroll.dto.CmIncomeTaxDto;
import jp.mosp.payroll.dto.CmMidwayEnterDto;
import jp.mosp.payroll.dto.PhPaymentDto;
import jp.mosp.payroll.dto.PtCurrentDto;

/**
 * @author koike
 *
 */
public abstract class AdjustmentAction extends CalculateAction {
	
	// フィールド
	protected int					adjustYear;
	protected Date					startAdjDate;
	protected Date					lastDate;
	
	protected String				targetData;
	protected int					adjTargetMonth;
	
	protected Date					targetBefDate;
	protected Date					targetAffDate;
	
	boolean							isCalcAdjust	= true;
	
	private int						socInsDeduction	= 0;	// 社会保険料等給与等からの控除分
															
	protected PdPayAllowanceDao		pdPayAllowanceDao;		// 給与控除明細データ
	protected PdPayDeductionDao		pdPayDeductionDao;		// 給与支払明細データ
	protected PdBonAllowanceDao		pdBonAllowanceDao;		// 賞与控除明細データ
	protected PdBonDeductionDao		pdBonDeductionDao;		// 賞与支払明細データ
															
	protected CdAdjustmentDao		cdAdjustmentDao;		// 年末調整データ
	protected CdAdjustmentDto		cdAdjustmentDto;		// 年末調整データ
	protected CmIncomeTaxDao		cmIncomeTaxDao;		// 人事マスタ所得税部 
	protected CmIncomeTaxDto		cmIncomeTaxDto;		// 人事マスタ所得税部
	protected MKihonPayrollDao		mKihonPayrollDao;		// 人事基本情報
	protected CmMidwayEnterDao		cmMidwayEnterDao;		// 人事マスタ中途入社部
	protected CmMidwayEnterDto		cmMidwayEnterDto;		// 人事マスタ中途入社部
	protected PhPaymentDao			phPaymentDao;			// 給与ヘッダー部
	protected PhPaymentDto			phPaymentDto;			// 給与ヘッダー部
	protected PhBounsDao			phBonusDao;			// 賞与ヘッダー部
	protected PhBounsDto			phBonusDto;			// 賞与ヘッダー部
	protected MKojinDao				mKojinDao;				// 人事管理情報      
	protected MKojinDto				mKojinDto;				// 人事管理情報    
															
	protected CmSocInsuranceDao		cmSocInsuranceDao;		// 人事マスタ社会保険部  
															
	protected PdPaySumDao			pdPaySumDao;			// 給与明細合計部
	protected PdPayTimeDao			pdPayTimeDao;
	protected PdBonSumDao			pdBonSumDao;			// 賞与明細合計部
															
	// 計算対象給与データ取得
	protected List<PhPaymentDto>	listPaymentData;
	// 計算対象賞与データ取得
	protected List<PhBounsDto>		listBonusData;
	protected CmCompanyDto			cmCompanyDto;
	

	/**
	 * 年調計算に必要な項目の合計計算
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws SQLException 
	 */
	protected void calcNeedAdjust() throws SQLException, IllegalAccessException, NoSuchFieldException {
		// 初期化
		socInsDeduction = 0;
		// 給与データ合計設定
		setTotalPaymentData();
		// 賞与データ合計設定
		setTotalBonusData();
		// 中途、調整収入データ設定
		setMidwayAdjustIncomeData();
		// 社会保険料等給与等からの控除分設定
		setPayInsDeduction();
		// 年税額設定(年調計算により上書きされる)
		cdAdjustmentDto.setFinalIncomeTax(cdAdjustmentDto.getIncomeTaxSum());
	}
	
	/**
	 * 年末調整計算
	 * @throws Exception 
	 */
	protected void adjustIncomeTax() throws Exception {
		// 給与所得控除後の給与当の金額設定
		setIncomePaymentData();
		if (isCalcAdjust) {
			// **　年末調整データテーブルから取得するものは入力してある前提　**
			// 配偶者、扶養、基礎および障害者等の控除額の合計設定
			setLegalTotalDeduction();
			// 差引課税給与所得金額
			setTaxedIncome();
			// 算出年税額設定
			setCalcIncomeTax();
			if (isCalcAdjust) {
				// 年末調整年税額設定
				setAdjustIncomeTax();
				// 年末調整定率控除税額設定
				setDeductedIncomeTax();
				// 年税額設定
				setFinalIncomeTax();
				// 所得税修正
				addIncomeTaxData();
				// 対象データ確定処理
				addTotalData();
			}
		}
		// 計算時点で年調計算対象外と判断された場合はステータスを対象外に
		if (!isCalcAdjust) {
			// 初期化
			isCalcAdjust = true;
			// ステータス設定(年末調整計算対象外)
			cdAdjustmentDto.setAdjustStatus(PayrollConst.ADJU_STATUS_OOT);
		} else {
			// ステータス設定(年末調整計算済み)
			cdAdjustmentDto.setAdjustStatus(PayrollConst.ADJU_STATUS_FIX);
		}
	}
	
	/**
	 * 対象データ、設定年月等設定
	 * @throws Exception
	 */
	protected void setTargetData() throws Exception {
		// 設定テーブルより対象データ設定情報取得
		targetData = part().mospconf().getConfValue(PayrollConst.CONF_ID_ADJ_TRGT, PayrollConst.CONF_CD_ADJ_TRGT);
		
		// CM_CONFテーブルに"ADJ_TRGT"が設定されていない場合は年末調整対象データ：給与とする。
		if (targetData.equals("")) {
			targetData = PayrollConst.ADJ_PAYMENT_TARGET;
		}
		// 対象期間設定
		setTargetPeriod();
	}
	
	/**
	 * データ作成(対象データが給与の場合)
	 * @throws Exception
	 */
	protected void setTargetPaymentData() throws Exception {
		if (targetData.equals(PayrollConst.ADJ_PAYMENT_TARGET)) {
			// 給与データ設定
			phPaymentDto = phPaymentDao.findForKey(kCode, targetAffDate);
		} else if (targetData.equals(PayrollConst.ADJ_BONUS_TARGET)) {
			// 賞与(未実装)
			setTargetBonusData();
		}
	}
	
	/**
	 * データ作成(対象データが賞与の場合)
	 */
	protected void setTargetBonusData() {
		// 未実装
	}
	
	/**
	 * 給与データ合計設定
	 * @throws SQLException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 */
	private void setTotalPaymentData() throws SQLException, IllegalAccessException, NoSuchFieldException {
		// 計算対象給与データ取得
		List<PhPaymentDto> listPaymentData = phPaymentDao.findForConditionDate(kCode, targetBefDate, targetAffDate);
		// 設定準備
		int taxation = 0;
		int socInsurance = 0;
		int incomeTax = 0;
		
		for (int i = 0; i < listPaymentData.size(); i++) {
			PhPaymentDto dto = listPaymentData.get(i);
			// 給与、手当等金額取得
			taxation += dto.getTaxation();
			// 給与、手当等社会保険料控除額取得
//			socInsurance += dto.calcSocialInsurance();
			socInsurance += dto.getSocInsTotal();
			// 給与、手当等税額
			incomeTax += dto.getIncomeTax();
		}
		// 年末調整対象給与分所得税除去
		if (targetData.equals(PayrollConst.ADJ_PAYMENT_TARGET) && phPaymentDto != null) {
			incomeTax -= phPaymentDto.getIncomeTax();
		}
		// 給与、手当等金額設定
		cdAdjustmentDto.setPaymentAllowance(taxation);
		// 社会保険料控除額設定
		socInsDeduction += socInsurance;
		// 給与、手当等税額設定
		cdAdjustmentDto.setPaymentIncomeTax(incomeTax);
	}
	
	/**
	 * 賞与データ合計設定
	 * @throws SQLException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 */
	protected void setTotalBonusData() throws SQLException, IllegalAccessException, NoSuchFieldException {
		// 計算対象賞与データ取得
		List<PhBounsDto> listBonusData = phBonusDao.findForConditionDate(kCode, startAdjDate, lastDate);
		// 設定準備
		int taxation = 0;
		int socInsurance = 0;
		int incomeTax = 0;
		for (int i = 0; i < listBonusData.size(); i++) {
			PhBounsDto dto = listBonusData.get(i);
			// 賞与等金額
			taxation += dto.getAllowanceTotal();
			// 賞与等社会保険料等控除額
			socInsurance += dto.getInsureMoney();
			// 賞与等税額
			incomeTax += dto.getIncomeTax();
		}
		// 賞与等金額設定
		cdAdjustmentDto.setBonusAllowance(taxation);
		// 社会保険料控除額設定
		socInsDeduction += socInsurance;
		// 賞与等税額設定
		cdAdjustmentDto.setBonusIncomeTax(incomeTax);
	}
	
	/**
	 * 中途、調整収入データ設定
	 */
	protected void setMidwayAdjustIncomeData() {
		// 設定準備
		int taxation = 0;
		int socInsurance = 0;
		int incomeTax = 0;
		// 収入金額 = 支給調整額 - 非課税調整額
		taxation = cdAdjustmentDto.getAllowanceAdjustment() - cdAdjustmentDto.getTaxFreeAdjustment();
		// 収入社会保険料等控除額 = 社会保険調整額
		socInsurance = cdAdjustmentDto.getSocInsAdjustment();
		// 収入税額 = 所得税調整額
		incomeTax = cdAdjustmentDto.getTaxIncAdjustment();
		// 対象年中途入社確認
		if (checkMidwayEnter()) {
			// 前勤務先収入金額を加算
			taxation += cmMidwayEnterDto.getFormerIncome();
			// 前勤務先社会保険額を加算
			socInsurance += cmMidwayEnterDto.getFormerInsurance();
			// 前勤務先所得税額を加算
			incomeTax += cmMidwayEnterDto.getFormerTax();
		}
		// 中途、調整収入金額
		cdAdjustmentDto.setMidwayAdjustIncome(taxation);
		// 社会保険料控除額設定
		socInsDeduction += socInsurance;
		// 中途、調整収入税額
		cdAdjustmentDto.setMidwayAdjustTax(incomeTax);
	}
	
	/**
	 * 社会保険料等給与等からの控除額設定
	 */
	protected void setPayInsDeduction() {
		int payInsDeduction = socInsDeduction;
		cdAdjustmentDto.setPayInsDeduction(payInsDeduction);
	}
	
	/**
	 * 中途入社確認
	 * @return 中途入社確認フラグ(true:中途入社、false:中途ではない)
	 */
	protected boolean checkMidwayEnter() {
		// 準備
		boolean isMidway = false;
		if (cmMidwayEnterDto != null) {
			// 中途入社区分が「中途入社」でかつ、入社日が対象年の場合はtrue
			if (cmMidwayEnterDto.getMidwayType().equals(LegalConst.MIDWAY_ENTER)) {
				// 入社年
//				int entYear = MospUtility.getYear(mKihonDto.getNyDate() );
				int entYear = mKihonDto.getNyDate();
				if (entYear == adjustYear) {
					isMidway = true;
				}
			}
		}
		return isMidway;
	}
	
	/**
	 * 給与所得控除後の給与当の金額設定
	 * @throws MospException
	 */
	protected void setIncomePaymentData() throws MospException {
		// 設定準備
		int adjustedIncomeTax = 0;
		// 年調給与額
		int adjustPayment = LegalUtility.setAdjustPayment(cdAdjustmentDto.getPaymentAllowance(), cdAdjustmentDto
			.getBonusAllowance(), cdAdjustmentDto.getMidwayAdjustIncome());
		// 年調計算確認
		isCalcAdjust = LegalUtility.checkAdjustPayment(adjustPayment);
		if (!isCalcAdjust) {
			// 年末調整計算を行わないので0円を設定
			// 対象外エラー設定
			String errMessage = MospUtility.getMessage(msg, PayrollConst.MSG_NO_TARGET,
					PayrollConst.NAM_CALC_ADJUSTMENT + PayrollConst.KEY_SEPARATOR + kCode);
			addErrMessage(errMessage);
			adjustedIncomeTax = 0;
		} else {
			adjustedIncomeTax = LegalUtility.setIncomePaymentData(adjustPayment);
		}
		// 設定
		cdAdjustmentDto.setAfterDeductIncome(adjustedIncomeTax);
	}
	
	/**
	 * 配偶者、扶養、基礎および障害者等の控除額の合計設定
	 */
	protected void setLegalTotalDeduction() {
		int deduction = 0;
		// 基礎控除額取得
		deduction += LegalUtility.getAdjustBasisDeduction();
		// 設定がない場合は0
		if (cmIncomeTaxDto == null) {
			deduction += 0;
		} else {
			// 配偶者控除額取得
			deduction += LegalUtility.getSpouseIntendType(cmIncomeTaxDto.getSpouseIntendType());
			// 扶養控除額
			deduction += LegalUtility.getDependentDeduction(cmIncomeTaxDto.getGeneralDependent(), cmIncomeTaxDto
				.getSpecificDependent(), cmIncomeTaxDto.getElderlyDependent(), cmIncomeTaxDto.getLiveWithEldRel(),
					cmIncomeTaxDto.getLiveWithHandiGe(), cmIncomeTaxDto.getLiveWithHandiSp(), cmIncomeTaxDto
						.getLiveWithHandiEl(), cmIncomeTaxDto.getLiveWithHandiEr());
			// 障害者等、寡婦、勤労学生の控除額取得
			deduction += LegalUtility.getHandicapDeduction(cmIncomeTaxDto.getSelfWidowType(), cmIncomeTaxDto
				.getSelfHandicapType(), cmIncomeTaxDto.getSelfStudentType(), cmIncomeTaxDto.getSpecificHandicap(),
					cmIncomeTaxDto.getGeneralHandicap());
		}
		
		cdAdjustmentDto.setDependentsDeduction(deduction);
	}
	
	/**
	 * 本人関連数取得
	 * @param 無し
	 * @return 本人関連数
	 * @throws 実行時例外
	 */
	public int countSelfTypes(CmIncomeTaxDto cmIncomeTaxDto) {
		int selfTypes = 0;
		// 本人区分2が一般障害、特別障害なら1
		String selfHandicapType = cmIncomeTaxDto.getSelfHandicapType();
		if (selfHandicapType != null && !selfHandicapType.equals("")) {
			selfTypes += 1;
		}
		// 本人区分1が寡婦(夫)、特別寡婦なら1
		String selfWidowType = cmIncomeTaxDto.getSelfWidowType();
		if (selfWidowType != null && !selfWidowType.equals("")) {
			selfTypes += 1;
		}
		// 本人区分3が勤労学生なら1
		String selfStudentType = cmIncomeTaxDto.getSelfStudentType();
		if (selfStudentType != null && !selfStudentType.equals("")) {
			selfTypes += 1;
		}
		return selfTypes;
	}
	
	/**
	 * 差引課税給与所得金額取得
	 */
	protected void setTaxedIncome() {
		// 差引課税給与所得金額
		int calcTaxedIncome = 0;
		// 所得税控除額の合計額
		int incomeDeduction = cdAdjustmentDto.getPayInsDeduction() // 社会保険料等給与等からの控除分
				+ cdAdjustmentDto.getSocialInsDeduction() // 申告による社会保険料の控除分
				+ cdAdjustmentDto.getMutualAidDeduction() // 申告による小規模企業共済等掛金の控除分
				+ cdAdjustmentDto.getLifeInsDeduction() // 生命保険料の控除額
				+ cdAdjustmentDto.getDamageInsDeduction() // 損害保険料の控除額
				+ cdAdjustmentDto.getSpouseSpDeduction() // 配偶者特別控除額
				+ cdAdjustmentDto.getDependentsDeduction(); // 配偶者控除額、扶養控除額、基礎控除額及び障害者等の控除額の合計額
		
		// 差引課税給与所得金額設定(1000未満切捨)
		calcTaxedIncome = (int)round(cdAdjustmentDto.getAfterDeductIncome() - incomeDeduction, -3,
				BigDecimal.ROUND_DOWN);
		calcTaxedIncome = calcTaxedIncome < 0 ? 0 : calcTaxedIncome;
		// 差引課税給与所得金額設定
		cdAdjustmentDto.setCalcTaxedIncome(calcTaxedIncome);
	}
	
	/**
	 * 算出年税額設定
	 * @throws MospException
	 */
	protected void setCalcIncomeTax() throws MospException {
		isCalcAdjust = LegalUtility.checkCalcTaxedIncome(cdAdjustmentDto.getCalcTaxedIncome());
		// 課税給与所得金額が16920000以上なら年末調整計算対象外
		if (!isCalcAdjust) {
			// 対象外エラー
			String errMessage = MospUtility.getMessage(msg, PayrollConst.MSG_NO_TARGET,
					PayrollConst.NAM_CALC_ADJUSTMENT + PayrollConst.KEY_SEPARATOR + kCode);
			addErrMessage(errMessage);
			cdAdjustmentDto.setCalcIncomeTax(0);
			return;
		}
		int calcIncomeTax = LegalUtility.getCalcIncomeTax(cdAdjustmentDto.getCalcTaxedIncome());
		cdAdjustmentDto.setCalcIncomeTax(calcIncomeTax);
	}
	
	/**
	 * 年調年税額設定
	 */
	protected void setAdjustIncomeTax() {
		// 年調年税額設定
		int adjustedIncomeTax = 0;
		// 年調年税額 = 算出年税額 - 住宅借入金額等特別控除額
		adjustedIncomeTax = cdAdjustmentDto.getCalcIncomeTax() - cdAdjustmentDto.getHouseLoanDeduction();
		// マイナスの場合は0に戻す
		if (adjustedIncomeTax < 0) {
			adjustedIncomeTax = 0;
		}
		// 設定
		cdAdjustmentDto.setAdjustedIncomeTax(adjustedIncomeTax);
	}
	
	/**
	 * 年末調整定率控除税額設定
	 */
	protected void setDeductedIncomeTax() {
		// 年末調整定率控除税額設定
		int deductedIncomeTax = LegalUtility.getDeductedIncomeTax(cdAdjustmentDto.getAdjustedIncomeTax());
		cdAdjustmentDto.setDeductedIncomeTax(deductedIncomeTax);
	}
	
	/**
	 * 年税額設定
	 */
	protected void setFinalIncomeTax() {
		// 年税額設定準備
		int finalIncomeTax = 0;
		// 年税額 = 年調年税額　- 年調定率控除額税額
		// 年税額取得(100円未満切捨)
		finalIncomeTax = (int)round(cdAdjustmentDto.getAdjustedIncomeTax() - cdAdjustmentDto.getDeductedIncomeTax(),
				-2, BigDecimal.ROUND_DOWN);
		// 設定
		cdAdjustmentDto.setFinalIncomeTax(finalIncomeTax);
	}
	
	/**
	 * 対象データ所得税設定
	 */
	private void addIncomeTaxData() {
		int incomeTax = 0;
		// 所得税合計
		int totalIncAdjsut = cdAdjustmentDto.getPaymentIncomeTax() + cdAdjustmentDto.getBonusIncomeTax()
				+ cdAdjustmentDto.getMidwayAdjustTax();
		if (targetData.equals(PayrollConst.ADJ_PAYMENT_TARGET)) {
			incomeTax = cdAdjustmentDto.getFinalIncomeTax() - totalIncAdjsut;
			// 所得税設定
			phPaymentDto.setIncomeTax(incomeTax);
		} else if (targetData.equals(PayrollConst.ADJ_BONUS_TARGET)) {
			// 未実装
		}
	}
	
	/**
	 * 対象データ確定処理
	 * @throws Exception
	 */
	private void addTotalData() throws Exception {
		if (targetData.equals(PayrollConst.ADJ_PAYMENT_TARGET)) {
			// 給与対象データ確定処理
			calcTotal(false);
			// 更新
			phPaymentDao.update(phPaymentDto, true);
		} else if (targetData.equals(PayrollConst.ADJ_BONUS_TARGET)) {
			// 賞与対象データ確定処理
			calcBonusTotal();
		}
	}
	
	/**
	 * 調整年設定
	 * @param adjustYear 調整年
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws SQLException 
	 * @throws MospException 
	 */
	protected void confirmAdjustYear(int adjustYear) throws SQLException, IllegalAccessException, NoSuchFieldException,
			MospException {
		// 調整年確認
		if (adjustYear != getAdjustYear()) {
			// 調整年不整合例外
			String errMessage = MospUtility.getMessage(msg, PayrollConst.MSG_DIF_ADJUST_YEAR, "");
			addErrMessage(errMessage);
			throw new MospException(PayrollConst.EX_DIF_ADJUST_YEAR, errMessage);
		}
		this.adjustYear = adjustYear;
		startAdjDate = getStartDateOfYear(adjustYear);
		lastDate = getLastDateOfYear(adjustYear);
	}
	
	/**
	 * 対象データ給与存在確認
	 * @param currentDto
	 * @throws Exception 
	 */
	protected boolean cheackTrgtPeriodPayData() throws Exception {
		boolean isTargetPeriod = true;
		// メッセージ表示準備
		String mes1 = "";
		String mes2 = "";
		// 11月の給与DTOが存在しない場合
		if (phPaymentDto == null) {
			isTargetPeriod = false;
			// 対象データ未設定エラー出力確認
			if (checkNoTargetError()) {
				// 対象データ確認
				if (targetData.equals(PayrollConst.ADJ_PAYMENT_TARGET)) {
					// 給与
					mes1 = String.valueOf(adjTargetMonth);
					mes2 = PayrollConst.NAM_DATA_M_PAYROLL;
				} else {
					// 賞与
				}
				// 11月分の給与が存在しない場合はエラー
				String errMessage = MospUtility.getMessage(msg, PayrollConst.MSG_ADJ_NO_TARGET_DATA, mes1
						+ PayrollConst.KEY_SEPARATOR + mes2 + PayrollConst.KEY_SEPARATOR + kCode);
				addErrMessage(errMessage);
			}
		}
		
		return isTargetPeriod;
	}
	
	private boolean checkNoTargetError() {
		Date tsDate;
		
		// 比較対象年月日設定
		// 対象年の12/1
		Date retireDate = getFirstDateOfMonth(String.valueOf(MospUtility.getYear(lastDate)), String.valueOf(MospUtility
			.getMonth(lastDate)));
		if (mKihonDto != null) {
			// 退職日がNULLの人
			if (mKihonDto.getTsDate() == 0) {
				return true;
			}
			// 退職日が対象年12/1以降
			tsDate = DateUtil.convIntegerDateToDate(mKihonDto.getTsDate());
			if (tsDate.after(retireDate)) {
				return true;
			}
			
			// 比較対象年月日を11/1に設定
			retireDate = addMonth(retireDate, -1);
			
			// 退職日が11/1以前の人
			if (tsDate.before(retireDate)) {
				// メッセージ不要
				return false;
			}
		} else {
			// メッセージ要
			return true;
		}
		return true;
	}
	
	/**
	 * 対象期間設定
	 * @param currentDto
	 * @throws Exception
	 */
	protected void setTargetPeriod() throws Exception {
		// 適用情報取得(給与適用月)
		String applyMonth;
		applyMonth = part().mospconf().getConfValue(PayrollConst.CONF_ID_PAY_ITBL, PayrollConst.CONF_CD_ADJUST_PAY);
		if (applyMonth.equals("")) {
			applyMonth = "1"; // 一ヶ月単位とする
		}
		// 対象年月設定
		adjTargetMonth = PayrollConst.TIME_ADJ_PAY_MONTH - Integer.parseInt(applyMonth);
		// 調整情報の修正(11月給与情報)
		targetAffDate = getYearMonth(String.valueOf(adjustYear), String.valueOf(adjTargetMonth));
		// 対象前年情報取得
		targetBefDate = addMonth(targetAffDate, -adjTargetMonth);
	}
	
	/**
	 * 差引超過額又は不足額取得
	 * @param dto 取得対象DTO
	 * @return 差引超過額又は不足額
	 */
	protected int getTaxGap(CdAdjustmentDto dto) {
		return dto.getFinalIncomeTax() - dto.getPaymentIncomeTax() - dto.getBonusIncomeTax() - dto.getMidwayAdjustTax();
	}
	
	/**
	 * データ操作準備
	 * @throws SQLException 
	 * @throws ClassNotFoundException 
	 */
	protected void prepareDao() throws ClassNotFoundException, SQLException {
		getConnection();
		mKihonPayrollDao = new MKihonPayrollDao();
		
		pdPayDeductionDao = new PdPayDeductionDao(cfg, cmd, aspUser, user, conn);
		
		pdPayAllowanceDao = new PdPayAllowanceDao(cfg, cmd, aspUser, user, conn); // 給与控除明細データ
		pdPayDeductionDao = new PdPayDeductionDao(cfg, cmd, aspUser, user, conn); // 給与支払明細データ
		pdBonAllowanceDao = new PdBonAllowanceDao(cfg, cmd, aspUser, user, conn); // 賞与控除明細データ
		pdBonDeductionDao = new PdBonDeductionDao(cfg, cmd, aspUser, user, conn); // 賞与支払明細データ
		
		cdAdjustmentDao = new CdAdjustmentDao();
		phPaymentDao = new PhPaymentDao(cfg, cmd, aspUser, user, conn);
		cmIncomeTaxDao = new CmIncomeTaxDao();
		cmMidwayEnterDao = new CmMidwayEnterDao();
		phBonusDao = new PhBounsDao(cfg, cmd, aspUser, user, conn);
		mKojinDao = new MKojinDao();
		cmSocInsuranceDao = new CmSocInsuranceDao();
		
		pdPaySumDao = new PdPaySumDao(cfg, cmd, aspUser, user, conn); // 給与明細合計部
		pdPayTimeDao = new PdPayTimeDao(cfg, cmd, aspUser, user, conn); // 給与明細合計部
		pdBonSumDao = new PdBonSumDao(cfg, cmd, aspUser, user, conn); // 賞与明細合計部
		
		cdSocInsuranceDao = new CdSocInsuranceDao(); // 社会保険計算データ		
		
		mKihonPayrollDao.initDao(cfg, cmd, aspUser, user, conn);
		cdAdjustmentDao.initDao(cfg, cmd, aspUser, user, conn);
		phPaymentDao.initDao(cfg, cmd, aspUser, user, conn);
		cmIncomeTaxDao.initDao(cfg, cmd, aspUser, user, conn);
		cmMidwayEnterDao.initDao(cfg, cmd, aspUser, user, conn);
		mKojinDao.initDao(cfg, cmd, aspUser, user, conn);
		cmSocInsuranceDao.initDao(cfg, cmd, aspUser, user, conn);
		cdSocInsuranceDao.initDao(cfg, cmd, aspUser, user, conn); // 社会保険計算データ
	}
	
	/**
	 * 年末調整計算対象者確認
	 * @return 年末調整計算対象者フラグ(true:対象者、false:非対象者)　
	 */
	protected boolean checkIsCalcAdjData() {
		Date tsDate;
		// 準備
		boolean isCreate = true;
		// 比較準備
		String year = String.valueOf(MospUtility.getYear(lastDate));
		String month = String.valueOf(MospUtility.getMonth(lastDate));
		// 対象年の12/1
		Date compEntranceDate = getFirstDateOfMonth(year, month);
		// 対象年の1/1
		Date compRetDate = startAdjDate;
		// 履歴情報がない場合
		if (mKihonDto == null) {
			isCreate = false;
			return isCreate;
		}
		
		// 入社日が対象年の12/1より前
		tsDate = DateUtil.convIntegerDateToDate(mKihonDto.getNyDate());
		if (tsDate.compareTo(compEntranceDate) <= 0) {
			// 退社日が空白もしくは対象年の1/1以降の社員
			if (mKihonDto.getNyDate() == 0 || tsDate.compareTo(compRetDate) >= 0) {
				isCreate = true;
			}
		} else {
			// 12/1以降なら非対象
			isCreate = false;
		}
		return isCreate;
	}
	
	/**
	 * 年調区分確認
	 * @return 確認結果(true：年調する、false：年調する以外)
	 * @throws Exception 
	 */
	public boolean confirmAdjustType() throws Exception {
		// 年調区分確認
		if (cmIncomeTaxDto != null) {
			// 年調区分:年調不要
			if (cmIncomeTaxDto.getAdjustmentType().equals(LegalConst.ADJUSTMENT_NOT_NEED)) {
				// 年調不要はエラー出力なしだが計算は行わない
				return false;
			}
			// 年調区分:年調する
			if (cmIncomeTaxDto.getAdjustmentType().equals(LegalConst.ADJUSTMENT_NEEDED)) {
				// 計算対象者確認
				if (checkIsCalcAdjData()) {
					// 対象者
					// 11月データ存在確認
					if (!cheackTrgtPeriodPayData()) {
						// 対象データが存在しない場合
						return false;
					}
				} else {
					// 非対象者
					return false;
				}
				
			}
			// 年調区分:未設定
			if (cmIncomeTaxDto.getAdjustmentType().equals("")) {
				// 未設定の場合はエラー出力
				addErrMessage(MospUtility.getMessage(msg, PayrollConst.MSG_NO_ADJUST_TYPE, kCode));
				// 非対象者
				return false;
			}
			
		} else {
			// 非対象者
			return false;
		}
		return true;
	}
	
	/**
	 * 年末調整データ作成対象者確認
	 * @throws SQLException 
	 * @throws IllegalAccessException 
	 * @throws MospException 
	 */
	public boolean checkCreateAdjustData(boolean needMessage) throws IllegalAccessException, SQLException,
			MospException {
		// 年末調整データ作成対象者確認
		int intStartAdjDate = DateUtil.convDateToInteger(startAdjDate);
		int intLastDate = DateUtil.convDateToInteger(lastDate);
		MKihonDto dto = mKihonPayrollDao.findForAdjustEmpData(kCode, intStartAdjDate, intLastDate);
		if (dto == null) {
			if (needMessage) {
				// データ作成対象外の場合はエラー
				String errMessage = MospUtility.getMessage(msg, PayrollConst.MSG_NO_TARGET,
						PayrollConst.NAM_NO_DATA_ADJUSTMENT + PayrollConst.KEY_SEPARATOR + kCode);
				addErrMessage(errMessage);
			}
			return false;
		}
		return true;
	}
	
	/**
	 * 年末調整状態設定(計算対象外)
	 */
	public void setAdjustOotStatus() {
		cdAdjustmentDto.setAdjustStatus(PayrollConst.ADJU_STATUS_OOT);
	}
	
	/**
	 * 対象データ所得税再計算
	 * @param isRegist　更新処理(true:更新する、false:更新しない)
	 * @throws Exception
	 */
	public void calcTargetIncomeTax(boolean isRegist) throws Exception {
		// 対象データが給与
		if (targetData.equals(PayrollConst.ADJ_PAYMENT_TARGET)) {
			if (phPaymentDto != null) {
				// 対象データ設定
				targetMonth = targetAffDate;
				// 対象データ給与復元
				setIncomeTax();
				if (isRegist) {
					phPaymentDao.update(phPaymentDto, false);
				}
			}
		} else if (targetData.equals(PayrollConst.ADJ_BONUS_TARGET)) {
			// 対象データが賞与
			if (phBonusDto != null) {
				// 対象データ設定
				targetMonth = targetAffDate;
				// 賞与対象データ確定処理
				setBonusIncomeTax();
			}
		}
	}
	
	/**
	 * 年調年取得
	 * @return 計算月
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws SQLException 
	 */
	protected int getAdjustYear() throws SQLException, IllegalAccessException, NoSuchFieldException {
		// DAO準備
		PtCurrentDao dao = new PtCurrentDao(cfg, cmd, aspUser, user, conn);
		PtCurrentDto dto = dao.findLatest(PayrollConst.CURRENT_ADJUST, PayrollConst.CALC_ADJUST,
				PayrollConst.CURRENT_START);
		if (dto == null) {
			return MospUtility.getYear(new Date());
		}
		return MospUtility.getYear(dto.getCalcDate());
	}
	
	/**
	 * 年操作
	 * @param date   操作日付
	 * @param amount 増減月数
	 * @return 操作後日付
	 */
	protected Date addYear(Date date, int amount) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		cal.add(Calendar.YEAR, amount);
		return cal.getTime();
	}
	
	/**
	 * 所属コード取得(M_SYOZOKU)
	 * @return 所属コードリスト
	 * @throws SQLException
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 */
	protected String[][] getStationArrayAll() throws SQLException, NoSuchFieldException, IllegalAccessException {
		// DAOの準備
		MSyozokuDao dao = new MSyozokuDao();
		dao.initDao(cfg, cmd, aspUser, user, conn);
		// 情報の取得
		List<MSyozokuDto> listStation = dao.findAll();
		// 配列の作成
		String[][] aryStation = new String[listStation.size()][2];
		for (int i = 0; i < listStation.size(); i++) {
			aryStation[i][0] = listStation.get(i).getSCode();
			aryStation[i][1] = listStation.get(i).getSName();
		}
		return aryStation;
	}
	
	/**
	 * 役職コード取得(M_YAKUSYOKU)
	 * @return 役職コードリスト
	 * @throws SQLException
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 */
	@Override
	protected String[][] getPositionArrayAll() throws SQLException, NoSuchFieldException, IllegalAccessException {
		// DAOの準備
		MYakusyokuDao dao = new MYakusyokuDao();
		dao.initDao(cfg, cmd, aspUser, user, conn);
		// 情報の取得
		List<MYakusyokuDto> listPosition = dao.findAll();
		// 配列の作成
		String[][] aryPosition = new String[listPosition.size()][2];
		for (int i = 0; i < listPosition.size(); i++) {
			aryPosition[i][0] = listPosition.get(i).getYcode();
			aryPosition[i][1] = listPosition.get(i).getYname();
		}
		return aryPosition;
	}
	
	/**
	 * コードリスト取得(CM_CODE)
	 * @param tId コード区分
	 * @return コードリスト
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws SQLException 
	 */
	@Override
	protected String[][] getCodeArray(String tId) throws SQLException, IllegalAccessException, NoSuchFieldException {
		// DAOの宣言
		CmCodeDao dao = new CmCodeDao();
		dao.initDao(cfg, cmd, aspUser, user, conn);
		// データの取得
		List<CmCodeDto> list = dao.findForCondition(tId);
		// データの整形
		String[][] array = new String[list.size()][2];
		for (int i = 0; i < list.size(); i++) {
			CmCodeDto dto = list.get(i);
			array[i][0] = dto.getTCode();
			array[i][1] = dto.getTName();
		}
		return array;
	}
	
	/**
	 * 設定リスト取得(UM_CONF)
	 * @param confId 設定区分
	 * @return 設定リスト
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws SQLException 
	 */
	@Override
	protected List<MosPConfDto> getConfList(String confId) throws SQLException, IllegalAccessException,
			NoSuchFieldException {
		// DAOの宣言
		MosPConfDao dao = new MosPConfDao();
		dao.initDao(cfg, cmd, aspUser, user, conn);
		// データの取得
		return dao.findForCondition(confId);
	}
	
	/**
	 * POI帳票出力データチェック＆出力(String)
	 * @param poi 出力POIインスタンスID
	 * @param rr 出力excel行数
	 * @param cc 出力excelカラム数
	 * @param sdata　出力文字列
	 * @throws Exception 
	 */
	public void prtItemChk(PoiUtility poi, int rr, int cc, String sdata) throws Exception {
		if (null != sdata) {
			poi.prtItem(rr, cc, sdata);
		}
	}
	
	/**
	 * POI帳票出力データチェック＆出力(Integer)
	 * @param poi 出力POIインスタンスID
	 * @param rr 出力excel行数
	 * @param cc 出力excelカラム数
	 * @param sdata　出力数値
	 * @throws Exception 
	 */
	public void prtItemChk(PoiUtility poi, int rr, int cc, Integer sdata) throws Exception {
		if (null != sdata) {
			poi.prtItem(rr, cc, sdata);
		}
	}
	
	/**
	 * POI帳票出力データチェック＆出力(Float)
	 * @param poi 出力POIインスタンスID
	 * @param rr 出力excel行数
	 * @param cc 出力excelカラム数
	 * @param sdata　出力数値
	 * @throws Exception 
	 */
	public void prtItemChk(PoiUtility poi, int rr, int cc, Float sdata) throws Exception {
		if (null != sdata) {
			poi.prtItem(rr, cc, sdata);
		}
	}
	
	/**
	 * ODS帳票出力データチェック＆出力
	 * @param odsBean 出力ODSインスタンスID
	 * @param arg0 出力ODSカラム数
	 * @param arg1 出力ODS行数
	 * @param arg2 出力文字列
	 */
	public void setValueChk(OdsBean odsBean, int arg0, int arg1, Object arg2) {
		if (null != arg2) {
			odsBean.setValue(arg0, arg1, arg2);
		}
		
	}
	
}
