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.sys.service.impl;
017    
018    import static org.kuali.kfs.sys.KFSConstants.BALANCE_TYPE_ACTUAL;
019    import static org.kuali.kfs.sys.KFSConstants.BLANK_SPACE;
020    import static org.kuali.kfs.sys.KFSConstants.GL_CREDIT_CODE;
021    import static org.kuali.kfs.sys.KFSConstants.GL_DEBIT_CODE;
022    
023    import java.sql.Timestamp;
024    import java.util.ArrayList;
025    import java.util.Collection;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.Map;
029    
030    import org.apache.commons.lang.StringUtils;
031    import org.kuali.kfs.coa.businessobject.Account;
032    import org.kuali.kfs.coa.businessobject.Chart;
033    import org.kuali.kfs.coa.businessobject.ObjectCode;
034    import org.kuali.kfs.coa.businessobject.OffsetDefinition;
035    import org.kuali.kfs.coa.businessobject.SubAccount;
036    import org.kuali.kfs.coa.businessobject.SubObjectCode;
037    import org.kuali.kfs.coa.service.BalanceTypeService;
038    import org.kuali.kfs.coa.service.ChartService;
039    import org.kuali.kfs.coa.service.ObjectTypeService;
040    import org.kuali.kfs.coa.service.OffsetDefinitionService;
041    import org.kuali.kfs.fp.businessobject.OffsetAccount;
042    import org.kuali.kfs.gl.businessobject.Balance;
043    import org.kuali.kfs.gl.businessobject.Encumbrance;
044    import org.kuali.kfs.gl.service.SufficientFundsService;
045    import org.kuali.kfs.gl.service.SufficientFundsServiceConstants;
046    import org.kuali.kfs.sys.KFSConstants;
047    import org.kuali.kfs.sys.KFSKeyConstants;
048    import org.kuali.kfs.sys.KFSPropertyConstants;
049    import org.kuali.kfs.sys.businessobject.Bank;
050    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
051    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
052    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
053    import org.kuali.kfs.sys.businessobject.SystemOptions;
054    import org.kuali.kfs.sys.businessobject.UniversityDate;
055    import org.kuali.kfs.sys.context.SpringContext;
056    import org.kuali.kfs.sys.dataaccess.GeneralLedgerPendingEntryDao;
057    import org.kuali.kfs.sys.document.AccountingDocument;
058    import org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource;
059    import org.kuali.kfs.sys.document.GeneralLedgerPostingDocument;
060    import org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBaseConstants;
061    import org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE;
062    import org.kuali.kfs.sys.service.FlexibleOffsetAccountService;
063    import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
064    import org.kuali.kfs.sys.service.HomeOriginationService;
065    import org.kuali.kfs.sys.service.OptionsService;
066    import org.kuali.kfs.sys.service.UniversityDateService;
067    import org.kuali.rice.kns.exception.ReferentialIntegrityException;
068    import org.kuali.rice.kns.service.DataDictionaryService;
069    import org.kuali.rice.kns.service.DateTimeService;
070    import org.kuali.rice.kns.service.KualiRuleService;
071    import org.kuali.rice.kns.service.ParameterService;
072    import org.kuali.rice.kns.service.PersistenceStructureService;
073    import org.kuali.rice.kns.util.GlobalVariables;
074    import org.kuali.rice.kns.util.KualiDecimal;
075    import org.kuali.rice.kns.util.ObjectUtils;
076    import org.springframework.transaction.annotation.Transactional;
077    
078    /**
079     * This class is the service implementation for the GeneralLedgerPendingEntry structure. This is the default implementation, that is
080     * delivered with Kuali.
081     */
082    @Transactional
083    public class GeneralLedgerPendingEntryServiceImpl implements GeneralLedgerPendingEntryService {
084        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(GeneralLedgerPendingEntryServiceImpl.class);
085    
086        private GeneralLedgerPendingEntryDao generalLedgerPendingEntryDao;
087        private KualiRuleService kualiRuleService;
088        private ChartService chartService;
089        private OptionsService optionsService;
090        private ParameterService parameterService;
091        private BalanceTypeService balanceTypeService;
092        private DateTimeService dateTimeService;
093        private DataDictionaryService dataDictionaryService;
094        private PersistenceStructureService persistenceStructureService;
095    
096        /**
097         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getExpenseSummary(java.util.List, java.lang.String,
098         *      java.lang.String, boolean, boolean)
099         */
100        public KualiDecimal getExpenseSummary(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String sufficientFundsObjectCode, boolean isDebit, boolean isYearEnd) {
101            LOG.debug("getExpenseSummary() started");
102    
103            ObjectTypeService objectTypeService = (ObjectTypeService) SpringContext.getBean(ObjectTypeService.class);
104            List<String> objectTypes = objectTypeService.getExpenseObjectTypes(universityFiscalYear);
105    
106            SystemOptions options = optionsService.getOptions(universityFiscalYear);
107    
108            Collection balanceTypeCodes = new ArrayList();
109            balanceTypeCodes.add(options.getActualFinancialBalanceTypeCd());
110    
111            return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYear, chartOfAccountsCode, accountNumber, objectTypes, balanceTypeCodes, sufficientFundsObjectCode, isDebit, isYearEnd);
112        }
113    
114        /**
115         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getEncumbranceSummary(java.lang.Integer, java.lang.String,
116         *      java.lang.String, java.lang.String, boolean, boolean)
117         */
118        public KualiDecimal getEncumbranceSummary(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String sufficientFundsObjectCode, boolean isDebit, boolean isYearEnd) {
119            LOG.debug("getEncumbranceSummary() started");
120    
121            ObjectTypeService objectTypeService = (ObjectTypeService) SpringContext.getBean(ObjectTypeService.class);
122            List<String> objectTypes = objectTypeService.getExpenseObjectTypes(universityFiscalYear);
123    
124            SystemOptions options = optionsService.getOptions(universityFiscalYear);
125    
126            List<String> balanceTypeCodes = balanceTypeService.getEncumbranceBalanceTypes(universityFiscalYear);
127    
128    
129            return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYear, chartOfAccountsCode, accountNumber, objectTypes, balanceTypeCodes, sufficientFundsObjectCode, isDebit, isYearEnd);
130        }
131    
132        /**
133         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getBudgetSummary(java.lang.Integer, java.lang.String,
134         *      java.lang.String, java.lang.String, boolean)
135         */
136        public KualiDecimal getBudgetSummary(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String sufficientFundsObjectCode, boolean isYearEnd) {
137            LOG.debug("getBudgetSummary() started");
138    
139            ObjectTypeService objectTypeService = (ObjectTypeService) SpringContext.getBean(ObjectTypeService.class);
140            List<String> objectTypes = objectTypeService.getExpenseObjectTypes(universityFiscalYear);
141    
142            SystemOptions options = optionsService.getOptions(universityFiscalYear);
143    
144            Collection balanceTypeCodes = new ArrayList();
145            balanceTypeCodes.add(options.getBudgetCheckingBalanceTypeCd());
146    
147            return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYear, chartOfAccountsCode, accountNumber, objectTypes, balanceTypeCodes, sufficientFundsObjectCode, isYearEnd);
148        }
149    
150        /**
151         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getCashSummary(java.util.Collection, java.lang.String,
152         *      java.lang.String, boolean)
153         */
154        public KualiDecimal getCashSummary(List universityFiscalYears, String chartOfAccountsCode, String accountNumber, boolean isDebit) {
155            LOG.debug("getCashSummary() started");
156    
157            Chart c = chartService.getByPrimaryId(chartOfAccountsCode);
158    
159            // Note, we are getting the options from the first fiscal year in the list. We are assuming that the
160            // balance type code for actual is the same in all the years in the list.
161            SystemOptions options = optionsService.getOptions((Integer) universityFiscalYears.get(0));
162    
163            Collection objectCodes = new ArrayList();
164            objectCodes.add(c.getFinancialCashObjectCode());
165    
166            Collection balanceTypeCodes = new ArrayList();
167            balanceTypeCodes.add(options.getActualFinancialBalanceTypeCd());
168    
169            return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYears, chartOfAccountsCode, accountNumber, objectCodes, balanceTypeCodes, isDebit);
170        }
171    
172        /**
173         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getActualSummary(java.util.List, java.lang.String,
174         *      java.lang.String, boolean)
175         */
176        public KualiDecimal getActualSummary(List universityFiscalYears, String chartOfAccountsCode, String accountNumber, boolean isDebit) {
177            LOG.debug("getActualSummary() started");
178    
179            List<String> codes = parameterService.getParameterValues(KfsParameterConstants.FINANCIAL_SYSTEM_ALL.class, SufficientFundsServiceConstants.SUFFICIENT_FUNDS_OBJECT_CODE_SPECIALS);
180    
181            // Note, we are getting the options from the first fiscal year in the list. We are assuming that the
182            // balance type code for actual is the same in all the years in the list.
183            SystemOptions options = optionsService.getOptions((Integer) universityFiscalYears.get(0));
184    
185            Collection balanceTypeCodes = new ArrayList();
186            balanceTypeCodes.add(options.getActualFinancialBalanceTypeCd());
187    
188            return generalLedgerPendingEntryDao.getTransactionSummary(universityFiscalYears, chartOfAccountsCode, accountNumber, codes, balanceTypeCodes, isDebit);
189        }
190    
191        /**
192         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#getByPrimaryId(java.lang.Integer, java.lang.String)
193         */
194        public GeneralLedgerPendingEntry getByPrimaryId(Integer transactionEntrySequenceId, String documentHeaderId) {
195            LOG.debug("getByPrimaryId() started");
196    
197            return generalLedgerPendingEntryDao.getByPrimaryId(documentHeaderId, transactionEntrySequenceId);
198        }
199    
200        public void fillInFiscalPeriodYear(GeneralLedgerPendingEntry glpe) {
201            LOG.debug("fillInFiscalPeriodYear() started");
202    
203            // TODO Handle year end documents
204    
205            if ((glpe.getUniversityFiscalPeriodCode() == null) || (glpe.getUniversityFiscalYear() == null)) {
206                UniversityDate ud = SpringContext.getBean(UniversityDateService.class).getCurrentUniversityDate();
207    
208                glpe.setUniversityFiscalYear(ud.getUniversityFiscalYear());
209                glpe.setUniversityFiscalPeriodCode(ud.getUniversityFiscalAccountingPeriod());
210            }
211        }
212    
213        /**
214         * Invokes generateEntries method on the financial document.
215         * 
216         * @param document - document whose pending entries need generated
217         * @return whether the business rules succeeded
218         */
219        public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySource glpeSource) {
220            boolean success = true;
221    
222            // we must clear them first before creating new ones
223            glpeSource.clearAnyGeneralLedgerPendingEntries();
224    
225            if ( LOG.isDebugEnabled() ) {
226                LOG.debug("deleting existing gl pending ledger entries for document " + glpeSource.getDocumentHeader().getDocumentNumber());
227            }
228            delete(glpeSource.getDocumentHeader().getDocumentNumber());
229    
230            if ( LOG.isDebugEnabled() ) {
231                LOG.debug("generating gl pending ledger entries for document " + glpeSource.getDocumentHeader().getDocumentNumber());
232            }
233            
234            GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper();
235            for (GeneralLedgerPendingEntrySourceDetail glpeSourceDetail : glpeSource.getGeneralLedgerPendingEntrySourceDetails()) {
236                success &= glpeSource.generateGeneralLedgerPendingEntries(glpeSourceDetail, sequenceHelper);
237                sequenceHelper.increment();
238            }
239    
240            // doc specific pending entries generation
241            success &= glpeSource.generateDocumentGeneralLedgerPendingEntries(sequenceHelper);
242            return success;
243        }
244    
245        /**
246         * This populates an empty GeneralLedgerPendingEntry explicitEntry object instance with default values.
247         * 
248         * @param accountingDocument
249         * @param accountingLine
250         * @param sequenceHelper
251         * @param explicitEntry
252         */
253        public void populateExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySource glpeSource, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntry explicitEntry) {
254            if (LOG.isDebugEnabled()) {
255                LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - start");
256            }
257    
258            explicitEntry.setFinancialDocumentTypeCode(glpeSource.getFinancialDocumentTypeCode());
259            explicitEntry.setVersionNumber(new Long(1));
260            explicitEntry.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter()));
261            Timestamp transactionTimestamp = new Timestamp(SpringContext.getBean(DateTimeService.class).getCurrentDate().getTime());
262            explicitEntry.setTransactionDate(new java.sql.Date(transactionTimestamp.getTime()));
263            explicitEntry.setTransactionEntryProcessedTs(new java.sql.Timestamp(transactionTimestamp.getTime()));
264            explicitEntry.setAccountNumber(glpeSourceDetail.getAccountNumber());
265            
266            if (ObjectUtils.isNull(glpeSourceDetail.getAccount()) && getPersistenceStructureService().hasReference(glpeSourceDetail.getClass(), KFSPropertyConstants.ACCOUNT)) {
267                glpeSourceDetail.refreshReferenceObject(KFSPropertyConstants.ACCOUNT);
268            }
269            
270            if ((ObjectUtils.isNull(glpeSourceDetail.getObjectCode()) || StringUtils.isBlank(glpeSourceDetail.getObjectCode().getFinancialObjectTypeCode())) && getPersistenceStructureService().hasReference(glpeSourceDetail.getClass(), KFSPropertyConstants.OBJECT_CODE) ) {
271                glpeSourceDetail.refreshReferenceObject(KFSPropertyConstants.OBJECT_CODE);
272            }
273            
274            if (ObjectUtils.isNotNull(glpeSourceDetail.getAccount())) {
275                if(StringUtils.isBlank(glpeSourceDetail.getAccount().getAccountSufficientFundsCode())) {
276                    glpeSourceDetail.getAccount().setAccountSufficientFundsCode(KFSConstants.SF_TYPE_NO_CHECKING);
277                }
278                
279                String sufficientFundsCode = glpeSourceDetail.getAccount().getAccountSufficientFundsCode();
280                ObjectCode objectCode = glpeSourceDetail.getObjectCode();
281                if(ObjectUtils.isNotNull(objectCode)) {
282                    String sifficientFundsObjectCode = SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(objectCode, sufficientFundsCode);
283                    explicitEntry.setAcctSufficientFundsFinObjCd(sifficientFundsObjectCode);
284                }
285            }
286            
287            if (!ObjectUtils.isNull(glpeSourceDetail.getObjectCode())) {
288                explicitEntry.setFinancialObjectTypeCode(glpeSourceDetail.getObjectCode().getFinancialObjectTypeCode());
289            }
290            
291            explicitEntry.setFinancialDocumentApprovedCode(GENERAL_LEDGER_PENDING_ENTRY_CODE.NO);
292            explicitEntry.setTransactionEncumbranceUpdateCode(BLANK_SPACE);
293            explicitEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_ACTUAL); // this is the default that most documents use
294            explicitEntry.setChartOfAccountsCode(glpeSourceDetail.getChartOfAccountsCode());
295            explicitEntry.setTransactionDebitCreditCode(glpeSource.isDebit(glpeSourceDetail) ? KFSConstants.GL_DEBIT_CODE : KFSConstants.GL_CREDIT_CODE);
296            explicitEntry.setFinancialSystemOriginationCode(SpringContext.getBean(HomeOriginationService.class).getHomeOrigination().getFinSystemHomeOriginationCode());
297            explicitEntry.setDocumentNumber(glpeSourceDetail.getDocumentNumber());
298            explicitEntry.setFinancialObjectCode(glpeSourceDetail.getFinancialObjectCode());
299            
300            explicitEntry.setOrganizationDocumentNumber(glpeSource.getDocumentHeader().getOrganizationDocumentNumber());
301            explicitEntry.setOrganizationReferenceId(glpeSourceDetail.getOrganizationReferenceId());
302            explicitEntry.setProjectCode(getEntryValue(glpeSourceDetail.getProjectCode(), GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankProjectCode()));
303            explicitEntry.setReferenceFinancialDocumentNumber(getEntryValue(glpeSourceDetail.getReferenceNumber(), BLANK_SPACE));
304            explicitEntry.setReferenceFinancialDocumentTypeCode(getEntryValue(glpeSourceDetail.getReferenceTypeCode(), BLANK_SPACE));
305            explicitEntry.setReferenceFinancialSystemOriginationCode(getEntryValue(glpeSourceDetail.getReferenceOriginCode(), BLANK_SPACE));
306            explicitEntry.setSubAccountNumber(getEntryValue(glpeSourceDetail.getSubAccountNumber(), GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankSubAccountNumber()));
307            explicitEntry.setFinancialSubObjectCode(getEntryValue(glpeSourceDetail.getFinancialSubObjectCode(), GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialSubObjectCode()));
308            explicitEntry.setTransactionEntryOffsetIndicator(false);
309            explicitEntry.setTransactionLedgerEntryAmount(glpeSource.getGeneralLedgerPendingEntryAmountForDetail(glpeSourceDetail));
310            explicitEntry.setTransactionLedgerEntryDescription(getEntryValue(glpeSourceDetail.getFinancialDocumentLineDescription(), glpeSource.getDocumentHeader().getDocumentDescription()));
311            explicitEntry.setUniversityFiscalPeriodCode(null); // null here, is assigned during batch or in specific document rule
312            // classes
313            explicitEntry.setUniversityFiscalYear(glpeSource.getPostingYear());
314            // TODO wait for core budget year data structures to be put in place
315            // explicitEntry.setBudgetYear(accountingLine.getBudgetYear());
316            // explicitEntry.setBudgetYearFundingSourceCode(budgetYearFundingSourceCode);
317    
318            if (LOG.isDebugEnabled()) {
319                LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - end");
320            }
321        }
322        
323        /**
324         * Convenience method to build a GLPE without a generalLedgerPendingEntrySourceDetail
325         * @param document a GeneralLedgerPostingDocument
326         * @param account the account for use in the GLPE
327         * @param objectCode the object code for use in the GLPE
328         * @param subAccountNumber the sub account number for use in the GLPE
329         * @param subObjectCode the subobject code for use in the GLPE
330         * @param organizationReferenceId the organization reference id to use in the GLPE
331         * @param projectCode the project code to use in the GLPE
332         * @param referenceNumber the reference number to use in the GLPE
333         * @param referenceTypeCode the reference type code to use in the GLPE
334         * @param referenceOriginCode the reference origin code to use in the GLPE
335         * @param description the description to put in the GLPE
336         * @param isDebit true if the GLPE represents a debit, false if it represents a credit
337         * @param amount the amount of the GLPE
338         * @param sequenceHelper the sequence helper to use
339         * @return a populated general ledger pending entry
340         */
341        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) {
342            if (LOG.isDebugEnabled()) {
343                LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - start");
344            }
345    
346            GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
347            explicitEntry.setFinancialDocumentTypeCode(document.getDocumentHeader().getWorkflowDocument().getDocumentType());
348            explicitEntry.setVersionNumber(new Long(1));
349            explicitEntry.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter()));
350            Timestamp transactionTimestamp = new Timestamp(SpringContext.getBean(DateTimeService.class).getCurrentDate().getTime());
351            explicitEntry.setTransactionDate(new java.sql.Date(transactionTimestamp.getTime()));
352            explicitEntry.setTransactionEntryProcessedTs(new java.sql.Timestamp(transactionTimestamp.getTime()));
353            explicitEntry.setAccountNumber(account.getAccountNumber());
354            if (account.getAccountSufficientFundsCode() == null) {
355                account.setAccountSufficientFundsCode(KFSConstants.SF_TYPE_NO_CHECKING);
356            }
357            explicitEntry.setAcctSufficientFundsFinObjCd(SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(objectCode, account.getAccountSufficientFundsCode()));
358            explicitEntry.setFinancialDocumentApprovedCode(GENERAL_LEDGER_PENDING_ENTRY_CODE.NO);
359            explicitEntry.setTransactionEncumbranceUpdateCode(BLANK_SPACE);
360            explicitEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_ACTUAL); // this is the default that most documents use
361            explicitEntry.setChartOfAccountsCode(account.getChartOfAccountsCode());
362            explicitEntry.setTransactionDebitCreditCode(isDebit ? KFSConstants.GL_DEBIT_CODE : KFSConstants.GL_CREDIT_CODE);
363            explicitEntry.setFinancialSystemOriginationCode(SpringContext.getBean(HomeOriginationService.class).getHomeOrigination().getFinSystemHomeOriginationCode());
364            explicitEntry.setDocumentNumber(document.getDocumentNumber());
365            explicitEntry.setFinancialObjectCode(objectCode.getFinancialObjectCode());
366            explicitEntry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode());
367            explicitEntry.setOrganizationDocumentNumber(document.getDocumentHeader().getOrganizationDocumentNumber());
368            explicitEntry.setOrganizationReferenceId(organizationReferenceId);
369            explicitEntry.setProjectCode(getEntryValue(projectCode, GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankProjectCode()));
370            explicitEntry.setReferenceFinancialDocumentNumber(getEntryValue(referenceNumber, BLANK_SPACE));
371            explicitEntry.setReferenceFinancialDocumentTypeCode(getEntryValue(referenceTypeCode, BLANK_SPACE));
372            explicitEntry.setReferenceFinancialSystemOriginationCode(getEntryValue(referenceOriginCode, BLANK_SPACE));
373            explicitEntry.setSubAccountNumber(getEntryValue(subAccountNumber, GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankSubAccountNumber()));
374            explicitEntry.setFinancialSubObjectCode(getEntryValue(subObjectCode, GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialSubObjectCode()));
375            explicitEntry.setTransactionEntryOffsetIndicator(false);
376            explicitEntry.setTransactionLedgerEntryAmount(amount);
377            explicitEntry.setTransactionLedgerEntryDescription(getEntryValue(description, document.getDocumentHeader().getDocumentDescription()));
378            explicitEntry.setUniversityFiscalPeriodCode(null); // null here, is assigned during batch or in specific document rule
379            // classes
380            explicitEntry.setUniversityFiscalYear(document.getPostingYear());
381    
382            if (LOG.isDebugEnabled()) {
383                LOG.debug("populateExplicitGeneralLedgerPendingEntry(AccountingDocument, AccountingLine, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - end");
384            }
385            
386            return explicitEntry;
387        }
388    
389        /**
390         * This populates an GeneralLedgerPendingEntry offsetEntry object instance with values that differ from the values supplied in
391         * the explicit entry that it was cloned from. Note that the entries do not contain BOs now.
392         * 
393         * @param universityFiscalYear
394         * @param explicitEntry
395         * @param sequenceHelper
396         * @param offsetEntry Cloned from the explicit entry
397         * @return whether the offset generation is successful
398         */
399        public boolean populateOffsetGeneralLedgerPendingEntry(Integer universityFiscalYear, GeneralLedgerPendingEntry explicitEntry, GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntry offsetEntry) {
400            LOG.debug("populateOffsetGeneralLedgerPendingEntry(Integer, GeneralLedgerPendingEntry, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - start");
401    
402            boolean success = true;
403    
404            // lookup offset object info
405            OffsetDefinition offsetDefinition = SpringContext.getBean(OffsetDefinitionService.class).getByPrimaryId(universityFiscalYear, explicitEntry.getChartOfAccountsCode(), explicitEntry.getFinancialDocumentTypeCode(), explicitEntry.getFinancialBalanceTypeCode());
406            if (ObjectUtils.isNull(offsetDefinition)) {
407                success = false;
408                GlobalVariables.getMessageMap().putError(KFSConstants.GENERAL_LEDGER_PENDING_ENTRIES_TAB_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_NO_OFFSET_DEFINITION, universityFiscalYear.toString(), explicitEntry.getChartOfAccountsCode(), explicitEntry.getFinancialDocumentTypeCode(), explicitEntry.getFinancialBalanceTypeCode());
409            }
410            else {
411                OffsetAccount flexibleOffsetAccount = SpringContext.getBean(FlexibleOffsetAccountService.class).getByPrimaryIdIfEnabled(explicitEntry.getChartOfAccountsCode(), explicitEntry.getAccountNumber(), getOffsetFinancialObjectCode(offsetDefinition));
412                flexOffsetAccountIfNecessary(flexibleOffsetAccount, offsetEntry);
413            }
414    
415            // update offset entry fields that are different from the explicit entry that it was created from
416            offsetEntry.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter()));
417            offsetEntry.setTransactionDebitCreditCode(getOffsetEntryDebitCreditCode(explicitEntry));
418    
419            String offsetObjectCode = getOffsetFinancialObjectCode(offsetDefinition);
420            offsetEntry.setFinancialObjectCode(offsetObjectCode);
421            if (offsetObjectCode.equals(AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectCode())) {
422                // no BO, so punt
423                offsetEntry.setAcctSufficientFundsFinObjCd(AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectCode());
424            }
425            else {
426                // Need current ObjectCode and Account BOs to get sufficient funds code. (Entries originally have no BOs.)
427                // todo: private or other methods to get these BOs, instead of using the entry and leaving some BOs filled in?
428                offsetEntry.refreshReferenceObject(KFSPropertyConstants.FINANCIAL_OBJECT);
429                offsetEntry.refreshReferenceObject(KFSPropertyConstants.ACCOUNT);
430                ObjectCode financialObject = offsetEntry.getFinancialObject();
431                // The ObjectCode reference may be invalid because a flexible offset account changed its chart code.
432                if (ObjectUtils.isNull(financialObject)) {
433                    throw new ReferentialIntegrityException("offset object code " + offsetEntry.getUniversityFiscalYear() + "-" + offsetEntry.getChartOfAccountsCode() + "-" + offsetEntry.getFinancialObjectCode());
434                }
435                offsetEntry.setAcctSufficientFundsFinObjCd(SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(financialObject, offsetEntry.getAccount().getAccountSufficientFundsCode()));
436            }
437    
438            offsetEntry.setFinancialObjectTypeCode(getOffsetFinancialObjectTypeCode(offsetDefinition));
439            offsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode());
440            offsetEntry.setTransactionEntryOffsetIndicator(true);
441            offsetEntry.setTransactionLedgerEntryDescription(KFSConstants.GL_PE_OFFSET_STRING);
442            offsetEntry.setFinancialSystemOriginationCode(explicitEntry.getFinancialSystemOriginationCode());
443    
444            LOG.debug("populateOffsetGeneralLedgerPendingEntry(Integer, GeneralLedgerPendingEntry, GeneralLedgerPendingEntrySequenceHelper, GeneralLedgerPendingEntry) - end");
445            return success;
446        }
447    
448        /**
449         * Applies the given flexible offset account to the given offset entry. Does nothing if flexibleOffsetAccount is null or its COA
450         * and account number are the same as the offset entry's.
451         * 
452         * @param flexibleOffsetAccount may be null
453         * @param offsetEntry may be modified
454         */
455        protected void flexOffsetAccountIfNecessary(OffsetAccount flexibleOffsetAccount, GeneralLedgerPendingEntry offsetEntry) {
456            LOG.debug("flexOffsetAccountIfNecessary(OffsetAccount, GeneralLedgerPendingEntry) - start");
457    
458            if (flexibleOffsetAccount == null) {
459                LOG.debug("flexOffsetAccountIfNecessary(OffsetAccount, GeneralLedgerPendingEntry) - end");
460                return; // They are not required and may also be disabled.
461            }
462            String flexCoa = flexibleOffsetAccount.getFinancialOffsetChartOfAccountCode();
463            String flexAccountNumber = flexibleOffsetAccount.getFinancialOffsetAccountNumber();
464            if (flexCoa.equals(offsetEntry.getChartOfAccountsCode()) && flexAccountNumber.equals(offsetEntry.getAccountNumber())) {
465                LOG.debug("flexOffsetAccountIfNecessary(OffsetAccount, GeneralLedgerPendingEntry) - end");
466                return; // no change, so leave sub-account as is
467            }
468            if (ObjectUtils.isNull(flexibleOffsetAccount.getFinancialOffsetAccount())) {
469                throw new ReferentialIntegrityException("flexible offset account " + flexCoa + "-" + flexAccountNumber);
470            }
471            offsetEntry.setChartOfAccountsCode(flexCoa);
472            offsetEntry.setAccountNumber(flexAccountNumber);
473            // COA and account number are part of the sub-account's key, so the original sub-account would be invalid.
474            offsetEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
475    
476            LOG.debug("flexOffsetAccountIfNecessary(OffsetAccount, GeneralLedgerPendingEntry) - end");
477        }
478    
479        /**
480         * Helper method that determines the offset entry's financial object type code.
481         * 
482         * @param offsetDefinition
483         * @return String
484         */
485        protected String getOffsetFinancialObjectTypeCode(OffsetDefinition offsetDefinition) {
486            LOG.debug("getOffsetFinancialObjectTypeCode(OffsetDefinition) - start");
487    
488            if (null != offsetDefinition && null != offsetDefinition.getFinancialObject()) {
489                String returnString = getEntryValue(offsetDefinition.getFinancialObject().getFinancialObjectTypeCode(), AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectType());
490                LOG.debug("getOffsetFinancialObjectTypeCode(OffsetDefinition) - end");
491                return returnString;
492            }
493            else {
494                LOG.debug("getOffsetFinancialObjectTypeCode(OffsetDefinition) - end");
495                return AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectType();
496            }
497    
498        }
499    
500        /**
501         * Helper method that determines the debit/credit code for the offset entry. If the explicit was a debit, the offset is a
502         * credit. Otherwise, it's opposite.
503         * 
504         * @param explicitEntry
505         * @return String
506         */
507        protected String getOffsetEntryDebitCreditCode(GeneralLedgerPendingEntry explicitEntry) {
508            LOG.debug("getOffsetEntryDebitCreditCode(GeneralLedgerPendingEntry) - start");
509    
510            String offsetDebitCreditCode = KFSConstants.GL_BUDGET_CODE;
511            if (KFSConstants.GL_DEBIT_CODE.equals(explicitEntry.getTransactionDebitCreditCode())) {
512                offsetDebitCreditCode = KFSConstants.GL_CREDIT_CODE;
513            }
514            else if (KFSConstants.GL_CREDIT_CODE.equals(explicitEntry.getTransactionDebitCreditCode())) {
515                offsetDebitCreditCode = KFSConstants.GL_DEBIT_CODE;
516            }
517    
518            LOG.debug("getOffsetEntryDebitCreditCode(GeneralLedgerPendingEntry) - end");
519            return offsetDebitCreditCode;
520        }
521    
522        /**
523         * Helper method that determines the offset entry's financial object code.
524         * 
525         * @param offsetDefinition
526         * @return String
527         */
528        protected String getOffsetFinancialObjectCode(OffsetDefinition offsetDefinition) {
529            LOG.debug("getOffsetFinancialObjectCode(OffsetDefinition) - start");
530    
531            if (null != offsetDefinition) {
532                String returnString = getEntryValue(offsetDefinition.getFinancialObjectCode(), AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectCode());
533                LOG.debug("getOffsetFinancialObjectCode(OffsetDefinition) - end");
534                return returnString;
535            }
536            else {
537                LOG.debug("getOffsetFinancialObjectCode(OffsetDefinition) - end");
538                return AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.getBlankFinancialObjectCode();
539            }
540    
541        }
542    
543        /**
544         * This populates an empty GeneralLedgerPendingEntry instance with default values for a bank offset. A global error will be
545         * posted as a side-effect if the given bank has not defined the necessary bank offset relations.
546         * 
547         * @param bank
548         * @param depositAmount
549         * @param financialDocument
550         * @param universityFiscalYear
551         * @param sequenceHelper
552         * @param bankOffsetEntry
553         * @param errorPropertyName
554         * @return whether the entry was populated successfully
555         */
556        public boolean populateBankOffsetGeneralLedgerPendingEntry(Bank bank, KualiDecimal depositAmount, GeneralLedgerPostingDocument financialDocument, Integer universityFiscalYear, GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntry bankOffsetEntry, String errorPropertyName) {
557            bankOffsetEntry.setFinancialDocumentTypeCode(dataDictionaryService.getDocumentTypeNameByClass(financialDocument.getClass()));
558            bankOffsetEntry.setVersionNumber(1L);
559            bankOffsetEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter());
560            Timestamp transactionTimestamp = new Timestamp(dateTimeService.getCurrentDate().getTime());
561            bankOffsetEntry.setTransactionDate(new java.sql.Date(transactionTimestamp.getTime()));
562            bankOffsetEntry.setTransactionEntryProcessedTs(new java.sql.Timestamp(transactionTimestamp.getTime()));
563            Account cashOffsetAccount = bank.getCashOffsetAccount();
564        
565            if (ObjectUtils.isNull(cashOffsetAccount)) {
566                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_NO_ACCOUNT, new String[] { bank.getBankCode() });
567                return false;
568            }
569         
570            if (!cashOffsetAccount.isActive()) {
571                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_ACCOUNT_CLOSED, new String[] {bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber() });
572                return false;
573            }
574        
575            if (cashOffsetAccount.isExpired()) {
576                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_ACCOUNT_EXPIRED, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber() });
577                return false;
578            }
579        
580            bankOffsetEntry.setChartOfAccountsCode(bank.getCashOffsetFinancialChartOfAccountCode());
581            bankOffsetEntry.setAccountNumber(bank.getCashOffsetAccountNumber());
582            bankOffsetEntry.setFinancialDocumentApprovedCode(AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE.NO);
583            bankOffsetEntry.setTransactionEncumbranceUpdateCode(BLANK_SPACE);
584            bankOffsetEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_ACTUAL);
585            bankOffsetEntry.setTransactionDebitCreditCode(depositAmount.isPositive() ? GL_DEBIT_CODE : GL_CREDIT_CODE);
586            bankOffsetEntry.setFinancialSystemOriginationCode(SpringContext.getBean(HomeOriginationService.class).getHomeOrigination().getFinSystemHomeOriginationCode());
587            bankOffsetEntry.setDocumentNumber(financialDocument.getDocumentNumber());
588            
589            ObjectCode cashOffsetObject = bank.getCashOffsetObject();
590            if (ObjectUtils.isNull(cashOffsetObject)) {
591                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_NO_OBJECT_CODE, new String[] { bank.getBankCode()});
592                return false;
593            }
594          
595            if (!cashOffsetObject.isFinancialObjectActiveCode()) {
596                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_INACTIVE_OBJECT_CODE, new String[] { bank.getBankCode(), cashOffsetObject.getFinancialObjectCode() });
597                return false;
598            }
599         
600            bankOffsetEntry.setFinancialObjectCode(bank.getCashOffsetObjectCode());
601            bankOffsetEntry.setFinancialObjectTypeCode(bank.getCashOffsetObject().getFinancialObjectTypeCode());
602            bankOffsetEntry.setOrganizationDocumentNumber(financialDocument.getDocumentHeader().getOrganizationDocumentNumber());
603            bankOffsetEntry.setOrganizationReferenceId(null);
604            bankOffsetEntry.setProjectCode(KFSConstants.getDashProjectCode());
605            bankOffsetEntry.setReferenceFinancialDocumentNumber(null);
606            bankOffsetEntry.setReferenceFinancialDocumentTypeCode(null);
607            bankOffsetEntry.setReferenceFinancialSystemOriginationCode(null);
608           
609            if (StringUtils.isBlank(bank.getCashOffsetSubAccountNumber())) {
610                bankOffsetEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
611            }
612            else {
613                SubAccount cashOffsetSubAccount = bank.getCashOffsetSubAccount();
614                if (ObjectUtils.isNull(cashOffsetSubAccount)) {
615                    GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_NONEXISTENT_SUB_ACCOUNT, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber(), bank.getCashOffsetSubAccountNumber() });
616                    return false;
617                }
618            
619                if (!cashOffsetSubAccount.isActive()) {
620                    GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_INACTIVE_SUB_ACCOUNT, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber(), bank.getCashOffsetSubAccountNumber() });
621                    return false;
622                }
623              
624                bankOffsetEntry.setSubAccountNumber(bank.getCashOffsetSubAccountNumber());
625            }
626          
627            if (StringUtils.isBlank(bank.getCashOffsetSubObjectCode())) {
628                bankOffsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode());
629            }
630            else {
631                SubObjectCode cashOffsetSubObject = bank.getCashOffsetSubObject();
632                if (ObjectUtils.isNull(cashOffsetSubObject)) {
633                    GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_NONEXISTENT_SUB_OBJ, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber(), cashOffsetObject.getFinancialObjectCode(), bank.getCashOffsetSubObjectCode() });
634                    return false;
635                }
636             
637                if (!cashOffsetSubObject.isActive()) {
638                    GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_BANK_OFFSET_INACTIVE_SUB_OBJ, new String[] { bank.getBankCode(), cashOffsetAccount.getChartOfAccountsCode(), cashOffsetAccount.getAccountNumber(), cashOffsetObject.getFinancialObjectCode(), bank.getCashOffsetSubObjectCode() });
639                    return false;
640                }
641              
642                bankOffsetEntry.setFinancialSubObjectCode(bank.getCashOffsetSubObjectCode());
643            }
644         
645            bankOffsetEntry.setTransactionEntryOffsetIndicator(true);
646            bankOffsetEntry.setTransactionLedgerEntryAmount(depositAmount.abs());
647            bankOffsetEntry.setUniversityFiscalPeriodCode(null); // null here, is assigned during batch or in specific document rule
648            bankOffsetEntry.setUniversityFiscalYear(universityFiscalYear);
649            bankOffsetEntry.setAcctSufficientFundsFinObjCd(SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(cashOffsetObject, cashOffsetAccount.getAccountSufficientFundsCode()));
650      
651            return true;
652        }
653    
654        /**
655         * @see org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService#save(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry)
656         */
657        public void save(GeneralLedgerPendingEntry generalLedgerPendingEntry) {
658            LOG.debug("save() started");
659    
660            generalLedgerPendingEntryDao.save(generalLedgerPendingEntry);
661        }
662    
663        public void delete(String documentHeaderId) {
664            LOG.debug("delete() started");
665    
666            this.generalLedgerPendingEntryDao.delete(documentHeaderId);
667        }
668    
669        public void deleteByFinancialDocumentApprovedCode(String financialDocumentApprovedCode) {
670            LOG.debug("deleteByFinancialDocumentApprovedCode() started");
671    
672            this.generalLedgerPendingEntryDao.deleteByFinancialDocumentApprovedCode(financialDocumentApprovedCode);
673        }
674    
675        /**
676         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findApprovedPendingLedgerEntries()
677         */
678        public Iterator findApprovedPendingLedgerEntries() {
679            LOG.debug("findApprovedPendingLedgerEntries() started");
680    
681            return generalLedgerPendingEntryDao.findApprovedPendingLedgerEntries();
682        }
683    
684        /**
685         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntries(org.kuali.kfs.gl.businessobject.Encumbrance,
686         *      boolean)
687         */
688        public Iterator findPendingLedgerEntries(Encumbrance encumbrance, boolean isApproved) {
689            LOG.debug("findPendingLedgerEntries() started");
690    
691            return generalLedgerPendingEntryDao.findPendingLedgerEntries(encumbrance, isApproved);
692        }
693    
694        /**
695         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#hasPendingGeneralLedgerEntry(org.kuali.kfs.coa.businessobject.Account)
696         */
697        public boolean hasPendingGeneralLedgerEntry(Account account) {
698            LOG.debug("hasPendingGeneralLedgerEntry() started");
699    
700            return generalLedgerPendingEntryDao.countPendingLedgerEntries(account) > 0;
701        }
702    
703        /**
704         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntries(Balance, boolean, boolean)
705         */
706        public Iterator findPendingLedgerEntries(Balance balance, boolean isApproved, boolean isConsolidated) {
707            LOG.debug("findPendingLedgerEntries() started");
708    
709            return generalLedgerPendingEntryDao.findPendingLedgerEntries(balance, isApproved, isConsolidated);
710        }
711    
712        /**
713         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForEntry(java.util.Map, boolean)
714         */
715        public Iterator findPendingLedgerEntriesForEntry(Map fieldValues, boolean isApproved) {
716            LOG.debug("findPendingLedgerEntriesForEntry() started");
717    
718            return generalLedgerPendingEntryDao.findPendingLedgerEntriesForEntry(fieldValues, isApproved);
719        }
720    
721        /**
722         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForEncumbrance(Map, boolean)
723         */
724        public Iterator findPendingLedgerEntriesForEncumbrance(Map fieldValues, boolean isApproved) {
725            LOG.debug("findPendingLedgerEntriesForEncumbrance() started");
726    
727            return generalLedgerPendingEntryDao.findPendingLedgerEntriesForEncumbrance(fieldValues, isApproved);
728        }
729    
730        /**
731         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForCashBalance(java.util.Map,
732         *      boolean)
733         */
734        public Iterator findPendingLedgerEntriesForCashBalance(Map fieldValues, boolean isApproved) {
735            LOG.debug("findPendingLedgerEntriesForCashBalance() started");
736    
737            return generalLedgerPendingEntryDao.findPendingLedgerEntriesForCashBalance(fieldValues, isApproved);
738        }
739    
740        /**
741         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForBalance(java.util.Map, boolean)
742         */
743        public Iterator findPendingLedgerEntriesForBalance(Map fieldValues, boolean isApproved) {
744            LOG.debug("findPendingLedgerEntriesForBalance() started");
745    
746            return generalLedgerPendingEntryDao.findPendingLedgerEntriesForBalance(fieldValues, isApproved);
747        }
748    
749        /**
750         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntriesForAccountBalance(java.util.Map,
751         *      boolean, boolean)
752         */
753        public Iterator findPendingLedgerEntriesForAccountBalance(Map fieldValues, boolean isApproved) {
754            LOG.debug("findPendingLedgerEntriesForAccountBalance() started");
755    
756            return generalLedgerPendingEntryDao.findPendingLedgerEntriesForAccountBalance(fieldValues, isApproved);
757        }
758    
759        /**
760         * @see org.kuali.module.gl.service.GeneralLedgerPendingEntryService#findPendingLedgerEntrySummaryForAccountBalance(java.util.Map,
761         *      boolean, boolean)
762         */
763        public Iterator findPendingLedgerEntrySummaryForAccountBalance(Map fieldValues, boolean isApproved) {
764            LOG.debug("findPendingLedgerEntrySummaryForAccountBalance() started");
765    
766            return generalLedgerPendingEntryDao.findPendingLedgerEntrySummaryForAccountBalance(fieldValues, isApproved);
767        }
768    
769        public Collection findPendingEntries(Map fieldValues, boolean isApproved) {
770            LOG.debug("findPendingEntries() started");
771    
772            return generalLedgerPendingEntryDao.findPendingEntries(fieldValues, isApproved);
773        }
774    
775        /**
776         * A helper method that checks the intended target value for null and empty strings. If the intended target value is not null or
777         * an empty string, it returns that value, ohterwise, it returns a backup value.
778         * 
779         * @param targetValue
780         * @param backupValue
781         * @return String
782         */
783        protected final String getEntryValue(String targetValue, String backupValue) {
784            LOG.debug("getEntryValue(String, String) - start");
785    
786            if (StringUtils.isNotBlank(targetValue)) {
787                LOG.debug("getEntryValue(String, String) - end");
788                return targetValue;
789            }
790            else {
791                LOG.debug("getEntryValue(String, String) - end");
792                return backupValue;
793            }
794        }
795        
796        /**
797         * Determines if the given GeneralLedgerPendingEntry represents offsets to cash
798         * @param generalLedgerPendingEntry the GeneralLedgerPendingEntry to check
799         * @return true if the GeneralLedgerPendingEntry represents an offset to cash; false otherwise
800         */
801        public boolean isOffsetToCash(GeneralLedgerPendingEntry generalLedgerPendingEntry) {
802            if (generalLedgerPendingEntry.isTransactionEntryOffsetIndicator()) {
803                final Chart entryChart = chartService.getByPrimaryId(generalLedgerPendingEntry.getChartOfAccountsCode());
804                if (!ObjectUtils.isNull(entryChart)) {
805                    return (entryChart.getFinancialCashObjectCode().equals(generalLedgerPendingEntry.getFinancialObjectCode()));
806                }
807            }
808            return false;
809        }
810        
811        /**
812         * Adds up the amounts of all cash to offset GeneralLedgerPendingEntry records on the given AccountingDocument
813         * @param glPostingDocument the accounting document total the offset to cash amount for
814         * @return the offset to cash amount, where debited values have been subtracted and credited values have been added
815         */
816        public KualiDecimal getOffsetToCashAmount(GeneralLedgerPostingDocument glPostingDocument) {
817            KualiDecimal total = KualiDecimal.ZERO;
818            for (GeneralLedgerPendingEntry glpe : glPostingDocument.getGeneralLedgerPendingEntries()) {
819                if (isOffsetToCash(glpe)) {
820                    if (glpe.getTransactionDebitCreditCode().equals(KFSConstants.GL_DEBIT_CODE)) {
821                        total = total.subtract(glpe.getTransactionLedgerEntryAmount());
822                    } else if (glpe.getTransactionDebitCreditCode().equals(KFSConstants.GL_CREDIT_CODE)) {
823                        total = total.add(glpe.getTransactionLedgerEntryAmount());
824                    }
825                }
826            }
827            return total;
828        }
829    
830        public void setBalanceTypeService(BalanceTypeService balanceTypeService) {
831            this.balanceTypeService = balanceTypeService;
832        }
833    
834        public void setChartService(ChartService chartService) {
835            this.chartService = chartService;
836        }
837    
838        public void setGeneralLedgerPendingEntryDao(GeneralLedgerPendingEntryDao generalLedgerPendingEntryDao) {
839            this.generalLedgerPendingEntryDao = generalLedgerPendingEntryDao;
840        }
841    
842        public void setParameterService(ParameterService parameterService) {
843            this.parameterService = parameterService;
844        }
845    
846        public void setKualiRuleService(KualiRuleService kualiRuleService) {
847            this.kualiRuleService = kualiRuleService;
848        }
849    
850        public void setOptionsService(OptionsService optionsService) {
851            this.optionsService = optionsService;
852        }
853    
854        /**
855         * Sets the dateTimeService attribute value.
856         * 
857         * @param dateTimeService The dateTimeService to set.
858         */
859        public void setDateTimeService(DateTimeService dateTimeService) {
860            this.dateTimeService = dateTimeService;
861        }
862    
863        /**
864         * Sets the dataDictionaryService attribute value.
865         * @param dataDictionaryService The dataDictionaryService to set.
866         */
867        public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
868            this.dataDictionaryService = dataDictionaryService;
869        }
870    
871        /**
872         * Gets the persistenceStructureService attribute. 
873         * @return Returns the persistenceStructureService.
874         */
875        public PersistenceStructureService getPersistenceStructureService() {
876            return persistenceStructureService;
877        }
878    
879        /**
880         * Sets the persistenceStructureService attribute value.
881         * @param persistenceStructureService The persistenceStructureService to set.
882         */
883        public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
884            this.persistenceStructureService = persistenceStructureService;
885        }
886    
887    }