001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.kfs.module.cam.batch.service.impl;
017
018 import static org.kuali.kfs.sys.KFSConstants.BALANCE_TYPE_ACTUAL;
019
020 import java.sql.Timestamp;
021 import java.text.DateFormat;
022 import java.text.ParseException;
023 import java.text.SimpleDateFormat;
024 import java.util.ArrayList;
025 import java.util.Calendar;
026 import java.util.Collection;
027 import java.util.HashMap;
028 import java.util.List;
029 import java.util.Map;
030 import java.util.SortedMap;
031 import java.util.TreeMap;
032
033 import org.apache.commons.lang.StringUtils;
034 import org.kuali.kfs.coa.businessobject.ObjectCode;
035 import org.kuali.kfs.coa.service.ObjectCodeService;
036 import org.kuali.kfs.module.cam.CamsConstants;
037 import org.kuali.kfs.module.cam.CamsKeyConstants;
038 import org.kuali.kfs.module.cam.batch.AssetPaymentInfo;
039 import org.kuali.kfs.module.cam.batch.service.AssetDepreciationService;
040 import org.kuali.kfs.module.cam.batch.service.ReportService;
041 import org.kuali.kfs.module.cam.businessobject.AssetDepreciationTransaction;
042 import org.kuali.kfs.module.cam.businessobject.AssetObjectCode;
043 import org.kuali.kfs.module.cam.document.AssetDepreciationDocument;
044 import org.kuali.kfs.module.cam.document.dataaccess.DepreciableAssetsDao;
045 import org.kuali.kfs.module.cam.document.dataaccess.DepreciationBatchDao;
046 import org.kuali.kfs.sys.KFSConstants;
047 import org.kuali.kfs.sys.KFSKeyConstants;
048 import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader;
049 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
050 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
051 import org.kuali.kfs.sys.businessobject.UniversityDate;
052 import org.kuali.kfs.sys.context.SpringContext;
053 import org.kuali.kfs.sys.dataaccess.UniversityDateDao;
054 import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
055 import org.kuali.kfs.sys.service.impl.KfsParameterConstants;
056 import org.kuali.rice.kew.exception.WorkflowException;
057 import org.kuali.rice.kns.service.BusinessObjectService;
058 import org.kuali.rice.kns.service.DataDictionaryService;
059 import org.kuali.rice.kns.service.DateTimeService;
060 import org.kuali.rice.kns.service.KualiConfigurationService;
061 import org.kuali.rice.kns.service.ParameterService;
062 import org.kuali.rice.kns.util.GlobalVariables;
063 import org.kuali.rice.kns.util.KualiDecimal;
064 import org.kuali.rice.kns.util.ObjectUtils;
065 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
066 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
067 import org.springframework.transaction.annotation.Transactional;
068
069 /**
070 * This class is a service that calculates the depreciation amount for each asset that has a eligible asset payment.
071 * <p>
072 * When an error occurs running this process, a pdf file will be created with the error message. However, this doesn't mean that
073 * this process automatically leaves all the records as they were right before running the program. If the process fails, is
074 * suggested to do the following before trying to run the process again: a.)Delete gl pending entry depreciation entries: DELETE
075 * FROM GL_PENDING_ENTRY_T WHERE FDOC_TYP_CD = 'DEPR' b.)Substract from the accumulated depreciation amount the depreciation
076 * calculated for the fiscal month that was ran, and then reset the depreciation amount field for the fiscal month that was ran. ex:
077 * Assuming that the fiscal month = 8 then: UPDATE CM_AST_PAYMENT_T SET AST_ACUM_DEPR1_AMT = AST_ACUM_DEPR1_AMT -
078 * AST_PRD8_DEPR1_AMT, AST_PRD8_DEPR1_AMT=0
079 */
080 @Transactional
081 public class AssetDepreciationServiceImpl implements AssetDepreciationService {
082 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetDepreciationServiceImpl.class);
083 private ParameterService parameterService;
084 private ReportService reportService;
085 private DateTimeService dateTimeService;
086 private DepreciableAssetsDao depreciableAssetsDao;
087 private KualiConfigurationService kualiConfigurationService;
088 private GeneralLedgerPendingEntryService generalLedgerPendingEntryService;
089 private BusinessObjectService businessObjectService;
090 private UniversityDateDao universityDateDao;
091 private WorkflowDocumentService workflowDocumentService;
092 private DataDictionaryService dataDictionaryService;
093 private Integer fiscalYear;
094 private Integer fiscalMonth;
095 private String errorMsg = "";
096 private List<String> documentNos = new ArrayList<String>();
097 private DepreciationBatchDao depreciationBatchDao;
098
099 /**
100 * @see org.kuali.kfs.module.cam.batch.service.AssetDepreciationService#runDepreciation()
101 */
102 public void runDepreciation() {
103 List<String[]> reportLog = new ArrayList<String[]>();
104 boolean hasErrors = false;
105 Calendar depreciationDate = Calendar.getInstance();
106 Calendar currentDate = Calendar.getInstance();
107 String depreciationDateParameter = null;
108 DateFormat dateFormat = new SimpleDateFormat(CamsConstants.DateFormats.YEAR_MONTH_DAY);
109
110 try {
111 LOG.info("*******" + CamsConstants.Depreciation.DEPRECIATION_BATCH + " HAS BEGUN *******");
112
113 /*
114 * Getting the system parameter "DEPRECIATION_DATE" When this parameter is used to determine which fiscal month and year
115 * is going to be depreciated If blank then the system will take the system date to determine the fiscal period
116 */
117 if (parameterService.parameterExists(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_RUN_DATE_PARAMETER)) {
118 depreciationDateParameter = ((List<String>) parameterService.getParameterValues(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_RUN_DATE_PARAMETER)).get(0).trim();
119 }
120 else {
121 throw new IllegalStateException(kualiConfigurationService.getPropertyString(CamsKeyConstants.Depreciation.DEPRECIATION_DATE_PARAMETER_NOT_FOUND));
122 }
123 // This validates the system parameter depreciation_date has a valid format of YYYY-MM-DD.
124 if (depreciationDateParameter != null && !depreciationDateParameter.trim().equals("")) {
125 try {
126 depreciationDate.setTime(dateFormat.parse(depreciationDateParameter));
127 }
128 catch (ParseException e) {
129 throw new IllegalArgumentException(kualiConfigurationService.getPropertyString(CamsKeyConstants.Depreciation.INVALID_DEPRECIATION_DATE_FORMAT));
130 }
131 }
132 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Depreciation run date: " + depreciationDateParameter);
133
134 UniversityDate universityDate = (UniversityDate) businessObjectService.findBySinglePrimaryKey(UniversityDate.class, new java.sql.Date(depreciationDate.getTimeInMillis()));
135 if (universityDate == null) {
136 throw new IllegalStateException(kualiConfigurationService.getPropertyString(KFSKeyConstants.ERROR_UNIV_DATE_NOT_FOUND));
137 }
138
139 this.fiscalYear = universityDate.getUniversityFiscalYear();
140 this.fiscalMonth = new Integer(universityDate.getUniversityFiscalAccountingPeriod());
141 // If the depreciation date is not = to the system date then, the depreciation process cannot run.
142 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Fiscal Year = " + this.fiscalYear + " & Fiscal Period=" + this.fiscalMonth);
143 reportLog.addAll(depreciableAssetsDao.generateStatistics(true, null, fiscalYear, fiscalMonth, depreciationDate));
144 // update if fiscal period is 12
145 depreciationBatchDao.updateAssetsCreatedInLastFiscalPeriod(fiscalMonth, fiscalYear);
146 // Retrieving eligible asset payment details
147 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Getting list of asset payments eligible for depreciation.");
148 Collection<AssetPaymentInfo> depreciableAssetsCollection = depreciationBatchDao.getListOfDepreciableAssetPaymentInfo(this.fiscalYear, this.fiscalMonth, depreciationDate);
149 // if we have assets eligible for depreciation then, calculate depreciation and create glpe's transactions
150 if (depreciableAssetsCollection != null && !depreciableAssetsCollection.isEmpty()) {
151 SortedMap<String, AssetDepreciationTransaction> depreciationTransactions = this.calculateDepreciation(depreciableAssetsCollection, depreciationDate);
152 processGeneralLedgerPendingEntry(depreciationTransactions);
153 }
154 else {
155 throw new IllegalStateException(kualiConfigurationService.getPropertyString(CamsKeyConstants.Depreciation.NO_ELIGIBLE_FOR_DEPRECIATION_ASSETS_FOUND));
156 }
157 }
158 catch (Exception e) {
159 LOG.info("Error occurred");
160 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "**************************************************************************");
161 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "AN ERROR HAS OCCURRED! - ERROR: " + e.getMessage());
162 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "**************************************************************************");
163 hasErrors = true;
164 this.errorMsg = "Depreciation process ran unsucessfuly.\nReason:" + e.getMessage();
165 }
166 finally {
167 if (!hasErrors) {
168 reportLog.addAll(depreciableAssetsDao.generateStatistics(false, this.documentNos, fiscalYear, fiscalMonth, depreciationDate));
169 }
170 // the report will be generated only when there is an error or when the log has something.
171 if (!reportLog.isEmpty() || !errorMsg.trim().equals(""))
172 reportService.generateDepreciationReport(reportLog, errorMsg, depreciationDateParameter);
173
174 LOG.info("*******" + CamsConstants.Depreciation.DEPRECIATION_BATCH + " HAS ENDED *******");
175 }
176 }
177
178 /**
179 * This method calculates the depreciation of each asset payment, creates the depreciation transactions that will be stored in
180 * the general ledger pending entry table
181 *
182 * @param depreciableAssetsCollection asset payments eligible for depreciation
183 * @return SortedMap with a list of depreciation transactions
184 */
185 protected SortedMap<String, AssetDepreciationTransaction> calculateDepreciation(Collection<AssetPaymentInfo> depreciableAssetsCollection, Calendar depreciationDate) {
186 LOG.debug("calculateDepreciation() - start");
187
188 List<String> organizationPlantFundObjectSubType = new ArrayList<String>();
189 List<String> campusPlantFundObjectSubType = new ArrayList<String>();
190 SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary = new TreeMap<String, AssetDepreciationTransaction>();
191 double monthsElapsed = 0d;
192 double assetLifeInMonths = 0d;
193 KualiDecimal accumulatedDepreciationAmount = KualiDecimal.ZERO;
194 Calendar assetDepreciationDate = Calendar.getInstance();
195
196 try {
197 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Getting the parameters for the plant fund object sub types.");
198 // Getting system parameters needed.
199 if (parameterService.parameterExists(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_ORGANIZATON_PLANT_FUND_SUB_OBJECT_TYPES)) {
200 organizationPlantFundObjectSubType = parameterService.getParameterValues(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_ORGANIZATON_PLANT_FUND_SUB_OBJECT_TYPES);
201 }
202 if (parameterService.parameterExists(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_CAMPUS_PLANT_FUND_OBJECT_SUB_TYPES)) {
203 campusPlantFundObjectSubType = parameterService.getParameterValues(KfsParameterConstants.CAPITAL_ASSETS_BATCH.class, CamsConstants.Parameters.DEPRECIATION_CAMPUS_PLANT_FUND_OBJECT_SUB_TYPES);
204 }
205 // Initializing the asset payment table.
206 depreciationBatchDao.resetPeriodValuesWhenFirstFiscalPeriod(fiscalMonth);
207 LOG.debug("getBaseAmountOfAssets(Collection<AssetPayment> depreciableAssetsCollection) - Started.");
208 // Invoking method that will calculate the base amount for each asset payment transactions, which could be more than 1
209 // per asset.
210 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Calculating the base amount for each asset.");
211 Map<Long, KualiDecimal> salvageValueAssetDeprAmounts = depreciationBatchDao.getPrimaryDepreciationBaseAmountForSV();
212 // Retrieving the object asset codes.
213 Map<String, AssetObjectCode> assetObjectCodeMap = buildChartObjectToCapitalizationObjectMap();
214 Map<String, ObjectCode> capitalizationObjectCodes = new HashMap<String, ObjectCode>();
215
216 // Reading asset payments
217 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Reading collection with eligible asset payment details.");
218 int counter = 0;
219 List<AssetPaymentInfo> saveList = new ArrayList<AssetPaymentInfo>();
220 for (AssetPaymentInfo assetPaymentInfo : depreciableAssetsCollection) {
221 AssetObjectCode assetObjectCode = assetObjectCodeMap.get(assetPaymentInfo.getChartOfAccountsCode() + "-" + assetPaymentInfo.getFinancialObjectCode());
222 if (assetObjectCode == null) {
223 LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Asset object code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetPaymentInfo.getFinancialObjectCode());
224 LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber());
225 continue;
226 }
227 ObjectCode accumulatedDepreciationFinancialObject = getDepreciationObjectCode(capitalizationObjectCodes, assetPaymentInfo, assetObjectCode.getAccumulatedDepreciationFinancialObjectCode());
228 ObjectCode depreciationExpenseFinancialObject = getDepreciationObjectCode(capitalizationObjectCodes, assetPaymentInfo, assetObjectCode.getDepreciationExpenseFinancialObjectCode());
229
230 if (ObjectUtils.isNull(accumulatedDepreciationFinancialObject)) {
231 LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Accumulated Depreciation Financial Object Code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetObjectCode.getAccumulatedDepreciationFinancialObjectCode());
232 LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber());
233 continue;
234 }
235
236 if (ObjectUtils.isNull(depreciationExpenseFinancialObject)) {
237 LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Depreciation Expense Financial Object Code not found for " + fiscalYear + "-" + assetPaymentInfo.getChartOfAccountsCode() + "-" + assetObjectCode.getDepreciationExpenseFinancialObjectCode());
238 LOG.error(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Asset payment is not included in depreciation " + assetPaymentInfo.getCapitalAssetNumber() + " - " + assetPaymentInfo.getPaymentSequenceNumber());
239 continue;
240 }
241 Long assetNumber = assetPaymentInfo.getCapitalAssetNumber();
242 assetDepreciationDate.setTime(assetPaymentInfo.getDepreciationDate());
243 accumulatedDepreciationAmount = KualiDecimal.ZERO;
244 KualiDecimal deprAmountSum = salvageValueAssetDeprAmounts.get(assetNumber);
245 // Calculating the life of the asset in months.
246 assetLifeInMonths = assetPaymentInfo.getDepreciableLifeLimit() * 12;
247 // Calculating the months elapsed for the asset using the depreciation date and the asset service date.
248 monthsElapsed = (depreciationDate.get(Calendar.MONTH) - assetDepreciationDate.get(Calendar.MONTH) + (depreciationDate.get(Calendar.YEAR) - assetDepreciationDate.get(Calendar.YEAR)) * 12) + 1;
249
250 // **************************************************************************************************************
251 // CALCULATING ACCUMULATED DEPRECIATION BASED ON FORMULA FOR SINGLE LINE AND SALVAGE VALUE DEPRECIATION METHODS.
252 // **************************************************************************************************************
253 KualiDecimal primaryDepreciationBaseAmount = assetPaymentInfo.getPrimaryDepreciationBaseAmount();
254 if (primaryDepreciationBaseAmount == null)
255 assetPaymentInfo.setPrimaryDepreciationBaseAmount(KualiDecimal.ZERO);
256
257 if (assetPaymentInfo.getAccumulatedPrimaryDepreciationAmount() == null)
258 assetPaymentInfo.setAccumulatedPrimaryDepreciationAmount(KualiDecimal.ZERO);
259
260 // If the months elapsed >= to the life of the asset (in months) then, the accumulated depreciation should be:
261 if (monthsElapsed >= assetLifeInMonths) {
262 if (CamsConstants.Asset.DEPRECIATION_METHOD_STRAIGHT_LINE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode())) {
263 accumulatedDepreciationAmount = primaryDepreciationBaseAmount;
264 }
265 else if (CamsConstants.Asset.DEPRECIATION_METHOD_SALVAGE_VALUE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode()) && deprAmountSum != null && deprAmountSum.isNonZero()) {
266 accumulatedDepreciationAmount = primaryDepreciationBaseAmount.subtract((primaryDepreciationBaseAmount.divide(deprAmountSum)).multiply(assetPaymentInfo.getSalvageAmount()));
267 }
268 } // If the month elapse < to the life of the asset (in months) then....
269 else {
270 if (CamsConstants.Asset.DEPRECIATION_METHOD_STRAIGHT_LINE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode())) {
271 accumulatedDepreciationAmount = new KualiDecimal((monthsElapsed / assetLifeInMonths) * primaryDepreciationBaseAmount.doubleValue());
272 }
273 else if (CamsConstants.Asset.DEPRECIATION_METHOD_SALVAGE_VALUE_CODE.equals(assetPaymentInfo.getPrimaryDepreciationMethodCode()) && deprAmountSum != null && deprAmountSum.isNonZero()) {
274 accumulatedDepreciationAmount = new KualiDecimal((monthsElapsed / assetLifeInMonths) * (primaryDepreciationBaseAmount.subtract((primaryDepreciationBaseAmount.divide(deprAmountSum)).multiply(assetPaymentInfo.getSalvageAmount()))).doubleValue());
275 }
276 }
277 // Calculating in process fiscal month depreciation amount
278 KualiDecimal transactionAmount = accumulatedDepreciationAmount.subtract(assetPaymentInfo.getAccumulatedPrimaryDepreciationAmount());
279
280 String transactionType = KFSConstants.GL_DEBIT_CODE;
281 if (transactionAmount.isNegative()) {
282 transactionType = KFSConstants.GL_CREDIT_CODE;
283 }
284 String plantAccount = "";
285 String plantCOA = "";
286
287 // getting the right Plant Fund Chart code & Plant Fund Account
288 if (organizationPlantFundObjectSubType.contains(assetPaymentInfo.getFinancialObjectSubTypeCode())) {
289 plantAccount = assetPaymentInfo.getOrganizationPlantAccountNumber();
290 plantCOA = assetPaymentInfo.getOrganizationPlantChartCode();
291 }
292 else if (campusPlantFundObjectSubType.contains(assetPaymentInfo.getFinancialObjectSubTypeCode())) {
293 plantAccount = assetPaymentInfo.getCampusPlantAccountNumber();
294 plantCOA = assetPaymentInfo.getCampusPlantChartCode();
295 }
296 if (StringUtils.isBlank(plantCOA) || StringUtils.isBlank(plantAccount)) {
297 // skip the payment
298 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());
299 continue;
300 }
301 LOG.info("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());
302 assetPaymentInfo.setAccumulatedPrimaryDepreciationAmount(accumulatedDepreciationAmount);
303 assetPaymentInfo.setTransactionAmount(transactionAmount);
304 counter++;
305 saveList.add(assetPaymentInfo);
306 // Saving depreciation amount in the asset payment table
307 if (counter % 1000 == 0) {
308 getDepreciationBatchDao().updateAssetPayments(saveList, fiscalMonth);
309 saveList.clear();
310 }
311 // if the asset has a depreciation amount <> 0 then, create its debit and credit entries.
312 if (transactionAmount.isNonZero()) {
313 this.populateDepreciationTransaction(assetPaymentInfo, transactionType, plantCOA, plantAccount, depreciationExpenseFinancialObject, depreciationTransactionSummary);
314 transactionType = (transactionType.equals(KFSConstants.GL_DEBIT_CODE) ? KFSConstants.GL_CREDIT_CODE : KFSConstants.GL_DEBIT_CODE);
315 this.populateDepreciationTransaction(assetPaymentInfo, transactionType, plantCOA, plantAccount, accumulatedDepreciationFinancialObject, depreciationTransactionSummary);
316 }
317 }
318 getDepreciationBatchDao().updateAssetPayments(saveList, fiscalMonth);
319 saveList.clear();
320 return depreciationTransactionSummary;
321 }
322 catch (Exception e) {
323 LOG.error("Error occurred", e);
324 throw new IllegalStateException(kualiConfigurationService.getPropertyString(CamsKeyConstants.Depreciation.ERROR_WHEN_CALCULATING_DEPRECIATION) + " :" + e.getMessage());
325 }
326 }
327
328
329 /**
330 * This method stores in a collection of business objects the depreciation transaction that later on will be passed to the
331 * processGeneralLedgerPendingEntry method in order to store the records in gl pending entry table
332 *
333 * @param assetPayment asset payment
334 * @param transactionType which can be [C]redit or [D]ebit
335 * @param plantCOA plant fund char of account code
336 * @param plantAccount plant fund char of account code
337 * @param financialObject char of account object code linked to the payment
338 * @param depreciationTransactionSummary
339 * @return none
340 */
341 protected void populateDepreciationTransaction(AssetPaymentInfo assetPayment, String transactionType, String plantCOA, String plantAccount, ObjectCode deprObjectCode, SortedMap<String, AssetDepreciationTransaction> depreciationTransactionSummary) {
342 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");
343 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "populateDepreciationTransaction(): populating AssetDepreciationTransaction pojo - Asset#:" + assetPayment.getCapitalAssetNumber());
344 AssetDepreciationTransaction depreciationTransaction = new AssetDepreciationTransaction();
345 depreciationTransaction.setCapitalAssetNumber(assetPayment.getCapitalAssetNumber());
346 depreciationTransaction.setChartOfAccountsCode(plantCOA);
347 depreciationTransaction.setAccountNumber(plantAccount);
348 depreciationTransaction.setSubAccountNumber(assetPayment.getSubAccountNumber());
349 depreciationTransaction.setFinancialObjectCode(deprObjectCode.getFinancialObjectCode());
350 depreciationTransaction.setFinancialSubObjectCode(assetPayment.getFinancialSubObjectCode());
351 depreciationTransaction.setFinancialObjectTypeCode(deprObjectCode.getFinancialObjectTypeCode());
352 depreciationTransaction.setTransactionType(transactionType);
353 depreciationTransaction.setProjectCode(assetPayment.getProjectCode());
354 depreciationTransaction.setTransactionAmount(assetPayment.getTransactionAmount());
355 depreciationTransaction.setTransactionLedgerEntryDescription(CamsConstants.Depreciation.TRANSACTION_DESCRIPTION + assetPayment.getCapitalAssetNumber());
356
357 String sKey = depreciationTransaction.getKey();
358
359 // Grouping the asset transactions by asset#, accounts, sub account, object, transaction type (C/D), etc. in order to
360 // only have one credit and one credit by group.
361 if (depreciationTransactionSummary.containsKey(sKey)) {
362 depreciationTransaction = depreciationTransactionSummary.get(sKey);
363 depreciationTransaction.setTransactionAmount(depreciationTransaction.getTransactionAmount().add(assetPayment.getTransactionAmount()));
364 }
365 else {
366 depreciationTransactionSummary.put(sKey, depreciationTransaction);
367 }
368 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");
369 }
370
371 /**
372 * This method stores the depreciation transactions in the general pending entry table and creates a new documentHeader entry.
373 * <p>
374 *
375 * @param trans SortedMap with the transactions
376 * @return none
377 */
378 protected void processGeneralLedgerPendingEntry(SortedMap<String, AssetDepreciationTransaction> trans) {
379 LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - start");
380
381 String financialSystemDocumentTypeCodeCode;
382 try {
383
384 String documentNumber = createNewDepreciationDocument();
385 financialSystemDocumentTypeCodeCode = CamsConstants.DocumentTypeName.ASSET_DEPRECIATION;
386 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Depreciation Document Type Code: " + financialSystemDocumentTypeCodeCode);
387
388 Timestamp transactionTimestamp = new Timestamp(dateTimeService.getCurrentDate().getTime());
389
390 GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper();
391 List<GeneralLedgerPendingEntry> saveList = new ArrayList<GeneralLedgerPendingEntry>();
392 int counter = 0;
393
394 for (AssetDepreciationTransaction t : trans.values()) {
395 if (t.getTransactionAmount().isNonZero()) {
396 counter++;
397 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Creating GLPE entries for asset:" + t.getCapitalAssetNumber());
398 GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
399 explicitEntry.setFinancialSystemOriginationCode(KFSConstants.ORIGIN_CODE_KUALI);
400 explicitEntry.setDocumentNumber(documentNumber);
401 explicitEntry.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter()));
402 sequenceHelper.increment();
403 explicitEntry.setChartOfAccountsCode(t.getChartOfAccountsCode());
404 explicitEntry.setAccountNumber(t.getAccountNumber());
405 explicitEntry.setSubAccountNumber(t.getSubAccountNumber());
406 explicitEntry.setFinancialObjectCode(t.getFinancialObjectCode());
407 explicitEntry.setFinancialSubObjectCode(t.getFinancialSubObjectCode());
408 explicitEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_ACTUAL);
409 explicitEntry.setFinancialObjectTypeCode(t.getFinancialObjectTypeCode());
410 explicitEntry.setUniversityFiscalYear(this.fiscalYear);
411 explicitEntry.setUniversityFiscalPeriodCode(StringUtils.leftPad(this.fiscalMonth.toString().trim(), 2, "0"));
412 explicitEntry.setTransactionLedgerEntryDescription(t.getTransactionLedgerEntryDescription());
413 explicitEntry.setTransactionLedgerEntryAmount(t.getTransactionAmount().abs());
414 explicitEntry.setTransactionDebitCreditCode(t.getTransactionType());
415 explicitEntry.setTransactionDate(new java.sql.Date(transactionTimestamp.getTime()));
416 explicitEntry.setFinancialDocumentTypeCode(financialSystemDocumentTypeCodeCode);
417 explicitEntry.setFinancialDocumentApprovedCode(KFSConstants.DocumentStatusCodes.APPROVED);
418 explicitEntry.setVersionNumber(new Long(1));
419 explicitEntry.setTransactionEntryProcessedTs(new java.sql.Timestamp(transactionTimestamp.getTime()));
420 // this.generalLedgerPendingEntryService.save(explicitEntry);
421 saveList.add(explicitEntry);
422 if (counter % 1000 == 0) {
423 // save here
424 getDepreciationBatchDao().savePendingGLEntries(saveList);
425 saveList.clear();
426 }
427 if (sequenceHelper.getSequenceCounter() == 99999) {
428 // create new document and sequence is reset
429 documentNumber = createNewDepreciationDocument();
430 sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper();
431 }
432 }
433 }
434 // save last list
435 getDepreciationBatchDao().savePendingGLEntries(saveList);
436 saveList.clear();
437
438 }
439 catch (Exception e) {
440 LOG.error("Error occurred", e);
441 throw new IllegalStateException(kualiConfigurationService.getPropertyString(CamsKeyConstants.Depreciation.ERROR_WHEN_UPDATING_GL_PENDING_ENTRY_TABLE) + " :" + e.getMessage());
442 }
443 LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - end");
444 }
445
446
447 protected String createNewDepreciationDocument() throws WorkflowException {
448 KualiWorkflowDocument workflowDocument = workflowDocumentService.createWorkflowDocument(CamsConstants.DocumentTypeName.ASSET_DEPRECIATION, GlobalVariables.getUserSession().getPerson());
449 // **************************************************************************************************
450 // Create a new document header object
451 // **************************************************************************************************
452 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Creating document header entry.");
453
454 FinancialSystemDocumentHeader documentHeader = new FinancialSystemDocumentHeader();
455 documentHeader.setWorkflowDocument(workflowDocument);
456 documentHeader.setDocumentNumber(workflowDocument.getRouteHeaderId().toString());
457 documentHeader.setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.APPROVED);
458 documentHeader.setExplanation(CamsConstants.Depreciation.DOCUMENT_DESCRIPTION);
459 documentHeader.setDocumentDescription(CamsConstants.Depreciation.DOCUMENT_DESCRIPTION);
460 documentHeader.setFinancialDocumentTotalAmount(KualiDecimal.ZERO);
461
462 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Saving document header entry.");
463 this.businessObjectService.save(documentHeader);
464 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Document Header entry was saved successfully.");
465 // **************************************************************************************************
466
467 String documentNumber = documentHeader.getDocumentNumber();
468 this.documentNos.add(documentNumber);
469 LOG.info(CamsConstants.Depreciation.DEPRECIATION_BATCH + "Document Number Created: " + documentNumber);
470 return documentNumber;
471 }
472
473
474 /**
475 * Depreciation object code is returned from cache or from DB
476 *
477 * @param capitalizationObjectCodes collection cache
478 * @param assetPaymentInfo
479 * @param capitalizationFinancialObjectCode
480 * @return
481 */
482 protected ObjectCode getDepreciationObjectCode(Map<String, ObjectCode> capObjectCodesCache, AssetPaymentInfo assetPaymentInfo, String capitalizationFinancialObjectCode) {
483 ObjectCode deprObjCode = null;
484 String key = assetPaymentInfo.getChartOfAccountsCode() + "-" + capitalizationFinancialObjectCode;
485 if ((deprObjCode = capObjectCodesCache.get(key)) == null) {
486 deprObjCode = SpringContext.getBean(ObjectCodeService.class).getByPrimaryId(fiscalYear, assetPaymentInfo.getChartOfAccountsCode(), capitalizationFinancialObjectCode);
487 if (ObjectUtils.isNotNull(deprObjCode)) {
488 capObjectCodesCache.put(key, deprObjCode);
489 }
490 }
491 return deprObjCode;
492 }
493
494 /**
495 * Builds map between object code to corresponding asset object code
496 *
497 * @return Map
498 */
499 protected Map<String, AssetObjectCode> buildChartObjectToCapitalizationObjectMap() {
500 Map<String, AssetObjectCode> assetObjectCodeMap = new HashMap<String, AssetObjectCode>();
501 Collection<AssetObjectCode> assetObjectCodes = depreciableAssetsDao.getAssetObjectCodes(fiscalYear);
502
503 for (AssetObjectCode assetObjectCode : assetObjectCodes) {
504 List<ObjectCode> objectCodes = assetObjectCode.getObjectCode();
505 for (ObjectCode objectCode : objectCodes) {
506 String key = objectCode.getChartOfAccountsCode() + "-" + objectCode.getFinancialObjectCode();
507 if (!assetObjectCodeMap.containsKey(key)) {
508 assetObjectCodeMap.put(key, assetObjectCode);
509 }
510 }
511 }
512 return assetObjectCodeMap;
513 }
514
515 public void setParameterService(ParameterService parameterService) {
516 this.parameterService = parameterService;
517 }
518
519 public void setDepreciableAssetsDao(DepreciableAssetsDao depreciableAssetsDao) {
520 this.depreciableAssetsDao = depreciableAssetsDao;
521 }
522
523 public void setCamsReportService(ReportService reportService) {
524 this.reportService = reportService;
525 }
526
527 public void setKualiConfigurationService(KualiConfigurationService kcs) {
528 kualiConfigurationService = kcs;
529 }
530
531 public void setGeneralLedgerPendingEntryService(GeneralLedgerPendingEntryService generalLedgerPendingEntryService) {
532 this.generalLedgerPendingEntryService = generalLedgerPendingEntryService;
533 }
534
535 public void setDateTimeService(DateTimeService dateTimeService) {
536 this.dateTimeService = dateTimeService;
537 }
538
539 public void setUniversityDateDao(UniversityDateDao universityDateDao) {
540 this.universityDateDao = universityDateDao;
541 }
542
543 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
544 this.businessObjectService = businessObjectService;
545 }
546
547 public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
548 this.workflowDocumentService = workflowDocumentService;
549 }
550
551
552 public DataDictionaryService getDataDictionaryService() {
553 return dataDictionaryService;
554 }
555
556 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
557 this.dataDictionaryService = dataDictionaryService;
558 }
559
560 /**
561 * Gets the depreciationBatchDao attribute.
562 *
563 * @return Returns the depreciationBatchDao.
564 */
565 public DepreciationBatchDao getDepreciationBatchDao() {
566 return depreciationBatchDao;
567 }
568
569 /**
570 * Sets the depreciationBatchDao attribute value.
571 *
572 * @param depreciationBatchDao The depreciationBatchDao to set.
573 */
574 public void setDepreciationBatchDao(DepreciationBatchDao depreciationBatchDao) {
575 this.depreciationBatchDao = depreciationBatchDao;
576 }
577 }