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.module.purap.service.impl;
17  
18  import org.kuali.ole.coa.businessobject.Account;
19  import org.kuali.ole.coa.businessobject.ObjectCode;
20  import org.kuali.ole.coa.businessobject.SubObjectCode;
21  import org.kuali.ole.coa.service.ObjectCodeService;
22  import org.kuali.ole.coa.service.SubObjectCodeService;
23  import org.kuali.ole.module.purap.PurapConstants;
24  import org.kuali.ole.module.purap.PurapConstants.PurapDocTypeCodes;
25  import org.kuali.ole.module.purap.businessobject.*;
26  import org.kuali.ole.module.purap.document.*;
27  import org.kuali.ole.module.purap.document.InvoiceDocument;
28  import org.kuali.ole.module.purap.document.service.InvoiceService;
29  import org.kuali.ole.module.purap.document.service.PaymentRequestService;
30  import org.kuali.ole.module.purap.document.service.PurapService;
31  import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
32  import org.kuali.ole.module.purap.service.PurapAccountRevisionService;
33  import org.kuali.ole.module.purap.service.PurapAccountingService;
34  import org.kuali.ole.module.purap.service.PurapGeneralLedgerService;
35  import org.kuali.ole.module.purap.util.SummaryAccount;
36  import org.kuali.ole.module.purap.util.UseTaxContainer;
37  import org.kuali.ole.select.businessobject.OleInvoiceAccountsPayableSummaryAccount;
38  import org.kuali.ole.select.businessobject.OleInvoiceItem;
39  import org.kuali.ole.select.businessobject.OlePaymentRequestItem;
40  import org.kuali.ole.sys.OLEConstants;
41  import org.kuali.ole.sys.businessobject.*;
42  import org.kuali.ole.sys.context.SpringContext;
43  import org.kuali.ole.sys.service.GeneralLedgerPendingEntryService;
44  import org.kuali.ole.sys.service.UniversityDateService;
45  import org.kuali.rice.core.api.datetime.DateTimeService;
46  import org.kuali.rice.core.api.util.type.KualiDecimal;
47  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
48  import org.kuali.rice.krad.service.BusinessObjectService;
49  import org.kuali.rice.krad.service.KualiRuleService;
50  import org.kuali.rice.krad.util.ObjectUtils;
51  import org.springframework.transaction.annotation.Transactional;
52  
53  import java.math.BigDecimal;
54  import java.util.*;
55  
56  import static org.kuali.ole.module.purap.PurapConstants.HUNDRED;
57  import static org.kuali.ole.module.purap.PurapConstants.PURAP_ORIGIN_CODE;
58  import static org.kuali.ole.sys.OLEConstants.*;
59  import static org.kuali.rice.core.api.util.type.KualiDecimal.ZERO;
60  
61  @Transactional
62  public class PurapGeneralLedgerServiceImpl implements PurapGeneralLedgerService {
63      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PurapGeneralLedgerServiceImpl.class);
64  
65      private BusinessObjectService businessObjectService;
66      private DateTimeService dateTimeService;
67      private GeneralLedgerPendingEntryService generalLedgerPendingEntryService;
68      private KualiRuleService kualiRuleService;
69      private PaymentRequestService paymentRequestService;
70      private ParameterService parameterService;
71      private PurapAccountingService purapAccountingService;
72      private PurchaseOrderService purchaseOrderService;
73      private UniversityDateService universityDateService;
74      private ObjectCodeService objectCodeService;
75      private SubObjectCodeService subObjectCodeService;
76      private InvoiceService invoiceService;
77  
78      /**
79       * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#customizeGeneralLedgerPendingEntry(org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument,
80       *      org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry,
81       *      java.lang.Integer, java.lang.String, java.lang.String, boolean)
82       */
83      public void customizeGeneralLedgerPendingEntry(PurchasingAccountsPayableDocument purapDocument, AccountingLine accountingLine, GeneralLedgerPendingEntry explicitEntry, Integer referenceDocumentNumber, String debitCreditCode, String docType, boolean isEncumbrance) {
84          LOG.debug("customizeGeneralLedgerPendingEntry() started");
85  
86          explicitEntry.setDocumentNumber(purapDocument.getDocumentNumber());
87          explicitEntry.setTransactionLedgerEntryDescription(entryDescription(purapDocument.getVendorName()));
88          explicitEntry.setFinancialSystemOriginationCode(PURAP_ORIGIN_CODE);
89  
90          // Always make the referring document the PO for all PURAP docs except for CM against a vendor.
91          // This is required for encumbrance entries. It's not required for actual/liability
92          // entries, but it makes things easier to deal with. If vendor, leave referring stuff blank.
93          if (ObjectUtils.isNotNull(referenceDocumentNumber)) {
94              explicitEntry.setReferenceFinancialDocumentNumber(referenceDocumentNumber.toString());
95              explicitEntry.setReferenceFinancialDocumentTypeCode(PurapDocTypeCodes.PO_DOCUMENT);
96              explicitEntry.setReferenceFinancialSystemOriginationCode(PURAP_ORIGIN_CODE);
97          }
98  
99          // DEFAULT TO USE CURRENT; don't use FY on doc in case it's a prior year
100         UniversityDate uDate = universityDateService.getCurrentUniversityDate();
101         explicitEntry.setUniversityFiscalYear(uDate.getUniversityFiscalYear());
102         explicitEntry.setUniversityFiscalPeriodCode(uDate.getUniversityFiscalAccountingPeriod());
103 
104         if (PurapDocTypeCodes.PO_DOCUMENT.equals(docType)) {
105             if (purapDocument.getPostingYear().compareTo(uDate.getUniversityFiscalYear()) > 0) {
106                 // USE NEXT AS SET ON PO; POs can be forward dated to not encumber until next fiscal year
107                 explicitEntry.setUniversityFiscalYear(purapDocument.getPostingYear());
108                 explicitEntry.setUniversityFiscalPeriodCode(MONTH1);
109             }
110         } else if (PurapDocTypeCodes.PAYMENT_REQUEST_DOCUMENT.equals(docType)) {
111             PaymentRequestDocument preq = (PaymentRequestDocument) purapDocument;
112             if (paymentRequestService.allowBackpost(preq)) {
113                 LOG.debug("createGlPendingTransaction() within range to allow backpost; posting entry to period 12 of previous FY");
114                 explicitEntry.setUniversityFiscalYear(uDate.getUniversityFiscalYear() - 1);
115                 explicitEntry.setUniversityFiscalPeriodCode(OLEConstants.MONTH12);
116             }
117 
118             // if alternate payee is paid for non-primary vendor payment, send alternate vendor name in GL desc
119             if (preq.getAlternateVendorHeaderGeneratedIdentifier() != null && preq.getAlternateVendorDetailAssignedIdentifier() != null && preq.getVendorHeaderGeneratedIdentifier().compareTo(preq.getAlternateVendorHeaderGeneratedIdentifier()) == 0 && preq.getVendorDetailAssignedIdentifier().compareTo(preq.getAlternateVendorDetailAssignedIdentifier()) == 0) {
120                 explicitEntry.setTransactionLedgerEntryDescription(entryDescription(preq.getPurchaseOrderDocument().getAlternateVendorName()));
121             }
122 
123         } else if (PurapDocTypeCodes.CREDIT_MEMO_DOCUMENT.equals(docType)) {
124             VendorCreditMemoDocument cm = (VendorCreditMemoDocument) purapDocument;
125             if (cm.isSourceDocumentPaymentRequest()) {
126                 // if CM is off of PREQ, use vendor name associated with PREQ (primary or alternate)
127                 PaymentRequestDocument cmPR = cm.getPaymentRequestDocument();
128                 PurchaseOrderDocument cmPO = cm.getPurchaseOrderDocument();
129                 // if alternate payee is paid for non-primary vendor payment, send alternate vendor name in GL desc
130                 if (cmPR.getAlternateVendorHeaderGeneratedIdentifier() != null && cmPR.getAlternateVendorDetailAssignedIdentifier() != null && cmPR.getVendorHeaderGeneratedIdentifier().compareTo(cmPR.getAlternateVendorHeaderGeneratedIdentifier()) == 0 && cmPR.getVendorDetailAssignedIdentifier().compareTo(cmPR.getAlternateVendorDetailAssignedIdentifier()) == 0) {
131                     explicitEntry.setTransactionLedgerEntryDescription(entryDescription(cmPO.getAlternateVendorName()));
132                 }
133             }
134         } else if (PurapDocTypeCodes.INVOICE_DOCUMENT.equals(docType)) {
135             InvoiceDocument prqs = (InvoiceDocument) purapDocument;
136             if (invoiceService.allowBackpost(prqs)) {
137                 LOG.debug("createGlPendingTransaction() within range to allow backpost; posting entry to period 12 of previous FY");
138                 explicitEntry.setUniversityFiscalYear(uDate.getUniversityFiscalYear() - 1);
139                 explicitEntry.setUniversityFiscalPeriodCode(OLEConstants.MONTH12);
140             }
141 
142             // if alternate payee is paid for non-primary vendor payment, send alternate vendor name in GL desc
143             if (prqs.getAlternateVendorHeaderGeneratedIdentifier() != null && prqs.getAlternateVendorDetailAssignedIdentifier() != null &&
144                     prqs.getVendorHeaderGeneratedIdentifier().compareTo(prqs.getAlternateVendorHeaderGeneratedIdentifier()) == 0 && prqs.getVendorDetailAssignedIdentifier().compareTo(prqs.getAlternateVendorDetailAssignedIdentifier()) == 0) {
145                 explicitEntry.setTransactionLedgerEntryDescription(entryDescription(prqs.getPurchaseOrderDocument().getAlternateVendorName()));
146             }
147 
148         } else {
149             throw new IllegalArgumentException("purapDocument (doc #" + purapDocument.getDocumentNumber() + ") is invalid");
150         }
151 
152         ObjectCode objectCode = objectCodeService.getByPrimaryId(explicitEntry.getUniversityFiscalYear(), explicitEntry.getChartOfAccountsCode(), explicitEntry.getFinancialObjectCode());
153         if (ObjectUtils.isNotNull(objectCode)) {
154             explicitEntry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode());
155         }
156 
157         SubObjectCode subObjectCode = subObjectCodeService.getByPrimaryId(explicitEntry.getUniversityFiscalYear(), explicitEntry.getChartOfAccountsCode(), explicitEntry.getAccountNumber(), explicitEntry.getFinancialObjectCode(), explicitEntry.getFinancialSubObjectCode());
158         if (ObjectUtils.isNotNull(subObjectCode)) {
159             explicitEntry.setFinancialSubObjectCode(subObjectCode.getFinancialSubObjectCode());
160         }
161 
162         if (isEncumbrance) {
163             explicitEntry.setFinancialBalanceTypeCode(BALANCE_TYPE_EXTERNAL_ENCUMBRANCE);
164 
165             // D - means the encumbrance is based on the document number
166             // R - means the encumbrance is based on the referring document number
167             // All encumbrances should set the update code to 'R' regardless of if they were created by the PO, PREQ, or CM
168             explicitEntry.setTransactionEncumbranceUpdateCode(ENCUMB_UPDT_REFERENCE_DOCUMENT_CD);
169         }
170 
171         // if the amount is negative, flip the D/C indicator
172         if (accountingLine.getAmount().doubleValue() < 0) {
173             if (GL_CREDIT_CODE.equals(debitCreditCode)) {
174                 explicitEntry.setTransactionDebitCreditCode(GL_DEBIT_CODE);
175             } else {
176                 explicitEntry.setTransactionDebitCreditCode(GL_CREDIT_CODE);
177             }
178         } else {
179             explicitEntry.setTransactionDebitCreditCode(debitCreditCode);
180         }
181 
182     }// end purapCustomizeGeneralLedgerPendingEntry()
183 
184     /**
185      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesCancelAccountsPayableDocument(org.kuali.ole.module.purap.document.AccountsPayableDocument)
186      */
187     public void generateEntriesCancelAccountsPayableDocument(AccountsPayableDocument apDocument) {
188         LOG.debug("generateEntriesCancelAccountsPayableDocument() started");
189         if (apDocument instanceof PaymentRequestDocument) {
190             LOG.debug("generateEntriesCancelAccountsPayableDocument() cancel PaymentRequestDocument");
191             generateEntriesCancelPaymentRequest((PaymentRequestDocument) apDocument);
192         } else if (apDocument instanceof VendorCreditMemoDocument) {
193             LOG.debug("generateEntriesCancelAccountsPayableDocument() cancel CreditMemoDocument");
194             generateEntriesCancelCreditMemo((VendorCreditMemoDocument) apDocument);
195         } else if (apDocument instanceof InvoiceDocument) {
196             LOG.debug("generateEntriesCancelAccountsPayableDocument() cancel CreditMemoDocument");
197             generateEntriesCancelInvoice((InvoiceDocument) apDocument);
198         } else {
199             // doc not found
200         }
201     }
202 
203     /**
204      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesCreatePaymentRequest(org.kuali.ole.module.purap.document.PaymentRequestDocument)
205      */
206     public void generateEntriesCreatePaymentRequest(PaymentRequestDocument preq) {
207         LOG.debug("generateEntriesCreatePaymentRequest() started");
208         List<SourceAccountingLine> encumbrances = relieveEncumbrance(preq);
209         List<SummaryAccount> summaryAccounts = purapAccountingService.generateSummaryAccountsWithNoZeroTotalsNoUseTax(preq);
210         generateEntriesPaymentRequest(preq, encumbrances, summaryAccounts, CREATE_PAYMENT_REQUEST);
211     }
212 
213     /**
214      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesCreatePaymentRequest(org.kuali.ole.module.purap.document.PaymentRequestDocument)
215      */
216     public void generateEntriesCreateInvoice(InvoiceDocument inv) {
217         LOG.debug("generateEntriesCreateInvoice() started");
218         List<SourceAccountingLine> encumbrances = relieveEncumbrance(inv);
219         List<SummaryAccount> summaryAccounts = purapAccountingService.generateSummaryAccountsWithNoZeroTotalsNoUseTax(inv);
220         generateEntriesInvoice(inv, encumbrances, summaryAccounts, CREATE_INVOICE);
221     }
222 
223 
224     /**
225      * Called from generateEntriesCancelAccountsPayableDocument() for Payment Request Document
226      *
227      * @param preq Payment Request document to cancel
228      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesCancelAccountsPayableDocument(org.kuali.ole.module.purap.document.AccountsPayableDocument)
229      */
230     protected void generateEntriesCancelPaymentRequest(PaymentRequestDocument preq) {
231         LOG.debug("generateEntriesCreatePaymentRequest() started");
232         List<SourceAccountingLine> encumbrances = reencumberEncumbrance(preq);
233         List<SummaryAccount> summaryAccounts = purapAccountingService.generateSummaryAccountsWithNoZeroTotalsNoUseTax(preq);
234         generateEntriesPaymentRequest(preq, encumbrances, summaryAccounts, CANCEL_PAYMENT_REQUEST);
235     }
236 
237 
238     protected void generateEntriesCancelInvoice(InvoiceDocument prqs) {
239         LOG.debug("generateEntriesCancelInvoice() started");
240         List<SourceAccountingLine> encumbrances = reencumberEncumbrance(prqs);
241         List<SummaryAccount> summaryAccounts = purapAccountingService.generateSummaryAccountsWithNoZeroTotalsNoUseTax(prqs);
242         generateEntriesInvoice(prqs, encumbrances, summaryAccounts, CANCEL_INVOICE);
243     }
244 
245 
246     /**
247      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesModifyPaymentRequest(org.kuali.ole.module.purap.document.PaymentRequestDocument)
248      */
249     public void generateEntriesModifyPaymentRequest(PaymentRequestDocument preq) {
250         LOG.debug("generateEntriesModifyPaymentRequest() started");
251 
252         Map<SourceAccountingLine, KualiDecimal> actualsPositive = new HashMap<SourceAccountingLine, KualiDecimal>();
253         List<SourceAccountingLine> newAccountingLines = purapAccountingService.generateSummaryWithNoZeroTotalsNoUseTax(preq.getItems());
254         for (SourceAccountingLine newAccount : newAccountingLines) {
255             actualsPositive.put(newAccount, newAccount.getAmount());
256             if (LOG.isDebugEnabled()) {
257                 LOG.debug("generateEntriesModifyPaymentRequest() actualsPositive: " + newAccount.getAccountNumber() + " = " + newAccount.getAmount());
258             }
259         }
260 
261         Map<SourceAccountingLine, KualiDecimal> actualsNegative = new HashMap<SourceAccountingLine, KualiDecimal>();
262         List<AccountsPayableSummaryAccount> oldAccountingLines = purapAccountingService.getAccountsPayableSummaryAccounts(preq.getPurapDocumentIdentifier(), PurapDocTypeCodes.PAYMENT_REQUEST_DOCUMENT);
263 
264         for (AccountsPayableSummaryAccount oldAccount : oldAccountingLines) {
265             actualsNegative.put(oldAccount.generateSourceAccountingLine(), oldAccount.getAmount());
266             if (LOG.isDebugEnabled()) {
267                 LOG.debug("generateEntriesModifyPaymentRequest() actualsNegative: " + oldAccount.getAccountNumber() + " = " + oldAccount.getAmount());
268             }
269         }
270 
271         // Add the positive entries and subtract the negative entries
272         Map<SourceAccountingLine, KualiDecimal> glEntries = new HashMap<SourceAccountingLine, KualiDecimal>();
273 
274         // Combine the two maps (copy all the positive entries)
275         LOG.debug("generateEntriesModifyPaymentRequest() Combine positive/negative entries");
276         glEntries.putAll(actualsPositive);
277 
278         for (Iterator<SourceAccountingLine> iter = actualsNegative.keySet().iterator(); iter.hasNext(); ) {
279             SourceAccountingLine key = (SourceAccountingLine) iter.next();
280 
281             KualiDecimal amt;
282             if (glEntries.containsKey(key)) {
283                 amt = (KualiDecimal) glEntries.get(key);
284                 amt = amt.subtract((KualiDecimal) actualsNegative.get(key));
285             } else {
286                 amt = ZERO;
287                 amt = amt.subtract((KualiDecimal) actualsNegative.get(key));
288             }
289             glEntries.put(key, amt);
290         }
291 
292         List<SummaryAccount> summaryAccounts = new ArrayList<SummaryAccount>();
293         for (Iterator<SourceAccountingLine> iter = glEntries.keySet().iterator(); iter.hasNext(); ) {
294             SourceAccountingLine account = (SourceAccountingLine) iter.next();
295             KualiDecimal amount = (KualiDecimal) glEntries.get(account);
296             if (ZERO.compareTo(amount) != 0) {
297                 account.setAmount(amount);
298                 SummaryAccount sa = new SummaryAccount(account);
299                 summaryAccounts.add(sa);
300             }
301         }
302 
303         LOG.debug("generateEntriesModifyPaymentRequest() Generate GL entries");
304         generateEntriesPaymentRequest(preq, null, summaryAccounts, MODIFY_PAYMENT_REQUEST);
305     }
306 
307 
308     /**
309      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesModifyPaymentRequest(org.kuali.ole.module.purap.document.PaymentRequestDocument)
310      */
311     public void generateEntriesModifyInvoice(InvoiceDocument inv) {
312         LOG.debug("generateEntriesModifyPaymentRequest() started");
313         LOG.info("inv.getItems() >>>>>>>>" + inv.getItems());
314         Map<SourceAccountingLine, KualiDecimal> actualsPositive = new HashMap<SourceAccountingLine, KualiDecimal>();
315         List<SourceAccountingLine> newAccountingLines = purapAccountingService.generateSummaryWithNoZeroTotalsNoUseTax(inv.getItems());
316         for (SourceAccountingLine newAccount : newAccountingLines) {
317             actualsPositive.put(newAccount, newAccount.getAmount());
318             if (LOG.isDebugEnabled()) {
319                 LOG.debug("generateEntriesModifyPaymentRequest() actualsPositive: " + newAccount.getAccountNumber() + " = " + newAccount.getAmount());
320             }
321         }
322 
323         Map<SourceAccountingLine, KualiDecimal> actualsNegative = new HashMap<SourceAccountingLine, KualiDecimal>();
324         List<OleInvoiceAccountsPayableSummaryAccount> oldAccountingLines = purapAccountingService.getAccountsPayableSummaryAccounts(inv.getPurapDocumentIdentifier(), PurapDocTypeCodes.INVOICE_DOCUMENT);
325 
326         for (OleInvoiceAccountsPayableSummaryAccount oldAccount : oldAccountingLines) {
327             actualsNegative.put(oldAccount.generateSourceAccountingLine(), oldAccount.getAmount());
328             if (LOG.isDebugEnabled()) {
329                 LOG.debug("generateEntriesModifyPaymentRequest() actualsNegative: " + oldAccount.getAccountNumber() + " = " + oldAccount.getAmount());
330             }
331         }
332 
333         // Add the positive entries and subtract the negative entries
334         Map<SourceAccountingLine, KualiDecimal> glEntries = new HashMap<SourceAccountingLine, KualiDecimal>();
335 
336         // Combine the two maps (copy all the positive entries)
337         LOG.debug("generateEntriesModifyPaymentRequest() Combine positive/negative entries");
338         glEntries.putAll(actualsPositive);
339 
340         for (Iterator<SourceAccountingLine> iter = actualsNegative.keySet().iterator(); iter.hasNext(); ) {
341             SourceAccountingLine key = (SourceAccountingLine) iter.next();
342 
343             KualiDecimal amt;
344             if (glEntries.containsKey(key)) {
345                 amt = (KualiDecimal) glEntries.get(key);
346                 amt = amt.subtract((KualiDecimal) actualsNegative.get(key));
347             } else {
348                 amt = ZERO;
349                 amt = amt.subtract((KualiDecimal) actualsNegative.get(key));
350             }
351             glEntries.put(key, amt);
352         }
353 
354         List<SummaryAccount> summaryAccounts = new ArrayList<SummaryAccount>();
355         for (Iterator<SourceAccountingLine> iter = glEntries.keySet().iterator(); iter.hasNext(); ) {
356             SourceAccountingLine account = (SourceAccountingLine) iter.next();
357             KualiDecimal amount = (KualiDecimal) glEntries.get(account);
358             if (ZERO.compareTo(amount) != 0) {
359                 account.setAmount(amount);
360                 SummaryAccount sa = new SummaryAccount(account);
361                 summaryAccounts.add(sa);
362             }
363         }
364 
365         LOG.debug("generateEntriesModifyInvoice() Generate GL entries");
366         generateEntriesInvoice(inv, null, summaryAccounts, MODIFY_INVOICE);
367     }
368 
369     /**
370      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesCreateCreditMemo(VendorCreditMemoDocument)
371      */
372     public void generateEntriesCreateCreditMemo(VendorCreditMemoDocument cm) {
373         LOG.debug("generateEntriesCreateCreditMemo() started");
374         generateEntriesCreditMemo(cm, CREATE_CREDIT_MEMO);
375     }
376 
377     /**
378      * Called from generateEntriesCancelAccountsPayableDocument() for Payment Request Document
379      *
380      * @param cm VendorCreditMemoDocument to cancel
381      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesCancelAccountsPayableDocument(org.kuali.ole.module.purap.document.AccountsPayableDocument)
382      */
383     protected void generateEntriesCancelCreditMemo(VendorCreditMemoDocument cm) {
384         LOG.debug("generateEntriesCancelCreditMemo() started");
385         if(!(cm != null && cm.getDocumentHeader() != null && cm.getDocumentHeader().getWorkflowDocument() != null && cm.getDocumentHeader().getWorkflowDocument().isDisapproved())) {
386             generateEntriesCreditMemo(cm, CANCEL_CREDIT_MEMO);
387         }
388     }
389 
390     /**
391      * Retrieves the next available sequence number from the general ledger pending entry table for this document
392      *
393      * @param documentNumber Document number to find next sequence number
394      * @return Next available sequence number
395      */
396     protected int getNextAvailableSequence(String documentNumber) {
397         LOG.debug("getNextAvailableSequence() started");
398         Map fieldValues = new HashMap();
399         fieldValues.put("financialSystemOriginationCode", PURAP_ORIGIN_CODE);
400         fieldValues.put("documentNumber", documentNumber);
401         int count = businessObjectService.countMatching(GeneralLedgerPendingEntry.class, fieldValues);
402         return count + 1;
403     }
404 
405     /**
406      * Creates the general ledger entries for Payment Request actions.
407      *
408      * @param preq            Payment Request document to create entries
409      * @param encumbrances    List of encumbrance accounts if applies
410      * @param summaryAccounts List of preq accounts to create entries
411      * @param processType     Type of process (create, modify, cancel)
412      * @return Boolean returned indicating whether entry creation succeeded
413      */
414     protected boolean generateEntriesPaymentRequest(PaymentRequestDocument preq, List encumbrances, List summaryAccounts, String processType) {
415         LOG.debug("generateEntriesPaymentRequest() started");
416         boolean success = true;
417         preq.setGeneralLedgerPendingEntries(new ArrayList());
418 
419         /*
420          * Can't let generalLedgerPendingEntryService just create all the entries because we need the sequenceHelper to carry over
421          * from the encumbrances to the actuals and also because we need to tell the PaymentRequestDocumentRule customize entry
422          * method how to customize differently based on if creating an encumbrance or actual.
423          */
424         GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper(getNextAvailableSequence(preq.getDocumentNumber()));
425 
426         // when cancelling a PREQ, do not book encumbrances if PO is CLOSED
427         if (encumbrances != null && !(CANCEL_PAYMENT_REQUEST.equals(processType) && PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED.equals(preq.getPurchaseOrderDocument().getApplicationDocumentStatus()))  && preq.getDocumentHeader() != null && preq.getDocumentHeader().getWorkflowDocument()!= null && !preq.getDocumentHeader().getWorkflowDocument().isDisapproved()) {
428             LOG.debug("generateEntriesPaymentRequest() generate encumbrance entries");
429             if (CREATE_PAYMENT_REQUEST.equals(processType)) {
430                 // on create, use CREDIT code for encumbrances
431                 preq.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
432             } else if (CANCEL_PAYMENT_REQUEST.equals(processType)) {
433                 // on cancel, use DEBIT code
434                 preq.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
435             } else if (MODIFY_PAYMENT_REQUEST.equals(processType)) {
436                 // no encumbrances for modify
437             }
438 
439             preq.setGenerateEncumbranceEntries(true);
440             for (Iterator iter = encumbrances.iterator(); iter.hasNext(); ) {
441                 AccountingLine accountingLine = (AccountingLine) iter.next();
442                 preq.generateGeneralLedgerPendingEntries(accountingLine, sequenceHelper);
443                 sequenceHelper.increment(); // increment for the next line
444             }
445         }
446 
447         if (ObjectUtils.isNotNull(summaryAccounts) && !summaryAccounts.isEmpty()) {
448             LOG.debug("generateEntriesPaymentRequest() now book the actuals");
449             preq.setGenerateEncumbranceEntries(false);
450 
451             if (CREATE_PAYMENT_REQUEST.equals(processType) || MODIFY_PAYMENT_REQUEST.equals(processType)) {
452                 // on create and modify, use DEBIT code
453                 preq.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
454             } else if (CANCEL_PAYMENT_REQUEST.equals(processType)) {
455                 // on cancel, use CREDIT code
456                 preq.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
457             }
458 
459             for (Iterator iter = summaryAccounts.iterator(); iter.hasNext(); ) {
460                 SummaryAccount summaryAccount = (SummaryAccount) iter.next();
461                 Account itemAccount;
462                 KualiDecimal prorateSurcharge = KualiDecimal.ZERO;
463                 for (Iterator<PaymentRequestItem> preqIter = preq.getItems().iterator(); preqIter.hasNext(); ) {
464                     OlePaymentRequestItem item = (OlePaymentRequestItem) preqIter.next();
465                     List<PurApAccountingLine> itemAccLineList = item.getSourceAccountingLines();
466                     if (item.getItemType().isQuantityBasedGeneralLedgerIndicator() && item.getExtendedPrice() != null && item.getExtendedPrice().compareTo(KualiDecimal.ZERO) != 0) {
467                         if (item.getItemSurcharge() != null && item.getItemTypeCode().equals("ITEM")) {
468                             prorateSurcharge = new KualiDecimal(item.getItemSurcharge()).multiply(item.getItemQuantity());
469                         }
470 
471                     }
472                     for (PurApAccountingLine itemAccLine : itemAccLineList) {
473                         itemAccount = itemAccLine.getAccount();
474                         if ((itemAccount.getAccountNumber().equals(summaryAccount.getAccount().getAccountNumber())) && ((itemAccount.getChartOfAccountsCode().equals(summaryAccount.getAccount().getChartOfAccountsCode())))) {
475                             summaryAccount.getAccount().setAmount(summaryAccount.getAccount().getAmount().subtract(prorateSurcharge));
476                         }
477                         prorateSurcharge = KualiDecimal.ZERO;
478                     }
479                 }
480                 KualiDecimal summaryAmount = summaryAccount.getAccount().getAmount();
481                 if (summaryAmount.isNonZero() && preq.getDocumentHeader() != null && preq.getDocumentHeader().getWorkflowDocument()!= null && !preq.getDocumentHeader().getWorkflowDocument().isDisapproved()) {
482                     preq.generateGeneralLedgerPendingEntries(summaryAccount.getAccount(), sequenceHelper);
483                     sequenceHelper.increment(); // increment for the next line
484                 }
485             }
486 
487             // generate offset accounts for use tax if it exists (useTaxContainers will be empty if not a use tax document)
488             List<UseTaxContainer> useTaxContainers = purapAccountingService.generateUseTaxAccount(preq);
489             for (UseTaxContainer useTaxContainer : useTaxContainers) {
490                 PurApItemUseTax offset = useTaxContainer.getUseTax();
491                 List<SourceAccountingLine> accounts = useTaxContainer.getAccounts();
492                 for (SourceAccountingLine sourceAccountingLine : accounts) {
493                     preq.generateGeneralLedgerPendingEntries(sourceAccountingLine, sequenceHelper, useTaxContainer.getUseTax());
494                     sequenceHelper.increment(); // increment for the next line
495                 }
496 
497             }
498 
499             // Manually save preq summary accounts
500             if (MODIFY_PAYMENT_REQUEST.equals(processType)) {
501                 //for modify, regenerate the summary from the doc
502                 List<SummaryAccount> summaryAccountsForModify = purapAccountingService.generateSummaryAccountsWithNoZeroTotalsNoUseTax(preq);
503                 saveAccountsPayableSummaryAccounts(summaryAccountsForModify, preq.getPurapDocumentIdentifier(), PurapDocTypeCodes.PAYMENT_REQUEST_DOCUMENT);
504             } else {
505                 //for create and cancel, use the summary accounts
506                 saveAccountsPayableSummaryAccounts(summaryAccounts, preq.getPurapDocumentIdentifier(), PurapDocTypeCodes.PAYMENT_REQUEST_DOCUMENT);
507             }
508 
509             // manually save cm account change tables (CAMS needs this)
510             if (CREATE_PAYMENT_REQUEST.equals(processType) || MODIFY_PAYMENT_REQUEST.equals(processType)) {
511                 SpringContext.getBean(PurapAccountRevisionService.class).savePaymentRequestAccountRevisions(preq.getItems(), preq.getPostingYearFromPendingGLEntries(), preq.getPostingPeriodCodeFromPendingGLEntries());
512             } else if (CANCEL_PAYMENT_REQUEST.equals(processType)) {
513                 SpringContext.getBean(PurapAccountRevisionService.class).cancelPaymentRequestAccountRevisions(preq.getItems(), preq.getPostingYearFromPendingGLEntries(), preq.getPostingPeriodCodeFromPendingGLEntries());
514             }
515         }
516 
517 
518         // Manually save GL entries for Payment Request and encumbrances
519         saveGLEntries(preq.getGeneralLedgerPendingEntries());
520 
521         return success;
522     }
523 
524     /**
525      * Creates the general ledger entries for Invoice actions.
526      *
527      * @param inv             Invoice document to create entries
528      * @param encumbrances    List of encumbrance accounts if applies
529      * @param summaryAccounts List of Invoice accounts to create entries
530      * @param processType     Type of process (create, modify, cancel)
531      * @return Boolean returned indicating whether entry creation succeeded
532      */
533     protected boolean generateEntriesInvoice(InvoiceDocument inv, List encumbrances, List summaryAccounts, String processType) {
534         LOG.debug("generateEntriesPaymentRequest() started");
535         boolean success = true;
536         inv.setGeneralLedgerPendingEntries(new ArrayList());
537 
538         /**
539          * Can't let generalLedgerPendingEntryService just create all the entries because we need the sequenceHelper to carry over
540          * from the encumbrances to the actuals and also because we need to tell the PaymentRequestDocumentRule customize entry
541          * method how to customize differently based on if creating an encumbrance or actual.
542          */
543         GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper(getNextAvailableSequence(inv.getDocumentNumber()));
544 
545         // when cancelling a PREQ, do not book encumbrances if PO is CLOSED
546         if (encumbrances != null && !(CANCEL_INVOICE.equals(processType) )) {
547             LOG.debug("generateEntriesInvoice() generate encumbrance entries");
548             if (CREATE_INVOICE.equals(processType)) {
549                 // on create, use CREDIT code for encumbrances
550                 inv.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
551             } else if (CANCEL_INVOICE.equals(processType)) {
552                 // on cancel, use DEBIT code
553                 inv.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
554             } else if (MODIFY_INVOICE.equals(processType)) {
555                 // no encumbrances for modify
556             }
557 
558             inv.setGenerateEncumbranceEntries(true);
559             for (Iterator iter = encumbrances.iterator(); iter.hasNext(); ) {
560                 AccountingLine accountingLine = (AccountingLine) iter.next();
561                 inv.generateGeneralLedgerPendingEntries(accountingLine, sequenceHelper);
562                 sequenceHelper.increment(); // increment for the next line
563             }
564         }
565 
566         if (ObjectUtils.isNotNull(summaryAccounts) && !summaryAccounts.isEmpty()) {
567             LOG.debug("generateEntriesInvoice() now book the actuals");
568             inv.setGenerateEncumbranceEntries(false);
569 
570             if (CREATE_INVOICE.equals(processType) || MODIFY_INVOICE.equals(processType)) {
571                 // on create and modify, use DEBIT code
572                 inv.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
573             } else if (CANCEL_INVOICE.equals(processType)) {
574                 // on cancel, use CREDIT code
575                 inv.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
576             }
577 
578             for (Iterator iter = summaryAccounts.iterator(); iter.hasNext(); ) {
579                 SummaryAccount summaryAccount = (SummaryAccount) iter.next();
580                 Account itemAccount;
581                 KualiDecimal prorateSurcharge = KualiDecimal.ZERO;
582                 for (Iterator<OleInvoiceItem> preqIter = inv.getItems().iterator(); preqIter.hasNext(); ) {
583                     OleInvoiceItem item = (OleInvoiceItem) preqIter.next();
584                     List<PurApAccountingLine> itemAccLineList = item.getSourceAccountingLines();
585                     if (item.getItemType().isQuantityBasedGeneralLedgerIndicator() && item.getExtendedPrice() != null && item.getExtendedPrice().compareTo(KualiDecimal.ZERO) != 0) {
586                         if (item.getItemSurcharge() != null && item.getItemTypeCode().equals("ITEM")) {
587                             prorateSurcharge = new KualiDecimal(item.getItemSurcharge()).multiply(item.getItemQuantity());
588                         }
589 
590                     }
591                     for (PurApAccountingLine itemAccLine : itemAccLineList) {
592                         itemAccount = itemAccLine.getAccount();
593                         if ((itemAccount.getAccountNumber().equals(summaryAccount.getAccount().getAccountNumber())) && ((itemAccount.getChartOfAccountsCode().equals(summaryAccount.getAccount().getChartOfAccountsCode())))) {
594                             summaryAccount.getAccount().setAmount(summaryAccount.getAccount().getAmount().subtract(prorateSurcharge));
595                         }
596                         prorateSurcharge = KualiDecimal.ZERO;
597                     }
598                 }
599                 KualiDecimal summaryAmount = summaryAccount.getAccount().getAmount();
600                 if (summaryAmount.isNonZero()) {
601                     inv.generateGeneralLedgerPendingEntries(summaryAccount.getAccount(), sequenceHelper);
602                     sequenceHelper.increment(); // increment for the next line
603                 }
604             }
605 
606             // generate offset accounts for use tax if it exists (useTaxContainers will be empty if not a use tax document)
607             List<UseTaxContainer> useTaxContainers = purapAccountingService.generateUseTaxAccount(inv);
608             for (UseTaxContainer useTaxContainer : useTaxContainers) {
609                 PurApItemUseTax offset = useTaxContainer.getUseTax();
610                 List<SourceAccountingLine> accounts = useTaxContainer.getAccounts();
611                 for (SourceAccountingLine sourceAccountingLine : accounts) {
612                     inv.generateGeneralLedgerPendingEntries(sourceAccountingLine, sequenceHelper, useTaxContainer.getUseTax());
613                     sequenceHelper.increment(); // increment for the next line
614                 }
615 
616             }
617 
618             // Manually save Invoice summary accounts
619             if (MODIFY_INVOICE.equals(processType)) {
620                 //for modify, regenerate the summary from the doc
621                 List<SummaryAccount> summaryAccountsForModify = purapAccountingService.generateSummaryAccountsWithNoZeroTotalsNoUseTax(inv);
622                 saveInvoiceAccountsPayableSummaryAccounts(summaryAccountsForModify, inv.getPurapDocumentIdentifier(), PurapDocTypeCodes.INVOICE_DOCUMENT);
623             } else {
624                 //for create and cancel, use the summary accounts
625                 saveInvoiceAccountsPayableSummaryAccounts(summaryAccounts, inv.getPurapDocumentIdentifier(), PurapDocTypeCodes.INVOICE_DOCUMENT);
626             }
627 
628             // manually save cm account change tables (CAMS needs this)
629             if (CREATE_INVOICE.equals(processType) || MODIFY_INVOICE.equals(processType)) {
630                 SpringContext.getBean(PurapAccountRevisionService.class).saveInvoiceAccountRevisions(inv.getItems(), inv.getPostingYearFromPendingGLEntries(), inv.getPostingPeriodCodeFromPendingGLEntries());
631             } else if (CANCEL_INVOICE.equals(processType)) {
632                 SpringContext.getBean(PurapAccountRevisionService.class).cancelInvoiceAccountRevisions(inv.getItems(), inv.getPostingYearFromPendingGLEntries(), inv.getPostingPeriodCodeFromPendingGLEntries());
633             }
634         }
635 
636 
637         // Manually save GL entries for Invoice and encumbrances
638         //  saveGLEntries(inv.getGeneralLedgerPendingEntries());
639 
640         return success;
641     }
642 
643     /**
644      * Creates the general ledger entries for Credit Memo actions.
645      *
646      * @param cm       Credit Memo document to create entries
647      * @param isCancel Indicates if request is a cancel or create
648      * @return Boolean returned indicating whether entry creation succeeded
649      */
650     protected boolean generateEntriesCreditMemo(VendorCreditMemoDocument cm, boolean isCancel) {
651         LOG.debug("generateEntriesCreditMemo() started");
652 
653         cm.setGeneralLedgerPendingEntries(new ArrayList());
654 
655         boolean success = true;
656         GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper(getNextAvailableSequence(cm.getDocumentNumber()));
657 
658         if (!cm.isSourceVendor()) {
659             LOG.debug("generateEntriesCreditMemo() create encumbrance entries for CM against a PO or PREQ (not vendor)");
660             PurchaseOrderDocument po = null;
661             if (cm.isSourceDocumentPurchaseOrder()) {
662                 LOG.debug("generateEntriesCreditMemo() PO type");
663                 po = purchaseOrderService.getCurrentPurchaseOrder(cm.getPurchaseOrderIdentifier());
664             } else if (cm.isSourceDocumentPaymentRequest()) {
665                 LOG.debug("generateEntriesCreditMemo() PREQ type");
666                 po = purchaseOrderService.getCurrentPurchaseOrder(cm.getPaymentRequestDocument().getPurchaseOrderIdentifier());
667             }
668 
669             // for CM cancel or create, do not book encumbrances if PO is CLOSED, but do update the amounts on the PO
670             //  Coomented for JIRA:OLE-5162 as encumbrance added here
671             //  UnCommented for JIRA:OLE-6992 as encumbrance added here for positive values
672             List encumbrances = getCreditMemoEncumbrance(cm, po, isCancel);
673             if (!(PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED.equals(po.getApplicationDocumentStatus()))) {
674                 if (encumbrances != null) {
675                     cm.setGenerateEncumbranceEntries(true);
676 
677                     // even if generating encumbrance entries on cancel, call is the same because the method gets negative amounts
678                     // from
679                     // the map so Debits on negatives = a credit
680                     cm.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
681 
682                     for (Iterator iter = encumbrances.iterator(); iter.hasNext(); ) {
683                         AccountingLine accountingLine = (AccountingLine) iter.next();
684                         if (accountingLine.getAmount().compareTo(ZERO) != 0) {
685                             cm.generateGeneralLedgerPendingEntries(accountingLine, sequenceHelper);
686                             sequenceHelper.increment(); // increment for the next line
687                         }
688                     }
689                 }
690             }
691         }
692 
693         List<SummaryAccount> summaryAccounts = purapAccountingService.generateSummaryAccountsWithNoZeroTotalsNoUseTax(cm);
694         if (summaryAccounts != null) {
695             LOG.debug("generateEntriesCreditMemo() now book the actuals");
696             cm.setGenerateEncumbranceEntries(false);
697 
698             if (!isCancel) {
699                 // on create, use CREDIT code
700                 cm.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
701             } else {
702                 // on cancel, use DEBIT code
703                 cm.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
704             }
705 
706             for (Iterator iter = summaryAccounts.iterator(); iter.hasNext(); ) {
707                 SummaryAccount summaryAccount = (SummaryAccount) iter.next();
708                 cm.generateGeneralLedgerPendingEntries(summaryAccount.getAccount(), sequenceHelper);
709                 sequenceHelper.increment(); // increment for the next line
710             }
711             // generate offset accounts for use tax if it exists (useTaxContainers will be empty if not a use tax document)
712             List<UseTaxContainer> useTaxContainers = purapAccountingService.generateUseTaxAccount(cm);
713             for (UseTaxContainer useTaxContainer : useTaxContainers) {
714                 PurApItemUseTax offset = useTaxContainer.getUseTax();
715                 List<SourceAccountingLine> accounts = useTaxContainer.getAccounts();
716                 for (SourceAccountingLine sourceAccountingLine : accounts) {
717                     cm.generateGeneralLedgerPendingEntries(sourceAccountingLine, sequenceHelper, useTaxContainer.getUseTax());
718                     sequenceHelper.increment(); // increment for the next line
719                 }
720 
721             }
722 
723             // manually save cm account change tables (CAMS needs this)
724             if (!isCancel) {
725                 SpringContext.getBean(PurapAccountRevisionService.class).saveCreditMemoAccountRevisions(cm.getItems(), cm.getPostingYearFromPendingGLEntries(), cm.getPostingPeriodCodeFromPendingGLEntries());
726             } else {
727                 SpringContext.getBean(PurapAccountRevisionService.class).cancelCreditMemoAccountRevisions(cm.getItems(), cm.getPostingYearFromPendingGLEntries(), cm.getPostingPeriodCodeFromPendingGLEntries());
728             }
729         }
730 
731         saveGLEntries(cm.getGeneralLedgerPendingEntries());
732 
733         LOG.debug("generateEntriesCreditMemo() ended");
734         return success;
735     }
736 
737     /**
738      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesApproveAmendPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
739      */
740     public void generateEntriesApproveAmendPurchaseOrder(PurchaseOrderDocument po) {
741         LOG.debug("generateEntriesApproveAmendPurchaseOrder() started");
742 
743         // Set outstanding encumbered quantity/amount on items
744         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
745             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
746 
747             // if invoice fields are null (as would be for new items), set fields to zero
748             item.setItemInvoicedTotalAmount(item.getItemInvoicedTotalAmount() == null ? ZERO : item.getItemInvoicedTotalAmount());
749             item.setItemInvoicedTotalQuantity(item.getItemInvoicedTotalQuantity() == null ? ZERO : item.getItemInvoicedTotalQuantity());
750 
751             if (!item.isItemActiveIndicator()) {
752                 // set outstanding encumbrance amounts to zero for inactive items
753                 item.setItemOutstandingEncumberedQuantity(ZERO);
754                 item.setItemOutstandingEncumberedAmount(ZERO);
755 
756                 for (Iterator iter = item.getSourceAccountingLines().iterator(); iter.hasNext(); ) {
757                     PurchaseOrderAccount account = (PurchaseOrderAccount) iter.next();
758                     account.setItemAccountOutstandingEncumbranceAmount(ZERO);
759                     account.setAlternateAmountForGLEntryCreation(ZERO);
760                 }
761             } else {
762                 // Set quantities
763                 //Because of Quantity is defaulted to 1, the Additional charges also having the same quantity. So checking for the Unit Price also.
764                 if (item.getItemQuantity() != null && item.getItemUnitPrice() != null) {
765                     item.setItemOutstandingEncumberedQuantity(item.getItemQuantity().subtract(item.getItemInvoicedTotalQuantity()));
766                 } else {
767                     // if order qty is null, outstanding encumbered qty should be null
768                     item.setItemOutstandingEncumberedQuantity(null);
769                 }
770 
771                 // Set amount
772                 if (item.getItemOutstandingEncumberedQuantity() != null && item.getItemOutstandingEncumberedQuantity().isGreaterThan(new KualiDecimal(0))) {
773                     //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
774                     KualiDecimal itemEncumber = new KualiDecimal(item.getItemOutstandingEncumberedQuantity().bigDecimalValue().multiply(item.getItemUnitPrice()));
775 
776                     //add tax for encumbrance
777                     KualiDecimal itemTaxAmount = item.getItemTaxAmount() == null ? ZERO : item.getItemTaxAmount();
778                     itemEncumber = itemEncumber.add(itemTaxAmount);
779 
780                     item.setItemOutstandingEncumberedAmount(itemEncumber);
781                 }
782                 else if(item.getItemOutstandingEncumberedQuantity() != null && item.getItemOutstandingEncumberedQuantity().isLessEqual(new KualiDecimal(0))) {
783                     KualiDecimal itemEncumber = new KualiDecimal(item.getItemQuantity().bigDecimalValue().multiply(item.getItemUnitPrice()));
784 
785                     //add tax for encumbrance
786                     KualiDecimal itemTaxAmount = item.getItemTaxAmount() == null ? ZERO : item.getItemTaxAmount();
787                     itemEncumber = itemEncumber.add(itemTaxAmount);
788 
789                     item.setItemOutstandingEncumberedAmount(itemEncumber);
790 
791                 }
792                 else
793                 {
794                     if (item.getItemUnitPrice() != null) {
795                         item.setItemOutstandingEncumberedAmount(new KualiDecimal(item.getItemUnitPrice().subtract(item.getItemInvoicedTotalAmount().bigDecimalValue())));
796                     }
797                 }
798 
799                 for (Iterator iter = item.getSourceAccountingLines().iterator(); iter.hasNext(); ) {
800                     PurchaseOrderAccount account = (PurchaseOrderAccount) iter.next();
801                     BigDecimal percent = new BigDecimal(account.getAccountLinePercent().toString());
802                     percent = percent.divide(new BigDecimal("100"), 3, BigDecimal.ROUND_HALF_UP);
803                     account.setItemAccountOutstandingEncumbranceAmount(item.getItemOutstandingEncumberedAmount().multiply(new KualiDecimal(percent)));
804                     account.setAlternateAmountForGLEntryCreation(account.getItemAccountOutstandingEncumbranceAmount());
805                 }
806             }
807         }
808 
809         PurchaseOrderDocument oldPO = purchaseOrderService.getCurrentPurchaseOrder(po.getPurapDocumentIdentifier());
810 
811         if (oldPO == null) {
812             throw new IllegalArgumentException("Current Purchase Order not found - poId = " + oldPO.getPurapDocumentIdentifier());
813         }
814 
815         List newAccounts = purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly());
816         List oldAccounts = purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(oldPO.getItemsActiveOnlySetupAlternateAmount());
817 
818         Map combination = new HashMap();
819 
820         // Add amounts from the new PO
821         for (Iterator iter = newAccounts.iterator(); iter.hasNext(); ) {
822             SourceAccountingLine newAccount = (SourceAccountingLine) iter.next();
823             combination.put(newAccount, newAccount.getAmount());
824         }
825 
826         LOG.debug("generateEntriesApproveAmendPurchaseOrder() combination after the add");
827         for (Iterator iter = combination.keySet().iterator(); iter.hasNext(); ) {
828             SourceAccountingLine element = (SourceAccountingLine) iter.next();
829             if (LOG.isDebugEnabled())
830                 LOG.debug("generateEntriesApproveAmendPurchaseOrder() " + element + " = " + ((KualiDecimal) combination.get(element)).floatValue());
831         }
832 
833         // Subtract the amounts from the old PO
834         for (Iterator iter = oldAccounts.iterator(); iter.hasNext(); ) {
835             SourceAccountingLine oldAccount = (SourceAccountingLine) iter.next();
836             if (combination.containsKey(oldAccount)) {
837                 KualiDecimal amount = (KualiDecimal) combination.get(oldAccount);
838                 amount = amount.subtract(oldAccount.getAmount());
839                 combination.put(oldAccount, amount);
840             } else {
841                 combination.put(oldAccount, ZERO.subtract(oldAccount.getAmount()));
842             }
843         }
844 
845         LOG.debug("generateEntriesApproveAmendPurchaseOrder() combination after the subtract");
846         for (Iterator iter = combination.keySet().iterator(); iter.hasNext(); ) {
847             SourceAccountingLine element = (SourceAccountingLine) iter.next();
848             if (LOG.isDebugEnabled())
849                 LOG.debug("generateEntriesApproveAmendPurchaseOrder() " + element + " = " + ((KualiDecimal) combination.get(element)).floatValue());
850         }
851 
852         List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
853         for (Iterator iter = combination.keySet().iterator(); iter.hasNext(); ) {
854             SourceAccountingLine account = (SourceAccountingLine) iter.next();
855             KualiDecimal amount = (KualiDecimal) combination.get(account);
856             if (ZERO.compareTo(amount) != 0) {
857                 account.setAmount(amount);
858                 encumbranceAccounts.add(account);
859             }
860         }
861 
862         po.setGlOnlySourceAccountingLines(encumbranceAccounts);
863         generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po);
864         saveGLEntries(po.getGeneralLedgerPendingEntries());
865         LOG.debug("generateEntriesApproveAmendPo() gl entries created; exit method");
866     }
867 
868     /**
869      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesClosePurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
870      */
871     public void generateEntriesClosePurchaseOrder(PurchaseOrderDocument po) {
872         LOG.debug("generateEntriesClosePurchaseOrder() started");
873 
874         // Set outstanding encumbered quantity/amount on items
875         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
876             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
877 
878             String logItmNbr = "Item # " + item.getItemLineNumber();
879 
880             if (!item.isItemActiveIndicator()) {
881                 continue;
882             }
883 
884             KualiDecimal itemAmount = null;
885             if (LOG.isDebugEnabled()) {
886                 LOG.debug("generateEntriesClosePurchaseOrder() " + logItmNbr + " Calculate based on amounts");
887             }
888             itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO : item.getItemOutstandingEncumberedAmount();
889 
890             KualiDecimal accountTotal = ZERO;
891             PurchaseOrderAccount lastAccount = null;
892             if (itemAmount.compareTo(ZERO) != 0) {
893                 // Sort accounts
894                 Collections.sort((List) item.getSourceAccountingLines());
895 
896                 for (Iterator iterAcct = item.getSourceAccountingLines().iterator(); iterAcct.hasNext(); ) {
897                     PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct.next();
898                     if (!acct.isEmpty()) {
899                         KualiDecimal acctAmount = itemAmount.multiply(new KualiDecimal(acct.getAccountLinePercent().toString())).divide(PurapConstants.HUNDRED);
900                         accountTotal = accountTotal.add(acctAmount);
901                         acct.setAlternateAmountForGLEntryCreation(acctAmount);
902                         lastAccount = acct;
903                     }
904                 }
905 
906                 // account for rounding by adjusting last account as needed
907                 if (lastAccount != null) {
908                     KualiDecimal difference = itemAmount.subtract(accountTotal);
909                     if (LOG.isDebugEnabled()) {
910                         LOG.debug("generateEntriesClosePurchaseOrder() difference: " + logItmNbr + " " + difference);
911                     }
912 
913                     KualiDecimal amount = lastAccount.getAlternateAmountForGLEntryCreation();
914                     if (ObjectUtils.isNotNull(amount)) {
915                         lastAccount.setAlternateAmountForGLEntryCreation(amount.add(difference));
916                     } else {
917                         lastAccount.setAlternateAmountForGLEntryCreation(difference);
918                     }
919                 }
920 
921             }
922         }// endfor
923 
924         po.setGlOnlySourceAccountingLines(purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly()));
925         if (shouldGenerateGLPEForPurchaseOrder(po)) {
926             generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po);
927             saveGLEntries(po.getGeneralLedgerPendingEntries());
928             LOG.debug("generateEntriesClosePurchaseOrder() gl entries created; exit method");
929         }
930 
931         //MSU Contribution DTT-3812 OLEMI-8642 OLECNTRB-957
932         // Set outstanding encumbered quantity/amount on items
933         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
934             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
935             if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
936                 item.setItemOutstandingEncumberedQuantity(KualiDecimal.ZERO);
937             }
938             item.setItemOutstandingEncumberedAmount(KualiDecimal.ZERO);
939             List<PurApAccountingLine> sourceAccountingLines = item.getSourceAccountingLines();
940             for (PurApAccountingLine purApAccountingLine : sourceAccountingLines) {
941                 PurchaseOrderAccount account = (PurchaseOrderAccount) purApAccountingLine;
942                 account.setItemAccountOutstandingEncumbranceAmount(KualiDecimal.ZERO);
943             }
944 
945         }// endfor
946 
947         LOG.debug("generateEntriesClosePurchaseOrder() no gl entries created because the amount is 0; exit method");
948     }
949 
950     /**
951      * We should not generate general ledger pending entries for Purchase Order Close Document and
952      * Purchase Order Reopen Document with $0 amount.
953      *
954      * @param po
955      * @return
956      */
957     protected boolean shouldGenerateGLPEForPurchaseOrder(PurchaseOrderDocument po) {
958         for (SourceAccountingLine acct : (List<SourceAccountingLine>) po.getSourceAccountingLines()) {
959             if (acct.getAmount().abs().compareTo(new KualiDecimal(0)) > 0) {
960                 return true;
961             }
962         }
963         return false;
964     }
965 
966     /**
967      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesReopenPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
968      */
969     public void generateEntriesReopenPurchaseOrder(PurchaseOrderDocument po) {
970         LOG.debug("generateEntriesReopenPurchaseOrder() started");
971 
972         //MSU Contribution DTT-3812 OLEMI-8642 OLECNTRB-957
973         // Set outstanding encumbered quantity/amount on items
974         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
975             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
976 
977             // if invoice fields are null (as would be for new items), set fields to zero
978             item.setItemInvoicedTotalAmount(item.getItemInvoicedTotalAmount() == null ? ZERO : item.getItemInvoicedTotalAmount());
979             item.setItemInvoicedTotalQuantity(item.getItemInvoicedTotalQuantity() == null ? ZERO : item.getItemInvoicedTotalQuantity());
980 
981             if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
982                 item.getItemQuantity().subtract(item.getItemInvoicedTotalQuantity());
983                 item.setItemOutstandingEncumberedQuantity(item.getItemQuantity().subtract(item.getItemInvoicedTotalQuantity()));
984                 if(item.getItemOutstandingEncumberedQuantity().isGreaterThan(new KualiDecimal(0))) {
985                     item.setItemOutstandingEncumberedAmount(new KualiDecimal(item.getItemOutstandingEncumberedQuantity().bigDecimalValue().multiply(item.getItemUnitPrice())));
986                 }
987                 else {
988                     item.setItemOutstandingEncumberedAmount(new KualiDecimal(item.getItemQuantity().bigDecimalValue().multiply(item.getItemUnitPrice())));
989                     item.setItemOutstandingEncumberedQuantity(new KualiDecimal(item.getItemQuantity().bigDecimalValue()));
990                 }
991             } else {
992                 if((item.getTotalAmount().subtract(item.getItemInvoicedTotalAmount()).isGreaterThan(new KualiDecimal(0)))) {
993                     item.setItemOutstandingEncumberedAmount(item.getTotalAmount().subtract(item.getItemInvoicedTotalAmount()));
994                 }
995                 else {
996                     item.setItemOutstandingEncumberedAmount(item.getTotalAmount());
997                     item.setItemOutstandingEncumberedQuantity(new KualiDecimal(item.getItemQuantity().bigDecimalValue()));
998                 }
999             }
1000             List<PurApAccountingLine> sourceAccountingLines = item.getSourceAccountingLines();
1001             for (PurApAccountingLine purApAccountingLine : sourceAccountingLines) {
1002                 PurchaseOrderAccount account = (PurchaseOrderAccount) purApAccountingLine;
1003                 account.setItemAccountOutstandingEncumbranceAmount(new KualiDecimal(item.getItemOutstandingEncumberedAmount().bigDecimalValue().multiply(account.getAccountLinePercent()).divide(OLEConstants.ONE_HUNDRED.bigDecimalValue())));
1004             }
1005         }// endfor
1006 
1007         // Set outstanding encumbered quantity/amount on items
1008         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
1009             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
1010 
1011             String logItmNbr = "Item # " + item.getItemLineNumber();
1012 
1013             if (!item.isItemActiveIndicator()) {
1014                 continue;
1015             }
1016 
1017             KualiDecimal itemAmount = null;
1018             if (item.getItemType().isAmountBasedGeneralLedgerIndicator()) {
1019                 if (LOG.isDebugEnabled()) {
1020                     LOG.debug("generateEntriesReopenPurchaseOrder() " + logItmNbr + " Calculate based on amounts");
1021                 }
1022                 itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO : item.getItemOutstandingEncumberedAmount();
1023             } else {
1024                 if (LOG.isDebugEnabled()) {
1025                     LOG.debug("generateEntriesReopenPurchaseOrder() " + logItmNbr + " Calculate based on quantities");
1026                 }
1027                 //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
1028                 itemAmount = new KualiDecimal(item.getItemOutstandingEncumberedQuantity().bigDecimalValue().multiply(item.getItemUnitPrice()));
1029             }
1030 
1031             KualiDecimal accountTotal = ZERO;
1032             PurchaseOrderAccount lastAccount = null;
1033             if (itemAmount.compareTo(ZERO) != 0) {
1034                 // Sort accounts
1035                 Collections.sort((List) item.getSourceAccountingLines());
1036 
1037                 for (Iterator iterAcct = item.getSourceAccountingLines().iterator(); iterAcct.hasNext(); ) {
1038                     PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct.next();
1039                     if (!acct.isEmpty()) {
1040                         KualiDecimal acctAmount = itemAmount.multiply(new KualiDecimal(acct.getAccountLinePercent().toString())).divide(PurapConstants.HUNDRED);
1041                         accountTotal = accountTotal.add(acctAmount);
1042                         acct.setAlternateAmountForGLEntryCreation(acctAmount);
1043                         lastAccount = acct;
1044                     }
1045                 }
1046 
1047                 // account for rounding by adjusting last account as needed
1048                 if (lastAccount != null) {
1049                     KualiDecimal difference = itemAmount.subtract(accountTotal);
1050                     if (LOG.isDebugEnabled()) {
1051                         LOG.debug("generateEntriesReopenPurchaseOrder() difference: " + logItmNbr + " " + difference);
1052                     }
1053 
1054                     KualiDecimal amount = lastAccount.getAlternateAmountForGLEntryCreation();
1055                     if (ObjectUtils.isNotNull(amount)) {
1056                         lastAccount.setAlternateAmountForGLEntryCreation(amount.add(difference));
1057                     } else {
1058                         lastAccount.setAlternateAmountForGLEntryCreation(difference);
1059                     }
1060                 }
1061 
1062             }
1063         }// endfor
1064 
1065         po.setGlOnlySourceAccountingLines(purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly()));
1066         if (shouldGenerateGLPEForPurchaseOrder(po)) {
1067             generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po);
1068             saveGLEntries(po.getGeneralLedgerPendingEntries());
1069             LOG.debug("generateEntriesReopenPurchaseOrder() gl entries created; exit method");
1070         }
1071         LOG.debug("generateEntriesReopenPurchaseOrder() no gl entries created because the amount is 0; exit method");
1072     }
1073 
1074     /**
1075      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesVoidPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1076      */
1077     public void generateEntriesVoidPurchaseOrder(PurchaseOrderDocument po) {
1078         LOG.debug("generateEntriesVoidPurchaseOrder() started");
1079 
1080         // Set outstanding encumbered quantity/amount on items
1081         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
1082             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
1083 
1084             String logItmNbr = "Item # " + item.getItemLineNumber();
1085 
1086             if (!item.isItemActiveIndicator()) {
1087                 continue;
1088             }
1089 
1090             //just use the outstanding amount as recalculating here, particularly the item tax will cause
1091             //amounts to be over or under encumbered and the remaining encumbered amount should be unencumbered during a close
1092             if (LOG.isDebugEnabled()) {
1093                 LOG.debug("generateEntriesVoidPurchaseOrder() " + logItmNbr + " Calculate based on amounts");
1094             }
1095             KualiDecimal itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO : item.getItemOutstandingEncumberedAmount();
1096 
1097             KualiDecimal accountTotal = ZERO;
1098             PurchaseOrderAccount lastAccount = null;
1099             if (itemAmount.compareTo(ZERO) != 0) {
1100                 // Sort accounts
1101                 Collections.sort((List) item.getSourceAccountingLines());
1102 
1103                 for (Iterator iterAcct = item.getSourceAccountingLines().iterator(); iterAcct.hasNext(); ) {
1104                     PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct.next();
1105                     if (!acct.isEmpty()) {
1106                         KualiDecimal acctAmount = itemAmount.multiply(new KualiDecimal(acct.getAccountLinePercent().toString())).divide(PurapConstants.HUNDRED);
1107                         accountTotal = accountTotal.add(acctAmount);
1108                         acct.setAlternateAmountForGLEntryCreation(acctAmount);
1109                         lastAccount = acct;
1110                     }
1111                 }
1112 
1113                 // account for rounding by adjusting last account as needed
1114                 if (lastAccount != null) {
1115                     KualiDecimal difference = itemAmount.subtract(accountTotal);
1116                     if (LOG.isDebugEnabled()) {
1117                         LOG.debug("generateEntriesVoidPurchaseOrder() difference: " + logItmNbr + " " + difference);
1118                     }
1119 
1120                     KualiDecimal amount = lastAccount.getAlternateAmountForGLEntryCreation();
1121                     if (ObjectUtils.isNotNull(amount)) {
1122                         lastAccount.setAlternateAmountForGLEntryCreation(amount.add(difference));
1123                     } else {
1124                         lastAccount.setAlternateAmountForGLEntryCreation(difference);
1125                     }
1126                 }
1127 
1128             }
1129         }// endfor
1130 
1131         po.setGlOnlySourceAccountingLines(purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly()));
1132         generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po);
1133         saveGLEntries(po.getGeneralLedgerPendingEntries());
1134         LOG.debug("generateEntriesVoidPurchaseOrder() gl entries created; exit method");
1135     }
1136 
1137     /**
1138      * Relieve the Encumbrance on a PO based on values in a PREQ. This is to be called when a PREQ is created. Note: This modifies
1139      * the encumbrance values on the PO and saves the PO
1140      *
1141      * @param preq PREQ for invoice
1142      * @return List of accounting lines to use to create the pending general ledger entries
1143      */
1144     protected List<SourceAccountingLine> relieveEncumbrance(PaymentRequestDocument preq) {
1145         LOG.debug("relieveEncumbrance() started");
1146 
1147         Map encumbranceAccountMap = new HashMap();
1148         PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(preq.getPurchaseOrderIdentifier());
1149 
1150         // Get each item one by one
1151         for (Iterator items = preq.getItems().iterator(); items.hasNext(); ) {
1152             PaymentRequestItem preqItem = (PaymentRequestItem) items.next();
1153             PurchaseOrderItem poItem = getPoItem(po, preqItem.getItemLineNumber(), preqItem.getItemType());
1154 
1155             boolean takeAll = false; // Set this true if we relieve the entire encumbrance
1156             KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item
1157 
1158             String logItmNbr = "Item # " + preqItem.getItemLineNumber();
1159             if (LOG.isDebugEnabled()) {
1160                 LOG.debug("relieveEncumbrance() " + logItmNbr);
1161             }
1162 
1163             // If there isn't a PO item or the extended price is 0, we don't need encumbrances
1164             if (poItem == null) {
1165                 if (LOG.isDebugEnabled()) {
1166                     LOG.debug("relieveEncumbrance() " + logItmNbr + " No encumbrances required because po item is null");
1167                 }
1168             } else {
1169                 final KualiDecimal preqItemTotalAmount = (preqItem.getTotalAmount() == null) ? KualiDecimal.ZERO : preqItem.getTotalAmount();
1170                 if (ZERO.compareTo(preqItemTotalAmount) == 0) {
1171                     /*
1172                      * This is a specialized case where PREQ item being processed must adjust the PO item's outstanding encumbered
1173                      * quantity. This kind of scenario is mostly seen on warranty type items. The following must be true to do this:
1174                      * PREQ item Extended Price must be ZERO, PREQ item invoice quantity must be not empty and not ZERO, and PO item
1175                      * is quantity based PO item unit cost is ZERO
1176                      */
1177                     if (LOG.isDebugEnabled()) {
1178                         LOG.debug("relieveEncumbrance() " + logItmNbr + " No GL encumbrances required because extended price is ZERO");
1179                     }
1180                     if ((poItem.getItemQuantity() != null) && ((BigDecimal.ZERO.compareTo(poItem.getItemUnitPrice())) == 0)) {
1181                         // po has order quantity and unit price is ZERO... reduce outstanding encumbered quantity
1182                         if (LOG.isDebugEnabled()) {
1183                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate po oustanding encumbrance");
1184                         }
1185 
1186                         // Do encumbrance calculations based on quantity
1187                         if ((preqItem.getItemQuantity() != null) && ((ZERO.compareTo(preqItem.getItemQuantity())) != 0)) {
1188                             KualiDecimal invoiceQuantity = preqItem.getItemQuantity();
1189                             KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1190 
1191                             KualiDecimal encumbranceQuantity;
1192                             if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) {
1193                                 // We bought more than the quantity on the PO
1194                                 if (LOG.isDebugEnabled()) {
1195                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1196                                 }
1197                                 encumbranceQuantity = outstandingEncumberedQuantity;
1198                                 poItem.setItemOutstandingEncumberedQuantity(ZERO);
1199                             } else {
1200                                 encumbranceQuantity = invoiceQuantity;
1201                                 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity));
1202                                 if (LOG.isDebugEnabled()) {
1203                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " adjusting oustanding encunbrance qty - encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity());
1204                                 }
1205                             }
1206 
1207                             if (poItem.getItemInvoicedTotalQuantity() == null) {
1208                                 poItem.setItemInvoicedTotalQuantity(invoiceQuantity);
1209                             } else {
1210                                 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity));
1211                             }
1212                         }
1213                     }
1214 
1215 
1216                 } else {
1217                     if (LOG.isDebugEnabled()) {
1218                         LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
1219                     }
1220 
1221                     // Do we calculate the encumbrance amount based on quantity or amount?
1222                     if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1223                         if (LOG.isDebugEnabled()) {
1224                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
1225                         }
1226 
1227                         // Do encumbrance calculations based on quantity
1228                         KualiDecimal invoiceQuantity = preqItem.getItemQuantity() == null ? ZERO : preqItem.getItemQuantity();
1229                         KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1230 
1231                         KualiDecimal encumbranceQuantity;
1232 
1233                         if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) {
1234                             // We bought more than the quantity on the PO
1235                             if (LOG.isDebugEnabled()) {
1236                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1237                             }
1238                             encumbranceQuantity = outstandingEncumberedQuantity;
1239                             poItem.setItemOutstandingEncumberedQuantity(ZERO);
1240                             takeAll = true;
1241                         }
1242                         else if (outstandingEncumberedQuantity.isLessEqual(new KualiDecimal(0))) {
1243                             // We bought more than the quantity on the PO
1244                             //  if (LOG.isDebugEnabled()) {
1245                             LOG.info("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1246                             // }
1247                             encumbranceQuantity = poItem.getItemQuantity();
1248                             poItem.setItemOutstandingEncumberedQuantity(ZERO);
1249                             takeAll = true;
1250                         }
1251 
1252                         else {
1253                             encumbranceQuantity = invoiceQuantity;
1254                             poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity));
1255                             if (ZERO.compareTo(poItem.getItemOutstandingEncumberedQuantity()) == 0) {
1256                                 takeAll = true;
1257                             }
1258                             if (LOG.isDebugEnabled()) {
1259                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity());
1260                             }
1261                         }
1262 
1263                         if (poItem.getItemInvoicedTotalQuantity() == null) {
1264                             poItem.setItemInvoicedTotalQuantity(invoiceQuantity);
1265                         } else {
1266                             poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity));
1267                         }
1268 
1269                         itemDisEncumber = new KualiDecimal(encumbranceQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
1270 
1271                         //add tax for encumbrance
1272                         KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
1273                         KualiDecimal encumbranceTaxAmount = encumbranceQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
1274                         itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount);
1275                     } else {
1276                         if (LOG.isDebugEnabled()) {
1277                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
1278                         }
1279 
1280                         // Do encumbrance calculations based on amount only
1281                         if ((poItem.getItemOutstandingEncumberedAmount().bigDecimalValue().signum() == -1) && (preqItemTotalAmount.bigDecimalValue().signum() == -1)) {
1282                             if (LOG.isDebugEnabled()) {
1283                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is negative: " + poItem.getItemOutstandingEncumberedAmount());
1284                             }
1285                             if (preqItemTotalAmount.compareTo(poItem.getItemOutstandingEncumberedAmount()) >= 0) {
1286                                 // extended price is equal to or greater than outstanding encumbered
1287                                 itemDisEncumber = preqItemTotalAmount;
1288                             }
1289                             else if (poItem.getItemOutstandingEncumberedAmount().isLessEqual(new KualiDecimal(0))) {
1290                                 // We bought more than the quantity on the PO
1291                                 //  if (LOG.isDebugEnabled()) {
1292                                 LOG.info("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1293                                 //  }
1294                                 itemDisEncumber = poItem.getItemQuantity().multiply(new KualiDecimal(poItem.getItemUnitPrice()));
1295                                 poItem.setItemOutstandingEncumberedQuantity(ZERO);
1296                                 takeAll = true;
1297                             }
1298 
1299                             else {
1300                                 // extended price is less than outstanding encumbered
1301                                 takeAll = true;
1302                                 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
1303                             }
1304                         } else {
1305                             if (LOG.isDebugEnabled()) {
1306                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is positive or ZERO: " + poItem.getItemOutstandingEncumberedAmount());
1307                             }
1308                             if (poItem.getItemOutstandingEncumberedAmount().compareTo(preqItemTotalAmount) >= 0) {
1309                                 // outstanding amount is equal to or greater than extended price
1310                                 itemDisEncumber = preqItemTotalAmount;
1311                             } else {
1312                                 // outstanding amount is less than extended price
1313                                 takeAll = true;
1314                                 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
1315                             }
1316                         }
1317                     }
1318 
1319                     if (LOG.isDebugEnabled()) {
1320                         LOG.debug("relieveEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber);
1321                     }
1322 
1323                     KualiDecimal newOutstandingEncumberedAmount = new KualiDecimal(0);
1324                     if (poItem.getItemOutstandingEncumberedAmount().isLessEqual(new KualiDecimal(0))) {
1325                         newOutstandingEncumberedAmount = itemDisEncumber;
1326                     }
1327                     else {
1328                         newOutstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount().subtract(itemDisEncumber);
1329                     }
1330                     if (LOG.isDebugEnabled()) {
1331                         LOG.debug("relieveEncumbrance() " + logItmNbr + " New Outstanding Encumbered amount is : " + newOutstandingEncumberedAmount);
1332                     }
1333                     poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1334 
1335                     KualiDecimal newInvoicedTotalAmount = poItem.getItemInvoicedTotalAmount().add(preqItemTotalAmount);
1336                     if (LOG.isDebugEnabled()) {
1337                         LOG.debug("relieveEncumbrance() " + logItmNbr + " New Invoiced Total Amount is: " + newInvoicedTotalAmount);
1338                     }
1339                     poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1340 
1341                     // Sort accounts
1342                     Collections.sort((List) poItem.getSourceAccountingLines());
1343 
1344                     // make the list of accounts for the disencumbrance entry
1345                     PurchaseOrderAccount lastAccount = null;
1346                     KualiDecimal accountTotal = ZERO;
1347                     for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
1348                         PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
1349                         if (!account.isEmpty()) {
1350                             KualiDecimal encumbranceAmount = null;
1351                             SourceAccountingLine acctString = account.generateSourceAccountingLine();
1352                             if (takeAll) {
1353                                 // fully paid; remove remaining encumbrance
1354                                 encumbranceAmount = account.getItemAccountOutstandingEncumbranceAmount();
1355                                 account.setItemAccountOutstandingEncumbranceAmount(ZERO);
1356                                 if (LOG.isDebugEnabled()) {
1357                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " take all");
1358                                 }
1359                             } else {
1360                                 // amount = item disencumber * account percent / 100
1361                                 encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED);
1362 
1363                                 account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().subtract(encumbranceAmount));
1364 
1365                                 // For rounding check at the end
1366                                 accountTotal = accountTotal.add(encumbranceAmount);
1367 
1368                                 // If we are zeroing out the encumbrance, we don't need to adjust for rounding
1369                                 if (!takeAll) {
1370                                     lastAccount = account;
1371                                 }
1372                             }
1373 
1374                             if (LOG.isDebugEnabled()) {
1375                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount);
1376                             }
1377                             if (ObjectUtils.isNull(encumbranceAccountMap.get(acctString))) {
1378                                 encumbranceAccountMap.put(acctString, encumbranceAmount);
1379                             } else {
1380                                 KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString);
1381                                 encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount));
1382                             }
1383 
1384                         }
1385                     }
1386 
1387                     // account for rounding by adjusting last account as needed
1388                     if (lastAccount != null) {
1389                         KualiDecimal difference = itemDisEncumber.subtract(accountTotal);
1390                         if (LOG.isDebugEnabled()) {
1391                             LOG.debug("relieveEncumbrance() difference: " + logItmNbr + " " + difference);
1392                         }
1393 
1394                         SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
1395                         KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1396                         if (ObjectUtils.isNull(amount)) {
1397                             encumbranceAccountMap.put(acctString, difference);
1398                         } else {
1399                             encumbranceAccountMap.put(acctString, amount.add(difference));
1400                         }
1401 
1402                         lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().subtract(difference));
1403                     }
1404                 }
1405             }
1406         }// endfor
1407 
1408         SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
1409 
1410         List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
1411         for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
1412             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
1413             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1414             if (amount.doubleValue() != 0) {
1415                 acctString.setAmount(amount);
1416                 encumbranceAccounts.add(acctString);
1417             }
1418         }
1419         //SpringContext.getBean(BusinessObjectService.class).save(po);
1420         return encumbranceAccounts;
1421     }
1422 
1423 
1424     /**
1425      * Relieve the Encumbrance on a PO based on values in a PREQ. This is to be called when a PREQ is created. Note: This modifies
1426      * the encumbrance values on the PO and saves the PO
1427      *
1428      * @param inv inv for InvoiceDocument
1429      * @return List of accounting lines to use to create the pending general ledger entries
1430      */
1431     protected List<SourceAccountingLine> relieveEncumbrance(InvoiceDocument inv) {
1432         LOG.debug("relieveEncumbrance() started");
1433 
1434         Map encumbranceAccountMap = new HashMap();
1435         // PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(inv.getPurchaseOrderIdentifier());
1436         for (PurchaseOrderDocument po : inv.getPurchaseOrderDocuments()) {
1437             // Get each item one by one
1438             for (Iterator items = inv.getItems().iterator(); items.hasNext(); ) {
1439                 InvoiceItem invItem = (InvoiceItem) items.next();
1440                 PurchaseOrderItem poItem = getPoItem(po, invItem.getItemLineNumber(), invItem.getItemType());
1441 
1442                 boolean takeAll = false; // Set this true if we relieve the entire encumbrance
1443                 KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item
1444 
1445                 String logItmNbr = "Item # " + invItem.getItemLineNumber();
1446                 if (LOG.isDebugEnabled()) {
1447                     LOG.debug("relieveEncumbrance() " + logItmNbr);
1448                 }
1449 
1450                 // If there isn't a PO item or the extended price is 0, we don't need encumbrances
1451                 if (poItem == null) {
1452                     if (LOG.isDebugEnabled()) {
1453                         LOG.debug("relieveEncumbrance() " + logItmNbr + " No encumbrances required because po item is null");
1454                     }
1455                 } else {
1456                     final KualiDecimal preqItemTotalAmount = (invItem.getTotalAmount() == null) ? KualiDecimal.ZERO : invItem.getTotalAmount();
1457                     if (ZERO.compareTo(preqItemTotalAmount) == 0) {
1458                     /*
1459                      * This is a specialized case where PREQ item being processed must adjust the PO item's outstanding encumbered
1460                      * quantity. This kind of scenario is mostly seen on warranty type items. The following must be true to do this:
1461                      * PREQ item Extended Price must be ZERO, PREQ item invoice quantity must be not empty and not ZERO, and PO item
1462                      * is quantity based PO item unit cost is ZERO
1463                      */
1464                         if (LOG.isDebugEnabled()) {
1465                             LOG.debug("relieveEncumbrance() " + logItmNbr + " No GL encumbrances required because extended price is ZERO");
1466                         }
1467                         if ((poItem.getItemQuantity() != null) && ((BigDecimal.ZERO.compareTo(poItem.getItemUnitPrice())) == 0)) {
1468                             // po has order quantity and unit price is ZERO... reduce outstanding encumbered quantity
1469                             if (LOG.isDebugEnabled()) {
1470                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate po oustanding encumbrance");
1471                             }
1472 
1473                             // Do encumbrance calculations based on quantity
1474                             if ((invItem.getItemQuantity() != null) && ((ZERO.compareTo(invItem.getItemQuantity())) != 0)) {
1475                                 KualiDecimal invoiceQuantity = invItem.getItemQuantity();
1476                                 KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1477 
1478                                 KualiDecimal encumbranceQuantity;
1479                                 if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) {
1480                                     // We bought more than the quantity on the PO
1481                                     if (LOG.isDebugEnabled()) {
1482                                         LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1483                                     }
1484                                     encumbranceQuantity = outstandingEncumberedQuantity;
1485                                     poItem.setItemOutstandingEncumberedQuantity(ZERO);
1486                                 } else {
1487                                     encumbranceQuantity = invoiceQuantity;
1488                                     poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity));
1489                                     if (LOG.isDebugEnabled()) {
1490                                         LOG.debug("relieveEncumbrance() " + logItmNbr + " adjusting oustanding encunbrance qty - encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity());
1491                                     }
1492                                 }
1493 
1494                                 if (poItem.getItemInvoicedTotalQuantity() == null) {
1495                                     poItem.setItemInvoicedTotalQuantity(invoiceQuantity);
1496                                 } else {
1497                                     poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity));
1498                                 }
1499                             }
1500                         }
1501 
1502 
1503                     } else {
1504                         if (LOG.isDebugEnabled()) {
1505                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
1506                         }
1507 
1508                         // Do we calculate the encumbrance amount based on quantity or amount?
1509                         if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1510                             if (LOG.isDebugEnabled()) {
1511                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
1512                             }
1513 
1514                             // Do encumbrance calculations based on quantity
1515                             KualiDecimal invoiceQuantity = invItem.getItemQuantity() == null ? ZERO : invItem.getItemQuantity();
1516                             KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1517 
1518                             KualiDecimal encumbranceQuantity;
1519 
1520                             if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) {
1521                                 // We bought more than the quantity on the PO
1522                                 if (LOG.isDebugEnabled()) {
1523                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1524                                 }
1525                                 encumbranceQuantity = outstandingEncumberedQuantity;
1526                                 poItem.setItemOutstandingEncumberedQuantity(ZERO);
1527                                 takeAll = true;
1528                             } else {
1529                                 encumbranceQuantity = invoiceQuantity;
1530                                 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity));
1531                                 if (ZERO.compareTo(poItem.getItemOutstandingEncumberedQuantity()) == 0) {
1532                                     takeAll = true;
1533                                 }
1534                                 if (LOG.isDebugEnabled()) {
1535                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity());
1536                                 }
1537                             }
1538 
1539                             if (poItem.getItemInvoicedTotalQuantity() == null) {
1540                                 poItem.setItemInvoicedTotalQuantity(invoiceQuantity);
1541                             } else {
1542                                 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity));
1543                             }
1544 
1545                             itemDisEncumber = new KualiDecimal(encumbranceQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
1546 
1547                             //add tax for encumbrance
1548                             KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
1549                             KualiDecimal encumbranceTaxAmount = encumbranceQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
1550                             itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount);
1551                         } else {
1552                             if (LOG.isDebugEnabled()) {
1553                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
1554                             }
1555 
1556                             // Do encumbrance calculations based on amount only
1557                             if ((poItem.getItemOutstandingEncumberedAmount().bigDecimalValue().signum() == -1) && (preqItemTotalAmount.bigDecimalValue().signum() == -1)) {
1558                                 if (LOG.isDebugEnabled()) {
1559                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is negative: " + poItem.getItemOutstandingEncumberedAmount());
1560                                 }
1561                                 if (preqItemTotalAmount.compareTo(poItem.getItemOutstandingEncumberedAmount()) >= 0) {
1562                                     // extended price is equal to or greater than outstanding encumbered
1563                                     itemDisEncumber = preqItemTotalAmount;
1564                                 } else {
1565                                     // extended price is less than outstanding encumbered
1566                                     takeAll = true;
1567                                     itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
1568                                 }
1569                             } else {
1570                                 if (LOG.isDebugEnabled()) {
1571                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is positive or ZERO: " + poItem.getItemOutstandingEncumberedAmount());
1572                                 }
1573                                 if (poItem.getItemOutstandingEncumberedAmount().compareTo(preqItemTotalAmount) >= 0) {
1574                                     // outstanding amount is equal to or greater than extended price
1575                                     itemDisEncumber = preqItemTotalAmount;
1576                                 } else {
1577                                     // outstanding amount is less than extended price
1578                                     takeAll = true;
1579                                     itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
1580                                 }
1581                             }
1582                         }
1583 
1584                         if (LOG.isDebugEnabled()) {
1585                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber);
1586                         }
1587 
1588                         KualiDecimal newOutstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount().subtract(itemDisEncumber);
1589                         if (LOG.isDebugEnabled()) {
1590                             LOG.debug("relieveEncumbrance() " + logItmNbr + " New Outstanding Encumbered amount is : " + newOutstandingEncumberedAmount);
1591                         }
1592                         poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1593 
1594                         KualiDecimal newInvoicedTotalAmount = poItem.getItemInvoicedTotalAmount().add(preqItemTotalAmount);
1595                         if (LOG.isDebugEnabled()) {
1596                             LOG.debug("relieveEncumbrance() " + logItmNbr + " New Invoiced Total Amount is: " + newInvoicedTotalAmount);
1597                         }
1598                         poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1599 
1600                         // Sort accounts
1601                         Collections.sort((List) poItem.getSourceAccountingLines());
1602 
1603                         // make the list of accounts for the disencumbrance entry
1604                         PurchaseOrderAccount lastAccount = null;
1605                         KualiDecimal accountTotal = ZERO;
1606                         for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
1607                             PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
1608                             if (!account.isEmpty()) {
1609                                 KualiDecimal encumbranceAmount = null;
1610                                 SourceAccountingLine acctString = account.generateSourceAccountingLine();
1611                                 if (takeAll) {
1612                                     // fully paid; remove remaining encumbrance
1613                                     encumbranceAmount = account.getItemAccountOutstandingEncumbranceAmount();
1614                                     account.setItemAccountOutstandingEncumbranceAmount(ZERO);
1615                                     if (LOG.isDebugEnabled()) {
1616                                         LOG.debug("relieveEncumbrance() " + logItmNbr + " take all");
1617                                     }
1618                                 } else {
1619                                     // amount = item disencumber * account percent / 100
1620                                     encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED);
1621 
1622                                     account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().subtract(encumbranceAmount));
1623 
1624                                     // For rounding check at the end
1625                                     accountTotal = accountTotal.add(encumbranceAmount);
1626 
1627                                     // If we are zeroing out the encumbrance, we don't need to adjust for rounding
1628                                     if (!takeAll) {
1629                                         lastAccount = account;
1630                                     }
1631                                 }
1632 
1633                                 if (LOG.isDebugEnabled()) {
1634                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount);
1635                                 }
1636                                 if (ObjectUtils.isNull(encumbranceAccountMap.get(acctString))) {
1637                                     encumbranceAccountMap.put(acctString, encumbranceAmount);
1638                                 } else {
1639                                     KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString);
1640                                     encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount));
1641                                 }
1642 
1643                             }
1644                         }
1645 
1646                         // account for rounding by adjusting last account as needed
1647                         if (lastAccount != null) {
1648                             KualiDecimal difference = itemDisEncumber.subtract(accountTotal);
1649                             if (LOG.isDebugEnabled()) {
1650                                 LOG.debug("relieveEncumbrance() difference: " + logItmNbr + " " + difference);
1651                             }
1652 
1653                             SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
1654                             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1655                             if (ObjectUtils.isNull(amount)) {
1656                                 encumbranceAccountMap.put(acctString, difference);
1657                             } else {
1658                                 encumbranceAccountMap.put(acctString, amount.add(difference));
1659                             }
1660 
1661                             lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().subtract(difference));
1662                         }
1663                     }
1664                 }
1665             }// endfor
1666         }
1667 
1668         List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
1669         for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
1670             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
1671             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1672             if (amount.doubleValue() != 0) {
1673                 acctString.setAmount(amount);
1674                 encumbranceAccounts.add(acctString);
1675             }
1676         }
1677 
1678         // SpringContext.getBean(BusinessObjectService.class).save(po);
1679         return encumbranceAccounts;
1680     }
1681 
1682 
1683     /**
1684      * Re-encumber the Encumbrance on a PO based on values in a PREQ. This is used when a PREQ is cancelled. Note: This modifies the
1685      * encumbrance values on the PO and saves the PO
1686      *
1687      * @param preq PREQ for invoice
1688      * @return List of accounting lines to use to create the pending general ledger entries
1689      */
1690     protected List<SourceAccountingLine> reencumberEncumbrance(PaymentRequestDocument preq) {
1691         LOG.debug("reencumberEncumbrance() started");
1692 
1693         PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(preq.getPurchaseOrderIdentifier());
1694         Map encumbranceAccountMap = new HashMap();
1695 
1696         // Get each item one by one
1697         for (Iterator items = preq.getItems().iterator(); items.hasNext(); ) {
1698             PaymentRequestItem payRequestItem = (PaymentRequestItem) items.next();
1699             PurchaseOrderItem poItem = getPoItem(po, payRequestItem.getItemLineNumber(), payRequestItem.getItemType());
1700 
1701             KualiDecimal itemReEncumber = null; // Amount to reencumber for this item
1702 
1703             String logItmNbr = "Item # " + payRequestItem.getItemLineNumber();
1704             if (LOG.isDebugEnabled()) {
1705                 LOG.debug("reencumberEncumbrance() " + logItmNbr);
1706             }
1707 
1708             // If there isn't a PO item or the total amount is 0, we don't need encumbrances
1709             final KualiDecimal preqItemTotalAmount = (payRequestItem.getTotalAmount() == null) ? KualiDecimal.ZERO : payRequestItem.getTotalAmount();
1710             if ((poItem == null) || (preqItemTotalAmount.doubleValue() == 0)) {
1711                 if (LOG.isDebugEnabled()) {
1712                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " No encumbrances required");
1713                 }
1714             } else {
1715                 if (LOG.isDebugEnabled()) {
1716                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
1717                 }
1718 
1719                 // Do we calculate the encumbrance amount based on quantity or amount?
1720                 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1721                     if (LOG.isDebugEnabled()) {
1722                         LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
1723                     }
1724 
1725                     // Do disencumbrance calculations based on quantity
1726                     KualiDecimal preqQuantity = payRequestItem.getItemQuantity() == null ? ZERO : payRequestItem.getItemQuantity();
1727                     KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1728                     KualiDecimal invoicedTotal = poItem.getItemInvoicedTotalQuantity() == null ? ZERO : poItem.getItemInvoicedTotalQuantity();
1729 
1730                     poItem.setItemInvoicedTotalQuantity(invoicedTotal.subtract(preqQuantity));
1731                     poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.add(preqQuantity));
1732 
1733                     //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
1734                     itemReEncumber = new KualiDecimal(preqQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
1735 
1736                     //add tax for encumbrance
1737                     KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
1738                     KualiDecimal encumbranceTaxAmount = preqQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
1739                     itemReEncumber = itemReEncumber.add(encumbranceTaxAmount);
1740 
1741                 } else {
1742                     if (LOG.isDebugEnabled()) {
1743                         LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
1744                     }
1745 
1746                     itemReEncumber = preqItemTotalAmount;
1747                     // if re-encumber amount is more than original PO ordered amount... do not exceed ordered amount
1748                     // this prevents negative encumbrance
1749                     if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() < 0)) {
1750                         // po item extended cost is negative
1751                         if ((poItem.getTotalAmount().compareTo(itemReEncumber)) > 0) {
1752                             itemReEncumber = poItem.getTotalAmount();
1753                         }
1754                     } else if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() >= 0)) {
1755                         // po item extended cost is positive
1756                         if ((poItem.getTotalAmount().compareTo(itemReEncumber)) < 0) {
1757                             itemReEncumber = poItem.getTotalAmount();
1758                         }
1759                     }
1760                 }
1761 
1762                 if (LOG.isDebugEnabled()) {
1763                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " Amount to reencumber: " + itemReEncumber);
1764                 }
1765 
1766                 KualiDecimal outstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount() == null ? ZERO : poItem.getItemOutstandingEncumberedAmount();
1767                 if (LOG.isDebugEnabled()) {
1768                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Outstanding Encumbrance Amount set to: " + outstandingEncumberedAmount);
1769                 }
1770                 KualiDecimal newOutstandingEncumberedAmount = outstandingEncumberedAmount.add(itemReEncumber);
1771                 if (LOG.isDebugEnabled()) {
1772                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Outstanding Encumbrance Amount to set: " + newOutstandingEncumberedAmount);
1773                 }
1774                 poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1775 
1776                 KualiDecimal invoicedTotalAmount = poItem.getItemInvoicedTotalAmount() == null ? ZERO : poItem.getItemInvoicedTotalAmount();
1777                 if (LOG.isDebugEnabled()) {
1778                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Invoiced Total Amount set to: " + invoicedTotalAmount);
1779                 }
1780                 KualiDecimal newInvoicedTotalAmount = invoicedTotalAmount.subtract(preqItemTotalAmount);
1781                 if (LOG.isDebugEnabled()) {
1782                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Invoiced Total Amount to set: " + newInvoicedTotalAmount);
1783                 }
1784                 poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1785 
1786                 // make the list of accounts for the reencumbrance entry
1787                 PurchaseOrderAccount lastAccount = null;
1788                 KualiDecimal accountTotal = ZERO;
1789 
1790                 // Sort accounts
1791                 Collections.sort((List) poItem.getSourceAccountingLines());
1792 
1793                 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
1794                     PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
1795                     if (!account.isEmpty()) {
1796                         SourceAccountingLine acctString = account.generateSourceAccountingLine();
1797 
1798                         // amount = item reencumber * account percent / 100
1799                         KualiDecimal reencumbranceAmount = itemReEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED);
1800 
1801                         account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(reencumbranceAmount));
1802 
1803                         // For rounding check at the end
1804                         accountTotal = accountTotal.add(reencumbranceAmount);
1805 
1806                         lastAccount = account;
1807 
1808                         if (LOG.isDebugEnabled()) {
1809                             LOG.debug("reencumberEncumbrance() " + logItmNbr + " " + acctString + " = " + reencumbranceAmount);
1810                         }
1811                         if (encumbranceAccountMap.containsKey(acctString)) {
1812                             KualiDecimal currentAmount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1813                             encumbranceAccountMap.put(acctString, reencumbranceAmount.add(currentAmount));
1814                         } else {
1815                             encumbranceAccountMap.put(acctString, reencumbranceAmount);
1816                         }
1817                     }
1818                 }
1819 
1820                 // account for rounding by adjusting last account as needed
1821                 if (lastAccount != null) {
1822                     KualiDecimal difference = itemReEncumber.subtract(accountTotal);
1823                     if (LOG.isDebugEnabled()) {
1824                         LOG.debug("reencumberEncumbrance() difference: " + logItmNbr + " " + difference);
1825                     }
1826 
1827                     SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
1828                     KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1829                     if (amount == null) {
1830                         encumbranceAccountMap.put(acctString, difference);
1831                     } else {
1832                         encumbranceAccountMap.put(acctString, amount.add(difference));
1833                     }
1834                     lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference));
1835                 }
1836             }
1837         }
1838 
1839         //SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
1840 
1841         //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966
1842         //  SpringContext.getBean(BusinessObjectService.class).save(po);
1843 
1844         List<SourceAccountingLine> encumbranceAccounts = new ArrayList<SourceAccountingLine>();
1845         for (Iterator<SourceAccountingLine> iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
1846             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
1847             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1848             if (amount.doubleValue() != 0) {
1849                 acctString.setAmount(amount);
1850                 encumbranceAccounts.add(acctString);
1851             }
1852         }
1853 
1854         SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
1855         return encumbranceAccounts;
1856     }
1857 
1858 
1859     protected List<SourceAccountingLine> reencumberEncumbrance(InvoiceDocument prqs) {
1860         LOG.debug("reencumberEncumbrance() started");
1861 
1862         PurchaseOrderDocument po = null;
1863                 //purchaseOrderService.getCurrentPurchaseOrder(prqs.getPurchaseOrderIdentifier());
1864         Map encumbranceAccountMap = new HashMap();
1865 
1866         // Get each item one by one
1867         for (Iterator items = prqs.getItems().iterator(); items.hasNext(); ) {
1868             InvoiceItem invItem = (InvoiceItem) items.next();
1869             po = purchaseOrderService.getCurrentPurchaseOrder(invItem.getPurchaseOrderIdentifier());
1870             PurchaseOrderItem poItem = null;
1871             if(po != null) {
1872                  poItem = getPoItem(po, invItem.getItemLineNumber(), invItem.getItemType());
1873             }
1874 
1875             KualiDecimal itemReEncumber = null; // Amount to reencumber for this item
1876 
1877             String logItmNbr = "Item # " + invItem.getItemLineNumber();
1878             if (LOG.isDebugEnabled()) {
1879                 LOG.debug("reencumberEncumbrance() " + logItmNbr);
1880             }
1881 
1882             // If there isn't a PO item or the total amount is 0, we don't need encumbrances
1883             final KualiDecimal preqItemTotalAmount = (invItem.getTotalAmount() == null) ? KualiDecimal.ZERO : invItem.getTotalAmount();
1884             if ((poItem == null) || (preqItemTotalAmount.doubleValue() == 0)) {
1885                 if (LOG.isDebugEnabled()) {
1886                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " No encumbrances required");
1887                 }
1888             } else {
1889                 if (LOG.isDebugEnabled()) {
1890                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
1891                 }
1892 
1893                 // Do we calculate the encumbrance amount based on quantity or amount?
1894                 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1895                     if (LOG.isDebugEnabled()) {
1896                         LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
1897                     }
1898 
1899                     // Do disencumbrance calculations based on quantity
1900                     KualiDecimal preqQuantity = invItem.getItemQuantity() == null ? ZERO : invItem.getItemQuantity();
1901                     KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1902                     KualiDecimal invoicedTotal = poItem.getItemInvoicedTotalQuantity() == null ? ZERO : poItem.getItemInvoicedTotalQuantity();
1903 
1904                     poItem.setItemInvoicedTotalQuantity(invoicedTotal.subtract(preqQuantity));
1905                     poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.add(preqQuantity));
1906 
1907                     //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
1908                     itemReEncumber = new KualiDecimal(preqQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
1909 
1910                     //add tax for encumbrance
1911                     KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
1912                     KualiDecimal encumbranceTaxAmount = preqQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
1913                     itemReEncumber = itemReEncumber.add(encumbranceTaxAmount);
1914 
1915                 } else {
1916                     if (LOG.isDebugEnabled()) {
1917                         LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
1918                     }
1919 
1920                     itemReEncumber = preqItemTotalAmount;
1921                     // if re-encumber amount is more than original PO ordered amount... do not exceed ordered amount
1922                     // this prevents negative encumbrance
1923                     if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() < 0)) {
1924                         // po item extended cost is negative
1925                         if ((poItem.getTotalAmount().compareTo(itemReEncumber)) > 0) {
1926                             itemReEncumber = poItem.getTotalAmount();
1927                         }
1928                     } else if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() >= 0)) {
1929                         // po item extended cost is positive
1930                         if ((poItem.getTotalAmount().compareTo(itemReEncumber)) < 0) {
1931                             itemReEncumber = poItem.getTotalAmount();
1932                         }
1933                     }
1934                 }
1935 
1936                 if (LOG.isDebugEnabled()) {
1937                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " Amount to reencumber: " + itemReEncumber);
1938                 }
1939 
1940                 KualiDecimal outstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount() == null ? ZERO : poItem.getItemOutstandingEncumberedAmount();
1941                 if (LOG.isDebugEnabled()) {
1942                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Outstanding Encumbrance Amount set to: " + outstandingEncumberedAmount);
1943                 }
1944                 KualiDecimal newOutstandingEncumberedAmount = outstandingEncumberedAmount.add(itemReEncumber);
1945                 if (LOG.isDebugEnabled()) {
1946                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Outstanding Encumbrance Amount to set: " + newOutstandingEncumberedAmount);
1947                 }
1948                 poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1949 
1950                 KualiDecimal invoicedTotalAmount = poItem.getItemInvoicedTotalAmount() == null ? ZERO : poItem.getItemInvoicedTotalAmount();
1951                 if (LOG.isDebugEnabled()) {
1952                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Invoiced Total Amount set to: " + invoicedTotalAmount);
1953                 }
1954                 KualiDecimal newInvoicedTotalAmount = invoicedTotalAmount.subtract(preqItemTotalAmount);
1955                 if (LOG.isDebugEnabled()) {
1956                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Invoiced Total Amount to set: " + newInvoicedTotalAmount);
1957                 }
1958                 poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1959 
1960                 // make the list of accounts for the reencumbrance entry
1961                 PurchaseOrderAccount lastAccount = null;
1962                 KualiDecimal accountTotal = ZERO;
1963 
1964                 // Sort accounts
1965                 Collections.sort((List) poItem.getSourceAccountingLines());
1966 
1967                 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
1968                     PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
1969                     if (!account.isEmpty()) {
1970                         SourceAccountingLine acctString = account.generateSourceAccountingLine();
1971 
1972                         // amount = item reencumber * account percent / 100
1973                         KualiDecimal reencumbranceAmount = itemReEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED);
1974 
1975                         account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(reencumbranceAmount));
1976 
1977                         // For rounding check at the end
1978                         accountTotal = accountTotal.add(reencumbranceAmount);
1979 
1980                         lastAccount = account;
1981 
1982                         if (LOG.isDebugEnabled()) {
1983                             LOG.debug("reencumberEncumbrance() " + logItmNbr + " " + acctString + " = " + reencumbranceAmount);
1984                         }
1985                         if (encumbranceAccountMap.containsKey(acctString)) {
1986                             KualiDecimal currentAmount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1987                             encumbranceAccountMap.put(acctString, reencumbranceAmount.add(currentAmount));
1988                         } else {
1989                             encumbranceAccountMap.put(acctString, reencumbranceAmount);
1990                         }
1991                     }
1992                 }
1993 
1994                 // account for rounding by adjusting last account as needed
1995                 if (lastAccount != null) {
1996                     KualiDecimal difference = itemReEncumber.subtract(accountTotal);
1997                     if (LOG.isDebugEnabled()) {
1998                         LOG.debug("reencumberEncumbrance() difference: " + logItmNbr + " " + difference);
1999                     }
2000 
2001                     SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
2002                     KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
2003                     if (amount == null) {
2004                         encumbranceAccountMap.put(acctString, difference);
2005                     } else {
2006                         encumbranceAccountMap.put(acctString, amount.add(difference));
2007                     }
2008                     lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference));
2009                 }
2010             }
2011         }
2012 
2013         //SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
2014 
2015         //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966
2016         // SpringContext.getBean(BusinessObjectService.class).save(po);
2017 
2018         List<SourceAccountingLine> encumbranceAccounts = new ArrayList<SourceAccountingLine>();
2019         for (Iterator<SourceAccountingLine> iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
2020             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
2021             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
2022             if (amount.doubleValue() != 0) {
2023                 acctString.setAmount(amount);
2024                 encumbranceAccounts.add(acctString);
2025             }
2026         }
2027         SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
2028         return encumbranceAccounts;
2029     }
2030 
2031 
2032     /**
2033      * Re-encumber the Encumbrance on a PO based on values in a PREQ. This is used when a PREQ is cancelled. Note: This modifies the
2034      * encumbrance values on the PO and saves the PO
2035      *
2036      * @param cm Credit Memo document
2037      * @param po Purchase Order document modify encumbrances
2038      * @return List of accounting lines to use to create the pending general ledger entries
2039      */
2040     protected List<SourceAccountingLine> getCreditMemoEncumbrance(VendorCreditMemoDocument cm, PurchaseOrderDocument po, boolean cancel) {
2041         LOG.debug("getCreditMemoEncumbrance() started");
2042 
2043         if (ObjectUtils.isNull(po)) {
2044             return null;
2045         }
2046 
2047         if (cancel) {
2048             LOG.debug("getCreditMemoEncumbrance() Receiving items back from vendor (cancelled CM)");
2049         } else {
2050             LOG.debug("getCreditMemoEncumbrance() Returning items to vendor");
2051         }
2052 
2053         Map encumbranceAccountMap = new HashMap();
2054 
2055         // Get each item one by one
2056         for (Iterator items = cm.getItems().iterator(); items.hasNext(); ) {
2057             CreditMemoItem cmItem = (CreditMemoItem) items.next();
2058             PurchaseOrderItem poItem = getPoItem(po, cmItem.getItemLineNumber(), cmItem.getItemType());
2059 
2060             KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item
2061             KualiDecimal itemAlterInvoiceAmt = null; // Amount to alter the invoicedAmt on the PO item
2062 
2063             String logItmNbr = "Item # " + cmItem.getItemLineNumber();
2064             if (LOG.isDebugEnabled()) {
2065                 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr);
2066             }
2067 
2068             final KualiDecimal cmItemTotalAmount = (cmItem.getTotalAmount() == null) ? KualiDecimal.ZERO : cmItem.getTotalAmount();
2069             ;
2070             // If there isn't a PO item or the total amount is 0, we don't need encumbrances
2071             if ((poItem == null) || (cmItemTotalAmount == null) || (cmItemTotalAmount.doubleValue() == 0) ||
2072                     (cmItemTotalAmount!=null && !cmItemTotalAmount.isNegative())) {
2073                 if (LOG.isDebugEnabled()) {
2074                     LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " No encumbrances required");
2075                 }
2076             } else {
2077                 if (LOG.isDebugEnabled()) {
2078                     LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
2079                 }
2080 
2081                 // Do we calculate the encumbrance amount based on quantity or amount?
2082                 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
2083                     if (LOG.isDebugEnabled()) {
2084                         LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
2085                     }
2086 
2087                     // Do encumbrance calculations based on quantity
2088                     KualiDecimal cmQuantity = cmItem.getItemQuantity() == null ? ZERO : cmItem.getItemQuantity();
2089 
2090                     KualiDecimal encumbranceQuantityChange = calculateQuantityChange(cancel, poItem, cmQuantity);
2091 
2092                     if (LOG.isDebugEnabled()) {
2093                         LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " encumbranceQtyChange " + encumbranceQuantityChange + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity() + " invoicedTotalQuantity " + poItem.getItemInvoicedTotalQuantity());
2094                     }
2095 
2096                     //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
2097                     itemDisEncumber = new KualiDecimal(encumbranceQuantityChange.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
2098 
2099                     //add tax for encumbrance
2100                     KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
2101                     KualiDecimal encumbranceTaxAmount = encumbranceQuantityChange.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
2102                     itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount);
2103 
2104                     itemAlterInvoiceAmt = cmItemTotalAmount;
2105                     if (cancel) {
2106                         itemAlterInvoiceAmt = itemAlterInvoiceAmt.multiply(new KualiDecimal("-1"));
2107                     }
2108                 } else {
2109                     if (LOG.isDebugEnabled()) {
2110                         LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
2111                     }
2112 
2113                     // Do encumbrance calculations based on amount only
2114                     if (cancel) {
2115                         // Decrease encumbrance
2116                         itemDisEncumber = cmItemTotalAmount.multiply(new KualiDecimal("-1"));
2117 
2118                         if (poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber).doubleValue() < 0) {
2119                             LOG.debug("getCreditMemoEncumbrance() Cancel overflow");
2120 
2121                             itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
2122                         }
2123                     } else {
2124                         // Increase encumbrance
2125                         itemDisEncumber = cmItemTotalAmount;
2126 
2127                         if (poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber).doubleValue() > poItem.getTotalAmount().doubleValue()) {
2128                             LOG.debug("getCreditMemoEncumbrance() Create overflow");
2129 
2130                             itemDisEncumber = poItem.getTotalAmount().subtract(poItem.getItemOutstandingEncumberedAmount());
2131                         }
2132                     }
2133                     itemAlterInvoiceAmt = itemDisEncumber;
2134                 }
2135 
2136                 // alter the encumbrance based on what was originally encumbered
2137                 poItem.setItemOutstandingEncumberedAmount(poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber));
2138 
2139                 // alter the invoiced amt based on what was actually credited on the credit memo
2140                 poItem.setItemInvoicedTotalAmount(poItem.getItemInvoicedTotalAmount().subtract(itemAlterInvoiceAmt));
2141                 if (poItem.getItemInvoicedTotalAmount().compareTo(ZERO) < 0) {
2142                     poItem.setItemInvoicedTotalAmount(ZERO);
2143                 }
2144 
2145 
2146                 if (LOG.isDebugEnabled()) {
2147                     LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber);
2148                 }
2149 
2150                 // Sort accounts
2151                 Collections.sort((List) poItem.getSourceAccountingLines());
2152 
2153                 // make the list of accounts for the disencumbrance entry
2154                 PurchaseOrderAccount lastAccount = null;
2155                 KualiDecimal accountTotal = ZERO;
2156                 // Collections.sort((List)poItem.getSourceAccountingLines());
2157                 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
2158                     PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
2159                     if (!account.isEmpty()) {
2160                         KualiDecimal encumbranceAmount = null;
2161 
2162                         SourceAccountingLine acctString = account.generateSourceAccountingLine();
2163                         // amount = item disencumber * account percent / 100
2164                         encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(new KualiDecimal(100));
2165 
2166                         account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(encumbranceAmount));
2167 
2168                         // For rounding check at the end
2169                         accountTotal = accountTotal.add(encumbranceAmount);
2170 
2171                         lastAccount = account;
2172 
2173                         if (LOG.isDebugEnabled()) {
2174                             LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount);
2175                         }
2176 
2177                         if (encumbranceAccountMap.get(acctString) == null) {
2178                             encumbranceAccountMap.put(acctString, encumbranceAmount);
2179                         } else {
2180                             KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString);
2181                             encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount));
2182                         }
2183                     }
2184                 }
2185 
2186                 // account for rounding by adjusting last account as needed
2187                 if (lastAccount != null) {
2188                     KualiDecimal difference = itemDisEncumber.subtract(accountTotal);
2189                     if (LOG.isDebugEnabled()) {
2190                         LOG.debug("getCreditMemoEncumbrance() difference: " + logItmNbr + " " + difference);
2191                     }
2192 
2193                     SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
2194                     KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
2195                     if (amount == null) {
2196                         encumbranceAccountMap.put(acctString, difference);
2197                     } else {
2198                         encumbranceAccountMap.put(acctString, amount.add(difference));
2199                     }
2200                     lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference));
2201                 }
2202             }
2203         }
2204 
2205         List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
2206         for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
2207             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
2208             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
2209             if (amount.doubleValue() != 0) {
2210                 acctString.setAmount(amount);
2211                 encumbranceAccounts.add(acctString);
2212             }
2213         }
2214 
2215         SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
2216         //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966
2217         // SpringContext.getBean(BusinessObjectService.class).save(po);
2218 
2219         return encumbranceAccounts;
2220     }
2221 
2222     /**
2223      * Save the given general ledger entries
2224      *
2225      * @param glEntries List of GeneralLedgerPendingEntries to be saved
2226      */
2227     protected void saveGLEntries(List<GeneralLedgerPendingEntry> glEntries) {
2228         LOG.debug("saveGLEntries() started");
2229         businessObjectService.save(glEntries);
2230     }
2231 
2232     /**
2233      * Save the given accounts for the given document.
2234      *
2235      * @param summaryAccounts         Accounts to be saved
2236      * @param purapDocumentIdentifier Purap document id for accounts
2237      */
2238     protected void saveAccountsPayableSummaryAccounts(List<SummaryAccount> summaryAccounts, Integer purapDocumentIdentifier, String docType) {
2239         LOG.debug("saveAccountsPayableSummaryAccounts() started");
2240         purapAccountingService.deleteSummaryAccounts(purapDocumentIdentifier, docType);
2241         List<AccountsPayableSummaryAccount> apSummaryAccounts = new ArrayList();
2242         for (SummaryAccount summaryAccount : summaryAccounts) {
2243             apSummaryAccounts.add(new AccountsPayableSummaryAccount(summaryAccount.getAccount(), purapDocumentIdentifier, docType));
2244         }
2245         businessObjectService.save(apSummaryAccounts);
2246     }
2247 
2248     /**
2249      * Save the given accounts for the given document.
2250      *
2251      * @param summaryAccounts         Accounts to be saved
2252      * @param purapDocumentIdentifier Purap document id for accounts
2253      * @param docType                 Document Type Used
2254      */
2255     protected void saveInvoiceAccountsPayableSummaryAccounts(List<SummaryAccount> summaryAccounts, Integer purapDocumentIdentifier, String docType) {
2256         LOG.debug("saveAccountsPayableSummaryAccounts() started");
2257         purapAccountingService.deleteSummaryAccounts(purapDocumentIdentifier, docType);
2258         List<OleInvoiceAccountsPayableSummaryAccount> apSummaryAccounts = new ArrayList();
2259         for (SummaryAccount summaryAccount : summaryAccounts) {
2260             apSummaryAccounts.add(new OleInvoiceAccountsPayableSummaryAccount(summaryAccount.getAccount(), purapDocumentIdentifier, docType));
2261         }
2262         businessObjectService.save(apSummaryAccounts);
2263     }
2264 
2265     /**
2266      * Find item in PO based on given parameters. Must send either the line # or item type.
2267      *
2268      * @param po       Purchase Order containing list of items
2269      * @param nbr      Line # of desired item (could be null)
2270      * @param itemType Item type of desired item
2271      * @return PurcahseOrderItem found matching given criteria
2272      */
2273     protected PurchaseOrderItem getPoItem(PurchaseOrderDocument po, Integer nbr, ItemType itemType) {
2274         LOG.debug("getPoItem() started");
2275         for (Iterator iter = po.getItems().iterator(); iter.hasNext(); ) {
2276             PurchaseOrderItem element = (PurchaseOrderItem) iter.next();
2277             if (itemType.isLineItemIndicator()) {
2278                 if (ObjectUtils.isNotNull(nbr) && ObjectUtils.isNotNull(element.getItemLineNumber()) && (nbr.compareTo(element.getItemLineNumber()) == 0)) {
2279                     return element;
2280                 }
2281             } else {
2282                 if (element.getItemTypeCode().equals(itemType.getItemTypeCode())) {
2283                     return element;
2284                 }
2285             }
2286         }
2287         return null;
2288     }
2289 
2290     /**
2291      * Format description for general ledger entry. Currently making sure length is less than 40 char.
2292      *
2293      * @param description String to be formatted
2294      * @return Formatted String
2295      */
2296     protected String entryDescription(String description) {
2297         if (description != null && description.length() > 40) {
2298             return description.toString().substring(0, 39);
2299         } else {
2300             return description;
2301         }
2302     }
2303 
2304     /**
2305      * Calculate quantity change for creating Credit Memo entries
2306      *
2307      * @param cancel     Boolean indicating whether entries are for creation or cancellation of credit memo
2308      * @param poItem     Purchase Order Item
2309      * @param cmQuantity Quantity on credit memo item
2310      * @return Calculated change
2311      */
2312     protected KualiDecimal calculateQuantityChange(boolean cancel, PurchaseOrderItem poItem, KualiDecimal cmQuantity) {
2313         LOG.debug("calculateQuantityChange() started");
2314 
2315         // Calculate quantity change & adjust invoiced quantity & outstanding encumbered quantity
2316         KualiDecimal encumbranceQuantityChange = null;
2317         if (cancel) {
2318             encumbranceQuantityChange = cmQuantity.multiply(new KualiDecimal("-1"));
2319         } else {
2320             encumbranceQuantityChange = cmQuantity;
2321         }
2322         poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().subtract(encumbranceQuantityChange));
2323         poItem.setItemOutstandingEncumberedQuantity(poItem.getItemOutstandingEncumberedQuantity().add(encumbranceQuantityChange));
2324 
2325         // Check for overflows
2326         if (cancel) {
2327             if (poItem.getItemOutstandingEncumberedQuantity().doubleValue() < 0) {
2328                 LOG.debug("calculateQuantityChange() Cancel overflow");
2329                 KualiDecimal difference = poItem.getItemOutstandingEncumberedQuantity().abs();
2330                 poItem.setItemOutstandingEncumberedQuantity(ZERO);
2331                 poItem.setItemInvoicedTotalQuantity(poItem.getItemQuantity());
2332                 encumbranceQuantityChange = encumbranceQuantityChange.add(difference);
2333             }
2334         }
2335 // Coomented for JIRA:OLE-5162 as encumbrance get doubled here.
2336        /* else {
2337             if (poItem.getItemInvoicedTotalQuantity().doubleValue() < 0) {
2338                 LOG.debug("calculateQuantityChange() Create overflow");
2339                 KualiDecimal difference = poItem.getItemInvoicedTotalQuantity().abs();
2340                 poItem.setItemOutstandingEncumberedQuantity(poItem.getItemQuantity());
2341                 poItem.setItemInvoicedTotalQuantity(ZERO);
2342                 encumbranceQuantityChange = encumbranceQuantityChange.add(difference);
2343             }
2344         } */
2345         return encumbranceQuantityChange;
2346     }
2347 
2348     public void setDateTimeService(DateTimeService dateTimeService) {
2349         this.dateTimeService = dateTimeService;
2350     }
2351 
2352     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
2353         this.businessObjectService = businessObjectService;
2354     }
2355 
2356     public void setGeneralLedgerPendingEntryService(GeneralLedgerPendingEntryService generalLedgerPendingEntryService) {
2357         this.generalLedgerPendingEntryService = generalLedgerPendingEntryService;
2358     }
2359 
2360     public void setKualiRuleService(KualiRuleService kualiRuleService) {
2361         this.kualiRuleService = kualiRuleService;
2362     }
2363 
2364     public void setPurapAccountingService(PurapAccountingService purapAccountingService) {
2365         this.purapAccountingService = purapAccountingService;
2366     }
2367 
2368     public void setUniversityDateService(UniversityDateService universityDateService) {
2369         this.universityDateService = universityDateService;
2370     }
2371 
2372     public void setPurchaseOrderService(PurchaseOrderService purchaseOrderService) {
2373         this.purchaseOrderService = purchaseOrderService;
2374     }
2375 
2376     public void setObjectCodeService(ObjectCodeService objectCodeService) {
2377         this.objectCodeService = objectCodeService;
2378     }
2379 
2380     public void setSubObjectCodeService(SubObjectCodeService subObjectCodeService) {
2381         this.subObjectCodeService = subObjectCodeService;
2382     }
2383 
2384     public void setParameterService(ParameterService parameterService) {
2385         this.parameterService = parameterService;
2386     }
2387 
2388     public void setPaymentRequestService(PaymentRequestService paymentRequestService) {
2389         this.paymentRequestService = paymentRequestService;
2390     }
2391 
2392     /**
2393      * Sets the invoiceService attribute value.
2394      *
2395      * @param invoiceService The invoiceService to set.
2396      */
2397 
2398     public void setInvoiceService(InvoiceService invoiceService) {
2399         this.invoiceService = invoiceService;
2400     }
2401 
2402 
2403 }