/*
 * MosP - Mind Open Source Project    http://www.mosp.jp/
 * Copyright (C) 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.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import jp.mosp.common.common.MospException;
import jp.mosp.common.common.MospUtility;
import jp.mosp.common.part.MosPCodePart;
import jp.mosp.mospcommon.system.AgreementBaseInfo;
import jp.mosp.payroll.dao.KdSubstituteHolidayDao;
import jp.mosp.payroll.dto.DetailDto;
import jp.mosp.payroll.dto.DetailMoneyDto;
import jp.mosp.payroll.dto.DetailPaDto;
import jp.mosp.payroll.dto.DetailPbDto;
import jp.mosp.payroll.dto.DetailPdDto;
import jp.mosp.payroll.dto.DetailTimeDto;
import jp.mosp.payroll.dto.KdSubstituteHolidayDto;
import jp.mosp.payroll.dto.PhPaymentDto;

/**
 * 給与明細クラス。<br>
 */
public class Payment extends PayrollSlip {
	
	private static final long		serialVersionUID	= -6106880371454177891L;
	
	/**
	 * 給与ヘッダー情報。<br>
	 */
	private PhPaymentDto			header;
	
	/**
	 * 勤怠明細情報。<br>
	 */
	private List<DetailTimeDto>		time;
	
	/**
	 * 支給明細情報。<br>
	 */
	private List<DetailPaDto>		allowance;
	
	/**
	 * 控除明細情報。<br>
	 */
	private List<DetailPdDto>		deduction;
	
	/**
	 * 内訳明細情報。<br>
	 */
	private List<DetailPbDto>		breakdown;
	
	/**
	 * 合計明細情報。<br>
	 */
	private List<DetailMoneyDto>	sum;
	

	/**
	 * インスタンスを生成し、フィールドを設定する。<br>
	 * @param header    給与ヘッダー情報
	 * @param time      勤怠明細情報
	 * @param allowance 支給明細情報
	 * @param deduction 控除明細情報
	 * @param breakdown 内訳明細情報
	 * @param sum       合計明細情報
	 */
	public Payment(PhPaymentDto header, List<DetailTimeDto> time, List<DetailPaDto> allowance,
			List<DetailPdDto> deduction, List<DetailPbDto> breakdown, List<DetailMoneyDto> sum) {
		this.header = header;
		this.time = time;
		this.allowance = allowance;
		this.deduction = deduction;
		this.breakdown = breakdown;
		this.sum = sum;
		initDetails();
	}
	
	/**
	 * インスタンスを生成し、フィールドを設定する。<br>
	 * @param header          給与ヘッダー情報
	 * @param time            勤怠明細情報
	 * @param allowance       支給明細情報
	 * @param deduction       控除明細情報
	 * @param breakdown       内訳明細情報
	 * @param sum             合計明細情報
	 * @param amountTime      勤怠明細情報
	 * @param amountAllowance 支給明細情報
	 * @param amountDeduction 控除明細情報
	 * @param amountBreakdown 内訳明細情報
	 * @param amountSum       合計明細情報
	 */
	public Payment(PhPaymentDto header, List<DetailTimeDto> time, List<DetailPaDto> allowance,
			List<DetailPdDto> deduction, List<DetailPbDto> breakdown, List<DetailMoneyDto> sum,
			List<DetailTimeDto> amountTime, List<DetailMoneyDto> amountAllowance, List<DetailMoneyDto> amountDeduction,
			List<DetailTimeDto> amountBreakdown, List<DetailMoneyDto> amountSum) {
		this.header = header;
		this.time = time;
		this.allowance = allowance;
		this.deduction = deduction;
		this.breakdown = breakdown;
		this.sum = sum;
		initDetails();
		setDetailsAmount(time, amountTime);
		setDetailsAmount(allowance, amountAllowance);
		setDetailsAmount(deduction, amountDeduction);
		setDetailsAmount(breakdown, amountBreakdown);
		setDetailsAmount(sum, amountSum);
	}
	
	/**
	 * 明細を初期化する。
	 */
	private void initDetails() {
		initDetails(time, getKCode(), getCalcMonth());
		initDetails(allowance, getKCode(), getCalcMonth());
		initDetails(deduction, getKCode(), getCalcMonth());
		initDetails(breakdown, getKCode(), getCalcMonth());
		initDetails(sum, getKCode(), getCalcMonth());
	}
	
	/**
	 * 明細値を計算する。
	 * @param mapParams パラメータMap
	 * @param kCode 社員コード
	 * @param targetMonth 対象年月日
	 * @param agreement 
	 * @param kdSubstituteHolidayDao 
	 * @throws MospException MosP例外処理が発生した場合
	 * @throws ClassNotFoundException クラスが見つからなかった場合
	 * @throws NoSuchFieldException フィールドが見つからなかった場合
	 * @throws IllegalAccessException メソッドにアクセスできない場合
	 * @throws SQLException SQL例外が発生した場合
	 */
	public void calcDetails(Map<String, String> mapParams, String kCode, Date targetMonth, AgreementBaseInfo agreement,
			KdSubstituteHolidayDao kdSubstituteHolidayDao) throws MospException, SQLException, IllegalAccessException,
			NoSuchFieldException, ClassNotFoundException {
		calcDetails(time, mapParams, kCode, targetMonth, agreement, kdSubstituteHolidayDao);
		calcDetails(allowance, mapParams, kCode, targetMonth, agreement, kdSubstituteHolidayDao);
		calcDetails(deduction, mapParams, kCode, targetMonth, agreement, kdSubstituteHolidayDao);
		calcDetails(breakdown, mapParams, kCode, targetMonth, agreement, kdSubstituteHolidayDao);
		calcDetails(sum, mapParams, kCode, targetMonth, agreement, kdSubstituteHolidayDao);
	}
	
	/**
	 * 明細値を設定する。
	 * @param aryTime      勤怠明細値
	 * @param aryAllowance 支給明細値
	 * @param aryDeduction 控除明細値
	 * @param aryBreakdown 内訳明細値
	 */
	public void setDetails(String[][] aryTime, String[][] aryAllowance, String[][] aryDeduction, String[][] aryBreakdown) {
		setDetails(time, aryTime);
		setDetails(allowance, aryAllowance);
		setDetails(deduction, aryDeduction);
		setDetails(breakdown, aryBreakdown);
	}
	
	/**
	 * 勤怠明細値を設定する。
	 * @param detailCode 明細コード
	 * @param amount 明細値
	 */
	public void setTimeAmount(String detailCode, float amount) {
		setDetailAmount(getDetailDto(time, detailCode), amount);
	}
	
	/**
	 * 支給明細値を設定する。
	 * @param detailCode 明細コード
	 * @param amount 明細値
	 */
	public void setAllowanceAmount(String detailCode, int amount) {
		setDetailAmount(getDetailDto(allowance, detailCode), amount);
	}
	
	/**
	 * 控除明細値を設定する。
	 * @param detailCode 明細コード
	 * @param amount 明細値
	 */
	public void setDeductionAmount(String detailCode, int amount) {
		setDetailAmount(getDetailDto(deduction, detailCode), amount);
	}
	
	/**
	 * 内訳明細値を設定する。
	 * @param detailCode 明細コード
	 * @param amount 明細値
	 */
	public void setBreakdownAmount(String detailCode, int amount) {
		setDetailAmount(getDetailDto(breakdown, detailCode), amount);
	}
	
	/**
	 * 合計明細値を設定する。
	 * @param detailCode 明細コード
	 * @param amount 明細値
	 */
	public void setSumAmount(String detailCode, int amount) {
		setDetailAmount(getDetailDto(sum, detailCode), amount);
	}
	
	/**
	 * 勤怠明細値を取得する。
	 * @param detailCode 明細コード
	 * @return 明細値
	 */
	public float getTimeAmount(String detailCode) {
		return getDetailAmount(time, detailCode);
	}
	
	/**
	 * 支給明細値を取得する。
	 * @param detailCode 明細コード
	 * @return 明細値
	 */
	public int getAllowanceAmount(String detailCode) {
		return (int)getDetailAmount(allowance, detailCode);
	}
	
	/**
	 * 控除明細値を取得する。
	 * @param detailCode 明細コード
	 * @return 明細値
	 */
	public int getDeductionAmount(String detailCode) {
		return (int)getDetailAmount(deduction, detailCode);
	}
	
	/**
	 * 内訳明細値を取得する。
	 * @param detailCode 明細コード
	 * @return 明細値
	 */
	public float getBreakdownAmount(String detailCode) {
		return getDetailAmount(breakdown, detailCode);
	}
	
	/**
	 * 合計明細値を取得する。
	 * @param detailCode 明細コード
	 * @return 明細値
	 */
	public int getSumAmount(String detailCode) {
		return (int)getDetailAmount(sum, detailCode);
	}
	
	/**
	 * 社員コードを設定する。
	 * @param kCode 設定する社員コード
	 */
	public void setKCode(String kCode) {
		header.setKCode(kCode);
	}
	
	/**
	 * 社員コードを取得する。<br>
	 * @return 社員コード
	 */
	public String getKCode() {
		return header.getKCode();
	}
	
	/**
	 * 計算年月日を設定する。<br>
	 * @param calcDate 設定する計算年月日
	 */
	public void setCalcDate(Date calcDate) {
		header.setCalcMonth(calcDate);
	}
	
	/**
	 * 計算年月を取得する。<br>
	 * @return 計算年月
	 */
	public Date getCalcMonth() {
		return header.getCalcMonth();
	}
	
	/**
	 * 支給日を設定する。<br>
	 * @param payDate 設定する支給日
	 */
	public void setPayDate(Date payDate) {
		header.setPayDate(payDate);
	}
	
	/**
	 * 伝票コードを設定する。<br>
	 * @param slipCode 設定する伝票コード
	 */
	public void setSlipCode(String slipCode) {
		header.setSlipCode(slipCode);
	}
	
	/**
	 * 給与ヘッダーを取得する。
	 * @return 明細値
	 */
	public PhPaymentDto getHeader() {
		return header;
	}
	
	/**
	 * 勤怠明細配列を取得する。
	 * @param checkDisplayType 0印字区分確認要否
	 * @return 明細配列
	 */
	public String[][] getTimeArray(boolean checkDisplayType) {
		return getAryDetail(time, checkDisplayType);
	}
	
	/**
	 * 支給明細配列を取得する。
	 * @param checkDisplayType 0印字区分確認要否
	 * @return 明細配列
	 */
	public String[][] getAllowanceArray(boolean checkDisplayType) {
		return getAryDetail(allowance, checkDisplayType);
	}
	
	/**
	 * 控除明細配列を取得する。
	 * @param checkDisplayType 0印字区分確認要否
	 * @return 明細配列
	 */
	public String[][] getDeductionArray(boolean checkDisplayType) {
		return getAryDetail(deduction, checkDisplayType);
	}
	
	/**
	 * 内訳明細配列を取得する。
	 * @param checkDisplayType 0印字区分確認要否
	 * @return 明細配列
	 */
	public String[][] getBreakdownArray(boolean checkDisplayType) {
		List<DetailPbDto> view = new ArrayList<DetailPbDto>();
		for (DetailPbDto dto : breakdown) {
			if (dto.getViewType() == PayrollConst.DETAIL_VIEW_ON) {
				view.add(dto);
			}
		}
		return getAryDetail(view, checkDisplayType);
	}
	
	/**
	 * 合計明細配列を取得する。
	 * @param checkDisplayType 0印字区分確認要否
	 * @return 明細配列
	 */
	public String[][] getSumArray(boolean checkDisplayType) {
		return getAryDetail(sum, checkDisplayType);
	}
	
	/**
	 * 勤怠明細リストを取得する。
	 * @return 明細リスト
	 */
	public List<DetailTimeDto> getTimeList() {
		return time;
	}
	
	/**
	 * 支給明細リストを取得する。
	 * @return 明細リスト
	 */
	public List<DetailPaDto> getAllowanceList() {
		return allowance;
	}
	
	/**
	 * 控除明細リストを取得する。
	 * @return 明細リスト
	 */
	public List<DetailPdDto> getDeductionList() {
		return deduction;
	}
	
	/**
	 * 内訳明細リストを取得する。
	 * @return 明細リスト
	 */
	public List<DetailPbDto> getBreakdownList() {
		return breakdown;
	}
	
	/**
	 * 合計明細リストを取得する。
	 * @return 明細リスト
	 */
	public List<DetailMoneyDto> getSumList() {
		return sum;
	}
	
	/**
	 * 計算年月文字列を取得する。<br>
	 * @return 計算年月文字列
	 */
	public String getCalcMonthStr() {
		return MospUtility.getDateString(getCalcMonth(), PayrollConst.FORMAT_YEAR_MONTH);
	}
	
	/**
	 * 支給日を取得する。
	 * @return 支給日
	 */
	public String getPayDate() {
		return MospUtility.getDateString(header.getPayDate(), PayrollConst.FORMAT_DATE);
	}
	
	/**
	 * 課税対象額を取得する。
	 * @return 課税対象額
	 */
	public int getTaxation() {
		return header.getTaxation();
	}
	
	/**
	 * 雇用保険対象額を取得する。
	 * @return 雇用保険対象額
	 */
	public int getInsureUnemploy() {
		return header.getInsureUnemploy();
	}
	
	/**
	 * 社会保険合計を取得する。
	 * @return 社会保険合計
	 */
	public int getSocInsTotal() {
		return header.getSocInsTotal();
	}
	
	/**
	 * 扶養等の数を取得する。
	 * @return 扶養等の数
	 */
	public int getDependent() {
		return header.getDependent();
	}
	
	/**
	 * 所得税額を取得する。
	 * @return 所得税額
	 */
	public int getIncomeTax() {
		return header.getIncomeTax();
	}
	
	/**
	 * 賞与計算対象額を取得する。
	 * @return 賞与計算対象額
	 */
	public int getBonusBase() {
		return header.getBonusBase();
	}
	
	/**
	 * 総支給金額を取得する。
	 * @return 総支給金額
	 */
	public int getAllowanceTotal() {
		return header.getAllowanceTotal();
	}
	
	/**
	 * 総控除金額を取得する。
	 * @return 総控除金額
	 */
	public int getDeductionTotal() {
		return header.getDeductionTotal();
	}
	
	/**
	 * 差引支給金額を取得する。
	 * @return 差引支給金額
	 */
	public int getPaymentTotal() {
		return header.getPaymentTotal();
	}
	
	/**
	 * 通勤手当を設定する。
	 * @param amount 通勤手当
	 */
	public void setCommutation(int amount) {
		setDetailAmount(getDetailDto(allowance, PayrollConst.DTL_COMMUTATION), amount);
	}
	
	/**
	 * 課税通勤手当を設定する。
	 * @param amount 課税通勤手当
	 */
	public void setCommuteTax(int amount) {
		setDetailAmount(getDetailDto(breakdown, PayrollConst.DTL_COMMUTE_TAX), amount);
	}
	
	/**
	 * 健康保険料を設定する。
	 * @param amount 健康保険料
	 */
	public void setHealthInsurance(int amount) {
		setDetailAmount(getDetailDto(deduction, PayrollConst.DTL_HEALTH_INS), amount);
	}
	
	/**
	 * 介護保険料を設定する。
	 * @param amount 介護保険料
	 */
	public void setNursingInsurance(int amount) {
		setDetailAmount(getDetailDto(deduction, PayrollConst.DTL_NURSING_INS), amount);
	}
	
	/**
	 * 厚生年金料を設定する。
	 * @param amount 厚生年金料
	 */
	public void setPensionInsurance(int amount) {
		setDetailAmount(getDetailDto(deduction, PayrollConst.DTL_PENSION_INS), amount);
	}
	
	/**
	 * 厚生年金基金料を設定する。
	 * @param amount 厚生年金基金料
	 */
	public void setPensionFund(int amount) {
		setDetailAmount(getDetailDto(deduction, PayrollConst.DTL_PENSION_FUND), amount);
	}
	
	/**
	 * 雇用保険料を設定する。
	 * @param amount 雇用保険料
	 */
	public void setEmployeeInsurance(int amount) {
		setDetailAmount(getDetailDto(deduction, PayrollConst.DTL_EMPLOYEE_INS), amount);
	}
	
	/**
	 * 所得税を設定する。
	 * @param amount 設定する所得税
	 */
	public void setIncomeTax(int amount) {
		setDetailAmount(getDetailDto(deduction, PayrollConst.DTL_INCOME_TAX), amount);
		header.setIncomeTax(amount);
	}
	
	/**
	 * 住民税を設定する。
	 * @param amount 設定する住民税
	 */
	public void setResidenceTax(int amount) {
		setDetailAmount(getDetailDto(deduction, PayrollConst.DTL_RESIDENCE_TAX), amount);
	}
	
	/**
	 * 銀行1振込額を設定する。
	 * @param amount 設定する銀行1振込額
	 */
	public void setBank1PayAmount(int amount) {
		setDetailAmount(getDetailDto(sum, PayrollConst.DTL_SUM_BANK1), amount);
	}
	
	/**
	 * 銀行2振込額を設定する。
	 * @param amount 設定する銀行2振込額
	 */
	public void setBank2PayAmount(int amount) {
		setDetailAmount(getDetailDto(sum, PayrollConst.DTL_SUM_BANK2), amount);
	}
	
	/**
	 * 現金支給額を設定する。
	 * @param amount 設定する銀行1振込額
	 */
	public void setCashPayAmount(int amount) {
		setDetailAmount(getDetailDto(sum, PayrollConst.DTL_SUM_CASH), amount);
	}
	
	/**
	 * 社会保険合計を計算する。
	 */
	public void calcSocInsTotal() {
		long sum = getDeductionAmount(PayrollConst.DTL_HEALTH_INS) + getDeductionAmount(PayrollConst.DTL_NURSING_INS)
				+ getDeductionAmount(PayrollConst.DTL_PENSION_INS) + getDeductionAmount(PayrollConst.DTL_PENSION_FUND)
				+ getDeductionAmount(PayrollConst.DTL_EMPLOYEE_INS);
		setSumAmount(PayrollConst.DTL_SUM_SOC_INS, (int)sum);
		header.setSocInsTotal((int)sum);
	}
	
	/**
	 * 総支給金額を計算する。
	 */
	public void calcAllowance() {
		long sum = 0L;
		for (DetailPaDto detailPaDto : allowance) {
			sum += detailPaDto.getAmount();
		}
		sum = sum < 0 ? 0 : sum;
		setSumAmount(PayrollConst.DTL_SUM_ALLOWANCE, (int)sum);
		header.setAllowanceTotal((int)sum);
	}
	
	/**
	 * 総控除金額を計算する。
	 */
	public void calcDeduction() {
		long sum = 0L;
		for (DetailPdDto detailPdDto : deduction) {
			sum += detailPdDto.getAmount();
		}
		sum = sum < 0 ? 0 : sum;
		setSumAmount(PayrollConst.DTL_SUM_DEDUCTION, (int)sum);
		header.setDeductionTotal((int)sum);
	}
	
	/**
	 * 差引支給額を計算する。
	 */
	public void calcPaymentTotal() {
		long sum = 0L;
		sum = getAllowanceTotal() - getDeductionTotal();
		setSumAmount(PayrollConst.DTL_SUM_TOTAL, (int)sum);
		header.setPaymentTotal((int)sum);
	}
	
	/**
	 * 雇用保険対象額を計算する。
	 */
	public void calcUnemployInsuration() {
		long insureUnemploy = 0L;
		for (DetailPaDto dto : allowance) {
			if (dto.getUeInsType() == PayrollConst.DETAIL_UE_ADD) {
				insureUnemploy += dto.getAmount();
				continue;
			}
			if (dto.getUeInsType() == PayrollConst.DETAIL_UE_BREAK) {
				for (DetailPbDto dtoBreak : breakdown) {
					if (dto.getDetailCode().equals(dtoBreak.getUpperCode())) {
						if (dtoBreak.getTotalType() == PayrollConst.DETAIL_TOTAL_UE) {
							insureUnemploy += dtoBreak.getAmount();
							continue;
						}
					}
				}
			}
		}
		insureUnemploy = insureUnemploy > 0 ? insureUnemploy : 0;
		header.setInsureUnemploy((int)insureUnemploy);
	}
	
	/**
	 * 課税対象額を計算する。
	 */
	public void calcTaxation() {
		long taxation = 0L;
		for (DetailPaDto dto : allowance) {
			if (dto.getTaxationType() == PayrollConst.DETAIL_TAX_ADD) {
				taxation += dto.getAmount();
				continue;
			}
			if (dto.getTaxationType() == PayrollConst.DETAIL_TAX_BREAK) {
				for (DetailPbDto dtoBreak : breakdown) {
					if (dto.getDetailCode().equals(dtoBreak.getUpperCode())) {
						if (dtoBreak.getTotalType() == PayrollConst.DETAIL_TOTAL_TAX) {
							taxation += dtoBreak.getAmount();
							continue;
						}
					}
				}
			}
		}
		taxation = taxation > 0 ? taxation : 0;
		setSumAmount(PayrollConst.DTL_SUM_TAXATION, (int)taxation);
		header.setTaxation((int)taxation);
	}
	
	/**
	 * 扶養等の数を設定する。
	 * @param dependent 設定する扶養等の数
	 */
	public void setDependent(byte dependent) {
		header.setDependent(dependent);
	}
	
	/**
	 * 社会保険料等控除後の金額を取得する。
	 * @return 社会保険料等控除後の金額
	 */
	public int getAfterDeduction() {
		int afterDeduction = getTaxation() - getSocInsTotal();
		return afterDeduction > 0 ? afterDeduction : 0;
	}
	
	/**
	 * 単価設定項目を取得する。
	 * @return 単価設定項目配列
	 */
	public String[][] getUnitItem() {
		List<DetailDto> list = new ArrayList<DetailDto>();
		for (int i = 0; i < time.size(); i++) {
			DetailDto dto = time.get(i);
			if (dto.getInputType() == PayrollConst.DETAIL_IN_UNIT) {
				list.add(dto);
			}
		}
		for (int i = 0; i < allowance.size(); i++) {
			DetailDto dto = allowance.get(i);
			if (dto.getInputType() == PayrollConst.DETAIL_IN_UNIT) {
				list.add(dto);
			}
		}
		for (int i = 0; i < deduction.size(); i++) {
			DetailDto dto = deduction.get(i);
			if (dto.getInputType() == PayrollConst.DETAIL_IN_UNIT) {
				list.add(dto);
			}
		}
		for (int i = 0; i < breakdown.size(); i++) {
			DetailDto dto = breakdown.get(i);
			if (dto.getInputType() == PayrollConst.DETAIL_IN_UNIT) {
				list.add(dto);
			}
		}
		for (int i = 0; i < sum.size(); i++) {
			DetailDto dto = sum.get(i);
			if (dto.getInputType() == PayrollConst.DETAIL_IN_UNIT) {
				list.add(dto);
			}
		}
		return getAryDetail(list, false);
	}
	
	/**
	 * 明細値を計算する。
	 * @param listDetail 明細リスト
	 * @param mapParams  パラメータMap
	 * @param kCode 社員コード
	 * @param targetDate 給与計算対象年月
	 * @param agreement 
	 * @param kdSubstituteHolidayDao 
	 * @throws MospException MosP例外処理が発生した場合
	 * @throws ClassNotFoundException クラスが見つからなかった場合
	 * @throws NoSuchFieldException フィールドが見つからなかった場合
	 * @throws IllegalAccessException メソッドにアクセスできない場合
	 * @throws SQLException SQL例外が発生した場合
	 */
	protected void calcDetails(List<?> listDetail, Map<String, String> mapParams, String kCode, Date targetDate,
			AgreementBaseInfo agreement, KdSubstituteHolidayDao kdSubstituteHolidayDao) throws MospException,
			SQLException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException {
		for (Object name : listDetail) {
			DetailDto dto = (DetailDto)name;
			// 残深休手当で平成22年4月1日以降の場合
			if (dto.getDetailCode().equals(PayrollConst.DTL_EACH_ALLOWANCE)
					&& MosPCodePart.afterLegalReformDate(targetDate)) {
				setDetailAmount(dto, (float)calcOverTimeLateNightWorkHoliday(mapParams, kCode, targetDate, agreement,
						kdSubstituteHolidayDao));
			} else {
				setDetailAmount(dto, calcExpr(dto.getExpression(), mapParams));
			}
		}
	}
	
	/**
	 * 残深休手当の計算する。<br>
	 * @param mapParams  パラメータ
	 * @param kCode 社員コード
	 * @param targetMonth 対象年月日
	 * @param agreement 
	 * @param kdSubstituteHolidayDao 
	 * @return 計算値
	 * @throws MospException MosP例外処理が発生した場合
	 * @throws ClassNotFoundException  クラスが見つからなかった場合
	 * @throws NoSuchFieldException フィールドが見つからなかった場合
	 * @throws IllegalAccessException メソッドにアクセスできない場合
	 * @throws SQLException SQL例外が発生した場合
	 */
	protected double calcOverTimeLateNightWorkHoliday(Map<String, String> mapParams, String kCode, Date targetMonth,
			AgreementBaseInfo agreement, KdSubstituteHolidayDao kdSubstituteHolidayDao) throws MospException,
			SQLException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException {
		try {
			if (agreement != null) {
				if (mapParams.size() != 0) {
					// 残業代の計算 + 深夜代の計算+ 休出代の計算
					return overTime(mapParams, kCode, targetMonth, agreement, kdSubstituteHolidayDao)
							+ lateNight(mapParams) + workHoliday(mapParams, kCode, targetMonth, agreement);
				}
			} else {
				return 0.0;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
	
	/**
	 * 残業時間の計算
	 * @param mapParams パラメータ
	 * @param kCode 社員コード
	 * @param targetDate 給与計算対象年月
	 * @param agreement 労使協定情報
	 * @return 残業時間の合計値 又は0.0
	 * @throws MospException MosP例外処理が発生した場合
	 * @throws ClassNotFoundException クラスが見つからなかった場合
	 * @throws NoSuchFieldException フィールドが見つからなかった場合
	 * @throws IllegalAccessException メソッドにアクセスできない場合
	 * @throws SQLException SQL例外が発生した場合
	 */
	protected double overTime(Map<String, String> mapParams, String kCode, Date targetDate,
			AgreementBaseInfo agreement, KdSubstituteHolidayDao kdSubstituteHolidayDao) throws MospException,
			SQLException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException {
		// 平日時間外
		double weekDayOvreTime = 0;
		// 所定休日時間外
		double weekHolidayOvreTime = 0;
		// 指定時間外
		double limitTerm = 0;
		// 月60時間超過平日時間外の計算
		double monthlyWeekOvreTime = 0;
		// 1年の限度時間外
		double limitYearOverTime = 0;
		// 代替休暇
		// 決済状況 = 確定のデータ取得
		KdSubstituteHolidayDto kdSubDaoFixed = new KdSubstituteHolidayDto();
		kdSubDaoFixed = (KdSubstituteHolidayDto)kdSubstituteHolidayDao.findForCondition(kCode, MospUtility
			.getYear(targetDate), MospUtility.getMonth(targetDate), "fixed");
		// 決済状況 = 決済のデータ取得
		// 給与計算対象年月の2ヶ月前のデータを取得する
		KdSubstituteHolidayDto kdSubDaoPayment = new KdSubstituteHolidayDto();
		kdSubDaoPayment = (KdSubstituteHolidayDto)kdSubstituteHolidayDao.findForCondition(kCode, MospUtility
			.getYear(targetDate), MospUtility.getMonth(targetDate) - 2, "payment");
		// 平日時間外の計算
		weekDayOvreTime = calcOverTime(agreement, checkParam(mapParams.get(PayrollConst.DTL_WEEK_DAY_OVRE_TIME)),
				checkParam(mapParams.get(PayrollConst.DTL_OVER_TIME_ALLOWANCE)));
		// 所定休日時間外の計算
		weekHolidayOvreTime = calcOverTime(agreement,
				checkParam(mapParams.get(PayrollConst.DTL_WEEK_HOLIDAY_OVRE_TIME)), checkParam(mapParams
					.get(PayrollConst.DTL_OVER_TIME_ALLOWANCE)));
		// 月60時間超過時間外の計算 決済状況（確定）
		monthlyWeekOvreTime = calcMon60HoursFixed(agreement, mapParams, kdSubDaoFixed);
		// 月60時間超過時間外の計算 決済状況（決済）
		monthlyWeekOvreTime += calcMon60HoursPayment(agreement, mapParams, kdSubDaoPayment);
		/* 計算結果 */
		// 全ての合計を返す
		return weekDayOvreTime + weekHolidayOvreTime + limitTerm + monthlyWeekOvreTime + limitYearOverTime;
	}
	
	/**
	 * 深夜時間の計算
	 * @param mapParams パラメータ
	 * @return 残業時間の合計値
	 * @throws MospException MosP例外処理が発生した場合
	 */
	protected double lateNight(Map<String, String> mapParams) throws MospException {
		return checkParam(mapParams.get(PayrollConst.DTL_LATE_NIGHT_ALLOWANCE))
				* (checkParam(mapParams.get(PayrollConst.DTL_SNJIKAN)) / 60);
	}
	
	/**
	 * 休出時間の計算
	 * @param mapParams パラメータ
	 * @param kCode 社員コード
	 * @param targetDate 給与計算対象年月
	 * @param agreement 労使協定情報
	 * @return 休出代時間の合計値
	 * @throws MospException MosP例外処理が発生した場合
	 * @throws ClassNotFoundException クラスが見つからなかった場合
	 * @throws NoSuchFieldException フィールドが見つからなかった場合
	 * @throws IllegalAccessException メソッドにアクセスできない場合
	 * @throws SQLException SQL例外が発生した場合
	 */
	protected double workHoliday(Map<String, String> mapParams, String kCode, Date targetDate,
			AgreementBaseInfo agreement) throws MospException, SQLException, IllegalAccessException,
			NoSuchFieldException, ClassNotFoundException {
		return checkParam(mapParams.get(PayrollConst.DTL_WOKR_HOLIDAY_ALLOWANCE1))
				* (agreement.getOfficialHolidayRate() * 0.01)
				* (checkParam(mapParams.get(PayrollConst.DTL_KSJIKAN)) / 60);
	}
	
	/**
	 * 日付操作（YYYY/MM/01型）
	 * @param yyyy 年
	 * @param mm 月
	 * @return YYYY/MM/01
	 * @throws MospException MosP例外処理が発生した場合
	 */
	protected Date aworkHoliday(String yyyy, String mm) throws MospException {
		return MospUtility.getDate(yyyy + "/" + mm + "/" + "01");
	}
	
	/**
	 * パラメータの中身をチェックする
	 * @param payrollConst パラメータ
	 * @return パラメータに関連する値、又は0.0 
	 */
	protected Double checkParam(String payrollConst) {
		if (payrollConst == null) {
			return 0.0;
		} else {
			return Double.valueOf(payrollConst);
		}
	}
	
	/**
	 * 残業時間
	 * @param overtime 残業時間（分単位）
	 * @param price 残業単価
	 * @param agreement 労使協定情報
	 * @return 残業の代金
	 */
	protected Double calcOverTime(AgreementBaseInfo agreement, Double overtime, Double price) {
		return price * (agreement.getOverTimeRate() * 0.01) * (overtime / 60);
	}
	
	/**
	 * 月60時間超過時間外の計算 決済状況（確定）
	 * @param agreement 労使協定情報
	 * @param mapParams パラメータ
	 * @param kdSubDaoFixed 決済状況（確定）
	 * @return 月60時間超過時間外の代金
	 */
	protected Double calcMon60HoursFixed(AgreementBaseInfo agreement, Map<String, String> mapParams,
			KdSubstituteHolidayDto kdSubDaoFixed) {
		//  決済状況（確定）が存在しない
		if (kdSubDaoFixed != null) {
			// 代替休暇(平日)
			double alteVacaWeek = kdSubDaoFixed.getPaymentAcquireTime() / substituteHolidayPremOverTime(agreement);
			// 代替休暇(所定休日)
			double alteVacaGiven = kdSubDaoFixed.getPaymentAcquireHoliday() / substituteHolidayPremWeek(agreement);
			// 代替休暇時間(平日)
			double alteVacaTimeWeek = checkParam(mapParams.get(PayrollConst.DTL_MONTHLY_OVRE_TIME)) - alteVacaWeek;
			// 代替休暇時間(所定休日)
			double alteVacaTimeGiven = checkParam(mapParams.get(PayrollConst.DTL_MONTHLY_WEEK_HOLIDAY)) - alteVacaGiven;
			// 計算 
			return ((alteVacaTimeWeek + alteVacaTimeGiven) / 60) * (agreement.getSubQuitRate() * 0.01)
					* checkParam(mapParams.get(PayrollConst.DTL_OVER_TIME_ALLOWANCE));
		} else {
			return 0.0;
		}
	}
	
	/**
	 * 月60時間超過時間外の計算 決済状況（決済）
	 * @param agreement 労使協定情報
	 * @param mapParams パラメータ
	 * @param kdSubDaoPayment 決済状況（決済）
	 * @return 月60時間超過時間外の代金
	 */
	protected Double calcMon60HoursPayment(AgreementBaseInfo agreement, Map<String, String> mapParams,
			KdSubstituteHolidayDto kdSubDaoPayment) {
		//  決済状況（決済）が存在しない
		if (kdSubDaoPayment != null) {
			// 代替休暇(平日)
			double substituteHolidayOverTime = kdSubDaoPayment.getLiquidationOverTime()
					/ substituteHolidayPremOverTime(agreement);
			// 代替休暇(所定休日)
			double substituteHolidayOverTimeWeek = kdSubDaoPayment.getLiquidationWeekHoliday()
					/ substituteHolidayPremWeek(agreement);
			// 計算 
			return checkParam(mapParams.get(PayrollConst.DTL_OVER_TIME_ALLOWANCE))
					* (agreement.getSubQuitRate() * 0.01)
					* ((substituteHolidayOverTime + substituteHolidayOverTimeWeek) / 60);
		} else {
			return 0.0;
		}
	}
	
	/**
	 * 代替休暇割増(平日)
	 * @param agreement 労使協定情報
	 * @return 代替休暇割増(平日) 
	 */
	protected Double substituteHolidayPremOverTime(AgreementBaseInfo agreement) {
		return (agreement.getSubQuitRate() - agreement.getSubAcquireRate()) * 0.01;
		
	}
	
	/**
	 * 代替休暇割増(所定休日)
	 * @param agreement 労使協定情報
	 * @return 代替休暇割増(所定休日)
	 */
	protected Double substituteHolidayPremWeek(AgreementBaseInfo agreement) {
		return (agreement.getSubQuitRate() - agreement.getSubAcquireHolidayRate()) * 0.01;
		
	}
	
}
