/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ld.service.impl; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.businessobject.A21SubAccount; import org.kuali.kfs.coa.businessobject.Account; import org.kuali.kfs.coa.service.AccountService; import org.kuali.kfs.coa.service.SubAccountService; import org.kuali.kfs.integration.ld.LaborLedgerObject; import org.kuali.kfs.module.ld.LaborConstants; import org.kuali.kfs.module.ld.LaborPropertyConstants; import org.kuali.kfs.module.ld.businessobject.BenefitsCalculation; import org.kuali.kfs.module.ld.businessobject.LaborObject; import org.kuali.kfs.module.ld.businessobject.PositionObjectBenefit; import org.kuali.kfs.module.ld.service.LaborBenefitsCalculationService; import org.kuali.kfs.module.ld.service.LaborPositionObjectBenefitService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.service.impl.KfsParameterConstants; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.util.ObjectUtils; import org.springframework.transaction.annotation.Transactional; /** * To provide its clients with access to the benefit calculation. */ @Transactional public class LaborBenefitsCalculationServiceImpl implements LaborBenefitsCalculationService { private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LaborBenefitsCalculationServiceImpl.class); private BusinessObjectService businessObjectService; private LaborPositionObjectBenefitService laborPositionObjectBenefitService; private AccountService accountService; private SubAccountService subAccountService; private String costSharingSourceAccountNumber; private String costSharingSourceSubAccountNumber; private String costSharingSourceAccountChartOfAccountsCode; /** * @see org.kuali.kfs.module.ld.service.LaborBenefitsCalculationService#getBenefitsCalculation(java.lang.Integer, * java.lang.String, java.lang.String) */ @Override public BenefitsCalculation getBenefitsCalculation(Integer universityFiscalYear, String chartOfAccountsCode, String benefitTypeCode) { Map<String, Object> fieldValues = new HashMap<String, Object>(); fieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear); fieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode); fieldValues.put(LaborPropertyConstants.POSITION_BENEFIT_TYPE_CODE, benefitTypeCode); return businessObjectService.findByPrimaryKey(BenefitsCalculation.class, fieldValues); } /** * @see org.kuali.kfs.module.ld.service.LaborBenefitsCalculationService#getBenefitsCalculation(java.lang.Integer, * java.lang.String, java.lang.String) */ @Override public BenefitsCalculation getBenefitsCalculation(Integer universityFiscalYear, String chartOfAccountsCode, String benefitTypeCode, String laborBenefitRateCategoryCode) { Map<String, Object> fieldValues = new HashMap<String, Object>(); fieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear); fieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode); fieldValues.put(LaborPropertyConstants.POSITION_BENEFIT_TYPE_CODE, benefitTypeCode); fieldValues.put(LaborPropertyConstants.LABOR_BENEFIT_RATE_CATEGORY_CODE, laborBenefitRateCategoryCode); return businessObjectService.findByPrimaryKey(BenefitsCalculation.class, fieldValues); } /** * @see org.kuali.kfs.module.ld.service.LaborBenefitsCalculationService#calculateFringeBenefit(java.lang.Integer, * java.lang.String, java.lang.String, org.kuali.rice.core.api.util.type.KualiDecimal) */ @Override public KualiDecimal calculateFringeBenefit(Integer fiscalYear, String chartCode, String objectCode, KualiDecimal salaryAmount, String accountNumber, String subAccountNumber) { LaborObject laborObject = new LaborObject(); laborObject.setUniversityFiscalYear(fiscalYear); laborObject.setChartOfAccountsCode(chartCode); laborObject.setFinancialObjectCode(objectCode); laborObject = (LaborObject) businessObjectService.retrieve(laborObject); return calculateFringeBenefit(laborObject, salaryAmount, accountNumber, subAccountNumber); } /** * @see org.kuali.kfs.module.ld.service.LaborBenefitsCalculationService#calculateFringeBenefit(org.kuali.kfs.module.ld.businessobject.LaborObject, * org.kuali.rice.core.api.util.type.KualiDecimal) */ @Override public KualiDecimal calculateFringeBenefit(LaborLedgerObject laborLedgerObject, KualiDecimal salaryAmount, String accountNumber, String subAccountNumber) { KualiDecimal fringeBenefit = KualiDecimal.ZERO; if (salaryAmount == null || salaryAmount.isZero() || ObjectUtils.isNull(laborLedgerObject)) { return fringeBenefit; } String FringeOrSalaryCode = laborLedgerObject.getFinancialObjectFringeOrSalaryCode(); if (!LaborConstants.SalaryExpenseTransfer.LABOR_LEDGER_SALARY_CODE.equals(FringeOrSalaryCode)) { return fringeBenefit; } Integer fiscalYear = laborLedgerObject.getUniversityFiscalYear(); String chartOfAccountsCode = laborLedgerObject.getChartOfAccountsCode(); String objectCode = laborLedgerObject.getFinancialObjectCode(); Collection<PositionObjectBenefit> positionObjectBenefits = laborPositionObjectBenefitService.getActivePositionObjectBenefits(fiscalYear, chartOfAccountsCode, objectCode); for (PositionObjectBenefit positionObjectBenefit : positionObjectBenefits) { KualiDecimal benefitAmount = this.calculateFringeBenefit(positionObjectBenefit, salaryAmount, accountNumber, subAccountNumber); fringeBenefit = fringeBenefit.add(benefitAmount); } return fringeBenefit; } /** * @see org.kuali.kfs.module.ld.service.LaborBenefitsCalculationService#calculateFringeBenefit(org.kuali.kfs.module.ld.businessobject.PositionObjectBenefit, * org.kuali.rice.core.api.util.type.KualiDecimal) */ @Override public KualiDecimal calculateFringeBenefit(PositionObjectBenefit positionObjectBenefit, KualiDecimal salaryAmount, String accountNumber, String subAccountNumber) { if (salaryAmount == null || salaryAmount.isZero() || ObjectUtils.isNull(positionObjectBenefit)) { return KualiDecimal.ZERO; } KualiDecimal fringeBenefitAmount = new KualiDecimal(0); //create a map for the search criteria to lookup the fringe benefit percentage Map<String, Object> fieldValues = new HashMap<String, Object>(); fieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, positionObjectBenefit.getUniversityFiscalYear()); fieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, positionObjectBenefit.getChartOfAccountsCode()); fieldValues.put(LaborPropertyConstants.POSITION_BENEFIT_TYPE_CODE, positionObjectBenefit.getFinancialObjectBenefitsTypeCode()); ParameterService parameterService = SpringContext.getBean(ParameterService.class); Boolean enableFringeBenefitCalculationByBenefitRate = parameterService.getParameterValueAsBoolean(KfsParameterConstants.FINANCIAL_SYSTEM_ALL.class, LaborConstants.BenefitCalculation.ENABLE_FRINGE_BENEFIT_CALC_BY_BENEFIT_RATE_CATEGORY_PARAMETER); //If system parameter is evaluated to use calculation by benefit rate category if (enableFringeBenefitCalculationByBenefitRate) { //get the benefit rate based off of the university fiscal year, chart of account code, labor benefit type code and labor benefit rate category code String laborBenefitRateCategoryCode = getBenefitRateCategoryCode(positionObjectBenefit.getChartOfAccountsCode(), accountNumber, subAccountNumber); //add the Labor Benefit Rate Category Code to the search criteria fieldValues.put("laborBenefitRateCategoryCode",laborBenefitRateCategoryCode); String search = fieldValues.get(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR) + "," + fieldValues.get(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE) + "," + fieldValues.get(LaborPropertyConstants.POSITION_BENEFIT_TYPE_CODE) + "," + fieldValues.get("laborBenefitRateCategoryCode"); LOG.info("Searching for Benefits Calculation {" + search + "}"); //perform the lookup based off the map BenefitsCalculation bc = businessObjectService.findByPrimaryKey(BenefitsCalculation.class, fieldValues); //make sure the benefits calculation isn't null and is active if ((bc != null) && (bc.isActive())) { LOG.info("Found a Benefit Calculation for {" + search + "}"); //lookup from the db the fringe benefit percentage from the list that is return. ***Should only return one value from the database. KualiDecimal fringeBenefitPercent = bc.getPositionFringeBenefitPercent(); LOG.debug("fringeBenefitPercent: " + fringeBenefitPercent); // calculate the benefit amount (ledger amt * (benfit pct/100) ) fringeBenefitAmount = fringeBenefitPercent.multiply(salaryAmount).divide(KFSConstants.ONE_HUNDRED.kualiDecimalValue()); }else{ LOG.info("Did not locate a Benefits Calculation for {" + search + "}."); //set the benefit amount to 0 fringeBenefitAmount = new KualiDecimal(0); } }else{ // calculate the benefit amount (ledger amt * (benfit pct/100) ) if (positionObjectBenefit.getBenefitsCalculation().isActive()) { KualiDecimal fringeBenefitPercent = positionObjectBenefit.getBenefitsCalculation().getPositionFringeBenefitPercent(); fringeBenefitAmount = fringeBenefitPercent.multiply(salaryAmount).divide(KFSConstants.ONE_HUNDRED.kualiDecimalValue()); } } LOG.debug("fringBenefitAmount: " + fringeBenefitAmount); return fringeBenefitAmount; } /** * @see org.kuali.kfs.module.ld.service.LaborBenefitsCalculationService#getBenefitRateCategoryCode(java.lang.String, * java.lang.String) */ @Override public String getBenefitRateCategoryCode(String chartOfAccountsCode, String accountNumber, String subAccountNumber) { this.setCostSharingSourceAccountNumber(null); this.setCostSharingSourceAccountChartOfAccountsCode(null); this.setCostSharingSourceSubAccountNumber(null); //make sure the sub accout number is filled in if (subAccountNumber != null) { LOG.info("Sub Account Number was filled in. Checking to see if it is a Cost Sharing Sub Account."); //make sure the system parameter exists if (SpringContext.getBean(ParameterService.class).parameterExists(KfsParameterConstants.FINANCIAL_SYSTEM_ALL.class, "USE_COST_SHARE_SOURCE_ACCOUNT_BENEFIT_RATE_IND")) { //parameter exists, determine the value of the parameter String sysParam2 = SpringContext.getBean(ParameterService.class).getParameterValueAsString(KfsParameterConstants.FINANCIAL_SYSTEM_ALL.class, "USE_COST_SHARE_SOURCE_ACCOUNT_BENEFIT_RATE_IND"); LOG.debug("sysParam2: " + sysParam2); //if sysParam2 == Y then check to see if it's a cost sharing sub account if (sysParam2.equalsIgnoreCase("Y")) { //lookup the A21SubAccount to get the cost sharing source account Map<String, Object> subFieldValues = new HashMap<String, Object>(); subFieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode); subFieldValues.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, subAccountNumber); subFieldValues.put(KFSPropertyConstants.SUB_ACCOUNT_TYPE_CODE, "CS"); LOG.info("Looking for a cost sharing sub account for sub account number " + subAccountNumber); if(ObjectUtils.isNull(businessObjectService)){ this.businessObjectService = SpringContext.getBean(BusinessObjectService.class); } //perform the lookup List<A21SubAccount> subAccountList = (List<A21SubAccount>) businessObjectService.findMatching(A21SubAccount.class, subFieldValues); //check to see if the lookup returns an empty list if (subAccountList.size() > 0) { LOG.info("Found A21 Sub Account. Retrieving source account number for cost sharing."); accountNumber = subAccountList.get(0).getCostShareSourceAccountNumber(); LOG.debug("Cost Sharing Source Account Number : " + accountNumber); this.setCostSharingSourceAccountNumber(accountNumber); this.setCostSharingSourceAccountChartOfAccountsCode(subAccountList.get(0).getCostShareChartOfAccountCode()); this.setCostSharingSourceSubAccountNumber(subAccountList.get(0).getCostShareSourceSubAccountNumber()); } else { LOG.info(subAccountNumber + " is not a cost sharing account. Using the Labor Benefit Rate Category from the account number."); } } else { LOG.info("Using the Grant Account to determine the labor benefit rate category code."); } } } LOG.info("Looking up Account {" + chartOfAccountsCode + "," + accountNumber + "}"); //lookup the account from the db based off the account code and the account number Account account = this.getAccountService().getByPrimaryId(chartOfAccountsCode, accountNumber); String laborBenefitRateCategoryCode = null; if (account == null) { LOG.info("The Account {" + chartOfAccountsCode + "," + accountNumber + "} could not be found."); } else { laborBenefitRateCategoryCode = account.getLaborBenefitRateCategoryCode(); } //make sure the laborBenefitRateCategoryCode is not null or blank if(StringUtils.isBlank(laborBenefitRateCategoryCode)){ LOG.info("The Account did not have a Labor Benefit Rate Category Code. Will use the system parameter default."); //The system parameter does not exist. Using a blank Labor Benefit Rate Category Code laborBenefitRateCategoryCode = StringUtils.defaultString(SpringContext.getBean(ParameterService.class).getParameterValueAsString(Account.class, LaborConstants.BenefitCalculation.DEFAULT_BENEFIT_RATE_CATEGORY_CODE_PARAMETER)); }else{ LOG.debug("Labor Benefit Rate Category Code for Account " + accountNumber + " is " + laborBenefitRateCategoryCode); } return laborBenefitRateCategoryCode; } /** * Sets the laborPositionObjectBenefitService attribute value. * * @param laborPositionObjectBenefitService The laborPositionObjectBenefitService to set. */ public void setLaborPositionObjectBenefitService(LaborPositionObjectBenefitService laborPositionObjectBenefitService) { this.laborPositionObjectBenefitService = laborPositionObjectBenefitService; } /** * Sets the businessObjectService attribute value. * * @param businessObjectService The businessObjectService to set. */ public void setBusinessObjectService(BusinessObjectService businessObjectService) { this.businessObjectService = businessObjectService; } /** * Gets the accountService attribute. * @return Returns the accountService. */ public AccountService getAccountService() { if(this.accountService == null){ this.setAccountService(SpringContext.getBean(AccountService.class)); } return accountService; } /** * Sets the accountService attribute value. * @param accountService The accountService to set. */ public void setAccountService(AccountService accountService) { this.accountService = accountService; } /** * Gets the subAccountService attribute. * @return Returns the subAccountService. */ public SubAccountService getSubAccountService() { if(this.subAccountService == null){ this.setSubAccountService(SpringContext.getBean(SubAccountService.class)); } return subAccountService; } /** * Sets the subAccountService attribute value. * @param subAccountService The subAccountService to set. */ public void setSubAccountService(SubAccountService subAccountService) { this.subAccountService = subAccountService; } /** * Gets the costSharingSourceAccountNumber attribute. * @return Returns the costSharingSourceAccountNumber. */ @Override public String getCostSharingSourceAccountNumber() { return costSharingSourceAccountNumber; } /** * Sets the costSharingSourceAccountNumber attribute value. * @param costSharingSourceAccountNumber The costSharingSourceAccountNumber to set. */ public void setCostSharingSourceAccountNumber(String costSharingSourceAccountNumber) { this.costSharingSourceAccountNumber = costSharingSourceAccountNumber; } /** * Gets the costSharingSourceSubAccountNumber attribute. * @return Returns the costSharingSourceSubAccountNumber. */ @Override public String getCostSharingSourceSubAccountNumber() { return costSharingSourceSubAccountNumber; } /** * Sets the costSharingSourceSubAccountNumber attribute value. * @param costSharingSourceSubAccountNumber The costSharingSourceSubAccountNumber to set. */ public void setCostSharingSourceSubAccountNumber(String costSharingSourceSubAccountNumber) { this.costSharingSourceSubAccountNumber = costSharingSourceSubAccountNumber; } /** * Gets the costSharingSourceAccountChartOfAccountsCode attribute. * @return Returns the costSharingSourceAccountChartOfAccountsCode. */ @Override public String getCostSharingSourceAccountChartOfAccountsCode() { return costSharingSourceAccountChartOfAccountsCode; } /** * Sets the costSharingSourceAccountChartOfAccountsCode attribute value. * @param costSharingSourceAccountChartOfAccountsCode The costSharingSourceAccountChartOfAccountsCode to set. */ public void setCostSharingSourceAccountChartOfAccountsCode(String costSharingSourceAccountChartOfAccountsCode) { this.costSharingSourceAccountChartOfAccountsCode = costSharingSourceAccountChartOfAccountsCode; } }