/*
 * MosP - Mind Open Source Project         http://www.mosp.jp/
 * Copyright (C) 1987-2009 MIND Co., Ltd.  http://www.e-mind.co.jp/
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
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.part.DatePart;
import jp.mosp.human.dao.MKojinDao;
import jp.mosp.human.dto.MKihonDto;
import jp.mosp.human.dto.MKojinDto;
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;
import jp.mosp.system.dao.MSyozokuDao;
import jp.mosp.system.dao.MYakusyokuDao;
import jp.mosp.system.dto.MSyozokuDto;
import jp.mosp.system.dto.MYakusyokuDto;

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      = 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 == this.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 = DatePart.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 = 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(this.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 = DatePart.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 int_startAdjDate	= DatePart.convDateToInteger( startAdjDate );
		int int_lastDate		= DatePart.convDateToInteger( lastDate );   
		MKihonDto dto = mKihonPayrollDao.findForAdjustEmpData(kCode, int_startAdjDate, int_lastDate);
		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.findForKey(PayrollConst.CURRENT_ADJUST);
		PtCurrentDto dto = dao.findLatest(PayrollConst.CURRENT_ADJUST, PayrollConst.CALC_ADJUST, PayrollConst.CURRENT_START);
		//		if (dto == null) {
//			dto = dao.findForKey(PayrollConst.CURRENT_CALC);
//		}
		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
	 */
	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 
	 */
	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 prtItem_chk(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 prtItem_chk(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 prtItem_chk(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 sdata　出力文字列
	 * @throws Exception 
	 */
	public  void setValue_chk(OdsBean odsBean, int arg0, int arg1, Object arg2){
		if(null != arg2){
			odsBean.setValue(arg0, arg1, arg2);
		}
		
	}
	
}
