/* * 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.cam.batch.service.impl; import static org.kuali.kfs.sys.KFSConstants.BALANCE_TYPE_ACTUAL; import java.math.BigDecimal; import java.sql.Timestamp; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import javax.mail.MessagingException; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.businessobject.ObjectCode; import org.kuali.kfs.coa.service.ObjectCodeService; import org.kuali.kfs.gl.service.impl.StringHelper; import org.kuali.kfs.module.cam.CamsConstants; import org.kuali.kfs.module.cam.CamsKeyConstants; import org.kuali.kfs.module.cam.CamsPropertyConstants; import org.kuali.kfs.module.cam.batch.AssetDepreciationStep; import org.kuali.kfs.module.cam.batch.AssetPaymentInfo; import org.kuali.kfs.module.cam.batch.service.AssetDepreciationService; import org.kuali.kfs.module.cam.batch.service.ReportService; import org.kuali.kfs.module.cam.businessobject.Asset; import org.kuali.kfs.module.cam.businessobject.AssetDepreciationConvention; import org.kuali.kfs.module.cam.businessobject.AssetDepreciationTransaction; import org.kuali.kfs.module.cam.businessobject.AssetObjectCode; import org.kuali.kfs.module.cam.businessobject.AssetYearEndDepreciation; import org.kuali.kfs.module.cam.document.dataaccess.DepreciableAssetsDao; import org.kuali.kfs.module.cam.document.dataaccess.DepreciationBatchDao; import org.kuali.kfs.module.cam.document.service.AssetDateService; import org.kuali.kfs.module.cam.document.service.AssetService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.batch.service.SchedulerService; import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader; import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry; import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper; import org.kuali.kfs.sys.businessobject.UniversityDate; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService; import org.kuali.kfs.sys.service.OptionsService; import org.kuali.kfs.sys.service.UniversityDateService; import org.kuali.kfs.sys.service.impl.KfsParameterConstants; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.mail.MailMessage; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.coreservice.api.parameter.Parameter; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.kew.api.WorkflowDocument; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kns.service.DataDictionaryService; import org.kuali.rice.krad.exception.InvalidAddressException; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.KRADServiceLocatorWeb; import org.kuali.rice.krad.service.MailService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; import org.kuali.rice.krad.workflow.service.WorkflowDocumentService; import org.springframework.transaction.annotation.Transactional; /** * This class is a service that calculates the depreciation amount for each asset that has a eligible asset payment. * <p> * When an error occurs running this process, a pdf file will be created with the error message. However, this doesn't mean that * this process automatically leaves all the records as they were right before running the program. If the process fails, is * suggested to do the following before trying to run the process again: a.)Delete gl pending entry depreciation entries: DELETE * FROM GL_PENDING_ENTRY_T WHERE FDOC_TYP_CD = 'DEPR' b.)Substract from the accumulated depreciation amount the depreciation * calculated for the fiscal month that was ran, and then reset the depreciation amount field for the fiscal month that was ran. ex: * Assuming that the fiscal month = 8 then: UPDATE CM_AST_PAYMENT_T SET AST_ACUM_DEPR1_AMT = AST_ACUM_DEPR1_AMT - * AST_PRD8_DEPR1_AMT, AST_PRD8_DEPR1_AMT=0 */ @Transactional public class AssetDepreciationServiceImpl implements AssetDepreciationService { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetDepreciationServiceImpl.class); protected ParameterService parameterService; protected AssetService assetService; protected ReportService reportService; protected DateTimeService dateTimeService; protected DepreciableAssetsDao depreciableAssetsDao; protected ConfigurationService kualiConfigurationService; protected GeneralLedgerPendingEntryService generalLedgerPendingEntryService; protected BusinessObjectService businessObjectService; protected UniversityDateService universityDateService; protected OptionsService optionsService; protected DataDictionaryService dataDictionaryService; protected DepreciationBatchDao depreciationBatchDao; protected String cronExpression; protected MailService mailService; protected volatile WorkflowDocumentService workflowDocumentService; private AssetDateService assetDateService; private SchedulerService schedulerService; /** * @see org.kuali.kfs.module.cam.batch.service.AssetDepreciationService#runDepreciation() */ @Override public void runDepreciation() { Integer fiscalYear = -1; Integer fiscalMonth = -1; String errorMsg = ""; List<String> documentNos = new ArrayList<String>(); List<String[]> reportLog = new ArrayList<String[]>(); Collection<AssetObjectCode> assetObjectCodes = new ArrayList<AssetObjectCode>(); boolean hasErrors = false; Calendar depreciationDate = dateTimeService.getCurrentCalendar(); java.sql.Date depDate = null; Calendar currentDate = dateTimeService.getCurrentCalendar(); String depreciationDateParameter = null; DateFormat dateFormat = new SimpleDateFormat(CamsConstants.DateFormats.YEAR_MONTH_DAY); boolean executeJob = false; String errorMessage = kualiConfigurationService.getPropertyValueAsString(CamsKeyConstants.Depreciation.DEPRECIATION_ALREADY_RAN_MSG); try { executeJob = runAssetDepreciation(); if(executeJob) { LOG.info("*******" + CamsConstants.Depreciation.DEPRECIATION_BATCH + " HAS BEGUN *******"); /* * Getting the system parameter "DEPRECIATION_DATE" When this parameter is used to determine which fiscal month and year * is going to be depreciated If blank then the system will take the system date to determine the fiscal period */ if (parameterService.parameterExists(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_RUN_DATE_PARAMETER)) { depreciationDateParameter = parameterService.getParameterValueAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_RUN_DATE_PARAMETER); } else { throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(CamsKeyConstants.Depreciation.DEPRECIATION_DATE_PARAMETER_NOT_FOUND)); } if(StringUtils.isBlank(depreciationDateParameter)) { depreciationDateParameter = dateFormat.format(dateTimeService.getCurrentDate()); } // This validates the system parameter depreciation_date has a valid format of YYYY-MM-DD. if ( !StringUtils.isBlank(depreciationDateParameter) ) { try { depreciationDate.setTime(dateFormat.parse(depreciationDateParameter.trim())); } catch (ParseException e) { throw new IllegalArgumentException(kualiConfigurationService.getPropertyValueAsString(CamsKeyConstants.Depreciation.INVALID_DEPRECIATION_DATE_FORMAT)); } } if ( LOG.isInfoEnabled() ) { LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Depreciation run date: " + depreciationDateParameter); } UniversityDate universityDate = businessObjectService.findBySinglePrimaryKey(UniversityDate.class, new java.sql.Date(depreciationDate.getTimeInMillis())); if (universityDate == null) { throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_UNIV_DATE_NOT_FOUND)); } fiscalYear = universityDate.getUniversityFiscalYear(); fiscalMonth = new Integer(universityDate.getUniversityFiscalAccountingPeriod()); assetObjectCodes = getAssetObjectCodes(fiscalYear); // If the depreciation date is not = to the system date then, the depreciation process cannot run. if ( LOG.isInfoEnabled() ) { LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Fiscal Year = " + fiscalYear + " & Fiscal Period=" + fiscalMonth); } int fiscalStartMonth = Integer.parseInt(optionsService.getCurrentYearOptions().getUniversityFiscalYearStartMo()); reportLog.addAll(depreciableAssetsDao.generateStatistics(true, null, fiscalYear, fiscalMonth, depreciationDate,dateTimeService.toDateString(depreciationDate.getTime()), assetObjectCodes,fiscalStartMonth, errorMessage)); // update if fiscal period is 12 // depreciationBatchDao.updateAssetsCreatedInLastFiscalPeriod(fiscalMonth, fiscalYear); updateAssetsDatesForLastFiscalPeriod(fiscalMonth, fiscalYear); // Retrieving eligible asset payment details LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Getting list of asset payments eligible for depreciation."); Collection<AssetPaymentInfo> depreciableAssetsCollection = depreciationBatchDao.getListOfDepreciableAssetPaymentInfo(fiscalYear, fiscalMonth, depreciationDate); // if we have assets eligible for depreciation then, calculate depreciation and create glpe's transactions if (depreciableAssetsCollection != null && !depreciableAssetsCollection.isEmpty()) { SortedMap<String, AssetDepreciationTransaction> depreciationTransactions = this.calculateDepreciation(fiscalYear, fiscalMonth, depreciableAssetsCollection, depreciationDate, assetObjectCodes); processGeneralLedgerPendingEntry(fiscalYear, fiscalMonth, documentNos, depreciationTransactions); } else { throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(CamsKeyConstants.Depreciation.NO_ELIGIBLE_FOR_DEPRECIATION_ASSETS_FOUND)); } } } catch (Exception e) { LOG.error("Error occurred"); LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "**************************************************************************"); LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "AN ERROR HAS OCCURRED! - ERROR: " + e.getMessage(),e); LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "**************************************************************************"); hasErrors = true; errorMsg = "Depreciation process ran unsucessfuly.\nReason:" + e.getMessage(); } finally { if (!hasErrors && executeJob) { int fiscalStartMonth = Integer.parseInt(optionsService.getCurrentYearOptions().getUniversityFiscalYearStartMo()); reportLog.addAll(depreciableAssetsDao.generateStatistics(false, documentNos, fiscalYear, fiscalMonth, depreciationDate,dateTimeService.toDateString(depreciationDate.getTime()), assetObjectCodes, fiscalStartMonth, errorMessage)); } // the report will be generated only when there is an error or when the log has something. if (!reportLog.isEmpty() || !errorMsg.trim().equals("")) { reportService.generateDepreciationReport(reportLog, errorMsg, depreciationDateParameter); } if (LOG.isDebugEnabled()) { LOG.debug("*******" + CamsConstants.Depreciation.DEPRECIATION_BATCH + " HAS ENDED *******"); } } } @Override public Collection<AssetObjectCode> getAssetObjectCodes(Integer fiscalYear) { LOG.debug("DepreciableAssetsDAoOjb.getAssetObjectCodes() - started"); LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Getting asset object codes."); Collection<AssetObjectCode> assetObjectCodesCollection; HashMap<String, Object> fields = new HashMap<String, Object>(); fields.put(CamsPropertyConstants.AssetObject.UNIVERSITY_FISCAL_YEAR, fiscalYear); fields.put(CamsPropertyConstants.AssetObject.ACTIVE, Boolean.TRUE); assetObjectCodesCollection = businessObjectService.findMatching(AssetObjectCode.class, fields); LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Finished getting asset object codes - which are:" + assetObjectCodesCollection.toString()); LOG.debug("DepreciableAssetsDAoOjb.getAssetObjectCodes() - ended"); return assetObjectCodesCollection; } // CSU 6702 BEGIN /** * @see org.kuali.kfs.module.cam.batch.service.AssetDepreciationService#runYearEndDepreciation(java.lang.Integer) */ @Override public void runYearEndDepreciation(Integer fiscalYearToDepreciate){ Integer fiscalYear = -1; Integer fiscalMonth = -1; List<String> documentNos = new ArrayList<String>(); String errorMsg = ""; List<String[]> reportLog = new ArrayList<String[]>(); boolean hasErrors = false; boolean includeRetired = false; Calendar depreciationDate = Calendar.getInstance(); AssetYearEndDepreciation assetYearEndDepreciation = null; assetService = SpringContext.getBean(AssetService.class); List<String> notAcceptedAssetStatus = new ArrayList<String>(); boolean statusContainsR = false; String notAcceptedAssetStatusString = ""; String depreciationDateParameter = fiscalYearToDepreciate.toString()+getLastDayOfFiscalyear(); notAcceptedAssetStatus.addAll(parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.NON_DEPRECIABLE_NON_CAPITAL_ASSETS_STATUS_CODES)); LOG.info("notAcceptedAssetStatusString = " + notAcceptedAssetStatusString); if (notAcceptedAssetStatus.contains("R")) { LOG.info("looks like notAcceptedAssetStatusString contains R"); statusContainsR = true; notAcceptedAssetStatus.remove("R"); for (int i = 0; i < notAcceptedAssetStatus.size(); i++) { String s = notAcceptedAssetStatus.get(i); notAcceptedAssetStatusString = notAcceptedAssetStatusString+s+";"; } if (notAcceptedAssetStatusString.endsWith(";")){ notAcceptedAssetStatusString = notAcceptedAssetStatusString.substring(0, (notAcceptedAssetStatusString.length()-1)); } Parameter.Builder param = Parameter.Builder.create( parameterService.getParameter(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.NON_DEPRECIABLE_NON_CAPITAL_ASSETS_STATUS_CODES) ); param.setValue(notAcceptedAssetStatusString); parameterService.updateParameter(param.build()); } try{ LOG.info("*******YEAR END DEPRECIATION - HAS BEGUN *******"); // // Getting the system parameter "INCLUDE_RETIRED_ASSETS_IND" When this parameter is used to determine whether // to include retired assets in the depreciation // if ( LOG.isInfoEnabled() ) { LOG.info("parameterService.getParameterValueAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.INCLUDE_RETIRED_ASSETS_IND) = " + parameterService.getParameterValueAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.INCLUDE_RETIRED_ASSETS_IND)); } includeRetired=parameterService.getParameterValueAsBoolean(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.INCLUDE_RETIRED_ASSETS_IND); UniversityDate universityDate = businessObjectService.findBySinglePrimaryKey(UniversityDate.class, new java.sql.Date(depreciationDate.getTimeInMillis())); if (universityDate == null) { throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_UNIV_DATE_NOT_FOUND)); } fiscalYear = universityDate.getUniversityFiscalYear(); fiscalMonth = new Integer(universityDate.getUniversityFiscalAccountingPeriod()); depreciationDate.setTime(java.sql.Date.valueOf(fiscalYearToDepreciate.toString()+getLastDayOfFiscalyear())); fiscalYear = fiscalYearToDepreciate; fiscalMonth = 12; Collection<AssetObjectCode> assetObjectCodes = getAssetObjectCodes(fiscalYear); // If the depreciation date is not = to the system date then, the depreciation process cannot run. if ( LOG.isInfoEnabled() ) { LOG.info("YEAR END DEPRECIATION - " + "Fiscal Year = " + fiscalYear + " & Fiscal Period=" + fiscalMonth); } // mjmc this caused arrayIndexOutOfBounds: 16 // TODO reportLog.addAll(depreciableAssetsDao.generateStatistics(true, null, fiscalYear, fiscalMonth, depreciationDate, true)); // update if fiscal period is 12 depreciationBatchDao.updateAssetsCreatedInLastFiscalPeriod(fiscalMonth, fiscalYear); // Retrieving eligible asset payment details LOG.info("YEAR END DEPRECIATION - Getting list of YEAR END DEPRECIATION asset payments eligible for depreciation."); Collection<AssetPaymentInfo> depreciableAssetsCollection = depreciationBatchDao.getListOfDepreciableAssetPaymentInfoYearEnd(fiscalYear, fiscalMonth, depreciationDate, includeRetired); // if we have assets eligible for depreciation then, calculate depreciation and create glpe's transactions if (depreciableAssetsCollection != null && !depreciableAssetsCollection.isEmpty()) { SortedMap<String, AssetDepreciationTransaction> depreciationTransactions = this.calculateYearEndDepreciation(depreciableAssetsCollection, depreciationDate, fiscalYearToDepreciate, fiscalYear, fiscalMonth, assetObjectCodes); processYearEndGeneralLedgerPendingEntry(fiscalYear, documentNos, depreciationTransactions); } else { throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(CamsKeyConstants.Depreciation.NO_ELIGIBLE_FOR_DEPRECIATION_ASSETS_FOUND)); } } catch(Exception e) { LOG.error("YEAR END DEPRECIATION - **************************************************************************"); LOG.error("YEAR END DEPRECIATION - AN ERROR HAS OCCURRED! - ERROR: " + e.getClass().getName() + " : " + e.getMessage()); LOG.error("YEAR END DEPRECIATION - **************************************************************************"); LOG.error(e); hasErrors = true; errorMsg = "YEAR END DEPRECIATION - process ran unsucessfuly.\nReason:" + e.getMessage(); } finally { if (!hasErrors) { // mjmc java.lang.ArrayIndexOutOfBoundsException: 16 // TODO reportLog.addAll(depreciableAssetsDao.generateStatistics(false, documentNos, fiscalYear, fiscalMonth, depreciationDate, true)); if (assetYearEndDepreciation != null) { assetYearEndDepreciation.setRunDate(new java.sql.Date(new java.util.Date().getTime())); } } // the report will be generated only when there is an error or when the log has something. if (!reportLog.isEmpty() || !errorMsg.trim().equals("")) { // mjmc java.lang.ArrayIndexOutOfBoundsException: 16 reportService.generateDepreciationReport(reportLog, errorMsg, depreciationDateParameter); } LOG.info("******* YEAR END DEPRECIATION - HAS ENDED *******"); } // reset param so that retired assets are not depreciated during the rest of the year if (statusContainsR){ notAcceptedAssetStatusString = notAcceptedAssetStatusString+";R"; if ( LOG.isInfoEnabled() ) { LOG.info("notAcceptedAssetStatusString after reset= " + notAcceptedAssetStatusString); } Parameter.Builder param = Parameter.Builder.create( parameterService.getParameter(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.NON_DEPRECIABLE_NON_CAPITAL_ASSETS_STATUS_CODES) ); param.setValue(notAcceptedAssetStatusString); parameterService.updateParameter(param.build()); if ( LOG.isInfoEnabled() ) { LOG.info(CamsConstants.Parameters.NON_DEPRECIABLE_NON_CAPITAL_ASSETS_STATUS_CODES+" now = "+ parameterService.getParameterValueAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.NON_DEPRECIABLE_NON_CAPITAL_ASSETS_STATUS_CODES)); } } } protected boolean runAssetDepreciation() throws ParseException { boolean executeJob = false; List<String> errorMessages = new ArrayList<String>(); Date currentDate = convertToDate(dateTimeService.toDateString(dateTimeService.getCurrentDate())); Date beginDate = getBlankOutBeginDate(errorMessages); Date endDate = getBlankOutEndDate(errorMessages); if (hasBlankOutPeriodStarted(beginDate, endDate, errorMessages)) { String blankOutPeriodrunDate = parameterService.getParameterValueAsString(AssetDepreciationStep.class, CamsConstants.Parameters.BLANK_OUT_PERIOD_RUN_DATE); if(!StringHelper.isNullOrEmpty(blankOutPeriodrunDate)){ Date runDate = convertToDate(blankOutPeriodrunDate); if(runDate.compareTo(beginDate)>=0 && runDate.compareTo(endDate)<=0) { if(currentDate.equals(runDate)) { executeJob = true; } else { LOG.info("Today is not BLANK_OUT_PERIOD_RUN_DATE. executeJob not set to true"); } } else { String blankOutBegin = parameterService.getParameterValueAsString(AssetDepreciationStep.class, CamsConstants.Parameters.BLANK_OUT_BEGIN_MMDD); String blankOutEnd = parameterService.getParameterValueAsString(AssetDepreciationStep.class, CamsConstants.Parameters.BLANK_OUT_END_MMDD); String message = "BLANK_OUT_PERIOD_RUN_DATE: " + blankOutPeriodrunDate + " is not in the blank out period range." + "Blank out period range is [ " + blankOutBegin + "-" + blankOutEnd + " ] ." ; errorMessages.add(message); LOG.info(message); } } else { String message = "Parameter BLANK_OUT_PERIOD_RUN_DATE (component: Asset Depreciation Step) is not set" + " Please set the date correctly to run the job."; errorMessages.add(message); LOG.info(message); } } else { if (getSchedulerService().cronConditionMet(this.cronExpression)) { executeJob = true; } else { LOG.info("Cron condition not met. executeJob not set to true"); } } if(!executeJob && !errorMessages.isEmpty()) { sendWarningMail(errorMessages); } return executeJob; } protected boolean hasBlankOutPeriodStarted(Date beginDate, Date endDate, List<String> errorMessages) throws ParseException { Date currentDate = convertToDate(dateTimeService.toDateString(dateTimeService.getCurrentDate())); String blankOutBegin = parameterService.getParameterValueAsString(AssetDepreciationStep.class, CamsConstants.Parameters.BLANK_OUT_BEGIN_MMDD); String blankOutEnd = parameterService.getParameterValueAsString(AssetDepreciationStep.class, CamsConstants.Parameters.BLANK_OUT_END_MMDD); if(ObjectUtils.isNotNull(beginDate) && ObjectUtils.isNotNull(endDate)) { if(currentDate.compareTo(beginDate)>=0 && currentDate.compareTo(endDate)<=0 ) { return true; } } else { String message = "Unable to determine blank out period for a given " + blankOutBegin + " - " + blankOutEnd + " range ."; errorMessages.add(message); LOG.info(message); } return false; } /** * * This method calculate blank out period end date. * @return blank out period end date in MM/dd/yyyy format. * @throws ParseException */ private Date getBlankOutEndDate(List<String> errorMessages) throws ParseException { String endDate = parameterService.getParameterValueAsString(AssetDepreciationStep.class, CamsConstants.Parameters.BLANK_OUT_END_MMDD); if(!StringHelper.isNullOrEmpty(endDate)) { int endDay = new Integer(StringUtils.substringAfterLast(endDate, "/")).intValue(); int endMonth = new Integer(StringUtils.substringBeforeLast(endDate, "/")).intValue()-1 ; Calendar blankOutEndcalendar = Calendar.getInstance(); blankOutEndcalendar.set(blankOutEndcalendar.get(Calendar.YEAR), endMonth , endDay); return convertToDate(dateTimeService.toString(blankOutEndcalendar.getTime(), CamsConstants.DateFormats.MONTH_DAY_YEAR)); } else { String message = "Parameter BLANK_OUT_END_MMDD (component:Asset Depreciation Step) is not set." ; errorMessages.add(message); LOG.info(message); } return null; } /** * * This method calculate blank out period begin date. * @return blank out period begin date in MM/dd/yyyy format. * @throws ParseException */ private Date getBlankOutBeginDate(List<String> errorMessages) throws ParseException { String beginDate = parameterService.getParameterValueAsString(AssetDepreciationStep.class, CamsConstants.Parameters.BLANK_OUT_BEGIN_MMDD); if(!StringHelper.isNullOrEmpty(beginDate)) { int beginDay = new Integer(StringUtils.substringAfterLast(beginDate, "/")).intValue(); int beginMonth = new Integer(StringUtils.substringBeforeLast(beginDate, "/")).intValue()-1; Calendar blankOutBegincalendar = Calendar.getInstance(); blankOutBegincalendar.set(blankOutBegincalendar.get(Calendar.YEAR),beginMonth , beginDay); return convertToDate(dateTimeService.toString(blankOutBegincalendar.getTime(), CamsConstants.DateFormats.MONTH_DAY_YEAR)); } else { String message = "Parameter BLANK_OUT_BEGIN_MMDD (component:Asset Depreciation Step) is not set."; errorMessages.add(message); LOG.info(message); } return null; } private Date convertToDate(String date) throws ParseException { DateFormat dateFormat = new SimpleDateFormat(CamsConstants.DateFormats.MONTH_DAY_YEAR); dateFormat.setLenient(false); return dateFormat.parse(date); } /** * This method calculates the depreciation of each asset payment, creates the depreciation transactions that will be stored in * the general ledger pending entry table * * @param depreciableAssetsCollection asset payments eligible for depreciation * @return SortedMap with a list of depreciation transactions */ protected SortedMap<String, AssetDepreciationTransaction> calculateDepreciation(Integer fiscalYear, Integer fiscalMonth, Collection<AssetPaymentInfo> depreciableAssetsCollection, Calendar depreciationDate, Collection<AssetObjectCode> assetObjectCodes) { LOG.debug("calculateDepreciation() - start"); Collection<String> organizationPlantFundObjectSubType = new ArrayList<String>(); Collection<String> campusPlantFundObjectSubType = new ArrayList<String>(); SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary = new TreeMap<String, AssetDepreciationTransaction>(); double monthsElapsed = 0d; double assetLifeInMonths = 0d; KualiDecimal accumulatedDepreciationAmount = KualiDecimal.ZERO; Calendar assetDepreciationDate = Calendar.getInstance(); try { LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Getting the parameters for the plant fund object sub types."); // Getting system parameters needed. if (parameterService.parameterExists(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_ORGANIZATON_PLANT_FUND_SUB_OBJECT_TYPES)) { organizationPlantFundObjectSubType = new ArrayList<String>( parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_ORGANIZATON_PLANT_FUND_SUB_OBJECT_TYPES) ); } if (parameterService.parameterExists(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_CAMPUS_PLANT_FUND_OBJECT_SUB_TYPES)) { campusPlantFundObjectSubType = new ArrayList<String>( parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_CAMPUS_PLANT_FUND_OBJECT_SUB_TYPES) ); } // Initializing the asset payment table. depreciationBatchDao.resetPeriodValuesWhenFirstFiscalPeriod(fiscalMonth); LOG.debug("getBaseAmountOfAssets(Collection<AssetPayment> depreciableAssetsCollection) - Started."); // Invoking method that will calculate the base amount for each asset payment transactions, which could be more than 1 // per asset. LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Calculating the base amount for each asset."); Map<Long, KualiDecimal> salvageValueAssetDeprAmounts = depreciationBatchDao.getPrimaryDepreciationBaseAmountForSV(); // Retrieving the object asset codes. Map<String, AssetObjectCode> assetObjectCodeMap = buildChartObjectToCapitalizationObjectMap(assetObjectCodes); Map<String, ObjectCode> capitalizationObjectCodes = new HashMap<String, ObjectCode>(); // Reading asset payments LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Reading collection with eligible asset payment details."); int counter = 0; List<AssetPaymentInfo> saveList = new ArrayList<AssetPaymentInfo>(); for (AssetPaymentInfo assetPaymentInfo : depreciableAssetsCollection) { AssetObjectCode assetObjectCode = assetObjectCodeMap.get(assetPaymentInfo.getChartOfAccountsCode() + "-" + assetPaymentInfo.getFinancialObjectCode()); if (assetObjectCode == null) { LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Asset object code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetPaymentInfo.getFinancialObjectCode()); LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber()); continue; } ObjectCode accumulatedDepreciationFinancialObject = getDepreciationObjectCode(fiscalYear, capitalizationObjectCodes, assetPaymentInfo, assetObjectCode.getAccumulatedDepreciationFinancialObjectCode()); ObjectCode depreciationExpenseFinancialObject = getDepreciationObjectCode(fiscalYear, capitalizationObjectCodes, assetPaymentInfo, assetObjectCode.getDepreciationExpenseFinancialObjectCode()); if (ObjectUtils.isNull(accumulatedDepreciationFinancialObject)) { LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Accumulated Depreciation Financial Object Code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetObjectCode.getAccumulatedDepreciationFinancialObjectCode()); LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber()); continue; } if (ObjectUtils.isNull(depreciationExpenseFinancialObject)) { LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Depreciation Expense Financial Object Code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetObjectCode.getDepreciationExpenseFinancialObjectCode()); LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber()); continue; } Long assetNumber = assetPaymentInfo.getCapitalAssetNumber(); assetDepreciationDate.setTime(assetPaymentInfo.getDepreciationDate()); accumulatedDepreciationAmount = KualiDecimal.ZERO; KualiDecimal deprAmountSum = salvageValueAssetDeprAmounts.get(assetNumber); // Calculating the life of the asset in months. assetLifeInMonths = assetPaymentInfo.getDepreciableLifeLimit() * 12; // Calculating the months elapsed for the asset using the depreciation date and the asset service date. monthsElapsed = (depreciationDate.get(Calendar.MONTH) - assetDepreciationDate.get(Calendar.MONTH) + (depreciationDate.get(Calendar.YEAR) - assetDepreciationDate.get(Calendar.YEAR)) * 12) + 1; // ************************************************************************************************************** // CALCULATING ACCUMULATED DEPRECIATION BASED ON FORMULA FOR SINGLE LINE AND SALVAGE VALUE DEPRECIATION METHODS. // ************************************************************************************************************** KualiDecimal primaryDepreciationBaseAmount = assetPaymentInfo.getPrimaryDepreciationBaseAmount(); if (primaryDepreciationBaseAmount == null) { assetPaymentInfo.setPrimaryDepreciationBaseAmount(KualiDecimal.ZERO); } if (assetPaymentInfo.getAccumulatedPrimaryDepreciationAmount() == null) { assetPaymentInfo.setAccumulatedPrimaryDepreciationAmount(KualiDecimal.ZERO); } // If the months elapsed >= to the life of the asset (in months) then, the accumulated depreciation should be: if (monthsElapsed >= assetLifeInMonths) { if (CamsConstants.Asset.DEPRECIATION_METHOD_STRAIGHT_LINE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode())) { accumulatedDepreciationAmount = primaryDepreciationBaseAmount; } else if (CamsConstants.Asset.DEPRECIATION_METHOD_SALVAGE_VALUE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode()) && deprAmountSum != null && deprAmountSum.isNonZero()) { accumulatedDepreciationAmount = primaryDepreciationBaseAmount.subtract((primaryDepreciationBaseAmount.divide(deprAmountSum)).multiply(assetPaymentInfo.getSalvageAmount())); } } // If the month elapse < to the life of the asset (in months) then.... else { if (CamsConstants.Asset.DEPRECIATION_METHOD_STRAIGHT_LINE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode())) { accumulatedDepreciationAmount = new KualiDecimal((monthsElapsed / assetLifeInMonths) * primaryDepreciationBaseAmount.doubleValue()); } else if (CamsConstants.Asset.DEPRECIATION_METHOD_SALVAGE_VALUE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode()) && deprAmountSum != null && deprAmountSum.isNonZero()) { accumulatedDepreciationAmount = new KualiDecimal((monthsElapsed / assetLifeInMonths) * (primaryDepreciationBaseAmount.subtract((primaryDepreciationBaseAmount.divide(deprAmountSum)).multiply(assetPaymentInfo.getSalvageAmount()))).doubleValue()); } } // Calculating in process fiscal month depreciation amount KualiDecimal transactionAmount = accumulatedDepreciationAmount.subtract(assetPaymentInfo.getAccumulatedPrimaryDepreciationAmount()); String transactionType = KFSConstants.GL_DEBIT_CODE; if (transactionAmount.isNegative()) { transactionType = KFSConstants.GL_CREDIT_CODE; } String plantAccount = ""; String plantCOA = ""; // getting the right Plant Fund Chart code & Plant Fund Account if (organizationPlantFundObjectSubType.contains(assetPaymentInfo.getFinancialObjectSubTypeCode())) { plantAccount = assetPaymentInfo.getOrganizationPlantAccountNumber(); plantCOA = assetPaymentInfo.getOrganizationPlantChartCode(); } else if (campusPlantFundObjectSubType.contains(assetPaymentInfo.getFinancialObjectSubTypeCode())) { plantAccount = assetPaymentInfo.getCampusPlantAccountNumber(); plantCOA = assetPaymentInfo.getCampusPlantChartCode(); } if (StringUtils.isBlank(plantCOA) || StringUtils.isBlank(plantAccount)) { // skip the payment LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Plant COA is " + plantCOA + " and plant account is " + plantAccount + " for Financial Object SubType Code = " + assetPaymentInfo.getFinancialObjectSubTypeCode() + " so Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber()); continue; } LOG.debug("Asset#: " + assetNumber + " - Payment sequence#:" + assetPaymentInfo.getPaymentSequenceNumber() + " - Asset Depreciation date:" + assetDepreciationDate + " - Life:" + assetLifeInMonths + " - Depreciation base amt:" + primaryDepreciationBaseAmount + " - Accumulated depreciation:" + assetPaymentInfo.getAccumulatedPrimaryDepreciationAmount() + " - Month Elapsed:" + monthsElapsed + " - Calculated accum depreciation:" + accumulatedDepreciationAmount + " - Depreciation amount:" + transactionAmount.toString() + " - Depreciation Method:" + assetPaymentInfo.getPrimaryDepreciationMethodCode()); assetPaymentInfo.setAccumulatedPrimaryDepreciationAmount(accumulatedDepreciationAmount); assetPaymentInfo.setTransactionAmount(transactionAmount); counter++; saveList.add(assetPaymentInfo); // Saving depreciation amount in the asset payment table if (counter % 1000 == 0) { getDepreciationBatchDao().updateAssetPayments(saveList, fiscalMonth); saveList.clear(); } // if the asset has a depreciation amount <> 0 then, create its debit and credit entries. if (transactionAmount.isNonZero()) { this.populateDepreciationTransaction(assetPaymentInfo, transactionType, plantCOA, plantAccount, depreciationExpenseFinancialObject, depreciationTransactionSummary); transactionType = (transactionType.equals(KFSConstants.GL_DEBIT_CODE) ? KFSConstants.GL_CREDIT_CODE : KFSConstants.GL_DEBIT_CODE); this.populateDepreciationTransaction(assetPaymentInfo, transactionType, plantCOA, plantAccount, accumulatedDepreciationFinancialObject, depreciationTransactionSummary); } } getDepreciationBatchDao().updateAssetPayments(saveList, fiscalMonth); saveList.clear(); return depreciationTransactionSummary; } catch (Exception e) { LOG.error("Error occurred", e); throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(CamsKeyConstants.Depreciation.ERROR_WHEN_CALCULATING_DEPRECIATION) + " :" + e.getMessage()); } } /** * This method stores in a collection of business objects the depreciation transaction that later on will be passed to the * processGeneralLedgerPendingEntry method in order to store the records in gl pending entry table * * @param assetPayment asset payment * @param transactionType which can be [C]redit or [D]ebit * @param plantCOA plant fund char of account code * @param plantAccount plant fund char of account code * @param financialObject char of account object code linked to the payment * @param depreciationTransactionSummary * @return none */ protected void populateDepreciationTransaction(AssetPaymentInfo assetPayment, String transactionType, String plantCOA, String plantAccount, ObjectCode deprObjectCode, SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary) { LOG.debug("populateDepreciationTransaction(AssetDepreciationTransaction depreciationTransaction, AssetPayment assetPayment, String transactionType, KualiDecimal transactionAmount, String plantCOA, String plantAccount, String accumulatedDepreciationFinancialObjectCode, String depreciationExpenseFinancialObjectCode, ObjectCode financialObject, SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary) - started"); LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "populateDepreciationTransaction(): populating AssetDepreciationTransaction pojo - Asset#:" + assetPayment.getCapitalAssetNumber()); AssetDepreciationTransaction depreciationTransaction = new AssetDepreciationTransaction(); depreciationTransaction.setCapitalAssetNumber(assetPayment.getCapitalAssetNumber()); depreciationTransaction.setChartOfAccountsCode(plantCOA); depreciationTransaction.setAccountNumber(plantAccount); depreciationTransaction.setSubAccountNumber(assetPayment.getSubAccountNumber()); depreciationTransaction.setFinancialObjectCode(deprObjectCode.getFinancialObjectCode()); depreciationTransaction.setFinancialSubObjectCode(assetPayment.getFinancialSubObjectCode()); depreciationTransaction.setFinancialObjectTypeCode(deprObjectCode.getFinancialObjectTypeCode()); depreciationTransaction.setTransactionType(transactionType); depreciationTransaction.setProjectCode(assetPayment.getProjectCode()); depreciationTransaction.setTransactionAmount(assetPayment.getTransactionAmount()); depreciationTransaction.setTransactionLedgerEntryDescription(CamsConstants.Depreciation.TRANSACTION_DESCRIPTION + assetPayment.getCapitalAssetNumber()); String sKey = depreciationTransaction.getKey(); // Grouping the asset transactions by asset#, accounts, sub account, object, transaction type (C/D), etc. in order to // only have one credit and one credit by group. if (depreciationTransactionSummary.containsKey(sKey)) { depreciationTransaction = depreciationTransactionSummary.get(sKey); depreciationTransaction.setTransactionAmount(depreciationTransaction.getTransactionAmount().add(assetPayment.getTransactionAmount())); } else { depreciationTransactionSummary.put(sKey, depreciationTransaction); } LOG.debug("populateDepreciationTransaction(AssetDepreciationTransaction depreciationTransaction, AssetPayment assetPayment, String transactionType, KualiDecimal transactionAmount, String plantCOA, String plantAccount, String accumulatedDepreciationFinancialObjectCode, String depreciationExpenseFinancialObjectCode, ObjectCode financialObject, SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary) - ended"); } /** * This method stores the depreciation transactions in the general pending entry table and creates a new documentHeader entry. * <p> * * @param trans SortedMap with the transactions * @return none */ protected void processGeneralLedgerPendingEntry(Integer fiscalYear, Integer fiscalMonth, List<String> documentNos, SortedMap<String, AssetDepreciationTransaction> trans) { LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - start"); String financialSystemDocumentTypeCodeCode; try { String documentNumber = createNewDepreciationDocument(documentNos); financialSystemDocumentTypeCodeCode = CamsConstants.DocumentTypeName.ASSET_DEPRECIATION; LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Depreciation Document Type Code: " + financialSystemDocumentTypeCodeCode); Timestamp transactionTimestamp = new Timestamp(dateTimeService.getCurrentDate().getTime()); GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper(); List<GeneralLedgerPendingEntry> saveList = new ArrayList<GeneralLedgerPendingEntry>(); int counter = 0; for (AssetDepreciationTransaction t : trans.values()) { if (t.getTransactionAmount().isNonZero()) { counter++; LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Creating GLPE entries for asset:" + t.getCapitalAssetNumber()); GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry(); explicitEntry.setFinancialSystemOriginationCode(KFSConstants.ORIGIN_CODE_KUALI); explicitEntry.setDocumentNumber(documentNumber); explicitEntry.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter())); sequenceHelper.increment(); explicitEntry.setChartOfAccountsCode(t.getChartOfAccountsCode()); explicitEntry.setAccountNumber(t.getAccountNumber()); explicitEntry.setSubAccountNumber(null); explicitEntry.setFinancialObjectCode(t.getFinancialObjectCode()); explicitEntry.setFinancialSubObjectCode(null); explicitEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_ACTUAL); explicitEntry.setFinancialObjectTypeCode(t.getFinancialObjectTypeCode()); explicitEntry.setUniversityFiscalYear(fiscalYear); explicitEntry.setUniversityFiscalPeriodCode(StringUtils.leftPad(fiscalMonth.toString().trim(), 2, "0")); explicitEntry.setTransactionLedgerEntryDescription(t.getTransactionLedgerEntryDescription()); explicitEntry.setTransactionLedgerEntryAmount(t.getTransactionAmount().abs()); explicitEntry.setTransactionDebitCreditCode(t.getTransactionType()); explicitEntry.setTransactionDate(new java.sql.Date(transactionTimestamp.getTime())); explicitEntry.setFinancialDocumentTypeCode(financialSystemDocumentTypeCodeCode); explicitEntry.setFinancialDocumentApprovedCode(KFSConstants.DocumentStatusCodes.APPROVED); explicitEntry.setVersionNumber(new Long(1)); explicitEntry.setTransactionEntryProcessedTs(new java.sql.Timestamp(transactionTimestamp.getTime())); // this.generalLedgerPendingEntryService.save(explicitEntry); saveList.add(explicitEntry); if (counter % 1000 == 0) { // save here getDepreciationBatchDao().savePendingGLEntries(saveList); saveList.clear(); } if (sequenceHelper.getSequenceCounter() == 99999) { // create new document and sequence is reset documentNumber = createNewDepreciationDocument(documentNos); sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper(); } } } // save last list getDepreciationBatchDao().savePendingGLEntries(saveList); saveList.clear(); } catch (Exception e) { LOG.error("Error occurred", e); throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(CamsKeyConstants.Depreciation.ERROR_WHEN_UPDATING_GL_PENDING_ENTRY_TABLE) + " :" + e.getMessage()); } LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - end"); } protected String createNewDepreciationDocument(List<String> documentNos) throws WorkflowException { WorkflowDocument workflowDocument = getWorkflowDocumentService().createWorkflowDocument(CamsConstants.DocumentTypeName.ASSET_DEPRECIATION, GlobalVariables.getUserSession().getPerson()); // ************************************************************************************************** // Create a new document header object // ************************************************************************************************** LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Creating document header entry."); FinancialSystemDocumentHeader documentHeader = new FinancialSystemDocumentHeader(); documentHeader.setWorkflowDocument(workflowDocument); documentHeader.setDocumentNumber(workflowDocument.getDocumentId()); documentHeader.setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.APPROVED); documentHeader.setExplanation(CamsConstants.Depreciation.DOCUMENT_DESCRIPTION); documentHeader.setDocumentDescription(CamsConstants.Depreciation.DOCUMENT_DESCRIPTION); documentHeader.setFinancialDocumentTotalAmount(KualiDecimal.ZERO); LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Saving document header entry."); this.businessObjectService.save(documentHeader); LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Document Header entry was saved successfully."); // ************************************************************************************************** String documentNumber = documentHeader.getDocumentNumber(); documentNos.add(documentNumber); LOG.debug(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Document Number Created: " + documentNumber); return documentNumber; } /** * Depreciation object code is returned from cache or from DB * * @param capitalizationObjectCodes collection cache * @param assetPaymentInfo * @param capitalizationFinancialObjectCode * @return */ protected ObjectCode getDepreciationObjectCode(Integer fiscalYear, Map<String, ObjectCode> capObjectCodesCache, AssetPaymentInfo assetPaymentInfo, String capitalizationFinancialObjectCode) { ObjectCode deprObjCode = null; String key = assetPaymentInfo.getChartOfAccountsCode() + "-" + capitalizationFinancialObjectCode; if ((deprObjCode = capObjectCodesCache.get(key)) == null) { deprObjCode = SpringContext.getBean(ObjectCodeService.class).getByPrimaryId(fiscalYear, assetPaymentInfo.getChartOfAccountsCode(), capitalizationFinancialObjectCode); if (ObjectUtils.isNotNull(deprObjCode)) { capObjectCodesCache.put(key, deprObjCode); } } return deprObjCode; } /** * Builds map between object code to corresponding asset object code * * @return Map */ protected Map<String, AssetObjectCode> buildChartObjectToCapitalizationObjectMap(Collection<AssetObjectCode> assetObjectCodes) { Map<String, AssetObjectCode> assetObjectCodeMap = new HashMap<String, AssetObjectCode>(); for (AssetObjectCode assetObjectCode : assetObjectCodes) { List<ObjectCode> objectCodes = assetObjectCode.getObjectCode(); for (ObjectCode objectCode : objectCodes) { String key = objectCode.getChartOfAccountsCode() + "-" + objectCode.getFinancialObjectCode(); if (!assetObjectCodeMap.containsKey(key)) { assetObjectCodeMap.put(key, assetObjectCode); } } } return assetObjectCodeMap; } private void sendWarningMail(List<String> errorMessages) { LOG.debug("sendEmail() starting"); MailMessage message = new MailMessage(); message.setFromAddress(mailService.getBatchMailingList()); String subject = "Asset Depreciation Job status"; message.setSubject(subject); Collection<String> toAddresses = parameterService.getParameterValuesAsString(AssetDepreciationStep.class, CamsConstants.Parameters.RUN_DATE_NOTIFICATION_EMAIL_ADDRESSES); message.getToAddresses().add(toAddresses); StringBuffer sb = new StringBuffer(); sb.append("Unable to run Depreciation process.Reason:\n"); for (String msg : errorMessages) { sb.append(msg + "\n"); } sb.append("Please set the dates correctly to run the job."); message.setMessage(sb.toString()); try { mailService.sendMessage(message); } catch (MessagingException e) { LOG.error("sendErrorEmail() Invalid email address. Message not sent", e); } catch (InvalidAddressException e) { LOG.error("sendErrorEmail() Invalid email address. Message not sent", e); } } /** * Get the last month and day of the fiscal year. Returned in the format '-mm-dd' * @return */ protected String getLastDayOfFiscalyear() { ParameterService parameterService = SpringContext.getBean(ParameterService.class); String date = parameterService.getParameterValueAsString(KfsParameterConstants.CAPITAL_ASSETS_ALL.class, CamsConstants.Parameters.FISCAL_YEAR_END_MONTH_AND_DAY); return "-" + date.substring(0,2) + "-" + date.substring(2); } protected void populateYearEndDepreciationTransaction(AssetPaymentInfo assetPayment, String transactionType, String plantCOA, String plantAccount, ObjectCode deprObjectCode, SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary) { LOG.info("\npopulateYearEndDepreciationTransaction - Asset#:" + assetPayment.getCapitalAssetNumber() + " amount:"+ assetPayment.getTransactionAmount()+" type:"+ transactionType); LOG.info("deprObjectCode.getFinancialObjectCode():" + deprObjectCode.getFinancialObjectCode() + " deprObjectCode.getFinancialObjectTypeCode():"+ deprObjectCode.getFinancialObjectTypeCode()); AssetDepreciationTransaction depreciationTransaction = new AssetDepreciationTransaction(); depreciationTransaction.setCapitalAssetNumber(assetPayment.getCapitalAssetNumber()); depreciationTransaction.setChartOfAccountsCode(plantCOA); depreciationTransaction.setAccountNumber(plantAccount); depreciationTransaction.setSubAccountNumber(assetPayment.getSubAccountNumber()); depreciationTransaction.setFinancialObjectCode(deprObjectCode.getFinancialObjectCode()); depreciationTransaction.setFinancialSubObjectCode(assetPayment.getFinancialSubObjectCode()); depreciationTransaction.setFinancialObjectTypeCode(deprObjectCode.getFinancialObjectTypeCode()); depreciationTransaction.setTransactionType(transactionType); depreciationTransaction.setProjectCode(assetPayment.getProjectCode()); depreciationTransaction.setTransactionAmount(assetPayment.getTransactionAmount()); depreciationTransaction.setTransactionLedgerEntryDescription("Year End Depreciation Asset " + assetPayment.getCapitalAssetNumber()); String sKey = depreciationTransaction.getKey(); // Grouping the asset transactions by asset#, accounts, sub account, object, transaction type (C/D), etc. in order to // only have one credit and one credit by group. if (depreciationTransactionSummary.containsKey(sKey)) { LOG.info("depreciationTransactionSummary.containsKey(sKey) where sKey=" + sKey); depreciationTransaction = depreciationTransactionSummary.get(sKey); depreciationTransaction.setTransactionAmount(depreciationTransaction.getTransactionAmount().add(assetPayment.getTransactionAmount())); } else { LOG.info("depreciationTransactionSummary DOESNT containsKey(sKey) where sKey=" + sKey); depreciationTransactionSummary.put(sKey, depreciationTransaction); } LOG.info("\n\n"); // LOG.info("populateYearEndDepreciationTransaction(AssetDepreciationTransaction depreciationTransaction, AssetPayment assetPayment, String transactionType, KualiDecimal transactionAmount, String plantCOA, String plantAccount, String accumulatedDepreciationFinancialObjectCode, String depreciationExpenseFinancialObjectCode, ObjectCode financialObject, SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary) - ended"); } protected SortedMap<String, AssetDepreciationTransaction> calculateYearEndDepreciation(Collection<AssetPaymentInfo> depreciableAssetsCollection, Calendar depreciationDate, Integer fiscalYearToDepreciate, Integer fiscalYear, Integer fiscalMonth, Collection<AssetObjectCode> assetObjectCodes) { LOG.info("calculateDepreciation() - start"); SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary = new TreeMap<String, AssetDepreciationTransaction>(); double monthsElapsed = 0d; double assetLifeInMonths = 0d; KualiDecimal accumulatedDepreciationAmount = KualiDecimal.ZERO; Calendar assetDepreciationDate = Calendar.getInstance(); try { LOG.info("YEAR END DEPRECIATION - Getting the parameters for the plant fund object sub types."); // Getting system parameters needed. Collection<String> organizationPlantFundObjectSubType = parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_ORGANIZATON_PLANT_FUND_SUB_OBJECT_TYPES); Collection<String> campusPlantFundObjectSubType = parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_CAMPUS_PLANT_FUND_OBJECT_SUB_TYPES); // Initializing the asset payment table. depreciationBatchDao.resetPeriodValuesWhenFirstFiscalPeriod(fiscalMonth); LOG.info("getBaseAmountOfAssets(Collection<AssetPayment> depreciableAssetsCollection) - Started."); // Invoking method that will calculate the base amount for each asset payment transactions, which could be more than 1 // per asset. LOG.info("YEAR END DEPRECIATION - Calculating the base amount for each asset."); Map<Long, KualiDecimal> salvageValueAssetDeprAmounts = depreciationBatchDao.getPrimaryDepreciationBaseAmountForSV(); // Retrieving the object asset codes. Map<String, AssetObjectCode> assetObjectCodeMap = buildChartObjectToCapitalizationObjectMap(assetObjectCodes); Map<String, ObjectCode> capitalizationObjectCodes = new HashMap<String, ObjectCode>(); // Reading asset payments LOG.info("YEAR END DEPRECIATION - Reading collection with eligible asset payment details."); int counter = 0; List<AssetPaymentInfo> saveList = new ArrayList<AssetPaymentInfo>(); for (AssetPaymentInfo assetPaymentInfo : depreciableAssetsCollection) { boolean asset_is_retired = false; boolean asset_is_not_in_last_year_of_life = false; HashMap<String, Object> pKeys = new HashMap<String, Object>(); // Asset must be valid and capital active 'A','C','S','U' Long assetNumber = assetPaymentInfo.getCapitalAssetNumber(); pKeys.put(CamsPropertyConstants.Asset.CAPITAL_ASSET_NUMBER, assetNumber); Asset asset = businessObjectService.findByPrimaryKey(Asset.class, pKeys); if (asset != null) { asset_is_retired = assetService.isAssetRetired(asset); if ( LOG.isInfoEnabled() ) { LOG.info("asset#" + assetNumber + " asset_is_retired = " + asset_is_retired); } } AssetObjectCode assetObjectCode = assetObjectCodeMap.get(assetPaymentInfo.getChartOfAccountsCode() + "-" + assetPaymentInfo.getFinancialObjectCode()); if (assetObjectCode == null) { LOG.error("YEAR END DEPRECIATION - " + "Asset object code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetPaymentInfo.getFinancialObjectCode()); LOG.error("YEAR END DEPRECIATION - " + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber()); continue; } else { LOG.info("YEAR END DEPRECIATION - " + "fiscal year " + fiscalYear + " chartOfAccountsCode:" + assetPaymentInfo.getChartOfAccountsCode() + " FinancialObjectCode:" + assetPaymentInfo.getFinancialObjectCode()); // LOG.info("YEAR END DEPRECIATION - " + "CapitalAssetNumber:" + assetPaymentInfo.getCapitalAssetNumber() + " PaymentSequenceNumber:" + assetPaymentInfo.getPaymentSequenceNumber()); } ObjectCode accumulatedDepreciationFinancialObject = getDepreciationObjectCode(fiscalYear, capitalizationObjectCodes, assetPaymentInfo, assetObjectCode.getAccumulatedDepreciationFinancialObjectCode()); ObjectCode depreciationExpenseFinancialObject = getDepreciationObjectCode(fiscalYear, capitalizationObjectCodes, assetPaymentInfo, assetObjectCode.getDepreciationExpenseFinancialObjectCode()); String retire_code = parameterService.getParameterValueAsString(org.kuali.kfs.module.cam.businessobject.AssetRetirementGlobal.class, CamsConstants.Parameters.DEFAULT_GAIN_LOSS_DISPOSITION_OBJECT_CODE); if ( LOG.isInfoEnabled() ) { LOG.info("retire_code from system parameter "+ CamsConstants.Parameters.DEFAULT_GAIN_LOSS_DISPOSITION_OBJECT_CODE+" = " + retire_code); } ObjectCode depreciationYearEndExpenseFinancialObject = getDepreciationObjectCode(fiscalYear, capitalizationObjectCodes, assetPaymentInfo, retire_code); if (ObjectUtils.isNull(accumulatedDepreciationFinancialObject)) { LOG.error("YEAR END DEPRECIATION - " + "Accumulated Depreciation Financial Object Code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetObjectCode.getAccumulatedDepreciationFinancialObjectCode()); LOG.error("YEAR END DEPRECIATION - " + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber()); continue; } else { // LOG.info("YEAR END DEPRECIATION - " + " AccumulatedDepreciationFinancialObjectCode:" + assetObjectCode.getAccumulatedDepreciationFinancialObjectCode()); // LOG.info("YEAR END DEPRECIATION - " + "CapitalAssetNumber:" + assetPaymentInfo.getCapitalAssetNumber() + " PaymentSequenceNumber:" + assetPaymentInfo.getPaymentSequenceNumber()); if ( LOG.isInfoEnabled() ) { LOG.info("YEAR END DEPRECIATION - " + "accumulatedDepreciationFinancialObject:" + accumulatedDepreciationFinancialObject.getFinancialObjectCode()); } } if (ObjectUtils.isNull(depreciationExpenseFinancialObject)) { LOG.error("YEAR END DEPRECIATION - " + "Depreciation Expense Financial Object Code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetObjectCode.getDepreciationExpenseFinancialObjectCode()); LOG.error("YEAR END DEPRECIATION - " + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber()); continue; } else { if ( LOG.isInfoEnabled() ) { LOG.info("YEAR END DEPRECIATION - " + "depreciationExpenseFinancialObject:" + depreciationExpenseFinancialObject.getFinancialObjectCode()); } } assetDepreciationDate.setTime(assetPaymentInfo.getDepreciationDate()); accumulatedDepreciationAmount = KualiDecimal.ZERO; KualiDecimal deprAmountSum = salvageValueAssetDeprAmounts.get(assetNumber); // Calculating the life of the asset in months. assetLifeInMonths = assetPaymentInfo.getDepreciableLifeLimit() * 12; // Calculating the months elapsed for the asset using the depreciation date and the asset service date. monthsElapsed = (depreciationDate.get(Calendar.MONTH) - assetDepreciationDate.get(Calendar.MONTH) + (depreciationDate.get(Calendar.YEAR) - assetDepreciationDate.get(Calendar.YEAR)) * 12) + 1; if ((assetLifeInMonths - monthsElapsed)>12){ asset_is_not_in_last_year_of_life = true; } // ************************************************************************************************************** // CALCULATING ACCUMULATED DEPRECIATION BASED ON FORMULA FOR SINGLE LINE AND SALVAGE VALUE DEPRECIATION METHODS. // ************************************************************************************************************** KualiDecimal primaryDepreciationBaseAmount = assetPaymentInfo.getPrimaryDepreciationBaseAmount(); if (primaryDepreciationBaseAmount == null) { primaryDepreciationBaseAmount = KualiDecimal.ZERO; assetPaymentInfo.setPrimaryDepreciationBaseAmount(KualiDecimal.ZERO); } if (assetPaymentInfo.getAccumulatedPrimaryDepreciationAmount() == null) { assetPaymentInfo.setAccumulatedPrimaryDepreciationAmount(KualiDecimal.ZERO); } // If the months elapsed >= to the life of the asset (in months) then, the accumulated depreciation should be: if (monthsElapsed >= assetLifeInMonths) { if (CamsConstants.Asset.DEPRECIATION_METHOD_STRAIGHT_LINE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode())) { accumulatedDepreciationAmount = primaryDepreciationBaseAmount; } else if (CamsConstants.Asset.DEPRECIATION_METHOD_SALVAGE_VALUE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode()) && deprAmountSum != null && deprAmountSum.isNonZero()) { accumulatedDepreciationAmount = primaryDepreciationBaseAmount.subtract((primaryDepreciationBaseAmount.divide(deprAmountSum)).multiply(assetPaymentInfo.getSalvageAmount())); } } // If the month elapse < to the life of the asset (in months) then.... else { if (CamsConstants.Asset.DEPRECIATION_METHOD_STRAIGHT_LINE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode())) { accumulatedDepreciationAmount = new KualiDecimal((monthsElapsed / assetLifeInMonths) * primaryDepreciationBaseAmount.doubleValue()); } else if (CamsConstants.Asset.DEPRECIATION_METHOD_SALVAGE_VALUE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode()) && deprAmountSum != null && deprAmountSum.isNonZero()) { accumulatedDepreciationAmount = new KualiDecimal((monthsElapsed / assetLifeInMonths) * (primaryDepreciationBaseAmount.subtract((primaryDepreciationBaseAmount.divide(deprAmountSum)).multiply(assetPaymentInfo.getSalvageAmount()))).doubleValue()); } } // Calculating in process fiscal month depreciation amount KualiDecimal transactionAmount = accumulatedDepreciationAmount.subtract(assetPaymentInfo.getAccumulatedPrimaryDepreciationAmount()); Map<String, String> primaryKeys = new HashMap<String, String>(); primaryKeys.put(CamsPropertyConstants.AssetDepreciationConvention.FINANCIAL_OBJECT_SUB_TYPE_CODE, asset.getFinancialObjectSubTypeCode()); AssetDepreciationConvention depreciationConvention = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(AssetDepreciationConvention.class, primaryKeys); String conventionCode = depreciationConvention.getDepreciationConventionCode(); if (CamsConstants.DepreciationConvention.HALF_YEAR.equalsIgnoreCase(conventionCode)) { if (asset_is_retired && asset_is_not_in_last_year_of_life) { // and not in last year of life mjmc transactionAmount = transactionAmount.divide(new KualiDecimal(2)); if ( LOG.isInfoEnabled() ) { LOG.info("transactionAmount after being halved = " + transactionAmount); } } } String transactionType = KFSConstants.GL_DEBIT_CODE; if (transactionAmount.isNegative()) { transactionType = KFSConstants.GL_CREDIT_CODE; } String plantAccount = ""; String plantCOA = ""; // getting the right Plant Fund Chart code & Plant Fund Account if (organizationPlantFundObjectSubType.contains(assetPaymentInfo.getFinancialObjectSubTypeCode())) { plantAccount = assetPaymentInfo.getOrganizationPlantAccountNumber(); plantCOA = assetPaymentInfo.getOrganizationPlantChartCode(); } else if (campusPlantFundObjectSubType.contains(assetPaymentInfo.getFinancialObjectSubTypeCode())) { plantAccount = assetPaymentInfo.getCampusPlantAccountNumber(); plantCOA = assetPaymentInfo.getCampusPlantChartCode(); } if (StringUtils.isBlank(plantCOA) || StringUtils.isBlank(plantAccount)) { // skip the payment LOG.error("YEAR END DEPRECIATION - " + "Plant COA is " + plantCOA + " and plant account is " + plantAccount + " for Financial Object SubType Code = " + assetPaymentInfo.getFinancialObjectSubTypeCode() + " so Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber()); continue; } SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); if ( LOG.isInfoEnabled() ) { LOG.info("Asset#: " + assetNumber + " - Payment sequence#:" + assetPaymentInfo.getPaymentSequenceNumber() + " - Asset Depreciation date:" + sdf.format(assetDepreciationDate.getTime()) + " - Life:" + assetLifeInMonths + " - Depreciation base amt:" + primaryDepreciationBaseAmount); LOG.info("Accumulated depreciation:" + assetPaymentInfo.getAccumulatedPrimaryDepreciationAmount() + " - Month Elapsed:" + monthsElapsed + " - Calculated accum depreciation:" + accumulatedDepreciationAmount + " - Depreciation amount:" + transactionAmount.toString() + " - Depreciation Method:" + assetPaymentInfo.getPrimaryDepreciationMethodCode()); } if (asset_is_retired && asset_is_not_in_last_year_of_life) { assetPaymentInfo.setAccumulatedPrimaryDepreciationAmount(accumulatedDepreciationAmount.subtract(transactionAmount)); } else { assetPaymentInfo.setAccumulatedPrimaryDepreciationAmount(accumulatedDepreciationAmount); } assetPaymentInfo.setTransactionAmount(transactionAmount); counter++; saveList.add(assetPaymentInfo); // Saving depreciation amount in the asset payment table if (counter % 1000 == 0) { getDepreciationBatchDao().updateAssetPayments(saveList, fiscalMonth); saveList.clear(); } // if the asset has a depreciation amount <> 0 then, create its debit and credit entries. if (transactionAmount.isNonZero()) { this.populateYearEndDepreciationTransaction(assetPaymentInfo, transactionType, plantCOA, plantAccount, depreciationExpenseFinancialObject, depreciationTransactionSummary); transactionType = (transactionType.equals(KFSConstants.GL_DEBIT_CODE) ? KFSConstants.GL_CREDIT_CODE : KFSConstants.GL_DEBIT_CODE); this.populateYearEndDepreciationTransaction(assetPaymentInfo, transactionType, plantCOA, plantAccount, accumulatedDepreciationFinancialObject, depreciationTransactionSummary); if (asset_is_retired) { this.populateYearEndDepreciationTransaction(assetPaymentInfo, transactionType, plantCOA, plantAccount, depreciationYearEndExpenseFinancialObject, depreciationTransactionSummary); transactionType = (transactionType.equals(KFSConstants.GL_DEBIT_CODE) ? KFSConstants.GL_CREDIT_CODE : KFSConstants.GL_DEBIT_CODE); this.populateYearEndDepreciationTransaction(assetPaymentInfo, transactionType, plantCOA, plantAccount, accumulatedDepreciationFinancialObject, depreciationTransactionSummary); } } } getDepreciationBatchDao().updateAssetPayments(saveList, fiscalMonth); saveList.clear(); return depreciationTransactionSummary; } catch (Exception e) { LOG.error("Error occurred", e); throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(CamsKeyConstants.Depreciation.ERROR_WHEN_CALCULATING_DEPRECIATION) + " :" + e.getMessage(), e); } } protected void processYearEndGeneralLedgerPendingEntry(Integer fiscalYear, List<String> documentNos, SortedMap<String, AssetDepreciationTransaction> trans) { Integer fiscalMonth = new Integer(13); processGeneralLedgerPendingEntry(fiscalYear, fiscalMonth, documentNos, trans); } /** * Depreciation (end of year) Period 13 assets incorrect depreciation start date Update asset created in period 13 with in * service date and depreciate date if batch runs in the last fiscal period * * @param fiscalMonth2 * @param fiscalYear2 */ protected void updateAssetsDatesForLastFiscalPeriod(Integer fiscalMonth, Integer fiscalYear) { if (fiscalMonth == 12) { LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Starting updateAssetsCreatedInLastFiscalPeriod()"); // Getting last date of fiscal year Date lastDateOfFiscalYear = universityDateService.getLastDateOfFiscalYear(fiscalYear); if (lastDateOfFiscalYear == null) { throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_UNIV_DATE_NOT_FOUND)); } final java.sql.Date lastFiscalYearDate = new java.sql.Date(lastDateOfFiscalYear.getTime()); List<String> movableEquipmentObjectSubTypes = new ArrayList<String>(); if (parameterService.parameterExists(Asset.class, CamsConstants.Parameters.MOVABLE_EQUIPMENT_OBJECT_SUB_TYPES)) { movableEquipmentObjectSubTypes.addAll(parameterService.getParameterValuesAsString(Asset.class, CamsConstants.Parameters.MOVABLE_EQUIPMENT_OBJECT_SUB_TYPES)); } // Only update assets with a object sub type code equals to any MOVABLE_EQUIPMENT_OBJECT_SUB_TYPES. if (!movableEquipmentObjectSubTypes.isEmpty()) { updateAssetDatesPerConvention(lastFiscalYearDate, movableEquipmentObjectSubTypes, CamsConstants.DepreciationConvention.CREATE_DATE); updateAssetDatesPerConvention(lastFiscalYearDate, movableEquipmentObjectSubTypes, CamsConstants.DepreciationConvention.FULL_YEAR); updateAssetDatesPerConvention(lastFiscalYearDate, movableEquipmentObjectSubTypes, CamsConstants.DepreciationConvention.HALF_YEAR); } LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Finished updateAssetsCreatedInLastFiscalPeriod()"); } } /** * Depreciation (end of year) Period 13 assets incorrect depreciation start date * <P> * Update assets created in period 13 with its in-service date and depreciation date per depreciation convention. * * @param lastFiscalYearDate * @param movableEquipmentObjectSubTypes * @param depreciationConventionCd */ protected void updateAssetDatesPerConvention(final java.sql.Date lastFiscalYearDate, List<String> movableEquipmentObjectSubTypes, String depreciationConventionCd) { List<Map<String, Object>> selectedAssets = getDepreciationBatchDao().getAssetsByDepreciationConvention(lastFiscalYearDate, movableEquipmentObjectSubTypes, depreciationConventionCd); if (selectedAssets != null && !selectedAssets.isEmpty()) { List<String> assetNumbers = new ArrayList<String>(); for (Map<String, Object> assetMap : selectedAssets) { assetNumbers.add(((BigDecimal) assetMap.get("CPTLAST_NBR")).toString()); } // calculate asset deprecation date per depreciation convention java.sql.Date depreciationDate = getAssetDateService().computeDepreciationDateForPeriod13(depreciationConventionCd, lastFiscalYearDate); getDepreciationBatchDao().updateAssetInServiceAndDepreciationDate(assetNumbers, lastFiscalYearDate, depreciationDate); LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Finished updateAssetInServiceAndDepreciationDate() for Depreciation convention " + depreciationConventionCd + " for " + assetNumbers.size() + " assets : " + assetNumbers.toString()); } } public void setParameterService(ParameterService parameterService) { this.parameterService = parameterService; } public void setDepreciableAssetsDao(DepreciableAssetsDao depreciableAssetsDao) { this.depreciableAssetsDao = depreciableAssetsDao; } public void setCamsReportService(ReportService reportService) { this.reportService = reportService; } public void setConfigurationService(ConfigurationService kcs) { kualiConfigurationService = kcs; } public void setGeneralLedgerPendingEntryService(GeneralLedgerPendingEntryService generalLedgerPendingEntryService) { this.generalLedgerPendingEntryService = generalLedgerPendingEntryService; } public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } public void setBusinessObjectService(BusinessObjectService businessObjectService) { this.businessObjectService = businessObjectService; } public DataDictionaryService getDataDictionaryService() { return dataDictionaryService; } public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { this.dataDictionaryService = dataDictionaryService; } /** * Gets the depreciationBatchDao attribute. * * @return Returns the depreciationBatchDao. */ public DepreciationBatchDao getDepreciationBatchDao() { return depreciationBatchDao; } /** * Sets the depreciationBatchDao attribute value. * * @param depreciationBatchDao The depreciationBatchDao to set. */ @Override public void setDepreciationBatchDao(DepreciationBatchDao depreciationBatchDao) { this.depreciationBatchDao = depreciationBatchDao; } public void setCronExpression(String cronExpression) { this.cronExpression = cronExpression; } public void setMailService(MailService mailService) { this.mailService = mailService; } public WorkflowDocumentService getWorkflowDocumentService() { if (workflowDocumentService == null) { workflowDocumentService = KRADServiceLocatorWeb.getWorkflowDocumentService(); } return workflowDocumentService; } public void setOptionsService(OptionsService optionsService) { this.optionsService = optionsService; } public AssetDateService getAssetDateService() { return assetDateService; } public void setAssetDateService(AssetDateService assetDateService) { this.assetDateService = assetDateService; } public void setUniversityDateService(UniversityDateService universityDateService) { this.universityDateService = universityDateService; } public SchedulerService getSchedulerService() { return schedulerService; } public void setSchedulerService(SchedulerService schedulerService) { this.schedulerService = schedulerService; } }