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 }