View Javadoc
1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.sys.service.impl;
17  
18  import static org.kuali.ole.sys.OLEConstants.BALANCE_TYPE_ACTUAL;
19  import static org.kuali.ole.sys.OLEConstants.BLANK_SPACE;
20  import static org.kuali.ole.sys.OLEConstants.GL_CREDIT_CODE;
21  import static org.kuali.ole.sys.OLEConstants.GL_DEBIT_CODE;
22  
23  import java.sql.Timestamp;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.commons.lang.StringUtils;
32  import org.kuali.ole.coa.businessobject.Account;
33  import org.kuali.ole.coa.businessobject.Chart;
34  import org.kuali.ole.coa.businessobject.ObjectCode;
35  import org.kuali.ole.coa.businessobject.OffsetDefinition;
36  import org.kuali.ole.coa.businessobject.SubAccount;
37  import org.kuali.ole.coa.businessobject.SubObjectCode;
38  import org.kuali.ole.coa.service.AccountService;
39  import org.kuali.ole.coa.service.BalanceTypeService;
40  import org.kuali.ole.coa.service.ChartService;
41  import org.kuali.ole.coa.service.ObjectCodeService;
42  import org.kuali.ole.coa.service.ObjectTypeService;
43  import org.kuali.ole.coa.service.OffsetDefinitionService;
44  import org.kuali.ole.fp.businessobject.OffsetAccount;
45  import org.kuali.ole.gl.businessobject.Balance;
46  import org.kuali.ole.gl.businessobject.Encumbrance;
47  import org.kuali.ole.gl.service.SufficientFundsService;
48  import org.kuali.ole.gl.service.SufficientFundsServiceConstants;
49  import org.kuali.ole.sys.OLEConstants;
50  import org.kuali.ole.sys.OLEKeyConstants;
51  import org.kuali.ole.sys.OLEPropertyConstants;
52  import org.kuali.ole.sys.businessobject.Bank;
53  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry;
54  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
55  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
56  import org.kuali.ole.sys.businessobject.SystemOptions;
57  import org.kuali.ole.sys.businessobject.UniversityDate;
58  import org.kuali.ole.sys.context.SpringContext;
59  import org.kuali.ole.sys.dataaccess.GeneralLedgerPendingEntryDao;
60  import org.kuali.ole.sys.document.GeneralLedgerPendingEntrySource;
61  import org.kuali.ole.sys.document.GeneralLedgerPostingDocument;
62  import org.kuali.ole.sys.document.validation.impl.AccountingDocumentRuleBaseConstants;
63  import org.kuali.ole.sys.document.validation.impl.AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE;
64  import org.kuali.ole.sys.service.FlexibleOffsetAccountService;
65  import org.kuali.ole.sys.service.GeneralLedgerPendingEntryService;
66  import org.kuali.ole.sys.service.HomeOriginationService;
67  import org.kuali.ole.sys.service.OptionsService;
68  import org.kuali.ole.sys.service.UniversityDateService;
69  import org.kuali.rice.core.api.datetime.DateTimeService;
70  import org.kuali.rice.core.api.util.type.KualiDecimal;
71  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
72  import org.kuali.rice.kns.service.DataDictionaryService;
73  import org.kuali.rice.krad.service.BusinessObjectService;
74  import org.kuali.rice.krad.service.KualiRuleService;
75  import org.kuali.rice.krad.service.PersistenceStructureService;
76  import org.kuali.rice.krad.util.GlobalVariables;
77  import org.kuali.rice.krad.util.ObjectUtils;
78  import org.springframework.transaction.annotation.Transactional;
79  
80  /**
81   * This class is the service implementation for the GeneralLedgerPendingEntry structure. This is the default implementation, that is
82   * delivered with Kuali.
83   */
84  @Transactional
85  public class GeneralLedgerPendingEntryServiceImpl implements GeneralLedgerPendingEntryService {
86      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(GeneralLedgerPendingEntryServiceImpl.class);
87  
88      protected GeneralLedgerPendingEntryDao generalLedgerPendingEntryDao;
89      protected KualiRuleService kualiRuleService;
90      protected ChartService chartService;
91      protected OptionsService optionsService;
92      protected ParameterService parameterService;
93      protected BalanceTypeService balanceTypeService;
94      protected DateTimeService dateTimeService;
95      protected DataDictionaryService dataDictionaryService;
96      protected PersistenceStructureService persistenceStructureService;
97      protected UniversityDateService universityDateService;
98  
99      /**
100      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getExpenseSummary(java.util.List, java.lang.String,
101      *      java.lang.String, boolean, boolean)
102      */
103     @Override
104     public KualiDecimal getExpenseSummary(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String sufficientFundsObjectCode, boolean isDebit, boolean isYearEnd) {
105         LOG.debug("getExpenseSummary() started");
106 
107         // FIXME! - this ObjectTypeService should be injected
108         ObjectTypeService objectTypeService = SpringContext.getBean(ObjectTypeService.class);
109         List<String> objectTypes = objectTypeService.getExpenseObjectTypes(universityFiscalYear);
110 
111         // FIXME! - cache this list - balance type code will not change during the lifetime of the server
112         SystemOptions options = optionsService.getOptions(universityFiscalYear);
113 
114         Collection balanceTypeCodes = new ArrayList();
115         balanceTypeCodes.add(options.getActualFinancialBalanceTypeCd());
116 
117         return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYear, chartOfAccountsCode, accountNumber, objectTypes, balanceTypeCodes, sufficientFundsObjectCode, isDebit, isYearEnd);
118     }
119 
120     /**
121      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getEncumbranceSummary(java.lang.Integer, java.lang.String,
122      *      java.lang.String, java.lang.String, boolean, boolean)
123      */
124     @Override
125     public KualiDecimal getEncumbranceSummary(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String sufficientFundsObjectCode, boolean isDebit, boolean isYearEnd) {
126         LOG.debug("getEncumbranceSummary() started");
127 
128         // FIXME! - this ObjectTypeService should be injected
129         ObjectTypeService objectTypeService = SpringContext.getBean(ObjectTypeService.class);
130         List<String> objectTypes = objectTypeService.getExpenseObjectTypes(universityFiscalYear);
131 
132         SystemOptions options = optionsService.getOptions(universityFiscalYear);
133 
134         // FIXME! - cache this list - balance type code will not change during the lifetime of the server
135         List<String> balanceTypeCodes = balanceTypeService.getEncumbranceBalanceTypes(universityFiscalYear);
136 
137 
138         return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYear, chartOfAccountsCode, accountNumber, objectTypes, balanceTypeCodes, sufficientFundsObjectCode, isDebit, isYearEnd);
139     }
140 
141     /**
142      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getBudgetSummary(java.lang.Integer, java.lang.String,
143      *      java.lang.String, java.lang.String, boolean)
144      */
145     @Override
146     public KualiDecimal getBudgetSummary(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String sufficientFundsObjectCode, boolean isYearEnd) {
147         LOG.debug("getBudgetSummary() started");
148 
149         ObjectTypeService objectTypeService = SpringContext.getBean(ObjectTypeService.class);
150         List<String> objectTypes = objectTypeService.getExpenseObjectTypes(universityFiscalYear);
151 
152         SystemOptions options = optionsService.getOptions(universityFiscalYear);
153 
154         // FIXME! - cache this list - balance type code will not change during the lifetime of the server
155         Collection balanceTypeCodes = new ArrayList();
156         balanceTypeCodes.add(options.getBudgetCheckingBalanceTypeCd());
157 
158         return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYear, chartOfAccountsCode, accountNumber, objectTypes, balanceTypeCodes, sufficientFundsObjectCode, isYearEnd);
159     }
160 
161     /**
162      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getCashSummary(java.util.Collection, java.lang.String,
163      *      java.lang.String, boolean)
164      */
165     @Override
166     public KualiDecimal getCashSummary(List universityFiscalYears, String chartOfAccountsCode, String accountNumber, boolean isDebit) {
167         LOG.debug("getCashSummary() started");
168 
169         Chart c = chartService.getByPrimaryId(chartOfAccountsCode);
170 
171         // Note, we are getting the options from the first fiscal year in the list. We are assuming that the
172         // balance type code for actual is the same in all the years in the list.
173         SystemOptions options = optionsService.getOptions((Integer) universityFiscalYears.get(0));
174 
175         // FIXME! - cache this list - will not change during the lifetime of the server
176         Collection objectCodes = new ArrayList();
177         objectCodes.add(c.getFinancialCashObjectCode());
178 
179         // FIXME! - cache this list - balance type code will not change during the lifetime of the server
180         Collection balanceTypeCodes = new ArrayList();
181         balanceTypeCodes.add(options.getActualFinancialBalanceTypeCd());
182 
183         return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYears, chartOfAccountsCode, accountNumber, objectCodes, balanceTypeCodes, isDebit);
184     }
185 
186     /**
187      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getActualSummary(java.util.List, java.lang.String,
188      *      java.lang.String, boolean)
189      */
190     @Override
191     public KualiDecimal getActualSummary(List universityFiscalYears, String chartOfAccountsCode, String accountNumber, boolean isDebit) {
192         LOG.debug("getActualSummary() started");
193 
194         Collection<String> codes = parameterService.getParameterValuesAsString(OleParameterConstants.FINANCIAL_SYSTEM_ALL.class, SufficientFundsServiceConstants.SUFFICIENT_FUNDS_OBJECT_CODE_SPECIALS);
195 
196         // Note, we are getting the options from the first fiscal year in the list. We are assuming that the
197         // balance type code for actual is the same in all the years in the list.
198         SystemOptions options = optionsService.getOptions((Integer) universityFiscalYears.get(0));
199 
200         // FIXME! - cache this list - balance type code will not change during the lifetime of the server
201         Collection balanceTypeCodes = new ArrayList();
202         balanceTypeCodes.add(options.getActualFinancialBalanceTypeCd());
203 
204         return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYears, chartOfAccountsCode, accountNumber, codes, balanceTypeCodes, isDebit);
205     }
206 
207     /**
208      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getByPrimaryId(java.lang.Integer, java.lang.String)
209      */
210     @Override
211     public GeneralLedgerPendingEntry getByPrimaryId(Integer transactionEntrySequenceId, String documentHeaderId) {
212         LOG.debug("getByPrimaryId() started");
213         Map<String, Object> keys = new HashMap<String, Object>();
214         keys.put(OLEPropertyConstants.DOCUMENT_NUMBER, documentHeaderId);
215         keys.put("transactionLedgerEntrySequenceNumber", transactionEntrySequenceId);
216         // FIXME! - this ObjectService should be injected
217         return SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(GeneralLedgerPendingEntry.class, keys);
218     }
219 
220     @Override
221     public void fillInFiscalPeriodYear(GeneralLedgerPendingEntry glpe) {
222         LOG.debug("fillInFiscalPeriodYear() started");
223 
224         // TODO Handle year end documents
225 
226         if ((glpe.getUniversityFiscalPeriodCode() == null) || (glpe.getUniversityFiscalYear() == null)) {
227             UniversityDate ud = universityDateService.getCurrentUniversityDate();
228 
229             glpe.setUniversityFiscalYear(ud.getUniversityFiscalYear());
230             glpe.setUniversityFiscalPeriodCode(ud.getUniversityFiscalAccountingPeriod());
231         }
232     }
233 
234     /**
235      * Invokes generateEntries method on the financial document.
236      *
237      * @param document - document whose pending entries need generated
238      * @return whether the business rules succeeded
239      */
240     @Override
241     public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySource glpeSource) {
242         boolean success = true;
243 
244         // we must clear them first before creating new ones
245         glpeSource.clearAnyGeneralLedgerPendingEntries();
246 
247         if (LOG.isDebugEnabled()) {
248             LOG.debug("deleting existing gl pending ledger entries for document " + glpeSource.getDocumentHeader().getDocumentNumber());
249         }
250         delete(glpeSource.getDocumentHeader().getDocumentNumber());
251 
252         if (LOG.isDebugEnabled()) {
253             LOG.debug("generating gl pending ledger entries for document " + glpeSource.getDocumentHeader().getDocumentNumber());
254         }
255 
256         GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper();
257         for (GeneralLedgerPendingEntrySourceDetail glpeSourceDetail : glpeSource.getGeneralLedgerPendingEntrySourceDetails()) {
258             success &= glpeSource.generateGeneralLedgerPendingEntries(glpeSourceDetail, sequenceHelper);
259             sequenceHelper.increment();
260         }
261 
262         // doc specific pending entries generation
263         success &= glpeSource.generateDocumentGeneralLedgerPendingEntries(sequenceHelper);
264 
265         return success;
266     }
267 
268     /**
269      * This populates an empty GeneralLedgerPendingEntry explicitEntry object instance with default values.
270      *
271      * @param accountingDocument
272      * @param accountingLine
273      * @param sequenceHelper
274      * @param explicitEntry
275      */
276     @Override
277     public void populateExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySource glpeSource, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntry explicitEntry) {
278         if (LOG.isDebugEnabled()) {
279             LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - start");
280         }
281 
282         explicitEntry.setFinancialDocumentTypeCode(glpeSource.getFinancialDocumentTypeCode());
283         explicitEntry.setVersionNumber(new Long(1));
284         explicitEntry.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter()));
285         Timestamp transactionTimestamp = new Timestamp(dateTimeService.getCurrentDate().getTime());
286         explicitEntry.setTransactionDate(new java.sql.Date(transactionTimestamp.getTime()));
287         explicitEntry.setTransactionEntryProcessedTs(transactionTimestamp);
288         explicitEntry.setAccountNumber(glpeSourceDetail.getAccountNumber());
289 
290         // JHK: changing implementation to work around object refresh issues
291 //        if (ObjectUtils.isNull(glpeSourceDetail.getAccount()) && getPersistenceStructureService().hasReference(glpeSourceDetail.getClass(), OLEPropertyConstants.ACCOUNT)) {
292 //            glpeSourceDetail.refreshReferenceObject(OLEPropertyConstants.ACCOUNT);
293 //        }
294 //
295 //        if ((ObjectUtils.isNull(glpeSourceDetail.getObjectCode()) || StringUtils.isBlank(glpeSourceDetail.getObjectCode().getFinancialObjectTypeCode())) && getPersistenceStructureService().hasReference(glpeSourceDetail.getClass(), OLEPropertyConstants.OBJECT_CODE)) {
296 //            glpeSourceDetail.refreshReferenceObject(OLEPropertyConstants.OBJECT_CODE);
297 //        }
298 
299         Account account = SpringContext.getBean(AccountService.class).getByPrimaryIdWithCaching(glpeSourceDetail.getChartOfAccountsCode(), glpeSourceDetail.getAccountNumber());
300         ObjectCode objectCode = SpringContext.getBean(ObjectCodeService.class).getByPrimaryIdWithCaching( glpeSource.getPostingYear(), glpeSourceDetail.getChartOfAccountsCode(), glpeSourceDetail.getFinancialObjectCode());
301 
302         if ( account != null ) {
303             if ( LOG.isDebugEnabled() ) {
304                 LOG.debug("GLPE: Testing to see what should be used for SF Object Code: " + glpeSourceDetail );
305             }
306             String sufficientFundsCode = account.getAccountSufficientFundsCode();
307             if (StringUtils.isBlank(sufficientFundsCode)) {
308                 sufficientFundsCode = OLEConstants.SF_TYPE_NO_CHECKING;
309                 if ( LOG.isDebugEnabled() ) {
310                     LOG.debug("Code was blank on the account - using 'N'");
311                 }
312             }
313 
314             if (objectCode != null) {
315                 if ( LOG.isDebugEnabled() ) {
316                     LOG.debug("SF Code / Object: " + sufficientFundsCode + " / " + objectCode);
317                 }
318                 String sifficientFundsObjectCode = SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(objectCode, sufficientFundsCode);
319                 explicitEntry.setAcctSufficientFundsFinObjCd(sifficientFundsObjectCode);
320             } else {
321                 LOG.debug( "Object code object was null, skipping setting of SF object field." );
322             }
323         }
324 
325         if ( objectCode != null ) {
326             explicitEntry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode());
327         }
328 
329         explicitEntry.setFinancialDocumentApprovedCode(GENERAL_LEDGER_PENDING_ENTRY_CODE.NO);
330         explicitEntry.setTransactionEncumbranceUpdateCode(BLANK_SPACE);
331         explicitEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_ACTUAL); // this is the default that most documents use
332         explicitEntry.setChartOfAccountsCode(glpeSourceDetail.getChartOfAccountsCode());
333         explicitEntry.setTransactionDebitCreditCode(glpeSource.isDebit(glpeSourceDetail) ? OLEConstants.GL_DEBIT_CODE : OLEConstants.GL_CREDIT_CODE);
334         explicitEntry.setFinancialSystemOriginationCode(SpringContext.getBean(HomeOriginationService.class).getHomeOrigination().getFinSystemHomeOriginationCode());
335         explicitEntry.setDocumentNumber(glpeSourceDetail.getDocumentNumber());
336         explicitEntry.setFinancialObjectCode(glpeSourceDetail.getFinancialObjectCode());
337 
338         explicitEntry.setOrganizationDocumentNumber(glpeSource.getDocumentHeader().getOrganizationDocumentNumber());
339         explicitEntry.setOrganizationReferenceId(glpeSourceDetail.getOrganizationReferenceId());
340         explicitEntry.setProjectCode(getEntryValue(glpeSourceDetail.getProjectCode(), GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankProjectCode()));
341         explicitEntry.setReferenceFinancialDocumentNumber(getEntryValue(glpeSourceDetail.getReferenceNumber(), BLANK_SPACE));
342         explicitEntry.setReferenceFinancialDocumentTypeCode(getEntryValue(glpeSourceDetail.getReferenceTypeCode(), BLANK_SPACE));
343         explicitEntry.setReferenceFinancialSystemOriginationCode(getEntryValue(glpeSourceDetail.getReferenceOriginCode(), BLANK_SPACE));
344         explicitEntry.setSubAccountNumber(getEntryValue(glpeSourceDetail.getSubAccountNumber(), GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankSubAccountNumber()));
345         explicitEntry.setFinancialSubObjectCode(getEntryValue(glpeSourceDetail.getFinancialSubObjectCode(), GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialSubObjectCode()));
346         explicitEntry.setTransactionEntryOffsetIndicator(false);
347         explicitEntry.setTransactionLedgerEntryAmount(glpeSource.getGeneralLedgerPendingEntryAmountForDetail(glpeSourceDetail));
348         explicitEntry.setTransactionLedgerEntryDescription(getEntryValue(glpeSourceDetail.getFinancialDocumentLineDescription(), glpeSource.getDocumentHeader().getDocumentDescription()));
349         explicitEntry.setUniversityFiscalPeriodCode(null); // null here, is assigned during batch or in specific document rule
350         // classes
351         explicitEntry.setUniversityFiscalYear(glpeSource.getPostingYear());
352         // TODO wait for core budget year data structures to be put in place
353         // explicitEntry.setBudgetYear(accountingLine.getBudgetYear());
354         // explicitEntry.setBudgetYearFundingSourceCode(budgetYearFundingSourceCode);
355 
356         if (LOG.isDebugEnabled()) {
357             LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - end");
358         }
359     }
360 
361     /**
362      * Convenience method to build a GLPE without a generalLedgerPendingEntrySourceDetail
363      *
364      * @param document a GeneralLedgerPostingDocument
365      * @param account the account for use in the GLPE
366      * @param objectCode the object code for use in the GLPE
367      * @param subAccountNumber the sub account number for use in the GLPE
368      * @param subObjectCode the subobject code for use in the GLPE
369      * @param organizationReferenceId the organization reference id to use in the GLPE
370      * @param projectCode the project code to use in the GLPE
371      * @param referenceNumber the reference number to use in the GLPE
372      * @param referenceTypeCode the reference type code to use in the GLPE
373      * @param referenceOriginCode the reference origin code to use in the GLPE
374      * @param description the description to put in the GLPE
375      * @param isDebit true if the GLPE represents a debit, false if it represents a credit
376      * @param amount the amount of the GLPE
377      * @param sequenceHelper the sequence helper to use
378      * @return a populated general ledger pending entry
379      */
380     @Override
381     public GeneralLedgerPendingEntry buildGeneralLedgerPendingEntry(GeneralLedgerPostingDocument document, Account account, ObjectCode objectCode, String subAccountNumber, String subObjectCode, String organizationReferenceId, String projectCode, String referenceNumber, String referenceTypeCode, String referenceOriginCode, String description, boolean isDebit, KualiDecimal amount, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
382         if (LOG.isDebugEnabled()) {
383             LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - start");
384         }
385 
386         GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
387         explicitEntry.setFinancialDocumentTypeCode(document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
388         explicitEntry.setVersionNumber(new Long(1));
389         explicitEntry.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter()));
390         Timestamp transactionTimestamp = new Timestamp(dateTimeService.getCurrentDate().getTime());
391         explicitEntry.setTransactionDate(new java.sql.Date(transactionTimestamp.getTime()));
392         explicitEntry.setTransactionEntryProcessedTs(transactionTimestamp);
393         explicitEntry.setAccountNumber(account.getAccountNumber());
394         if (account.getAccountSufficientFundsCode() == null) {
395             account.setAccountSufficientFundsCode(OLEConstants.SF_TYPE_NO_CHECKING);
396         }
397         // FIXME! - inject the sufficient funds service
398         explicitEntry.setAcctSufficientFundsFinObjCd(SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(objectCode, account.getAccountSufficientFundsCode()));
399         explicitEntry.setFinancialDocumentApprovedCode(GENERAL_LEDGER_PENDING_ENTRY_CODE.NO);
400         explicitEntry.setTransactionEncumbranceUpdateCode(BLANK_SPACE);
401         explicitEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_ACTUAL); // this is the default that most documents use
402         explicitEntry.setChartOfAccountsCode(account.getChartOfAccountsCode());
403         explicitEntry.setTransactionDebitCreditCode(isDebit ? OLEConstants.GL_DEBIT_CODE : OLEConstants.GL_CREDIT_CODE);
404         // FIXME! - Home origination service should be injected and the result cached - this value never changes
405         explicitEntry.setFinancialSystemOriginationCode(SpringContext.getBean(HomeOriginationService.class).getHomeOrigination().getFinSystemHomeOriginationCode());
406         explicitEntry.setDocumentNumber(document.getDocumentNumber());
407         explicitEntry.setFinancialObjectCode(objectCode.getFinancialObjectCode());
408         explicitEntry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode());
409         explicitEntry.setOrganizationDocumentNumber(document.getDocumentHeader().getOrganizationDocumentNumber());
410         explicitEntry.setOrganizationReferenceId(organizationReferenceId);
411         explicitEntry.setProjectCode(getEntryValue(projectCode, GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankProjectCode()));
412         explicitEntry.setReferenceFinancialDocumentNumber(getEntryValue(referenceNumber, BLANK_SPACE));
413         explicitEntry.setReferenceFinancialDocumentTypeCode(getEntryValue(referenceTypeCode, BLANK_SPACE));
414         explicitEntry.setReferenceFinancialSystemOriginationCode(getEntryValue(referenceOriginCode, BLANK_SPACE));
415         explicitEntry.setSubAccountNumber(getEntryValue(subAccountNumber, GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankSubAccountNumber()));
416         explicitEntry.setFinancialSubObjectCode(getEntryValue(subObjectCode, GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialSubObjectCode()));
417         explicitEntry.setTransactionEntryOffsetIndicator(false);
418         explicitEntry.setTransactionLedgerEntryAmount(amount);
419         explicitEntry.setTransactionLedgerEntryDescription(getEntryValue(description, document.getDocumentHeader().getDocumentDescription()));
420         explicitEntry.setUniversityFiscalPeriodCode(null); // null here, is assigned during batch or in specific document rule
421         // classes
422         explicitEntry.setUniversityFiscalYear(document.getPostingYear());
423 
424         if (LOG.isDebugEnabled()) {
425             LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - end");
426         }
427 
428         return explicitEntry;
429     }
430 
431     /**
432      * This populates an GeneralLedgerPendingEntry offsetEntry object instance with values that differ from the values supplied in
433      * the explicit entry that it was cloned from. Note that the entries do not contain BOs now.
434      *
435      * @param universityFiscalYear
436      * @param explicitEntry
437      * @param sequenceHelper
438      * @param offsetEntry Cloned from the explicit entry
439      * @return whether the offset generation is successful
440      */
441     @Override
442     public boolean populateOffsetGeneralLedgerPendingEntry(Integer universityFiscalYear, GeneralLedgerPendingEntry explicitEntry, GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntry offsetEntry) {
443         LOG.debug("populateOffsetGeneralLedgerPendingEntry(Integer, GeneralLedgerPendingEntry, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - start");
444 
445         boolean success = true;
446 
447         // lookup offset object info
448         // FIXME! - OffsetDefinitionService should be injected (and probably cache the result)
449         OffsetDefinition offsetDefinition = SpringContext.getBean(OffsetDefinitionService.class).getByPrimaryId(universityFiscalYear, explicitEntry.getChartOfAccountsCode(), explicitEntry.getFinancialDocumentTypeCode(), explicitEntry.getFinancialBalanceTypeCode());
450         if (ObjectUtils.isNull(offsetDefinition)) {
451             success = false;
452             GlobalVariables.getMessageMap().putError(OLEConstants.GENERAL_LEDGER_PENDING_ENTRIES_TAB_ERRORS, OLEKeyConstants.ERROR_DOCUMENT_NO_OFFSET_DEFINITION, universityFiscalYear.toString(), explicitEntry.getChartOfAccountsCode(), explicitEntry.getFinancialDocumentTypeCode(), explicitEntry.getFinancialBalanceTypeCode());
453         }
454         else {
455             // FIXME! - FlexibleOffsetAccountService should be injected
456             OffsetAccount flexibleOffsetAccount = SpringContext.getBean(FlexibleOffsetAccountService.class).getByPrimaryIdIfEnabled(explicitEntry.getChartOfAccountsCode(), explicitEntry.getAccountNumber(), getOffsetFinancialObjectCode(offsetDefinition));
457             flexOffsetAccountIfNecessary(flexibleOffsetAccount, offsetEntry);
458         }
459 
460         // update offset entry fields that are different from the explicit entry that it was created from
461         offsetEntry.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter()));
462         offsetEntry.setTransactionDebitCreditCode(getOffsetEntryDebitCreditCode(explicitEntry));
463 
464         String offsetObjectCode = getOffsetFinancialObjectCode(offsetDefinition);
465         offsetEntry.setFinancialObjectCode(offsetObjectCode);
466         if (offsetObjectCode.equals(AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectCode())) {
467             // no BO, so punt
468             offsetEntry.setAcctSufficientFundsFinObjCd(AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectCode());
469         }
470         else {
471             // Need current ObjectCode and Account BOs to get sufficient funds code. (Entries originally have no BOs.)
472             // todo: private or other methods to get these BOs, instead of using the entry and leaving some BOs filled in?
473             offsetEntry.refreshReferenceObject(OLEPropertyConstants.FINANCIAL_OBJECT);
474             offsetEntry.refreshReferenceObject(OLEPropertyConstants.ACCOUNT);
475             ObjectCode financialObject = offsetEntry.getFinancialObject();
476             // The ObjectCode reference may be invalid because a flexible offset account changed its chart code.
477             if (ObjectUtils.isNull(financialObject)) {
478                 throw new RuntimeException("offset object code " + offsetEntry.getUniversityFiscalYear() + "-" + offsetEntry.getChartOfAccountsCode() + "-" + offsetEntry.getFinancialObjectCode());
479             }
480             // FIXME! - inject the sufficient funds service
481             Account account = SpringContext.getBean(AccountService.class).getByPrimaryIdWithCaching(offsetEntry.getChartOfAccountsCode(), offsetEntry.getAccountNumber());
482             offsetEntry.setAcctSufficientFundsFinObjCd(SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(financialObject, account.getAccountSufficientFundsCode()));
483         }
484 
485         offsetEntry.setFinancialObjectTypeCode(getOffsetFinancialObjectTypeCode(offsetDefinition));
486         offsetEntry.setFinancialSubObjectCode(OLEConstants.getDashFinancialSubObjectCode());
487         offsetEntry.setTransactionEntryOffsetIndicator(true);
488         offsetEntry.setTransactionLedgerEntryDescription(OLEConstants.GL_PE_OFFSET_STRING);
489         offsetEntry.setFinancialSystemOriginationCode(explicitEntry.getFinancialSystemOriginationCode());
490 
491         LOG.debug("populateOffsetGeneralLedgerPendingEntry(Integer, GeneralLedgerPendingEntry, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - end");
492         return success;
493     }
494 
495     /**
496      * Applies the given flexible offset account to the given offset entry. Does nothing if flexibleOffsetAccount is null or its COA
497      * and account number are the same as the offset entry's.
498      *
499      * @param flexibleOffsetAccount may be null
500      * @param offsetEntry may be modified
501      */
502     protected void flexOffsetAccountIfNecessary(OffsetAccount flexibleOffsetAccount, GeneralLedgerPendingEntry offsetEntry) {
503         LOG.debug("flexOffsetAccountIfNecessary(OffsetAccount, GeneralLedgerPendingEntry) - start");
504 
505         if (flexibleOffsetAccount == null) {
506             LOG.debug("flexOffsetAccountIfNecessary(OffsetAccount, GeneralLedgerPendingEntry) - end");
507             return; // They are not required and may also be disabled.
508         }
509         String flexCoa = flexibleOffsetAccount.getFinancialOffsetChartOfAccountCode();
510         String flexAccountNumber = flexibleOffsetAccount.getFinancialOffsetAccountNumber();
511         if (flexCoa.equals(offsetEntry.getChartOfAccountsCode()) && flexAccountNumber.equals(offsetEntry.getAccountNumber())) {
512             LOG.debug("flexOffsetAccountIfNecessary(OffsetAccount, GeneralLedgerPendingEntry) - end");
513             return; // no change, so leave sub-account as is
514         }
515         if (ObjectUtils.isNull(flexibleOffsetAccount.getFinancialOffsetAccount())) {
516             throw new RuntimeException("flexible offset account " + flexCoa + "-" + flexAccountNumber);
517         }
518         offsetEntry.setChartOfAccountsCode(flexCoa);
519         offsetEntry.setAccountNumber(flexAccountNumber);
520         // COA and account number are part of the sub-account's key, so the original sub-account would be invalid.
521         offsetEntry.setSubAccountNumber(OLEConstants.getDashSubAccountNumber());
522 
523         LOG.debug("flexOffsetAccountIfNecessary(OffsetAccount, GeneralLedgerPendingEntry) - end");
524     }
525 
526     /**
527      * Helper method that determines the offset entry's financial object type code.
528      *
529      * @param offsetDefinition
530      * @return String
531      */
532     protected String getOffsetFinancialObjectTypeCode(OffsetDefinition offsetDefinition) {
533         LOG.debug("getOffsetFinancialObjectTypeCode(OffsetDefinition) - start");
534 
535         if (null != offsetDefinition && null != offsetDefinition.getFinancialObject()) {
536             String returnString = getEntryValue(offsetDefinition.getFinancialObject().getFinancialObjectTypeCode(), AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectType());
537             LOG.debug("getOffsetFinancialObjectTypeCode(OffsetDefinition) - end");
538             return returnString;
539         }
540         else {
541             LOG.debug("getOffsetFinancialObjectTypeCode(OffsetDefinition) - end");
542             return AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectType();
543         }
544 
545     }
546 
547     /**
548      * Helper method that determines the debit/credit code for the offset entry. If the explicit was a debit, the offset is a
549      * credit. Otherwise, it's opposite.
550      *
551      * @param explicitEntry
552      * @return String
553      */
554     protected String getOffsetEntryDebitCreditCode(GeneralLedgerPendingEntry explicitEntry) {
555         LOG.debug("getOffsetEntryDebitCreditCode(GeneralLedgerPendingEntry) - start");
556 
557         String offsetDebitCreditCode = OLEConstants.GL_BUDGET_CODE;
558         if (OLEConstants.GL_DEBIT_CODE.equals(explicitEntry.getTransactionDebitCreditCode())) {
559             offsetDebitCreditCode = OLEConstants.GL_CREDIT_CODE;
560         }
561         else if (OLEConstants.GL_CREDIT_CODE.equals(explicitEntry.getTransactionDebitCreditCode())) {
562             offsetDebitCreditCode = OLEConstants.GL_DEBIT_CODE;
563         }
564 
565         LOG.debug("getOffsetEntryDebitCreditCode(GeneralLedgerPendingEntry) - end");
566         return offsetDebitCreditCode;
567     }
568 
569     /**
570      * Helper method that determines the offset entry's financial object code.
571      *
572      * @param offsetDefinition
573      * @return String
574      */
575     protected String getOffsetFinancialObjectCode(OffsetDefinition offsetDefinition) {
576         LOG.debug("getOffsetFinancialObjectCode(OffsetDefinition) - start");
577 
578         if (null != offsetDefinition) {
579             String returnString = getEntryValue(offsetDefinition.getFinancialObjectCode(), AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectCode());
580             LOG.debug("getOffsetFinancialObjectCode(OffsetDefinition) - end");
581             return returnString;
582         }
583         else {
584             LOG.debug("getOffsetFinancialObjectCode(OffsetDefinition) - end");
585             return AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectCode();
586         }
587 
588     }
589 
590     /**
591      * This populates an empty GeneralLedgerPendingEntry instance with default values for a bank offset. A global error will be
592      * posted as a side-effect if the given bank has not defined the necessary bank offset relations.
593      *
594      * @param bank
595      * @param depositAmount
596      * @param financialDocument
597      * @param universityFiscalYear
598      * @param sequenceHelper
599      * @param bankOffsetEntry
600      * @param errorPropertyName
601      * @return whether the entry was populated successfully
602      */
603     @Override
604     public boolean populateBankOffsetGeneralLedgerPendingEntry(Bank bank, KualiDecimal depositAmount, GeneralLedgerPostingDocument financialDocument, Integer universityFiscalYear, GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntry bankOffsetEntry, String errorPropertyName) {
605         bankOffsetEntry.setFinancialDocumentTypeCode(dataDictionaryService.getDocumentTypeNameByClass(financialDocument.getClass()));
606         bankOffsetEntry.setVersionNumber(1L);
607         bankOffsetEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter());
608         Timestamp transactionTimestamp = new Timestamp(dateTimeService.getCurrentDate().getTime());
609         bankOffsetEntry.setTransactionDate(new java.sql.Date(transactionTimestamp.getTime()));
610         bankOffsetEntry.setTransactionEntryProcessedTs(transactionTimestamp);
611         Account cashOffsetAccount = bank.getCashOffsetAccount();
612 
613         if (ObjectUtils.isNull(cashOffsetAccount)) {
614             GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_NO_ACCOUNT, new String[] { bank.getBankCode() });
615             return false;
616         }
617 
618         if (!cashOffsetAccount.isActive()) {
619             GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_ACCOUNT_CLOSED, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber() });
620             return false;
621         }
622 
623         if (cashOffsetAccount.isExpired()) {
624             GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_ACCOUNT_EXPIRED, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber() });
625             return false;
626         }
627 
628         bankOffsetEntry.setChartOfAccountsCode(bank.getCashOffsetFinancialChartOfAccountCode());
629         bankOffsetEntry.setAccountNumber(bank.getCashOffsetAccountNumber());
630         bankOffsetEntry.setFinancialDocumentApprovedCode(AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.NO);
631         bankOffsetEntry.setTransactionEncumbranceUpdateCode(BLANK_SPACE);
632         bankOffsetEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_ACTUAL);
633         bankOffsetEntry.setTransactionDebitCreditCode(depositAmount.isPositive() ? GL_DEBIT_CODE : GL_CREDIT_CODE);
634         bankOffsetEntry.setFinancialSystemOriginationCode(SpringContext.getBean(HomeOriginationService.class).getHomeOrigination().getFinSystemHomeOriginationCode());
635         bankOffsetEntry.setDocumentNumber(financialDocument.getDocumentNumber());
636 
637         ObjectCode cashOffsetObject = bank.getCashOffsetObject();
638         if (ObjectUtils.isNull(cashOffsetObject)) {
639             GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_NO_OBJECT_CODE, new String[] { bank.getBankCode() });
640             return false;
641         }
642 
643         if (!cashOffsetObject.isFinancialObjectActiveCode()) {
644             GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_INACTIVE_OBJECT_CODE, new String[] { bank.getBankCode(), cashOffsetObject.getFinancialObjectCode() });
645             return false;
646         }
647 
648         bankOffsetEntry.setFinancialObjectCode(bank.getCashOffsetObjectCode());
649         bankOffsetEntry.setFinancialObjectTypeCode(bank.getCashOffsetObject().getFinancialObjectTypeCode());
650         bankOffsetEntry.setOrganizationDocumentNumber(financialDocument.getDocumentHeader().getOrganizationDocumentNumber());
651         bankOffsetEntry.setOrganizationReferenceId(null);
652         bankOffsetEntry.setProjectCode(OLEConstants.getDashProjectCode());
653         bankOffsetEntry.setReferenceFinancialDocumentNumber(null);
654         bankOffsetEntry.setReferenceFinancialDocumentTypeCode(null);
655         bankOffsetEntry.setReferenceFinancialSystemOriginationCode(null);
656 
657         if (StringUtils.isBlank(bank.getCashOffsetSubAccountNumber())) {
658             bankOffsetEntry.setSubAccountNumber(OLEConstants.getDashSubAccountNumber());
659         }
660         else {
661             SubAccount cashOffsetSubAccount = bank.getCashOffsetSubAccount();
662             if (ObjectUtils.isNull(cashOffsetSubAccount)) {
663                 GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_NONEXISTENT_SUB_ACCOUNT, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber(), bank.getCashOffsetSubAccountNumber() });
664                 return false;
665             }
666 
667             if (!cashOffsetSubAccount.isActive()) {
668                 GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_INACTIVE_SUB_ACCOUNT, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber(), bank.getCashOffsetSubAccountNumber() });
669                 return false;
670             }
671 
672             bankOffsetEntry.setSubAccountNumber(bank.getCashOffsetSubAccountNumber());
673         }
674 
675         if (StringUtils.isBlank(bank.getCashOffsetSubObjectCode())) {
676             bankOffsetEntry.setFinancialSubObjectCode(OLEConstants.getDashFinancialSubObjectCode());
677         }
678         else {
679             SubObjectCode cashOffsetSubObject = bank.getCashOffsetSubObject();
680             if (ObjectUtils.isNull(cashOffsetSubObject)) {
681                 GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_NONEXISTENT_SUB_OBJ, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber(), cashOffsetObject.getFinancialObjectCode(), bank.getCashOffsetSubObjectCode() });
682                 return false;
683             }
684 
685             if (!cashOffsetSubObject.isActive()) {
686                 GlobalVariables.getMessageMap().putError(errorPropertyName, OLEKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_INACTIVE_SUB_OBJ, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber(), cashOffsetObject.getFinancialObjectCode(), bank.getCashOffsetSubObjectCode() });
687                 return false;
688             }
689 
690             bankOffsetEntry.setFinancialSubObjectCode(bank.getCashOffsetSubObjectCode());
691         }
692 
693         bankOffsetEntry.setTransactionEntryOffsetIndicator(true);
694         bankOffsetEntry.setTransactionLedgerEntryAmount(depositAmount.abs());
695         bankOffsetEntry.setUniversityFiscalPeriodCode(null); // null here, is assigned during batch or in specific document rule
696         bankOffsetEntry.setUniversityFiscalYear(universityFiscalYear);
697         bankOffsetEntry.setAcctSufficientFundsFinObjCd(SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(cashOffsetObject, cashOffsetAccount.getAccountSufficientFundsCode()));
698 
699         return true;
700     }
701 
702     /**
703      * @see org.kuali.ole.sys.service.GeneralLedgerPendingEntryService#save(org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry)
704      */
705     @Override
706     public void save(GeneralLedgerPendingEntry generalLedgerPendingEntry) {
707         LOG.debug("save() started");
708         SpringContext.getBean(BusinessObjectService.class).save(generalLedgerPendingEntry);
709     }
710 
711     @Override
712     public void delete(String documentHeaderId) {
713         LOG.debug("delete() started");
714 
715         this.generalLedgerPendingEntryDao.delete(documentHeaderId);
716     }
717 
718     @Override
719     public void deleteByFinancialDocumentApprovedCode(String financialDocumentApprovedCode) {
720         LOG.debug("deleteByFinancialDocumentApprovedCode() started");
721 
722         this.generalLedgerPendingEntryDao.deleteByFinancialDocumentApprovedCode(financialDocumentApprovedCode);
723     }
724 
725     /**
726      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findApprovedPendingLedgerEntries()
727      */
728     @Override
729     public Iterator findApprovedPendingLedgerEntries() {
730         LOG.debug("findApprovedPendingLedgerEntries() started");
731 
732         return generalLedgerPendingEntryDao.findApprovedPendingLedgerEntries();
733     }
734 
735     /**
736      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntries(org.kuali.ole.gl.businessobject.Encumbrance,
737      *      boolean)
738      */
739     @Override
740     public Iterator findPendingLedgerEntries(Encumbrance encumbrance, boolean isApproved) {
741         LOG.debug("findPendingLedgerEntries() started");
742 
743         return generalLedgerPendingEntryDao.findPendingLedgerEntries(encumbrance, isApproved);
744     }
745 
746     /**
747      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#hasPendingGeneralLedgerEntry(org.kuali.ole.coa.businessobject.Account)
748      */
749     @Override
750     public boolean hasPendingGeneralLedgerEntry(Account account) {
751         LOG.debug("hasPendingGeneralLedgerEntry() started");
752 
753         return generalLedgerPendingEntryDao.countPendingLedgerEntries(account) > 0;
754     }
755 
756     /**
757      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntries(Balance, boolean, boolean)
758      */
759     @Override
760     public Iterator findPendingLedgerEntries(Balance balance, boolean isApproved, boolean isConsolidated) {
761         LOG.debug("findPendingLedgerEntries() started");
762 
763         return generalLedgerPendingEntryDao.findPendingLedgerEntries(balance, isApproved, isConsolidated);
764     }
765 
766     /**
767      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForEntry(java.util.Map, boolean)
768      */
769     @Override
770     public Iterator findPendingLedgerEntriesForEntry(Map fieldValues, boolean isApproved) {
771         LOG.debug("findPendingLedgerEntriesForEntry() started");
772 
773         UniversityDate currentUniversityDate = universityDateService.getCurrentUniversityDate();
774         String currentFiscalPeriodCode = currentUniversityDate.getUniversityFiscalAccountingPeriod();
775         Integer currentFiscalYear = currentUniversityDate.getUniversityFiscalYear();
776         List<String> encumbranceBalanceTypes = getEncumbranceBalanceTypes(fieldValues, currentFiscalYear);
777 
778         return generalLedgerPendingEntryDao.findPendingLedgerEntriesForEntry(fieldValues, isApproved, currentFiscalPeriodCode, currentFiscalYear, encumbranceBalanceTypes);
779     }
780 
781     /**
782      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForEncumbrance(Map, boolean)
783      */
784     @Override
785     public Iterator findPendingLedgerEntriesForEncumbrance(Map fieldValues, boolean isApproved) {
786         LOG.debug("findPendingLedgerEntriesForEncumbrance() started");
787 
788         UniversityDate currentUniversityDate = universityDateService.getCurrentUniversityDate();
789         String currentFiscalPeriodCode = currentUniversityDate.getUniversityFiscalAccountingPeriod();
790         Integer currentFiscalYear = currentUniversityDate.getUniversityFiscalYear();
791         SystemOptions currentYearOptions = optionsService.getCurrentYearOptions();
792         List<String> encumbranceBalanceTypes = getEncumbranceBalanceTypes(fieldValues, currentFiscalYear);
793 
794         return generalLedgerPendingEntryDao.findPendingLedgerEntriesForEncumbrance(fieldValues, isApproved, currentFiscalPeriodCode, currentFiscalYear, currentYearOptions, encumbranceBalanceTypes);
795     }
796 
797     /**
798      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForCashBalance(java.util.Map,
799      *      boolean)
800      */
801     @Override
802     public Iterator findPendingLedgerEntriesForCashBalance(Map fieldValues, boolean isApproved) {
803         LOG.debug("findPendingLedgerEntriesForCashBalance() started");
804 
805         UniversityDate currentUniversityDate = universityDateService.getCurrentUniversityDate();
806         String currentFiscalPeriodCode = currentUniversityDate.getUniversityFiscalAccountingPeriod();
807         Integer currentFiscalYear = currentUniversityDate.getUniversityFiscalYear();
808         List<String> encumbranceBalanceTypes = getEncumbranceBalanceTypes(fieldValues, currentFiscalYear);
809 
810         return generalLedgerPendingEntryDao.findPendingLedgerEntriesForCashBalance(fieldValues, isApproved, currentFiscalPeriodCode, currentFiscalYear, encumbranceBalanceTypes);
811     }
812 
813     /**
814      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForBalance(java.util.Map, boolean)
815      */
816     @Override
817     public Iterator findPendingLedgerEntriesForBalance(Map fieldValues, boolean isApproved) {
818         LOG.debug("findPendingLedgerEntriesForBalance() started");
819 
820         UniversityDate currentUniversityDate = universityDateService.getCurrentUniversityDate();
821         String currentFiscalPeriodCode = currentUniversityDate.getUniversityFiscalAccountingPeriod();
822         Integer currentFiscalYear = currentUniversityDate.getUniversityFiscalYear();
823         List<String> encumbranceBalanceTypes = getEncumbranceBalanceTypes(fieldValues, currentFiscalYear);
824 
825         return generalLedgerPendingEntryDao.findPendingLedgerEntriesForBalance(fieldValues, isApproved, currentFiscalPeriodCode, currentFiscalYear, encumbranceBalanceTypes);
826     }
827 
828     /**
829      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForAccountBalance(java.util.Map,
830      *      boolean, boolean)
831      */
832     @Override
833     public Iterator findPendingLedgerEntriesForAccountBalance(Map fieldValues, boolean isApproved) {
834         LOG.debug("findPendingLedgerEntriesForAccountBalance() started");
835 
836         UniversityDate currentUniversityDate = universityDateService.getCurrentUniversityDate();
837         String currentFiscalPeriodCode = currentUniversityDate.getUniversityFiscalAccountingPeriod();
838         Integer currentFiscalYear = currentUniversityDate.getUniversityFiscalYear();
839         List<String> encumbranceBalanceTypes = getEncumbranceBalanceTypes(fieldValues, currentFiscalYear);
840 
841         return generalLedgerPendingEntryDao.findPendingLedgerEntriesForAccountBalance(fieldValues, isApproved, currentFiscalPeriodCode, currentFiscalYear, encumbranceBalanceTypes);
842     }
843 
844     /**
845      * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntrySummaryForAccountBalance(java.util.Map,
846      *      boolean, boolean)
847      */
848     @Override
849     public Iterator findPendingLedgerEntrySummaryForAccountBalance(Map fieldValues, boolean isApproved) {
850         LOG.debug("findPendingLedgerEntrySummaryForAccountBalance() started");
851 
852         UniversityDate currentUniversityDate = universityDateService.getCurrentUniversityDate();
853         String currentFiscalPeriodCode = currentUniversityDate.getUniversityFiscalAccountingPeriod();
854         Integer currentFiscalYear = currentUniversityDate.getUniversityFiscalYear();
855         List<String> encumbranceBalanceTypes = getEncumbranceBalanceTypes(fieldValues, currentFiscalYear);
856 
857         return generalLedgerPendingEntryDao.findPendingLedgerEntrySummaryForAccountBalance(fieldValues, isApproved, currentFiscalPeriodCode, currentFiscalYear, encumbranceBalanceTypes);
858     }
859 
860     @Override
861     public Collection findPendingEntries(Map fieldValues, boolean isApproved) {
862         LOG.debug("findPendingEntries() started");
863 
864         UniversityDate currentUniversityDate = universityDateService.getCurrentUniversityDate();
865         String currentFiscalPeriodCode = currentUniversityDate.getUniversityFiscalAccountingPeriod();
866         Integer currentFiscalYear = currentUniversityDate.getUniversityFiscalYear();
867         List<String> encumbranceBalanceTypes = getEncumbranceBalanceTypes(fieldValues, currentFiscalYear);
868 
869         return generalLedgerPendingEntryDao.findPendingEntries(fieldValues, isApproved, currentFiscalPeriodCode, currentFiscalYear, encumbranceBalanceTypes);
870     }
871 
872     /**
873      * A helper method that checks the intended target value for null and empty strings. If the intended target value is not null or
874      * an empty string, it returns that value, ohterwise, it returns a backup value.
875      *
876      * @param targetValue
877      * @param backupValue
878      * @return String
879      */
880     protected final String getEntryValue(String targetValue, String backupValue) {
881         LOG.debug("getEntryValue(String, String) - start");
882 
883         if (StringUtils.isNotBlank(targetValue)) {
884             LOG.debug("getEntryValue(String, String) - end");
885             return targetValue;
886         }
887         else {
888             LOG.debug("getEntryValue(String, String) - end");
889             return backupValue;
890         }
891     }
892 
893     /**
894      * Determines if the given GeneralLedgerPendingEntry represents offsets to cash
895      *
896      * @param generalLedgerPendingEntry the GeneralLedgerPendingEntry to check
897      * @return true if the GeneralLedgerPendingEntry represents an offset to cash; false otherwise
898      */
899     @Override
900     public boolean isOffsetToCash(GeneralLedgerPendingEntry generalLedgerPendingEntry) {
901         if (generalLedgerPendingEntry.isTransactionEntryOffsetIndicator()) {
902             final Chart entryChart = chartService.getByPrimaryId(generalLedgerPendingEntry.getChartOfAccountsCode());
903             if (!ObjectUtils.isNull(entryChart)) {
904                 return (entryChart.getFinancialCashObjectCode().equals(generalLedgerPendingEntry.getFinancialObjectCode()));
905             }
906         }
907         return false;
908     }
909 
910     /**
911      * Adds up the amounts of all cash to offset GeneralLedgerPendingEntry records on the given AccountingDocument
912      *
913      * @param glPostingDocument the accounting document total the offset to cash amount for
914      * @return the offset to cash amount, where debited values have been subtracted and credited values have been added
915      */
916     @Override
917     public KualiDecimal getOffsetToCashAmount(GeneralLedgerPostingDocument glPostingDocument) {
918         KualiDecimal total = KualiDecimal.ZERO;
919         for (GeneralLedgerPendingEntry glpe : glPostingDocument.getGeneralLedgerPendingEntries()) {
920             if (isOffsetToCash(glpe)) {
921                 if (glpe.getTransactionDebitCreditCode().equals(OLEConstants.GL_DEBIT_CODE)) {
922                     total = total.subtract(glpe.getTransactionLedgerEntryAmount());
923                 }
924                 else if (glpe.getTransactionDebitCreditCode().equals(OLEConstants.GL_CREDIT_CODE)) {
925                     total = total.add(glpe.getTransactionLedgerEntryAmount());
926                 }
927             }
928         }
929         return total;
930     }
931 
932     /**
933      * @see org.kuali.ole.sys.service.GeneralLedgerPendingEntryService#getEncumbranceBalanceTypes(java.util.Map, java.lang.Integer)
934      */
935     @Override
936     public List<String> getEncumbranceBalanceTypes(Map fieldValues, Integer currentFiscalYear) {
937 
938         String fiscalYearFromForm = null;
939         if (fieldValues.containsKey(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR)) {
940             fiscalYearFromForm = (String) fieldValues.get(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR);
941         }
942         boolean includeNullFiscalYearInLookup = null != currentFiscalYear && currentFiscalYear.toString().equals(fiscalYearFromForm);
943 
944         // handle encumbrance balance type
945         Map<String, Object> localFieldValues = new HashMap();
946         localFieldValues.putAll(fieldValues);
947 
948         if (includeNullFiscalYearInLookup) {
949             localFieldValues.remove(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR);
950         }
951 
952         // parse the fiscal year (it's not a required field on the lookup screens
953         String universityFiscalYearStr = (String) localFieldValues.get(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR);
954         if (StringUtils.isNotBlank(universityFiscalYearStr)) {
955             Integer universityFiscalYear = new Integer(universityFiscalYearStr);
956             return balanceTypeService.getEncumbranceBalanceTypes(universityFiscalYear);
957         }
958         else {
959             return balanceTypeService.getCurrentYearEncumbranceBalanceTypes();
960         }
961 
962     }
963 
964     public void setBalanceTypeService(BalanceTypeService balanceTypeService) {
965         this.balanceTypeService = balanceTypeService;
966     }
967 
968     public void setChartService(ChartService chartService) {
969         this.chartService = chartService;
970     }
971 
972     public void setGeneralLedgerPendingEntryDao(GeneralLedgerPendingEntryDao generalLedgerPendingEntryDao) {
973         this.generalLedgerPendingEntryDao = generalLedgerPendingEntryDao;
974     }
975 
976     public void setParameterService(ParameterService parameterService) {
977         this.parameterService = parameterService;
978     }
979 
980     public void setKualiRuleService(KualiRuleService kualiRuleService) {
981         this.kualiRuleService = kualiRuleService;
982     }
983 
984     public void setOptionsService(OptionsService optionsService) {
985         this.optionsService = optionsService;
986     }
987 
988     /**
989      * Sets the dateTimeService attribute value.
990      *
991      * @param dateTimeService The dateTimeService to set.
992      */
993     public void setDateTimeService(DateTimeService dateTimeService) {
994         this.dateTimeService = dateTimeService;
995     }
996 
997     /**
998      * Sets the dataDictionaryService attribute value.
999      *
1000      * @param dataDictionaryService The dataDictionaryService to set.
1001      */
1002     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
1003         this.dataDictionaryService = dataDictionaryService;
1004     }
1005 
1006     /**
1007      * Gets the persistenceStructureService attribute.
1008      *
1009      * @return Returns the persistenceStructureService.
1010      */
1011     public PersistenceStructureService getPersistenceStructureService() {
1012         return persistenceStructureService;
1013     }
1014 
1015     /**
1016      * Sets the persistenceStructureService attribute value.
1017      *
1018      * @param persistenceStructureService The persistenceStructureService to set.
1019      */
1020     public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
1021         this.persistenceStructureService = persistenceStructureService;
1022     }
1023 
1024     /**
1025      * Sets the universityDateService.
1026      *
1027      * @param universityDateService
1028      */
1029     public void setUniversityDateService(UniversityDateService universityDateService) {
1030         this.universityDateService = universityDateService;
1031     }
1032 }