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