1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.ole.gl.batch.service.impl;
17  
18  import java.sql.Date;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.kuali.ole.coa.businessobject.Account;
27  import org.kuali.ole.coa.service.AccountService;
28  import org.kuali.ole.gl.GeneralLedgerConstants;
29  import org.kuali.ole.gl.batch.SufficientFundsAccountUpdateStep;
30  import org.kuali.ole.gl.batch.service.SufficientFundsAccountUpdateService;
31  import org.kuali.ole.gl.businessobject.Balance;
32  import org.kuali.ole.gl.businessobject.SufficientFundBalances;
33  import org.kuali.ole.gl.businessobject.SufficientFundRebuild;
34  import org.kuali.ole.gl.dataaccess.BalanceDao;
35  import org.kuali.ole.gl.dataaccess.SufficientFundBalancesDao;
36  import org.kuali.ole.gl.dataaccess.SufficientFundRebuildDao;
37  import org.kuali.ole.gl.service.SufficientFundsService;
38  import org.kuali.ole.sys.Message;
39  import org.kuali.ole.sys.OLEConstants;
40  import org.kuali.ole.sys.OLEKeyConstants;
41  import org.kuali.ole.sys.OLEPropertyConstants;
42  import org.kuali.ole.sys.businessobject.SystemOptions;
43  import org.kuali.ole.sys.context.SpringContext;
44  import org.kuali.ole.sys.service.ReportWriterService;
45  import org.kuali.rice.core.api.config.property.ConfigurationService;
46  import org.kuali.rice.core.api.datetime.DateTimeService;
47  import org.kuali.rice.core.api.util.type.KualiDecimal;
48  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
49  import org.kuali.rice.krad.service.BusinessObjectService;
50  import org.springframework.transaction.annotation.Transactional;
51  
52  
53  
54  
55  @Transactional
56  public class SufficientFundsAccountUpdateServiceImpl implements SufficientFundsAccountUpdateService {
57      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SufficientFundsAccountUpdateServiceImpl.class);
58  
59      private DateTimeService dateTimeService;
60      private ConfigurationService kualiConfigurationService;
61      private BalanceDao balanceDao;
62      private SufficientFundBalancesDao sufficientFundBalancesDao;
63      private SufficientFundRebuildDao sufficientFundRebuildDao;
64      private SufficientFundsService sufficientFundsService;
65      private AccountService accountService;
66      private ReportWriterService reportWriterService;
67      private BusinessObjectService boService;
68  
69      private Date runDate;
70      private SystemOptions options;
71  
72      Map batchError;
73      List reportSummary;
74      List<Message> transactionErrors;
75  
76      private Integer universityFiscalYear;
77      private int sfrbRecordsConvertedCount = 0;
78      private int sfrbRecordsReadCount = 0;
79      private int sfrbRecordsDeletedCount = 0;
80      private int sfrbNotDeletedCount = 0;
81      private int sfblDeletedCount = 0;
82      private int sfblInsertedCount = 0;
83      private int sfblUpdatedCount = 0;
84      private int warningCount = 0;
85  
86  
87      private SufficientFundBalances currentSfbl = null;
88  
89      
90  
91  
92      public SufficientFundsAccountUpdateServiceImpl() {
93          super();
94      }
95  
96      
97  
98  
99  
100 
101     protected Integer getFiscalYear() {
102         String val = SpringContext.getBean(ParameterService.class).getParameterValueAsString(SufficientFundsAccountUpdateStep.class, GeneralLedgerConstants.FISCAL_YEAR_PARM);
103         return Integer.parseInt(val);
104     }
105 
106     
107 
108 
109 
110     @Override
111     public void rebuildSufficientFunds() { 
112         List <SufficientFundRebuild> rebuildSfrbList = new ArrayList<SufficientFundRebuild>();
113 
114         universityFiscalYear = getFiscalYear();
115         if ( LOG.isInfoEnabled() ) {
116             LOG.info( "Rebuilding sufficient funds for fiscal year: " + universityFiscalYear );
117         }
118         initService();
119 
120         
121         runDate = dateTimeService.getCurrentSqlDate();
122 
123         
124         LOG.info("rebuildSufficientFunds() Converting O types to A types");
125         Map criteria = new HashMap();
126         criteria.put(OLEPropertyConstants.ACCOUNT_FINANCIAL_OBJECT_TYPE_CODE, OLEConstants.SF_TYPE_OBJECT);
127 
128         for (Iterator iter = boService.findMatching(SufficientFundRebuild.class, criteria).iterator(); iter.hasNext();) {
129             SufficientFundRebuild sfrb = (SufficientFundRebuild) iter.next();
130             ++sfrbRecordsReadCount;
131 
132             transactionErrors = new ArrayList<Message>();
133 
134             convertOtypeToAtypes(sfrb);
135 
136             if (transactionErrors.size() > 0) {
137                 reportWriterService.writeError(sfrb, transactionErrors);
138                 rebuildSfrbList.add(sfrb);
139             }
140           }
141         criteria.clear();
142 
143         
144         LOG.info("rebuildSufficientFunds() Calculating SF balances for all A types");
145 
146         criteria.put(OLEPropertyConstants.ACCOUNT_FINANCIAL_OBJECT_TYPE_CODE, OLEConstants.SF_TYPE_ACCOUNT);
147 
148         for (Iterator iter = boService.findMatching(SufficientFundRebuild.class, criteria).iterator(); iter.hasNext();) {
149             SufficientFundRebuild sfrb = (SufficientFundRebuild) iter.next();
150             ++sfrbRecordsReadCount;
151 
152             transactionErrors = new ArrayList<Message>();
153 
154             calculateSufficientFundsByAccount(sfrb);
155 
156             if (transactionErrors.size() > 0) {
157                 reportWriterService.writeError(sfrb, transactionErrors);
158                 rebuildSfrbList.add(sfrb);
159             }
160 
161         }
162         sufficientFundRebuildDao.purgeSufficientFundRebuild();
163         boService.save( rebuildSfrbList);
164 
165         
166         
167         
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
180 
181 
182         
183         LOG.info("rebuildSufficientFunds() Create report");
184 
185         
186         reportWriterService.writeStatisticLine("                                   SFRB RECORDS CONVERTED FROM OBJECT TO ACCOUNT  %,9d\n", sfrbRecordsConvertedCount);
187         reportWriterService.writeStatisticLine("                                   POST CONVERSION SFRB RECORDS READ              %,9d\n", sfrbRecordsReadCount);
188         reportWriterService.writeStatisticLine("                                   SFRB RECORDS DELETED                           %,9d\n", sfrbRecordsDeletedCount);
189         reportWriterService.writeStatisticLine("                                   SFRB RECORDS KEPT DUE TO ERRORS                %,9d\n", sfrbNotDeletedCount);
190         reportWriterService.writeStatisticLine("                                   SFBL RECORDS DELETED                           %,9d\n", sfblDeletedCount);
191         reportWriterService.writeStatisticLine("                                   SFBL RECORDS ADDED                             %,9d\n", sfblInsertedCount);
192         reportWriterService.writeStatisticLine("                                   SFBL RECORDS UDPATED                           %,9d\n", sfblUpdatedCount);
193     }
194 
195     
196 
197 
198     protected void initService() {
199         batchError = new HashMap();
200         reportSummary = new ArrayList();
201 
202         runDate = new Date(dateTimeService.getCurrentDate().getTime());
203 
204         options = (SystemOptions)boService.findBySinglePrimaryKey(SystemOptions.class, universityFiscalYear);
205 
206         if (options == null) {
207             throw new IllegalStateException(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.ERROR_UNIV_DATE_NOT_FOUND));
208         }
209     }
210 
211     
212 
213 
214 
215 
216 
217     @Override
218     public void convertOtypeToAtypes(SufficientFundRebuild sfrb) {
219         ++sfrbRecordsConvertedCount;
220         Collection fundBalances = sufficientFundBalancesDao.getByObjectCode(universityFiscalYear, sfrb.getChartOfAccountsCode(), sfrb.getAccountNumberFinancialObjectCode());
221         Map criteria = new HashMap();
222 
223         for (Iterator fundBalancesIter = fundBalances.iterator(); fundBalancesIter.hasNext();) {
224             SufficientFundBalances sfbl = (SufficientFundBalances) fundBalancesIter.next();
225             criteria.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, sfbl.getChartOfAccountsCode());
226             criteria.put(OLEPropertyConstants.ACCOUNT_FINANCIAL_OBJECT_TYPE_CODE, OLEConstants.SF_TYPE_ACCOUNT);
227             criteria.put(OLEPropertyConstants.ACCOUNT_NUMBER_FINANCIAL_OBJECT_CODE, sfbl.getAccountNumber());
228 
229             SufficientFundRebuild altSfrb = (SufficientFundRebuild)boService.findByPrimaryKey(SufficientFundRebuild.class, criteria);
230             if (altSfrb == null) {
231                 altSfrb = new SufficientFundRebuild();
232                 altSfrb.setAccountFinancialObjectTypeCode(OLEConstants.SF_TYPE_ACCOUNT);
233                 altSfrb.setAccountNumberFinancialObjectCode(sfbl.getAccountNumber());
234                 altSfrb.setChartOfAccountsCode(sfbl.getChartOfAccountsCode());
235                 boService.save(altSfrb);
236             }
237             criteria.clear();
238         }
239     }
240 
241     
242 
243 
244 
245 
246     @Override
247     public void calculateSufficientFundsByAccount(SufficientFundRebuild sfrb) {
248         Account sfrbAccount = accountService.getByPrimaryId(sfrb.getChartOfAccountsCode(), sfrb.getAccountNumberFinancialObjectCode());
249         if (sfrbAccount == null) {
250             String msg = "Account found in SufficientFundsRebuild table that is not in Accounts table [" + sfrb.getChartOfAccountsCode() + "-" + sfrb.getAccountNumberFinancialObjectCode() + "].";
251             LOG.error(msg);
252             throw new RuntimeException(msg);
253         }
254         if ((sfrbAccount.getAccountSufficientFundsCode() != null)
255                 && (OLEConstants.SF_TYPE_ACCOUNT.equals(sfrbAccount.getAccountSufficientFundsCode())
256                         || OLEConstants.SF_TYPE_CASH_AT_ACCOUNT.equals(sfrbAccount.getAccountSufficientFundsCode())
257                         || OLEConstants.SF_TYPE_CONSOLIDATION.equals(sfrbAccount.getAccountSufficientFundsCode())
258                         || OLEConstants.SF_TYPE_LEVEL.equals(sfrbAccount.getAccountSufficientFundsCode())
259                         || OLEConstants.SF_TYPE_OBJECT.equals(sfrbAccount.getAccountSufficientFundsCode())
260                         || OLEConstants.SF_TYPE_NO_CHECKING.equals(sfrbAccount.getAccountSufficientFundsCode()))) {
261             ++sfrbRecordsDeletedCount;
262              sfblDeletedCount += sufficientFundBalancesDao.deleteByAccountNumber(universityFiscalYear, sfrb.getChartOfAccountsCode(), sfrbAccount.getAccountNumber());
263 
264             if (OLEConstants.SF_TYPE_NO_CHECKING.equalsIgnoreCase(sfrbAccount.getAccountSufficientFundsCode())) {
265                 
266                 return;
267             }
268 
269             Iterator balancesIterator = balanceDao.findAccountBalances(universityFiscalYear, sfrb.getChartOfAccountsCode(), sfrb.getAccountNumberFinancialObjectCode(), sfrbAccount.getAccountSufficientFundsCode());
270 
271             if (balancesIterator == null) {
272                 addTransactionError(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.ERROR_BALANCE_NOT_FOUND_FOR) + universityFiscalYear + ")");
273                 ++warningCount;
274                 ++sfrbNotDeletedCount;
275                 return;
276             }
277 
278             String currentFinObjectCd = "";
279             while (balancesIterator.hasNext()) {
280                 Balance balance = (Balance) balancesIterator.next();
281                 if ( LOG.isDebugEnabled() ) {
282                     LOG.debug("Processing Balance for SF: " + balance.getChartOfAccountsCode() + " / " + balance.getAccountNumber() + " / " + balance.getObjectCode() );
283                 }
284                 String tempFinObjectCd = sufficientFundsService.getSufficientFundsObjectCode(balance.getFinancialObject(), sfrbAccount.getAccountSufficientFundsCode());
285                 if ( LOG.isDebugEnabled() ) {
286                     LOG.debug("SF Code: " + sfrbAccount.getAccountSufficientFundsCode() + " / Using SF Object Code: '" + tempFinObjectCd + "'" );
287                 }
288                 if (!tempFinObjectCd.equals(currentFinObjectCd)) {
289                     
290                     currentFinObjectCd = tempFinObjectCd;
291 
292                     if (currentSfbl != null && amountsAreNonZero(currentSfbl)) {
293                         boService.save(currentSfbl);
294                         ++sfblInsertedCount;
295                     }
296 
297                     currentSfbl = new SufficientFundBalances();
298                     currentSfbl.setUniversityFiscalYear(universityFiscalYear);
299                     currentSfbl.setChartOfAccountsCode(sfrb.getChartOfAccountsCode());
300                     currentSfbl.setAccountNumber(sfrbAccount.getAccountNumber());
301                     currentSfbl.setFinancialObjectCode(currentFinObjectCd);
302                     currentSfbl.setAccountSufficientFundsCode(sfrbAccount.getAccountSufficientFundsCode());
303                     currentSfbl.setAccountActualExpenditureAmt(KualiDecimal.ZERO);
304                     currentSfbl.setAccountEncumbranceAmount(KualiDecimal.ZERO);
305                     currentSfbl.setCurrentBudgetBalanceAmount(KualiDecimal.ZERO);
306                 }
307 
308                 if (sfrbAccount.isForContractsAndGrants()) {
309                     if ( LOG.isDebugEnabled() ) {
310                         LOG.debug("Account is C&G.  Adding C&G beginning balance amount (" + balance.getContractsGrantsBeginningBalanceAmount() + ") to the annual balance amount.");
311                     }
312                     balance.setAccountLineAnnualBalanceAmount(balance.getAccountLineAnnualBalanceAmount().add(balance.getContractsGrantsBeginningBalanceAmount()));
313                 }
314 
315                 if (OLEConstants.SF_TYPE_CASH_AT_ACCOUNT.equals(sfrbAccount.getAccountSufficientFundsCode())) {
316                     if ( LOG.isDebugEnabled() ) {
317                         LOG.debug("SF type is Cash at account");
318                     }
319                     processCash(sfrbAccount, balance);
320                  }
321                 else {
322                     processObjectOrAccount(sfrbAccount, balance);
323                  }
324             }
325 
326             
327             if (currentSfbl != null && amountsAreNonZero(currentSfbl)) {
328                 boService.save(currentSfbl);
329                 ++sfblInsertedCount;
330             }
331          }
332         else {
333             addTransactionError(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.ERROR_INVALID_ACCOUNT_SF_CODE_FOR));
334             ++warningCount;
335             ++sfrbNotDeletedCount;
336             return;
337         }
338     }
339 
340     
341 
342 
343 
344 
345 
346     protected boolean amountsAreNonZero(SufficientFundBalances sfbl) {
347         boolean zero = true;
348         zero &= KualiDecimal.ZERO.equals(sfbl.getAccountActualExpenditureAmt());
349         zero &= KualiDecimal.ZERO.equals(sfbl.getAccountEncumbranceAmount());
350         zero &= KualiDecimal.ZERO.equals(sfbl.getCurrentBudgetBalanceAmount());
351         return !zero;
352     }
353 
354     
355 
356 
357 
358 
359 
360     protected void processObjectOrAccount(Account sfrbAccount, Balance balance) {
361         if (options.getFinObjTypeExpenditureexpCd().equals(balance.getObjectTypeCode()) || options.getFinObjTypeExpendNotExpCode().equals(balance.getObjectTypeCode()) || options.getFinObjTypeExpNotExpendCode().equals(balance.getObjectTypeCode()) || options.getFinancialObjectTypeTransferExpenseCd().equals(balance.getObjectTypeCode())) {
362             if (options.getActualFinancialBalanceTypeCd().equals(balance.getBalanceTypeCode())) {
363                 processObjtAcctActual(balance);
364             }
365             else if (options.getExtrnlEncumFinBalanceTypCd().equals(balance.getBalanceTypeCode()) || options.getIntrnlEncumFinBalanceTypCd().equals(balance.getBalanceTypeCode()) || options.getPreencumbranceFinBalTypeCd().equals(balance.getBalanceTypeCode()) || options.getCostShareEncumbranceBalanceTypeCd().equals(balance.getBalanceTypeCode())) {
366                 processObjtAcctEncmbrnc(balance);
367             }
368             else if (options.getBudgetCheckingBalanceTypeCd().equals(balance.getBalanceTypeCode())) {
369                 processObjtAcctBudget(balance);
370             }
371         } else {
372             if ( LOG.isDebugEnabled() ) {
373                 LOG.debug("Skipped balance record.  Object Type did not match.");
374                 LOG.debug( balance.getObjectTypeCode() + " NOT IN ( " + options.getFinObjTypeExpenditureexpCd() + "," + options.getFinObjTypeExpendNotExpCode() + "," + options.getFinObjTypeExpNotExpendCode() + "," + options.getFinancialObjectTypeTransferExpenseCd() );
375             }
376         }
377     }
378 
379     
380 
381 
382 
383 
384     protected void processObjtAcctActual(Balance balance) {
385         currentSfbl.setAccountActualExpenditureAmt(currentSfbl.getAccountActualExpenditureAmt().add(balance.getAccountLineAnnualBalanceAmount()));
386     }
387 
388     
389 
390 
391 
392 
393     protected void processObjtAcctEncmbrnc(Balance balance) {
394         currentSfbl.setAccountEncumbranceAmount(currentSfbl.getAccountEncumbranceAmount().add(balance.getAccountLineAnnualBalanceAmount()));
395         currentSfbl.setAccountEncumbranceAmount(currentSfbl.getAccountEncumbranceAmount().add(balance.getBeginningBalanceLineAmount()));
396     }
397 
398     
399 
400 
401 
402 
403     protected void processObjtAcctBudget(Balance balance) {
404         currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().add(balance.getAccountLineAnnualBalanceAmount()));
405         currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().add(balance.getBeginningBalanceLineAmount()));
406     }
407 
408     
409 
410 
411 
412 
413 
414     protected void processCash(Account sfrbAccount, Balance balance) {
415         if (balance.getBalanceTypeCode().equals(options.getActualFinancialBalanceTypeCd())) {
416             if (balance.getObjectCode().equals(sfrbAccount.getChartOfAccounts().getFinancialCashObjectCode()) || balance.getObjectCode().equals(sfrbAccount.getChartOfAccounts().getFinAccountsPayableObjectCode())) {
417                 processCashActual(sfrbAccount, balance);
418             }
419         }
420         else if (balance.getBalanceTypeCode().equals(options.getExtrnlEncumFinBalanceTypCd()) || balance.getBalanceTypeCode().equals(options.getIntrnlEncumFinBalanceTypCd()) || balance.getBalanceTypeCode().equals(options.getPreencumbranceFinBalTypeCd()) || options.getCostShareEncumbranceBalanceTypeCd().equals(balance.getBalanceTypeCode())) {
421             if (balance.getObjectTypeCode().equals(options.getFinObjTypeExpenditureexpCd()) || balance.getObjectTypeCode().equals(options.getFinObjTypeExpendNotExpCode()) || options.getFinancialObjectTypeTransferExpenseCd().equals(balance.getObjectTypeCode()) || options.getFinObjTypeExpNotExpendCode().equals(balance.getObjectTypeCode())) {
422                 processCashEncumbrance(balance);
423             }
424         }
425     }
426 
427     
428 
429 
430 
431 
432 
433     protected void processCashActual(Account sfrbAccount, Balance balance) {
434         if (balance.getObjectCode().equals(sfrbAccount.getChartOfAccounts().getFinancialCashObjectCode())) {
435             currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().add(balance.getAccountLineAnnualBalanceAmount()));
436             currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().add(balance.getBeginningBalanceLineAmount()));
437         }
438         if (balance.getObjectCode().equals(sfrbAccount.getChartOfAccounts().getFinAccountsPayableObjectCode())) {
439             currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().subtract(balance.getAccountLineAnnualBalanceAmount()));
440             currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().subtract(balance.getBeginningBalanceLineAmount()));
441         }
442     }
443 
444     
445 
446 
447 
448 
449     protected void processCashEncumbrance(Balance balance) {
450         currentSfbl.setAccountEncumbranceAmount(currentSfbl.getAccountEncumbranceAmount().add(balance.getAccountLineAnnualBalanceAmount()));
451         currentSfbl.setAccountEncumbranceAmount(currentSfbl.getAccountEncumbranceAmount().add(balance.getBeginningBalanceLineAmount()));
452     }
453 
454     
455 
456 
457 
458     protected void addTransactionError(String errorMessage) {
459         transactionErrors.add(new Message(errorMessage, Message.TYPE_WARNING));
460     }
461 
462     public void setDateTimeService(DateTimeService dateTimeService) {
463         this.dateTimeService = dateTimeService;
464     }
465 
466     public void setConfigurationService(ConfigurationService kualiConfigurationService) {
467         this.kualiConfigurationService = kualiConfigurationService;
468     }
469 
470     public void setBalanceDao(BalanceDao balanceDao) {
471         this.balanceDao = balanceDao;
472     }
473 
474     public void setSufficientFundBalancesDao(SufficientFundBalancesDao sufficientFundBalancesDao) {
475         this.sufficientFundBalancesDao = sufficientFundBalancesDao;
476     }
477 
478     public void setReportWriterService(ReportWriterService sfrs) {
479         reportWriterService = sfrs;
480     }
481 
482     public void setAccountService(AccountService accountService) {
483         this.accountService = accountService;
484     }
485 
486     public void setSufficientFundsService(SufficientFundsService sfs) {
487         sufficientFundsService = sfs;
488     }
489 
490     public void setBusinessObjectService(BusinessObjectService bos) {
491         boService = bos;
492     }
493 
494     public void setSufficientFundRebuildDao(SufficientFundRebuildDao sufficientFundRebuildDao) {
495         this.sufficientFundRebuildDao = sufficientFundRebuildDao;
496     }
497 }