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.ld.batch.service.impl; 017 018 import java.io.File; 019 import java.io.FilenameFilter; 020 import java.math.BigDecimal; 021 import java.util.HashMap; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 026 import org.kuali.kfs.gl.GeneralLedgerConstants; 027 import org.kuali.kfs.gl.batch.service.BalancingService; 028 import org.kuali.kfs.gl.batch.service.PosterService; 029 import org.kuali.kfs.gl.batch.service.impl.BalancingServiceBaseImpl; 030 import org.kuali.kfs.gl.businessobject.Balance; 031 import org.kuali.kfs.gl.businessobject.Entry; 032 import org.kuali.kfs.gl.businessobject.LedgerBalanceHistory; 033 import org.kuali.kfs.gl.businessobject.OriginEntryInformation; 034 import org.kuali.kfs.module.ld.LaborConstants; 035 import org.kuali.kfs.module.ld.LaborKeyConstants; 036 import org.kuali.kfs.module.ld.batch.LaborBalancingStep; 037 import org.kuali.kfs.module.ld.businessobject.LaborBalanceHistory; 038 import org.kuali.kfs.module.ld.businessobject.LaborEntryHistory; 039 import org.kuali.kfs.module.ld.businessobject.LaborOriginEntry; 040 import org.kuali.kfs.module.ld.businessobject.LedgerBalance; 041 import org.kuali.kfs.module.ld.businessobject.LedgerEntry; 042 import org.kuali.kfs.sys.FileUtil; 043 import org.kuali.kfs.sys.KFSConstants; 044 import org.kuali.kfs.sys.KFSKeyConstants; 045 import org.kuali.kfs.sys.KFSPropertyConstants; 046 import org.kuali.kfs.sys.Message; 047 import org.kuali.rice.kns.util.KualiDecimal; 048 import org.kuali.rice.kns.util.ObjectUtils; 049 import org.springframework.transaction.annotation.Transactional; 050 051 /** 052 * Service implementation of BalancingService for Labor balancing 053 */ 054 @Transactional 055 public class LaborBalancingServiceImpl extends BalancingServiceBaseImpl<LaborEntryHistory, LaborBalanceHistory> implements BalancingService { 056 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LaborBalancingServiceImpl.class); 057 058 protected File laborPosterInputFile = null; 059 protected File laborPosterErrorOutputFile = null; 060 061 /** 062 * @see org.kuali.kfs.gl.batch.service.BalancingService#getPosterInputFile() 063 */ 064 public File getPosterInputFile() { 065 // avoid running scanning logic on file system 066 if (laborPosterInputFile != null) { 067 return laborPosterInputFile; 068 } 069 070 FilenameFilter filenameFilter = new FilenameFilter() { 071 public boolean accept(File dir, String name) { 072 return (name.startsWith(LaborConstants.BatchFileSystem.POSTER_INPUT_FILE) && 073 name.endsWith(GeneralLedgerConstants.BatchFileSystem.EXTENSION)); 074 } 075 }; 076 077 laborPosterInputFile = FileUtil.getNewestFile(new File(batchFileDirectoryName), filenameFilter); 078 079 return laborPosterInputFile; 080 } 081 082 /** 083 * @see org.kuali.kfs.gl.batch.service.BalancingService#getPosterErrorOutputFile() 084 */ 085 public File getPosterErrorOutputFile() { 086 // avoid running scanning logic on file system 087 if (laborPosterErrorOutputFile != null) { 088 return laborPosterErrorOutputFile; 089 } 090 091 FilenameFilter filenameFilter = new FilenameFilter() { 092 public boolean accept(File dir, String name) { 093 return (name.startsWith(LaborConstants.BatchFileSystem.POSTER_ERROR_OUTPUT_FILE) && 094 name.endsWith(GeneralLedgerConstants.BatchFileSystem.EXTENSION)); 095 } 096 }; 097 098 laborPosterErrorOutputFile = FileUtil.getNewestFile(new File(batchFileDirectoryName), filenameFilter); 099 100 return laborPosterErrorOutputFile; 101 } 102 103 104 /** 105 * @see org.kuali.kfs.gl.batch.service.BalancingService#getPastFiscalYearsToConsider() 106 */ 107 public int getPastFiscalYearsToConsider() { 108 return Integer.parseInt(parameterService.getParameterValue(LaborBalancingStep.class, LaborConstants.Balancing.NUMBER_OF_PAST_FISCAL_YEARS_TO_INCLUDE)); 109 } 110 111 /** 112 * @see org.kuali.kfs.gl.batch.service.BalancingService#getComparisonFailuresToPrintPerReport() 113 */ 114 public int getComparisonFailuresToPrintPerReport() { 115 return Integer.parseInt(parameterService.getParameterValue(LaborBalancingStep.class, LaborConstants.Balancing.NUMBER_OF_COMPARISON_FAILURES_TO_PRINT_PER_REPORT)); 116 } 117 118 /** 119 * @see org.kuali.kfs.gl.batch.service.BalancingService#getShortTableLabel(java.lang.String) 120 */ 121 public String getShortTableLabel(String businessObjectName) { 122 Map<String, String> names = new HashMap<String, String>(); 123 names.put((Entry.class).getSimpleName(), kualiConfigurationService.getPropertyString(LaborKeyConstants.Balancing.REPORT_ENTRY_LABEL)); 124 names.put((LaborEntryHistory.class).getSimpleName(), kualiConfigurationService.getPropertyString(LaborKeyConstants.Balancing.REPORT_ENTRY_LABEL)); 125 names.put((Balance.class).getSimpleName(), kualiConfigurationService.getPropertyString(LaborKeyConstants.Balancing.REPORT_BALANCE_LABEL)); 126 names.put((LaborBalanceHistory.class).getSimpleName(), kualiConfigurationService.getPropertyString(LaborKeyConstants.Balancing.REPORT_BALANCE_LABEL)); 127 128 return names.get(businessObjectName) == null ? kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_UNKNOWN_LABEL) : names.get(businessObjectName); 129 } 130 131 /** 132 * @see org.kuali.kfs.gl.batch.service.BalancingService#getOriginEntry(java.lang.String, int) 133 */ 134 public OriginEntryInformation getOriginEntry(String inputLine, int lineNumber) { 135 LaborOriginEntry originEntry = new LaborOriginEntry(); 136 originEntry.setFromTextFileForBatch(inputLine, lineNumber); 137 138 return originEntry; 139 } 140 141 /** 142 * @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceBaseImpl#updateHistoriesHelper(java.lang.Integer, java.lang.Integer, java.io.File, java.io.File) 143 */ 144 protected int updateHistoriesHelper(Integer postMode, Integer startUniversityFiscalYear, File inputFile, File errorFile) { 145 if(postMode == PosterService.MODE_ENTRIES){ 146 return super.updateHistoriesHelper(postMode, startUniversityFiscalYear, inputFile, errorFile); 147 } 148 return 0; 149 } 150 151 /** 152 * @see org.kuali.kfs.gl.batch.service.BalancingService#updateEntryHistory(org.kuali.kfs.gl.businessobject.OriginEntryInformation) 153 * @see org.kuali.kfs.module.ld.batch.service.impl.LaborPosterServiceImpl#postAsLedgerEntry(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date) 154 */ 155 public void updateEntryHistory(Integer postMode, OriginEntryInformation originEntry) { 156 if(postMode == PosterService.MODE_ENTRIES){ 157 // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end? 158 LaborOriginEntry laborOriginEntry = (LaborOriginEntry) originEntry; 159 LaborEntryHistory ledgerEntryHistory = new LaborEntryHistory(laborOriginEntry); 160 161 LaborEntryHistory retrievedLedgerEntryHistory = (LaborEntryHistory) businessObjectService.retrieve(ledgerEntryHistory); 162 if(ObjectUtils.isNotNull(retrievedLedgerEntryHistory)) { 163 ledgerEntryHistory = retrievedLedgerEntryHistory; 164 } 165 166 ledgerEntryHistory.addAmount(laborOriginEntry.getTransactionLedgerEntryAmount()); 167 168 businessObjectService.save(ledgerEntryHistory); 169 } 170 } 171 172 /** 173 * @see org.kuali.kfs.gl.batch.service.BalancingService#updateBalanceHistory(org.kuali.kfs.gl.businessobject.OriginEntryInformation) 174 * @see org.kuali.kfs.module.ld.batch.service.impl.LaborPosterServiceImpl#updateLedgerBalance(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date) 175 */ 176 public void updateBalanceHistory(Integer postMode, OriginEntryInformation originEntry) { 177 if(postMode == PosterService.MODE_ENTRIES){ 178 // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end? 179 LaborOriginEntry laborOriginEntry = (LaborOriginEntry) originEntry; 180 LaborBalanceHistory ledgerBalanceHistory = new LaborBalanceHistory(laborOriginEntry); 181 182 LaborBalanceHistory retrievedLedgerBalanceHistory = (LaborBalanceHistory) businessObjectService.retrieve(ledgerBalanceHistory); 183 if(ObjectUtils.isNotNull(retrievedLedgerBalanceHistory)) { 184 ledgerBalanceHistory = retrievedLedgerBalanceHistory; 185 } 186 187 // Make sure the amount update properly recognized debit / credit logic. This is modeled after LaborPosterServiceImpl#updateLedgerBalance 188 KualiDecimal amount = laborOriginEntry.getTransactionLedgerEntryAmount(); 189 laborOriginEntry.refreshReferenceObject(KFSPropertyConstants.BALANCE_TYPE); 190 laborOriginEntry.refreshReferenceObject(KFSPropertyConstants.OBJECT_TYPE); 191 if (laborOriginEntry.getBalanceType().isFinancialOffsetGenerationIndicator()) { 192 if (!laborOriginEntry.getTransactionDebitCreditCode().equals(laborOriginEntry.getObjectType().getFinObjectTypeDebitcreditCd())) { 193 amount = amount.negated(); 194 } 195 } 196 197 ledgerBalanceHistory.addAmount(laborOriginEntry.getUniversityFiscalPeriodCode(), amount); 198 199 businessObjectService.save(ledgerBalanceHistory); 200 } 201 } 202 203 /** 204 * Compares entries in the Balance and BalanceHistory tables to ensure the amounts match. 205 * @return count is compare failures 206 */ 207 protected Integer compareBalanceHistory() { 208 Integer countComparisionFailures = 0; 209 210 List data = ledgerEntryBalanceCachingDao.compareBalanceHistory(LedgerBalance.class, balanceHistoryPersistentClass, getPastFiscalYearsToConsider()); 211 212 213 if (!data.isEmpty()) { 214 for (Iterator itr = data.iterator(); itr.hasNext();) { 215 LaborBalanceHistory balance = createBalanceFromMap((Map)itr.next()); 216 countComparisionFailures++; 217 if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) { 218 reportWriterService.writeError(balance, new Message(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, balance.getClass().getSimpleName())); 219 } 220 } 221 } 222 223 return countComparisionFailures; 224 } 225 226 /** 227 * Compares entries in the Entry and EntryHistory tables to ensure the amounts match. 228 * @return count is compare failures 229 */ 230 protected Integer compareEntryHistory() { 231 Integer countComparisionFailures = 0; 232 233 List data = ledgerEntryBalanceCachingDao.compareEntryHistory(LedgerEntry.class, entryHistoryPersistentClass, getPastFiscalYearsToConsider()); 234 235 if (!data.isEmpty()) { 236 for (Iterator itr = data.iterator(); itr.hasNext();) { 237 LaborEntryHistory entry = createEntryHistoryFromMap((Map)itr.next()); 238 countComparisionFailures++; 239 if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) { 240 reportWriterService.writeError(entry, new Message(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, entry.getClass().getSimpleName())); 241 } 242 243 } 244 } 245 246 return countComparisionFailures; 247 } 248 249 250 /** 251 * 252 * @see org.kuali.kfs.gl.batch.service.BalancingService#clearBalanceHistory() 253 */ 254 255 public void clearHistories() { 256 Map<String, Object> fieldValues = new HashMap<String, Object>(); 257 businessObjectService.deleteMatching(LaborEntryHistory.class, fieldValues); 258 businessObjectService.deleteMatching(LaborBalanceHistory.class, fieldValues); 259 260 reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_HISTORY_PURGED)); 261 262 } 263 264 /** 265 * @see org.kuali.kfs.gl.batch.service.BalancingService#getBalance(org.kuali.kfs.gl.businessobject.LedgerBalanceHistory) 266 */ 267 public Balance getBalance(LedgerBalanceHistory ledgerBalanceHistory) { 268 LedgerBalance ledgerBalance = new LedgerBalance((LaborBalanceHistory) ledgerBalanceHistory); 269 return (LedgerBalance) businessObjectService.retrieve(ledgerBalance); 270 } 271 272 /** 273 * @see org.kuali.kfs.gl.batch.service.BalancingService#clearPosterFileCache() 274 */ 275 public void clearPosterFileCache() { 276 this.laborPosterInputFile = null; 277 this.laborPosterErrorOutputFile = null; 278 } 279 280 protected LaborBalanceHistory createBalanceFromMap(Map<String, Object> map) { 281 LaborBalanceHistory balance = new LaborBalanceHistory(); 282 balance.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue()); 283 balance.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE)); 284 balance.setAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_NUMBER)); 285 balance.setSubAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_ACCOUNT_NUMBER)); 286 balance.setObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE)); 287 balance.setSubObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_OBJECT_CODE)); 288 balance.setBalanceTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE)); 289 balance.setObjectTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_TYPE_CODE)); 290 balance.setEmplid((String)map.get(LaborConstants.ColumnNames.EMPLOYEE_IDENTIFIER)); 291 balance.setPositionNumber((String)map.get(LaborConstants.ColumnNames.POSITION_NUMBER)); 292 293 balance.setAccountLineAnnualBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNTING_LINE_ACTUALS_BALANCE_AMOUNT))); 294 balance.setContractsGrantsBeginningBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.CONTRACT_AND_GRANTS_BEGINNING_BALANCE))); 295 balance.setBeginningBalanceLineAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.BEGINNING_BALANCE))); 296 balance.setMonth1Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_1_ACCT_AMT))); 297 balance.setMonth2Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_2_ACCT_AMT))); 298 balance.setMonth3Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_3_ACCT_AMT))); 299 balance.setMonth4Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_4_ACCT_AMT))); 300 balance.setMonth5Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_5_ACCT_AMT))); 301 balance.setMonth6Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_6_ACCT_AMT))); 302 balance.setMonth7Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_7_ACCT_AMT))); 303 balance.setMonth8Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_8_ACCT_AMT))); 304 balance.setMonth9Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_9_ACCT_AMT))); 305 balance.setMonth10Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_10_ACCT_AMT))); 306 balance.setMonth11Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_11_ACCT_AMT))); 307 balance.setMonth12Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_12_ACCT_AMT))); 308 balance.setMonth13Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_13_ACCT_AMT))); 309 310 return balance; 311 312 } 313 314 protected LaborEntryHistory createEntryHistoryFromMap(Map<String, Object> map) { 315 LaborEntryHistory entry = new LaborEntryHistory(); 316 entry.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue()); 317 entry.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE)); 318 entry.setFinancialObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE)); 319 entry.setFinancialBalanceTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE)); 320 entry.setUniversityFiscalPeriodCode((String)map.get(GeneralLedgerConstants.ColumnNames.FISCAL_PERIOD_CODE)); 321 entry.setTransactionDebitCreditCode((String)map.get(GeneralLedgerConstants.ColumnNames.TRANSACTION_DEBIT_CREDIT_CD)); 322 entry.setTransactionLedgerEntryAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.TRANSACTION_LEDGER_ENTRY_AMOUNT))); 323 324 return entry; 325 326 } 327 328 protected KualiDecimal convertBigDecimalToKualiDecimal(BigDecimal biggy) { 329 if (ObjectUtils.isNull(biggy)) 330 return new KualiDecimal(0); 331 else 332 return new KualiDecimal(biggy); 333 334 } 335 336 /** 337 * @see org.kuali.kfs.gl.batch.service.BalancingService#getReversalInputFile() 338 */ 339 public File getReversalInputFile(){ 340 return null; 341 } 342 343 /** 344 * @see org.kuali.kfs.gl.batch.service.BalancingService#getReversalErrorOutputFile() 345 */ 346 public File getReversalErrorOutputFile(){ 347 return null; 348 } 349 350 /** 351 * @see org.kuali.kfs.gl.batch.service.BalancingService#getICRInputFile() 352 */ 353 public File getICRInputFile(){ 354 return null; 355 } 356 357 /** 358 * @see org.kuali.kfs.gl.batch.service.BalancingService#getICRErrorOutputFile() 359 */ 360 public File getICRErrorOutputFile(){ 361 return null; 362 } 363 364 }