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) {
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                 } else {
780                     if (item.getItemUnitPrice() != null) {
781                         item.setItemOutstandingEncumberedAmount(new KualiDecimal(item.getItemUnitPrice().subtract(item.getItemInvoicedTotalAmount().bigDecimalValue())));
782                     }
783                 }
784 
785                 for (Iterator iter = item.getSourceAccountingLines().iterator(); iter.hasNext(); ) {
786                     PurchaseOrderAccount account = (PurchaseOrderAccount) iter.next();
787                     BigDecimal percent = new BigDecimal(account.getAccountLinePercent().toString());
788                     percent = percent.divide(new BigDecimal("100"), 3, BigDecimal.ROUND_HALF_UP);
789                     account.setItemAccountOutstandingEncumbranceAmount(item.getItemOutstandingEncumberedAmount().multiply(new KualiDecimal(percent)));
790                     account.setAlternateAmountForGLEntryCreation(account.getItemAccountOutstandingEncumbranceAmount());
791                 }
792             }
793         }
794 
795         PurchaseOrderDocument oldPO = purchaseOrderService.getCurrentPurchaseOrder(po.getPurapDocumentIdentifier());
796 
797         if (oldPO == null) {
798             throw new IllegalArgumentException("Current Purchase Order not found - poId = " + oldPO.getPurapDocumentIdentifier());
799         }
800 
801         List newAccounts = purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly());
802         List oldAccounts = purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(oldPO.getItemsActiveOnlySetupAlternateAmount());
803 
804         Map combination = new HashMap();
805 
806         // Add amounts from the new PO
807         for (Iterator iter = newAccounts.iterator(); iter.hasNext(); ) {
808             SourceAccountingLine newAccount = (SourceAccountingLine) iter.next();
809             combination.put(newAccount, newAccount.getAmount());
810         }
811 
812         LOG.debug("generateEntriesApproveAmendPurchaseOrder() combination after the add");
813         for (Iterator iter = combination.keySet().iterator(); iter.hasNext(); ) {
814             SourceAccountingLine element = (SourceAccountingLine) iter.next();
815             if (LOG.isDebugEnabled())
816                 LOG.debug("generateEntriesApproveAmendPurchaseOrder() " + element + " = " + ((KualiDecimal) combination.get(element)).floatValue());
817         }
818 
819         // Subtract the amounts from the old PO
820         for (Iterator iter = oldAccounts.iterator(); iter.hasNext(); ) {
821             SourceAccountingLine oldAccount = (SourceAccountingLine) iter.next();
822             if (combination.containsKey(oldAccount)) {
823                 KualiDecimal amount = (KualiDecimal) combination.get(oldAccount);
824                 amount = amount.subtract(oldAccount.getAmount());
825                 combination.put(oldAccount, amount);
826             } else {
827                 combination.put(oldAccount, ZERO.subtract(oldAccount.getAmount()));
828             }
829         }
830 
831         LOG.debug("generateEntriesApproveAmendPurchaseOrder() combination after the subtract");
832         for (Iterator iter = combination.keySet().iterator(); iter.hasNext(); ) {
833             SourceAccountingLine element = (SourceAccountingLine) iter.next();
834             if (LOG.isDebugEnabled())
835                 LOG.debug("generateEntriesApproveAmendPurchaseOrder() " + element + " = " + ((KualiDecimal) combination.get(element)).floatValue());
836         }
837 
838         List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
839         for (Iterator iter = combination.keySet().iterator(); iter.hasNext(); ) {
840             SourceAccountingLine account = (SourceAccountingLine) iter.next();
841             KualiDecimal amount = (KualiDecimal) combination.get(account);
842             if (ZERO.compareTo(amount) != 0) {
843                 account.setAmount(amount);
844                 encumbranceAccounts.add(account);
845             }
846         }
847 
848         po.setGlOnlySourceAccountingLines(encumbranceAccounts);
849         generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po);
850         saveGLEntries(po.getGeneralLedgerPendingEntries());
851         LOG.debug("generateEntriesApproveAmendPo() gl entries created; exit method");
852     }
853 
854     /**
855      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesClosePurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
856      */
857     public void generateEntriesClosePurchaseOrder(PurchaseOrderDocument po) {
858         LOG.debug("generateEntriesClosePurchaseOrder() started");
859 
860         // Set outstanding encumbered quantity/amount on items
861         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
862             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
863 
864             String logItmNbr = "Item # " + item.getItemLineNumber();
865 
866             if (!item.isItemActiveIndicator()) {
867                 continue;
868             }
869 
870             KualiDecimal itemAmount = null;
871             if (LOG.isDebugEnabled()) {
872                 LOG.debug("generateEntriesClosePurchaseOrder() " + logItmNbr + " Calculate based on amounts");
873             }
874             itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO : item.getItemOutstandingEncumberedAmount();
875 
876             KualiDecimal accountTotal = ZERO;
877             PurchaseOrderAccount lastAccount = null;
878             if (itemAmount.compareTo(ZERO) != 0) {
879                 // Sort accounts
880                 Collections.sort((List) item.getSourceAccountingLines());
881 
882                 for (Iterator iterAcct = item.getSourceAccountingLines().iterator(); iterAcct.hasNext(); ) {
883                     PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct.next();
884                     if (!acct.isEmpty()) {
885                         KualiDecimal acctAmount = itemAmount.multiply(new KualiDecimal(acct.getAccountLinePercent().toString())).divide(PurapConstants.HUNDRED);
886                         accountTotal = accountTotal.add(acctAmount);
887                         acct.setAlternateAmountForGLEntryCreation(acctAmount);
888                         lastAccount = acct;
889                     }
890                 }
891 
892                 // account for rounding by adjusting last account as needed
893                 if (lastAccount != null) {
894                     KualiDecimal difference = itemAmount.subtract(accountTotal);
895                     if (LOG.isDebugEnabled()) {
896                         LOG.debug("generateEntriesClosePurchaseOrder() difference: " + logItmNbr + " " + difference);
897                     }
898 
899                     KualiDecimal amount = lastAccount.getAlternateAmountForGLEntryCreation();
900                     if (ObjectUtils.isNotNull(amount)) {
901                         lastAccount.setAlternateAmountForGLEntryCreation(amount.add(difference));
902                     } else {
903                         lastAccount.setAlternateAmountForGLEntryCreation(difference);
904                     }
905                 }
906 
907             }
908         }// endfor
909 
910         po.setGlOnlySourceAccountingLines(purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly()));
911         if (shouldGenerateGLPEForPurchaseOrder(po)) {
912             generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po);
913             saveGLEntries(po.getGeneralLedgerPendingEntries());
914             LOG.debug("generateEntriesClosePurchaseOrder() gl entries created; exit method");
915         }
916 
917         //MSU Contribution DTT-3812 OLEMI-8642 OLECNTRB-957
918         // Set outstanding encumbered quantity/amount on items
919         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
920             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
921             if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
922                 item.setItemOutstandingEncumberedQuantity(KualiDecimal.ZERO);
923             }
924             item.setItemOutstandingEncumberedAmount(KualiDecimal.ZERO);
925             List<PurApAccountingLine> sourceAccountingLines = item.getSourceAccountingLines();
926             for (PurApAccountingLine purApAccountingLine : sourceAccountingLines) {
927                 PurchaseOrderAccount account = (PurchaseOrderAccount) purApAccountingLine;
928                 account.setItemAccountOutstandingEncumbranceAmount(KualiDecimal.ZERO);
929             }
930 
931         }// endfor
932 
933         LOG.debug("generateEntriesClosePurchaseOrder() no gl entries created because the amount is 0; exit method");
934     }
935 
936     /**
937      * We should not generate general ledger pending entries for Purchase Order Close Document and
938      * Purchase Order Reopen Document with $0 amount.
939      *
940      * @param po
941      * @return
942      */
943     protected boolean shouldGenerateGLPEForPurchaseOrder(PurchaseOrderDocument po) {
944         for (SourceAccountingLine acct : (List<SourceAccountingLine>) po.getSourceAccountingLines()) {
945             if (acct.getAmount().abs().compareTo(new KualiDecimal(0)) > 0) {
946                 return true;
947             }
948         }
949         return false;
950     }
951 
952     /**
953      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesReopenPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
954      */
955     public void generateEntriesReopenPurchaseOrder(PurchaseOrderDocument po) {
956         LOG.debug("generateEntriesReopenPurchaseOrder() started");
957 
958         //MSU Contribution DTT-3812 OLEMI-8642 OLECNTRB-957
959         // Set outstanding encumbered quantity/amount on items
960         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
961             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
962             if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
963                 item.getItemQuantity().subtract(item.getItemInvoicedTotalQuantity());
964                 item.setItemOutstandingEncumberedQuantity(item.getItemQuantity().subtract(item.getItemInvoicedTotalQuantity()));
965                 item.setItemOutstandingEncumberedAmount(new KualiDecimal(item.getItemOutstandingEncumberedQuantity().bigDecimalValue().multiply(item.getItemUnitPrice())));
966             } else {
967                 item.setItemOutstandingEncumberedAmount(item.getTotalAmount().subtract(item.getItemInvoicedTotalAmount()));
968             }
969             List<PurApAccountingLine> sourceAccountingLines = item.getSourceAccountingLines();
970             for (PurApAccountingLine purApAccountingLine : sourceAccountingLines) {
971                 PurchaseOrderAccount account = (PurchaseOrderAccount) purApAccountingLine;
972                 account.setItemAccountOutstandingEncumbranceAmount(new KualiDecimal(item.getItemOutstandingEncumberedAmount().bigDecimalValue().multiply(account.getAccountLinePercent()).divide(OLEConstants.ONE_HUNDRED.bigDecimalValue())));
973             }
974         }// endfor
975 
976         // Set outstanding encumbered quantity/amount on items
977         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
978             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
979 
980             String logItmNbr = "Item # " + item.getItemLineNumber();
981 
982             if (!item.isItemActiveIndicator()) {
983                 continue;
984             }
985 
986             KualiDecimal itemAmount = null;
987             if (item.getItemType().isAmountBasedGeneralLedgerIndicator()) {
988                 if (LOG.isDebugEnabled()) {
989                     LOG.debug("generateEntriesReopenPurchaseOrder() " + logItmNbr + " Calculate based on amounts");
990                 }
991                 itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO : item.getItemOutstandingEncumberedAmount();
992             } else {
993                 if (LOG.isDebugEnabled()) {
994                     LOG.debug("generateEntriesReopenPurchaseOrder() " + logItmNbr + " Calculate based on quantities");
995                 }
996                 //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
997                 itemAmount = new KualiDecimal(item.getItemOutstandingEncumberedQuantity().bigDecimalValue().multiply(item.getItemUnitPrice()));
998             }
999 
1000             KualiDecimal accountTotal = ZERO;
1001             PurchaseOrderAccount lastAccount = null;
1002             if (itemAmount.compareTo(ZERO) != 0) {
1003                 // Sort accounts
1004                 Collections.sort((List) item.getSourceAccountingLines());
1005 
1006                 for (Iterator iterAcct = item.getSourceAccountingLines().iterator(); iterAcct.hasNext(); ) {
1007                     PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct.next();
1008                     if (!acct.isEmpty()) {
1009                         KualiDecimal acctAmount = itemAmount.multiply(new KualiDecimal(acct.getAccountLinePercent().toString())).divide(PurapConstants.HUNDRED);
1010                         accountTotal = accountTotal.add(acctAmount);
1011                         acct.setAlternateAmountForGLEntryCreation(acctAmount);
1012                         lastAccount = acct;
1013                     }
1014                 }
1015 
1016                 // account for rounding by adjusting last account as needed
1017                 if (lastAccount != null) {
1018                     KualiDecimal difference = itemAmount.subtract(accountTotal);
1019                     if (LOG.isDebugEnabled()) {
1020                         LOG.debug("generateEntriesReopenPurchaseOrder() difference: " + logItmNbr + " " + difference);
1021                     }
1022 
1023                     KualiDecimal amount = lastAccount.getAlternateAmountForGLEntryCreation();
1024                     if (ObjectUtils.isNotNull(amount)) {
1025                         lastAccount.setAlternateAmountForGLEntryCreation(amount.add(difference));
1026                     } else {
1027                         lastAccount.setAlternateAmountForGLEntryCreation(difference);
1028                     }
1029                 }
1030 
1031             }
1032         }// endfor
1033 
1034         po.setGlOnlySourceAccountingLines(purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly()));
1035         if (shouldGenerateGLPEForPurchaseOrder(po)) {
1036             generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po);
1037             saveGLEntries(po.getGeneralLedgerPendingEntries());
1038             LOG.debug("generateEntriesReopenPurchaseOrder() gl entries created; exit method");
1039         }
1040         LOG.debug("generateEntriesReopenPurchaseOrder() no gl entries created because the amount is 0; exit method");
1041     }
1042 
1043     /**
1044      * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesVoidPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1045      */
1046     public void generateEntriesVoidPurchaseOrder(PurchaseOrderDocument po) {
1047         LOG.debug("generateEntriesVoidPurchaseOrder() started");
1048 
1049         // Set outstanding encumbered quantity/amount on items
1050         for (Iterator items = po.getItems().iterator(); items.hasNext(); ) {
1051             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
1052 
1053             String logItmNbr = "Item # " + item.getItemLineNumber();
1054 
1055             if (!item.isItemActiveIndicator()) {
1056                 continue;
1057             }
1058 
1059             //just use the outstanding amount as recalculating here, particularly the item tax will cause
1060             //amounts to be over or under encumbered and the remaining encumbered amount should be unencumbered during a close
1061             if (LOG.isDebugEnabled()) {
1062                 LOG.debug("generateEntriesVoidPurchaseOrder() " + logItmNbr + " Calculate based on amounts");
1063             }
1064             KualiDecimal itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO : item.getItemOutstandingEncumberedAmount();
1065 
1066             KualiDecimal accountTotal = ZERO;
1067             PurchaseOrderAccount lastAccount = null;
1068             if (itemAmount.compareTo(ZERO) != 0) {
1069                 // Sort accounts
1070                 Collections.sort((List) item.getSourceAccountingLines());
1071 
1072                 for (Iterator iterAcct = item.getSourceAccountingLines().iterator(); iterAcct.hasNext(); ) {
1073                     PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct.next();
1074                     if (!acct.isEmpty()) {
1075                         KualiDecimal acctAmount = itemAmount.multiply(new KualiDecimal(acct.getAccountLinePercent().toString())).divide(PurapConstants.HUNDRED);
1076                         accountTotal = accountTotal.add(acctAmount);
1077                         acct.setAlternateAmountForGLEntryCreation(acctAmount);
1078                         lastAccount = acct;
1079                     }
1080                 }
1081 
1082                 // account for rounding by adjusting last account as needed
1083                 if (lastAccount != null) {
1084                     KualiDecimal difference = itemAmount.subtract(accountTotal);
1085                     if (LOG.isDebugEnabled()) {
1086                         LOG.debug("generateEntriesVoidPurchaseOrder() difference: " + logItmNbr + " " + difference);
1087                     }
1088 
1089                     KualiDecimal amount = lastAccount.getAlternateAmountForGLEntryCreation();
1090                     if (ObjectUtils.isNotNull(amount)) {
1091                         lastAccount.setAlternateAmountForGLEntryCreation(amount.add(difference));
1092                     } else {
1093                         lastAccount.setAlternateAmountForGLEntryCreation(difference);
1094                     }
1095                 }
1096 
1097             }
1098         }// endfor
1099 
1100         po.setGlOnlySourceAccountingLines(purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly()));
1101         generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po);
1102         saveGLEntries(po.getGeneralLedgerPendingEntries());
1103         LOG.debug("generateEntriesVoidPurchaseOrder() gl entries created; exit method");
1104     }
1105 
1106     /**
1107      * 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
1108      * the encumbrance values on the PO and saves the PO
1109      *
1110      * @param preq PREQ for invoice
1111      * @return List of accounting lines to use to create the pending general ledger entries
1112      */
1113     protected List<SourceAccountingLine> relieveEncumbrance(PaymentRequestDocument preq) {
1114         LOG.debug("relieveEncumbrance() started");
1115 
1116         Map encumbranceAccountMap = new HashMap();
1117         PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(preq.getPurchaseOrderIdentifier());
1118 
1119         // Get each item one by one
1120         for (Iterator items = preq.getItems().iterator(); items.hasNext(); ) {
1121             PaymentRequestItem preqItem = (PaymentRequestItem) items.next();
1122             PurchaseOrderItem poItem = getPoItem(po, preqItem.getItemLineNumber(), preqItem.getItemType());
1123 
1124             boolean takeAll = false; // Set this true if we relieve the entire encumbrance
1125             KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item
1126 
1127             String logItmNbr = "Item # " + preqItem.getItemLineNumber();
1128             if (LOG.isDebugEnabled()) {
1129                 LOG.debug("relieveEncumbrance() " + logItmNbr);
1130             }
1131 
1132             // If there isn't a PO item or the extended price is 0, we don't need encumbrances
1133             if (poItem == null) {
1134                 if (LOG.isDebugEnabled()) {
1135                     LOG.debug("relieveEncumbrance() " + logItmNbr + " No encumbrances required because po item is null");
1136                 }
1137             } else {
1138                 final KualiDecimal preqItemTotalAmount = (preqItem.getTotalAmount() == null) ? KualiDecimal.ZERO : preqItem.getTotalAmount();
1139                 if (ZERO.compareTo(preqItemTotalAmount) == 0) {
1140                     /*
1141                      * This is a specialized case where PREQ item being processed must adjust the PO item's outstanding encumbered
1142                      * quantity. This kind of scenario is mostly seen on warranty type items. The following must be true to do this:
1143                      * PREQ item Extended Price must be ZERO, PREQ item invoice quantity must be not empty and not ZERO, and PO item
1144                      * is quantity based PO item unit cost is ZERO
1145                      */
1146                     if (LOG.isDebugEnabled()) {
1147                         LOG.debug("relieveEncumbrance() " + logItmNbr + " No GL encumbrances required because extended price is ZERO");
1148                     }
1149                     if ((poItem.getItemQuantity() != null) && ((BigDecimal.ZERO.compareTo(poItem.getItemUnitPrice())) == 0)) {
1150                         // po has order quantity and unit price is ZERO... reduce outstanding encumbered quantity
1151                         if (LOG.isDebugEnabled()) {
1152                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate po oustanding encumbrance");
1153                         }
1154 
1155                         // Do encumbrance calculations based on quantity
1156                         if ((preqItem.getItemQuantity() != null) && ((ZERO.compareTo(preqItem.getItemQuantity())) != 0)) {
1157                             KualiDecimal invoiceQuantity = preqItem.getItemQuantity();
1158                             KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1159 
1160                             KualiDecimal encumbranceQuantity;
1161                             if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) {
1162                                 // We bought more than the quantity on the PO
1163                                 if (LOG.isDebugEnabled()) {
1164                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1165                                 }
1166                                 encumbranceQuantity = outstandingEncumberedQuantity;
1167                                 poItem.setItemOutstandingEncumberedQuantity(ZERO);
1168                             } else {
1169                                 encumbranceQuantity = invoiceQuantity;
1170                                 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity));
1171                                 if (LOG.isDebugEnabled()) {
1172                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " adjusting oustanding encunbrance qty - encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity());
1173                                 }
1174                             }
1175 
1176                             if (poItem.getItemInvoicedTotalQuantity() == null) {
1177                                 poItem.setItemInvoicedTotalQuantity(invoiceQuantity);
1178                             } else {
1179                                 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity));
1180                             }
1181                         }
1182                     }
1183 
1184 
1185                 } else {
1186                     if (LOG.isDebugEnabled()) {
1187                         LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
1188                     }
1189 
1190                     // Do we calculate the encumbrance amount based on quantity or amount?
1191                     if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1192                         if (LOG.isDebugEnabled()) {
1193                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
1194                         }
1195 
1196                         // Do encumbrance calculations based on quantity
1197                         KualiDecimal invoiceQuantity = preqItem.getItemQuantity() == null ? ZERO : preqItem.getItemQuantity();
1198                         KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1199 
1200                         KualiDecimal encumbranceQuantity;
1201 
1202                         if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) {
1203                             // We bought more than the quantity on the PO
1204                             if (LOG.isDebugEnabled()) {
1205                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1206                             }
1207                             encumbranceQuantity = outstandingEncumberedQuantity;
1208                             poItem.setItemOutstandingEncumberedQuantity(ZERO);
1209                             takeAll = true;
1210                         } else {
1211                             encumbranceQuantity = invoiceQuantity;
1212                             poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity));
1213                             if (ZERO.compareTo(poItem.getItemOutstandingEncumberedQuantity()) == 0) {
1214                                 takeAll = true;
1215                             }
1216                             if (LOG.isDebugEnabled()) {
1217                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity());
1218                             }
1219                         }
1220 
1221                         if (poItem.getItemInvoicedTotalQuantity() == null) {
1222                             poItem.setItemInvoicedTotalQuantity(invoiceQuantity);
1223                         } else {
1224                             poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity));
1225                         }
1226 
1227                         itemDisEncumber = new KualiDecimal(encumbranceQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
1228 
1229                         //add tax for encumbrance
1230                         KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
1231                         KualiDecimal encumbranceTaxAmount = encumbranceQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
1232                         itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount);
1233                     } else {
1234                         if (LOG.isDebugEnabled()) {
1235                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
1236                         }
1237 
1238                         // Do encumbrance calculations based on amount only
1239                         if ((poItem.getItemOutstandingEncumberedAmount().bigDecimalValue().signum() == -1) && (preqItemTotalAmount.bigDecimalValue().signum() == -1)) {
1240                             if (LOG.isDebugEnabled()) {
1241                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is negative: " + poItem.getItemOutstandingEncumberedAmount());
1242                             }
1243                             if (preqItemTotalAmount.compareTo(poItem.getItemOutstandingEncumberedAmount()) >= 0) {
1244                                 // extended price is equal to or greater than outstanding encumbered
1245                                 itemDisEncumber = preqItemTotalAmount;
1246                             } else {
1247                                 // extended price is less than outstanding encumbered
1248                                 takeAll = true;
1249                                 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
1250                             }
1251                         } else {
1252                             if (LOG.isDebugEnabled()) {
1253                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is positive or ZERO: " + poItem.getItemOutstandingEncumberedAmount());
1254                             }
1255                             if (poItem.getItemOutstandingEncumberedAmount().compareTo(preqItemTotalAmount) >= 0) {
1256                                 // outstanding amount is equal to or greater than extended price
1257                                 itemDisEncumber = preqItemTotalAmount;
1258                             } else {
1259                                 // outstanding amount is less than extended price
1260                                 takeAll = true;
1261                                 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
1262                             }
1263                         }
1264                     }
1265 
1266                     if (LOG.isDebugEnabled()) {
1267                         LOG.debug("relieveEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber);
1268                     }
1269 
1270                     KualiDecimal newOutstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount().subtract(itemDisEncumber);
1271                     if (LOG.isDebugEnabled()) {
1272                         LOG.debug("relieveEncumbrance() " + logItmNbr + " New Outstanding Encumbered amount is : " + newOutstandingEncumberedAmount);
1273                     }
1274                     poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1275 
1276                     KualiDecimal newInvoicedTotalAmount = poItem.getItemInvoicedTotalAmount().add(preqItemTotalAmount);
1277                     if (LOG.isDebugEnabled()) {
1278                         LOG.debug("relieveEncumbrance() " + logItmNbr + " New Invoiced Total Amount is: " + newInvoicedTotalAmount);
1279                     }
1280                     poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1281 
1282                     // Sort accounts
1283                     Collections.sort((List) poItem.getSourceAccountingLines());
1284 
1285                     // make the list of accounts for the disencumbrance entry
1286                     PurchaseOrderAccount lastAccount = null;
1287                     KualiDecimal accountTotal = ZERO;
1288                     for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
1289                         PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
1290                         if (!account.isEmpty()) {
1291                             KualiDecimal encumbranceAmount = null;
1292                             SourceAccountingLine acctString = account.generateSourceAccountingLine();
1293                             if (takeAll) {
1294                                 // fully paid; remove remaining encumbrance
1295                                 encumbranceAmount = account.getItemAccountOutstandingEncumbranceAmount();
1296                                 account.setItemAccountOutstandingEncumbranceAmount(ZERO);
1297                                 if (LOG.isDebugEnabled()) {
1298                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " take all");
1299                                 }
1300                             } else {
1301                                 // amount = item disencumber * account percent / 100
1302                                 encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED);
1303 
1304                                 account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().subtract(encumbranceAmount));
1305 
1306                                 // For rounding check at the end
1307                                 accountTotal = accountTotal.add(encumbranceAmount);
1308 
1309                                 // If we are zeroing out the encumbrance, we don't need to adjust for rounding
1310                                 if (!takeAll) {
1311                                     lastAccount = account;
1312                                 }
1313                             }
1314 
1315                             if (LOG.isDebugEnabled()) {
1316                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount);
1317                             }
1318                             if (ObjectUtils.isNull(encumbranceAccountMap.get(acctString))) {
1319                                 encumbranceAccountMap.put(acctString, encumbranceAmount);
1320                             } else {
1321                                 KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString);
1322                                 encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount));
1323                             }
1324 
1325                         }
1326                     }
1327 
1328                     // account for rounding by adjusting last account as needed
1329                     if (lastAccount != null) {
1330                         KualiDecimal difference = itemDisEncumber.subtract(accountTotal);
1331                         if (LOG.isDebugEnabled()) {
1332                             LOG.debug("relieveEncumbrance() difference: " + logItmNbr + " " + difference);
1333                         }
1334 
1335                         SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
1336                         KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1337                         if (ObjectUtils.isNull(amount)) {
1338                             encumbranceAccountMap.put(acctString, difference);
1339                         } else {
1340                             encumbranceAccountMap.put(acctString, amount.add(difference));
1341                         }
1342 
1343                         lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().subtract(difference));
1344                     }
1345                 }
1346             }
1347         }// endfor
1348 
1349         SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
1350 
1351         List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
1352         for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
1353             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
1354             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1355             if (amount.doubleValue() != 0) {
1356                 acctString.setAmount(amount);
1357                 encumbranceAccounts.add(acctString);
1358             }
1359         }
1360        // SpringContext.getBean(BusinessObjectService.class).save(po);
1361         return encumbranceAccounts;
1362     }
1363 
1364 
1365     /**
1366      * 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
1367      * the encumbrance values on the PO and saves the PO
1368      *
1369      * @param inv inv for InvoiceDocument
1370      * @return List of accounting lines to use to create the pending general ledger entries
1371      */
1372     protected List<SourceAccountingLine> relieveEncumbrance(InvoiceDocument inv) {
1373         LOG.debug("relieveEncumbrance() started");
1374 
1375         Map encumbranceAccountMap = new HashMap();
1376         // PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(inv.getPurchaseOrderIdentifier());
1377         for (PurchaseOrderDocument po : inv.getPurchaseOrderDocuments()) {
1378             // Get each item one by one
1379             for (Iterator items = inv.getItems().iterator(); items.hasNext(); ) {
1380                 InvoiceItem invItem = (InvoiceItem) items.next();
1381                 PurchaseOrderItem poItem = getPoItem(po, invItem.getItemLineNumber(), invItem.getItemType());
1382 
1383                 boolean takeAll = false; // Set this true if we relieve the entire encumbrance
1384                 KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item
1385 
1386                 String logItmNbr = "Item # " + invItem.getItemLineNumber();
1387                 if (LOG.isDebugEnabled()) {
1388                     LOG.debug("relieveEncumbrance() " + logItmNbr);
1389                 }
1390 
1391                 // If there isn't a PO item or the extended price is 0, we don't need encumbrances
1392                 if (poItem == null) {
1393                     if (LOG.isDebugEnabled()) {
1394                         LOG.debug("relieveEncumbrance() " + logItmNbr + " No encumbrances required because po item is null");
1395                     }
1396                 } else {
1397                     final KualiDecimal preqItemTotalAmount = (invItem.getTotalAmount() == null) ? KualiDecimal.ZERO : invItem.getTotalAmount();
1398                     if (ZERO.compareTo(preqItemTotalAmount) == 0) {
1399                     /*
1400                      * This is a specialized case where PREQ item being processed must adjust the PO item's outstanding encumbered
1401                      * quantity. This kind of scenario is mostly seen on warranty type items. The following must be true to do this:
1402                      * PREQ item Extended Price must be ZERO, PREQ item invoice quantity must be not empty and not ZERO, and PO item
1403                      * is quantity based PO item unit cost is ZERO
1404                      */
1405                         if (LOG.isDebugEnabled()) {
1406                             LOG.debug("relieveEncumbrance() " + logItmNbr + " No GL encumbrances required because extended price is ZERO");
1407                         }
1408                         if ((poItem.getItemQuantity() != null) && ((BigDecimal.ZERO.compareTo(poItem.getItemUnitPrice())) == 0)) {
1409                             // po has order quantity and unit price is ZERO... reduce outstanding encumbered quantity
1410                             if (LOG.isDebugEnabled()) {
1411                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate po oustanding encumbrance");
1412                             }
1413 
1414                             // Do encumbrance calculations based on quantity
1415                             if ((invItem.getItemQuantity() != null) && ((ZERO.compareTo(invItem.getItemQuantity())) != 0)) {
1416                                 KualiDecimal invoiceQuantity = invItem.getItemQuantity();
1417                                 KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1418 
1419                                 KualiDecimal encumbranceQuantity;
1420                                 if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) {
1421                                     // We bought more than the quantity on the PO
1422                                     if (LOG.isDebugEnabled()) {
1423                                         LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1424                                     }
1425                                     encumbranceQuantity = outstandingEncumberedQuantity;
1426                                     poItem.setItemOutstandingEncumberedQuantity(ZERO);
1427                                 } else {
1428                                     encumbranceQuantity = invoiceQuantity;
1429                                     poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity));
1430                                     if (LOG.isDebugEnabled()) {
1431                                         LOG.debug("relieveEncumbrance() " + logItmNbr + " adjusting oustanding encunbrance qty - encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity());
1432                                     }
1433                                 }
1434 
1435                                 if (poItem.getItemInvoicedTotalQuantity() == null) {
1436                                     poItem.setItemInvoicedTotalQuantity(invoiceQuantity);
1437                                 } else {
1438                                     poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity));
1439                                 }
1440                             }
1441                         }
1442 
1443 
1444                     } else {
1445                         if (LOG.isDebugEnabled()) {
1446                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
1447                         }
1448 
1449                         // Do we calculate the encumbrance amount based on quantity or amount?
1450                         if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1451                             if (LOG.isDebugEnabled()) {
1452                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
1453                             }
1454 
1455                             // Do encumbrance calculations based on quantity
1456                             KualiDecimal invoiceQuantity = invItem.getItemQuantity() == null ? ZERO : invItem.getItemQuantity();
1457                             KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1458 
1459                             KualiDecimal encumbranceQuantity;
1460 
1461                             if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) {
1462                                 // We bought more than the quantity on the PO
1463                                 if (LOG.isDebugEnabled()) {
1464                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO");
1465                                 }
1466                                 encumbranceQuantity = outstandingEncumberedQuantity;
1467                                 poItem.setItemOutstandingEncumberedQuantity(ZERO);
1468                                 takeAll = true;
1469                             } else {
1470                                 encumbranceQuantity = invoiceQuantity;
1471                                 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity));
1472                                 if (ZERO.compareTo(poItem.getItemOutstandingEncumberedQuantity()) == 0) {
1473                                     takeAll = true;
1474                                 }
1475                                 if (LOG.isDebugEnabled()) {
1476                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity());
1477                                 }
1478                             }
1479 
1480                             if (poItem.getItemInvoicedTotalQuantity() == null) {
1481                                 poItem.setItemInvoicedTotalQuantity(invoiceQuantity);
1482                             } else {
1483                                 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity));
1484                             }
1485 
1486                             itemDisEncumber = new KualiDecimal(encumbranceQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
1487 
1488                             //add tax for encumbrance
1489                             KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
1490                             KualiDecimal encumbranceTaxAmount = encumbranceQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
1491                             itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount);
1492                         } else {
1493                             if (LOG.isDebugEnabled()) {
1494                                 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
1495                             }
1496 
1497                             // Do encumbrance calculations based on amount only
1498                             if ((poItem.getItemOutstandingEncumberedAmount().bigDecimalValue().signum() == -1) && (preqItemTotalAmount.bigDecimalValue().signum() == -1)) {
1499                                 if (LOG.isDebugEnabled()) {
1500                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is negative: " + poItem.getItemOutstandingEncumberedAmount());
1501                                 }
1502                                 if (preqItemTotalAmount.compareTo(poItem.getItemOutstandingEncumberedAmount()) >= 0) {
1503                                     // extended price is equal to or greater than outstanding encumbered
1504                                     itemDisEncumber = preqItemTotalAmount;
1505                                 } else {
1506                                     // extended price is less than outstanding encumbered
1507                                     takeAll = true;
1508                                     itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
1509                                 }
1510                             } else {
1511                                 if (LOG.isDebugEnabled()) {
1512                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is positive or ZERO: " + poItem.getItemOutstandingEncumberedAmount());
1513                                 }
1514                                 if (poItem.getItemOutstandingEncumberedAmount().compareTo(preqItemTotalAmount) >= 0) {
1515                                     // outstanding amount is equal to or greater than extended price
1516                                     itemDisEncumber = preqItemTotalAmount;
1517                                 } else {
1518                                     // outstanding amount is less than extended price
1519                                     takeAll = true;
1520                                     itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
1521                                 }
1522                             }
1523                         }
1524 
1525                         if (LOG.isDebugEnabled()) {
1526                             LOG.debug("relieveEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber);
1527                         }
1528 
1529                         KualiDecimal newOutstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount().subtract(itemDisEncumber);
1530                         if (LOG.isDebugEnabled()) {
1531                             LOG.debug("relieveEncumbrance() " + logItmNbr + " New Outstanding Encumbered amount is : " + newOutstandingEncumberedAmount);
1532                         }
1533                         poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1534 
1535                         KualiDecimal newInvoicedTotalAmount = poItem.getItemInvoicedTotalAmount().add(preqItemTotalAmount);
1536                         if (LOG.isDebugEnabled()) {
1537                             LOG.debug("relieveEncumbrance() " + logItmNbr + " New Invoiced Total Amount is: " + newInvoicedTotalAmount);
1538                         }
1539                         poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1540 
1541                         // Sort accounts
1542                         Collections.sort((List) poItem.getSourceAccountingLines());
1543 
1544                         // make the list of accounts for the disencumbrance entry
1545                         PurchaseOrderAccount lastAccount = null;
1546                         KualiDecimal accountTotal = ZERO;
1547                         for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
1548                             PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
1549                             if (!account.isEmpty()) {
1550                                 KualiDecimal encumbranceAmount = null;
1551                                 SourceAccountingLine acctString = account.generateSourceAccountingLine();
1552                                 if (takeAll) {
1553                                     // fully paid; remove remaining encumbrance
1554                                     encumbranceAmount = account.getItemAccountOutstandingEncumbranceAmount();
1555                                     account.setItemAccountOutstandingEncumbranceAmount(ZERO);
1556                                     if (LOG.isDebugEnabled()) {
1557                                         LOG.debug("relieveEncumbrance() " + logItmNbr + " take all");
1558                                     }
1559                                 } else {
1560                                     // amount = item disencumber * account percent / 100
1561                                     encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED);
1562 
1563                                     account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().subtract(encumbranceAmount));
1564 
1565                                     // For rounding check at the end
1566                                     accountTotal = accountTotal.add(encumbranceAmount);
1567 
1568                                     // If we are zeroing out the encumbrance, we don't need to adjust for rounding
1569                                     if (!takeAll) {
1570                                         lastAccount = account;
1571                                     }
1572                                 }
1573 
1574                                 if (LOG.isDebugEnabled()) {
1575                                     LOG.debug("relieveEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount);
1576                                 }
1577                                 if (ObjectUtils.isNull(encumbranceAccountMap.get(acctString))) {
1578                                     encumbranceAccountMap.put(acctString, encumbranceAmount);
1579                                 } else {
1580                                     KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString);
1581                                     encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount));
1582                                 }
1583 
1584                             }
1585                         }
1586 
1587                         // account for rounding by adjusting last account as needed
1588                         if (lastAccount != null) {
1589                             KualiDecimal difference = itemDisEncumber.subtract(accountTotal);
1590                             if (LOG.isDebugEnabled()) {
1591                                 LOG.debug("relieveEncumbrance() difference: " + logItmNbr + " " + difference);
1592                             }
1593 
1594                             SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
1595                             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1596                             if (ObjectUtils.isNull(amount)) {
1597                                 encumbranceAccountMap.put(acctString, difference);
1598                             } else {
1599                                 encumbranceAccountMap.put(acctString, amount.add(difference));
1600                             }
1601 
1602                             lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().subtract(difference));
1603                         }
1604                     }
1605                 }
1606             }// endfor
1607         }
1608 
1609         List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
1610         for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
1611             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
1612             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1613             if (amount.doubleValue() != 0) {
1614                 acctString.setAmount(amount);
1615                 encumbranceAccounts.add(acctString);
1616             }
1617         }
1618 
1619         // SpringContext.getBean(BusinessObjectService.class).save(po);
1620         return encumbranceAccounts;
1621     }
1622 
1623 
1624     /**
1625      * 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
1626      * encumbrance values on the PO and saves the PO
1627      *
1628      * @param preq PREQ for invoice
1629      * @return List of accounting lines to use to create the pending general ledger entries
1630      */
1631     protected List<SourceAccountingLine> reencumberEncumbrance(PaymentRequestDocument preq) {
1632         LOG.debug("reencumberEncumbrance() started");
1633 
1634         PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(preq.getPurchaseOrderIdentifier());
1635         Map encumbranceAccountMap = new HashMap();
1636 
1637         // Get each item one by one
1638         for (Iterator items = preq.getItems().iterator(); items.hasNext(); ) {
1639             PaymentRequestItem payRequestItem = (PaymentRequestItem) items.next();
1640             PurchaseOrderItem poItem = getPoItem(po, payRequestItem.getItemLineNumber(), payRequestItem.getItemType());
1641 
1642             KualiDecimal itemReEncumber = null; // Amount to reencumber for this item
1643 
1644             String logItmNbr = "Item # " + payRequestItem.getItemLineNumber();
1645             if (LOG.isDebugEnabled()) {
1646                 LOG.debug("reencumberEncumbrance() " + logItmNbr);
1647             }
1648 
1649             // If there isn't a PO item or the total amount is 0, we don't need encumbrances
1650             final KualiDecimal preqItemTotalAmount = (payRequestItem.getTotalAmount() == null) ? KualiDecimal.ZERO : payRequestItem.getTotalAmount();
1651             if ((poItem == null) || (preqItemTotalAmount.doubleValue() == 0)) {
1652                 if (LOG.isDebugEnabled()) {
1653                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " No encumbrances required");
1654                 }
1655             } else {
1656                 if (LOG.isDebugEnabled()) {
1657                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
1658                 }
1659 
1660                 // Do we calculate the encumbrance amount based on quantity or amount?
1661                 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1662                     if (LOG.isDebugEnabled()) {
1663                         LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
1664                     }
1665 
1666                     // Do disencumbrance calculations based on quantity
1667                     KualiDecimal preqQuantity = payRequestItem.getItemQuantity() == null ? ZERO : payRequestItem.getItemQuantity();
1668                     KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1669                     KualiDecimal invoicedTotal = poItem.getItemInvoicedTotalQuantity() == null ? ZERO : poItem.getItemInvoicedTotalQuantity();
1670 
1671                     poItem.setItemInvoicedTotalQuantity(invoicedTotal.subtract(preqQuantity));
1672                     poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.add(preqQuantity));
1673 
1674                     //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
1675                     itemReEncumber = new KualiDecimal(preqQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
1676 
1677                     //add tax for encumbrance
1678                     KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
1679                     KualiDecimal encumbranceTaxAmount = preqQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
1680                     itemReEncumber = itemReEncumber.add(encumbranceTaxAmount);
1681 
1682                 } else {
1683                     if (LOG.isDebugEnabled()) {
1684                         LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
1685                     }
1686 
1687                     itemReEncumber = preqItemTotalAmount;
1688                     // if re-encumber amount is more than original PO ordered amount... do not exceed ordered amount
1689                     // this prevents negative encumbrance
1690                     if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() < 0)) {
1691                         // po item extended cost is negative
1692                         if ((poItem.getTotalAmount().compareTo(itemReEncumber)) > 0) {
1693                             itemReEncumber = poItem.getTotalAmount();
1694                         }
1695                     } else if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() >= 0)) {
1696                         // po item extended cost is positive
1697                         if ((poItem.getTotalAmount().compareTo(itemReEncumber)) < 0) {
1698                             itemReEncumber = poItem.getTotalAmount();
1699                         }
1700                     }
1701                 }
1702 
1703                 if (LOG.isDebugEnabled()) {
1704                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " Amount to reencumber: " + itemReEncumber);
1705                 }
1706 
1707                 KualiDecimal outstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount() == null ? ZERO : poItem.getItemOutstandingEncumberedAmount();
1708                 if (LOG.isDebugEnabled()) {
1709                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Outstanding Encumbrance Amount set to: " + outstandingEncumberedAmount);
1710                 }
1711                 KualiDecimal newOutstandingEncumberedAmount = outstandingEncumberedAmount.add(itemReEncumber);
1712                 if (LOG.isDebugEnabled()) {
1713                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Outstanding Encumbrance Amount to set: " + newOutstandingEncumberedAmount);
1714                 }
1715                 poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1716 
1717                 KualiDecimal invoicedTotalAmount = poItem.getItemInvoicedTotalAmount() == null ? ZERO : poItem.getItemInvoicedTotalAmount();
1718                 if (LOG.isDebugEnabled()) {
1719                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Invoiced Total Amount set to: " + invoicedTotalAmount);
1720                 }
1721                 KualiDecimal newInvoicedTotalAmount = invoicedTotalAmount.subtract(preqItemTotalAmount);
1722                 if (LOG.isDebugEnabled()) {
1723                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Invoiced Total Amount to set: " + newInvoicedTotalAmount);
1724                 }
1725                 poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1726 
1727                 // make the list of accounts for the reencumbrance entry
1728                 PurchaseOrderAccount lastAccount = null;
1729                 KualiDecimal accountTotal = ZERO;
1730 
1731                 // Sort accounts
1732                 Collections.sort((List) poItem.getSourceAccountingLines());
1733 
1734                 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
1735                     PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
1736                     if (!account.isEmpty()) {
1737                         SourceAccountingLine acctString = account.generateSourceAccountingLine();
1738 
1739                         // amount = item reencumber * account percent / 100
1740                         KualiDecimal reencumbranceAmount = itemReEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED);
1741 
1742                         account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(reencumbranceAmount));
1743 
1744                         // For rounding check at the end
1745                         accountTotal = accountTotal.add(reencumbranceAmount);
1746 
1747                         lastAccount = account;
1748 
1749                         if (LOG.isDebugEnabled()) {
1750                             LOG.debug("reencumberEncumbrance() " + logItmNbr + " " + acctString + " = " + reencumbranceAmount);
1751                         }
1752                         if (encumbranceAccountMap.containsKey(acctString)) {
1753                             KualiDecimal currentAmount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1754                             encumbranceAccountMap.put(acctString, reencumbranceAmount.add(currentAmount));
1755                         } else {
1756                             encumbranceAccountMap.put(acctString, reencumbranceAmount);
1757                         }
1758                     }
1759                 }
1760 
1761                 // account for rounding by adjusting last account as needed
1762                 if (lastAccount != null) {
1763                     KualiDecimal difference = itemReEncumber.subtract(accountTotal);
1764                     if (LOG.isDebugEnabled()) {
1765                         LOG.debug("reencumberEncumbrance() difference: " + logItmNbr + " " + difference);
1766                     }
1767 
1768                     SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
1769                     KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1770                     if (amount == null) {
1771                         encumbranceAccountMap.put(acctString, difference);
1772                     } else {
1773                         encumbranceAccountMap.put(acctString, amount.add(difference));
1774                     }
1775                     lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference));
1776                 }
1777             }
1778         }
1779 
1780         //SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
1781 
1782         //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966
1783         SpringContext.getBean(BusinessObjectService.class).save(po);
1784 
1785         List<SourceAccountingLine> encumbranceAccounts = new ArrayList<SourceAccountingLine>();
1786         for (Iterator<SourceAccountingLine> iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
1787             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
1788             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1789             if (amount.doubleValue() != 0) {
1790                 acctString.setAmount(amount);
1791                 encumbranceAccounts.add(acctString);
1792             }
1793         }
1794 
1795         return encumbranceAccounts;
1796     }
1797 
1798 
1799     protected List<SourceAccountingLine> reencumberEncumbrance(InvoiceDocument prqs) {
1800         LOG.debug("reencumberEncumbrance() started");
1801 
1802         PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(prqs.getPurchaseOrderIdentifier());
1803         Map encumbranceAccountMap = new HashMap();
1804 
1805         // Get each item one by one
1806         for (Iterator items = prqs.getItems().iterator(); items.hasNext(); ) {
1807             InvoiceItem invItem = (InvoiceItem) items.next();
1808             PurchaseOrderItem poItem = getPoItem(po, invItem.getItemLineNumber(), invItem.getItemType());
1809 
1810             KualiDecimal itemReEncumber = null; // Amount to reencumber for this item
1811 
1812             String logItmNbr = "Item # " + invItem.getItemLineNumber();
1813             if (LOG.isDebugEnabled()) {
1814                 LOG.debug("reencumberEncumbrance() " + logItmNbr);
1815             }
1816 
1817             // If there isn't a PO item or the total amount is 0, we don't need encumbrances
1818             final KualiDecimal preqItemTotalAmount = (invItem.getTotalAmount() == null) ? KualiDecimal.ZERO : invItem.getTotalAmount();
1819             if ((poItem == null) || (preqItemTotalAmount.doubleValue() == 0)) {
1820                 if (LOG.isDebugEnabled()) {
1821                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " No encumbrances required");
1822                 }
1823             } else {
1824                 if (LOG.isDebugEnabled()) {
1825                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
1826                 }
1827 
1828                 // Do we calculate the encumbrance amount based on quantity or amount?
1829                 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1830                     if (LOG.isDebugEnabled()) {
1831                         LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
1832                     }
1833 
1834                     // Do disencumbrance calculations based on quantity
1835                     KualiDecimal preqQuantity = invItem.getItemQuantity() == null ? ZERO : invItem.getItemQuantity();
1836                     KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity();
1837                     KualiDecimal invoicedTotal = poItem.getItemInvoicedTotalQuantity() == null ? ZERO : poItem.getItemInvoicedTotalQuantity();
1838 
1839                     poItem.setItemInvoicedTotalQuantity(invoicedTotal.subtract(preqQuantity));
1840                     poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.add(preqQuantity));
1841 
1842                     //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
1843                     itemReEncumber = new KualiDecimal(preqQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
1844 
1845                     //add tax for encumbrance
1846                     KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
1847                     KualiDecimal encumbranceTaxAmount = preqQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
1848                     itemReEncumber = itemReEncumber.add(encumbranceTaxAmount);
1849 
1850                 } else {
1851                     if (LOG.isDebugEnabled()) {
1852                         LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
1853                     }
1854 
1855                     itemReEncumber = preqItemTotalAmount;
1856                     // if re-encumber amount is more than original PO ordered amount... do not exceed ordered amount
1857                     // this prevents negative encumbrance
1858                     if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() < 0)) {
1859                         // po item extended cost is negative
1860                         if ((poItem.getTotalAmount().compareTo(itemReEncumber)) > 0) {
1861                             itemReEncumber = poItem.getTotalAmount();
1862                         }
1863                     } else if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() >= 0)) {
1864                         // po item extended cost is positive
1865                         if ((poItem.getTotalAmount().compareTo(itemReEncumber)) < 0) {
1866                             itemReEncumber = poItem.getTotalAmount();
1867                         }
1868                     }
1869                 }
1870 
1871                 if (LOG.isDebugEnabled()) {
1872                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " Amount to reencumber: " + itemReEncumber);
1873                 }
1874 
1875                 KualiDecimal outstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount() == null ? ZERO : poItem.getItemOutstandingEncumberedAmount();
1876                 if (LOG.isDebugEnabled()) {
1877                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Outstanding Encumbrance Amount set to: " + outstandingEncumberedAmount);
1878                 }
1879                 KualiDecimal newOutstandingEncumberedAmount = outstandingEncumberedAmount.add(itemReEncumber);
1880                 if (LOG.isDebugEnabled()) {
1881                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Outstanding Encumbrance Amount to set: " + newOutstandingEncumberedAmount);
1882                 }
1883                 poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1884 
1885                 KualiDecimal invoicedTotalAmount = poItem.getItemInvoicedTotalAmount() == null ? ZERO : poItem.getItemInvoicedTotalAmount();
1886                 if (LOG.isDebugEnabled()) {
1887                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Invoiced Total Amount set to: " + invoicedTotalAmount);
1888                 }
1889                 KualiDecimal newInvoicedTotalAmount = invoicedTotalAmount.subtract(preqItemTotalAmount);
1890                 if (LOG.isDebugEnabled()) {
1891                     LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Invoiced Total Amount to set: " + newInvoicedTotalAmount);
1892                 }
1893                 poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1894 
1895                 // make the list of accounts for the reencumbrance entry
1896                 PurchaseOrderAccount lastAccount = null;
1897                 KualiDecimal accountTotal = ZERO;
1898 
1899                 // Sort accounts
1900                 Collections.sort((List) poItem.getSourceAccountingLines());
1901 
1902                 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
1903                     PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
1904                     if (!account.isEmpty()) {
1905                         SourceAccountingLine acctString = account.generateSourceAccountingLine();
1906 
1907                         // amount = item reencumber * account percent / 100
1908                         KualiDecimal reencumbranceAmount = itemReEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED);
1909 
1910                         account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(reencumbranceAmount));
1911 
1912                         // For rounding check at the end
1913                         accountTotal = accountTotal.add(reencumbranceAmount);
1914 
1915                         lastAccount = account;
1916 
1917                         if (LOG.isDebugEnabled()) {
1918                             LOG.debug("reencumberEncumbrance() " + logItmNbr + " " + acctString + " = " + reencumbranceAmount);
1919                         }
1920                         if (encumbranceAccountMap.containsKey(acctString)) {
1921                             KualiDecimal currentAmount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1922                             encumbranceAccountMap.put(acctString, reencumbranceAmount.add(currentAmount));
1923                         } else {
1924                             encumbranceAccountMap.put(acctString, reencumbranceAmount);
1925                         }
1926                     }
1927                 }
1928 
1929                 // account for rounding by adjusting last account as needed
1930                 if (lastAccount != null) {
1931                     KualiDecimal difference = itemReEncumber.subtract(accountTotal);
1932                     if (LOG.isDebugEnabled()) {
1933                         LOG.debug("reencumberEncumbrance() difference: " + logItmNbr + " " + difference);
1934                     }
1935 
1936                     SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
1937                     KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1938                     if (amount == null) {
1939                         encumbranceAccountMap.put(acctString, difference);
1940                     } else {
1941                         encumbranceAccountMap.put(acctString, amount.add(difference));
1942                     }
1943                     lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference));
1944                 }
1945             }
1946         }
1947 
1948         //SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
1949 
1950         //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966
1951         SpringContext.getBean(BusinessObjectService.class).save(po);
1952 
1953         List<SourceAccountingLine> encumbranceAccounts = new ArrayList<SourceAccountingLine>();
1954         for (Iterator<SourceAccountingLine> iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
1955             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
1956             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
1957             if (amount.doubleValue() != 0) {
1958                 acctString.setAmount(amount);
1959                 encumbranceAccounts.add(acctString);
1960             }
1961         }
1962 
1963         return encumbranceAccounts;
1964     }
1965 
1966 
1967     /**
1968      * 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
1969      * encumbrance values on the PO and saves the PO
1970      *
1971      * @param cm Credit Memo document
1972      * @param po Purchase Order document modify encumbrances
1973      * @return List of accounting lines to use to create the pending general ledger entries
1974      */
1975     protected List<SourceAccountingLine> getCreditMemoEncumbrance(VendorCreditMemoDocument cm, PurchaseOrderDocument po, boolean cancel) {
1976         LOG.debug("getCreditMemoEncumbrance() started");
1977 
1978         if (ObjectUtils.isNull(po)) {
1979             return null;
1980         }
1981 
1982         if (cancel) {
1983             LOG.debug("getCreditMemoEncumbrance() Receiving items back from vendor (cancelled CM)");
1984         } else {
1985             LOG.debug("getCreditMemoEncumbrance() Returning items to vendor");
1986         }
1987 
1988         Map encumbranceAccountMap = new HashMap();
1989 
1990         // Get each item one by one
1991         for (Iterator items = cm.getItems().iterator(); items.hasNext(); ) {
1992             CreditMemoItem cmItem = (CreditMemoItem) items.next();
1993             PurchaseOrderItem poItem = getPoItem(po, cmItem.getItemLineNumber(), cmItem.getItemType());
1994 
1995             KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item
1996             KualiDecimal itemAlterInvoiceAmt = null; // Amount to alter the invoicedAmt on the PO item
1997 
1998             String logItmNbr = "Item # " + cmItem.getItemLineNumber();
1999             if (LOG.isDebugEnabled()) {
2000                 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr);
2001             }
2002 
2003             final KualiDecimal cmItemTotalAmount = (cmItem.getTotalAmount() == null) ? KualiDecimal.ZERO : cmItem.getTotalAmount();
2004             ;
2005             // If there isn't a PO item or the total amount is 0, we don't need encumbrances
2006             if ((poItem == null) || (cmItemTotalAmount == null) || (cmItemTotalAmount.doubleValue() == 0) ||
2007                     (cmItemTotalAmount!=null && !cmItemTotalAmount.isNegative())) {
2008                 if (LOG.isDebugEnabled()) {
2009                     LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " No encumbrances required");
2010                 }
2011             } else {
2012                 if (LOG.isDebugEnabled()) {
2013                     LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries");
2014                 }
2015 
2016                 // Do we calculate the encumbrance amount based on quantity or amount?
2017                 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
2018                     if (LOG.isDebugEnabled()) {
2019                         LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity");
2020                     }
2021 
2022                     // Do encumbrance calculations based on quantity
2023                     KualiDecimal cmQuantity = cmItem.getItemQuantity() == null ? ZERO : cmItem.getItemQuantity();
2024 
2025                     KualiDecimal encumbranceQuantityChange = calculateQuantityChange(cancel, poItem, cmQuantity);
2026 
2027                     if (LOG.isDebugEnabled()) {
2028                         LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " encumbranceQtyChange " + encumbranceQuantityChange + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity() + " invoicedTotalQuantity " + poItem.getItemInvoicedTotalQuantity());
2029                     }
2030 
2031                     //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits
2032                     itemDisEncumber = new KualiDecimal(encumbranceQuantityChange.bigDecimalValue().multiply(poItem.getItemUnitPrice()));
2033 
2034                     //add tax for encumbrance
2035                     KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount();
2036                     KualiDecimal encumbranceTaxAmount = encumbranceQuantityChange.divide(poItem.getItemQuantity()).multiply(itemTaxAmount);
2037                     itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount);
2038 
2039                     itemAlterInvoiceAmt = cmItemTotalAmount;
2040                     if (cancel) {
2041                         itemAlterInvoiceAmt = itemAlterInvoiceAmt.multiply(new KualiDecimal("-1"));
2042                     }
2043                 } else {
2044                     if (LOG.isDebugEnabled()) {
2045                         LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount");
2046                     }
2047 
2048                     // Do encumbrance calculations based on amount only
2049                     if (cancel) {
2050                         // Decrease encumbrance
2051                         itemDisEncumber = cmItemTotalAmount.multiply(new KualiDecimal("-1"));
2052 
2053                         if (poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber).doubleValue() < 0) {
2054                             LOG.debug("getCreditMemoEncumbrance() Cancel overflow");
2055 
2056                             itemDisEncumber = poItem.getItemOutstandingEncumberedAmount();
2057                         }
2058                     } else {
2059                         // Increase encumbrance
2060                         itemDisEncumber = cmItemTotalAmount;
2061 
2062                         if (poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber).doubleValue() > poItem.getTotalAmount().doubleValue()) {
2063                             LOG.debug("getCreditMemoEncumbrance() Create overflow");
2064 
2065                             itemDisEncumber = poItem.getTotalAmount().subtract(poItem.getItemOutstandingEncumberedAmount());
2066                         }
2067                     }
2068                     itemAlterInvoiceAmt = itemDisEncumber;
2069                 }
2070 
2071                 // alter the encumbrance based on what was originally encumbered
2072                 poItem.setItemOutstandingEncumberedAmount(poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber));
2073 
2074                 // alter the invoiced amt based on what was actually credited on the credit memo
2075                 poItem.setItemInvoicedTotalAmount(poItem.getItemInvoicedTotalAmount().subtract(itemAlterInvoiceAmt));
2076                 if (poItem.getItemInvoicedTotalAmount().compareTo(ZERO) < 0) {
2077                     poItem.setItemInvoicedTotalAmount(ZERO);
2078                 }
2079 
2080 
2081                 if (LOG.isDebugEnabled()) {
2082                     LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber);
2083                 }
2084 
2085                 // Sort accounts
2086                 Collections.sort((List) poItem.getSourceAccountingLines());
2087 
2088                 // make the list of accounts for the disencumbrance entry
2089                 PurchaseOrderAccount lastAccount = null;
2090                 KualiDecimal accountTotal = ZERO;
2091                 // Collections.sort((List)poItem.getSourceAccountingLines());
2092                 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) {
2093                     PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next();
2094                     if (!account.isEmpty()) {
2095                         KualiDecimal encumbranceAmount = null;
2096 
2097                         SourceAccountingLine acctString = account.generateSourceAccountingLine();
2098                         // amount = item disencumber * account percent / 100
2099                         encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(new KualiDecimal(100));
2100 
2101                         account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(encumbranceAmount));
2102 
2103                         // For rounding check at the end
2104                         accountTotal = accountTotal.add(encumbranceAmount);
2105 
2106                         lastAccount = account;
2107 
2108                         if (LOG.isDebugEnabled()) {
2109                             LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount);
2110                         }
2111 
2112                         if (encumbranceAccountMap.get(acctString) == null) {
2113                             encumbranceAccountMap.put(acctString, encumbranceAmount);
2114                         } else {
2115                             KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString);
2116                             encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount));
2117                         }
2118                     }
2119                 }
2120 
2121                 // account for rounding by adjusting last account as needed
2122                 if (lastAccount != null) {
2123                     KualiDecimal difference = itemDisEncumber.subtract(accountTotal);
2124                     if (LOG.isDebugEnabled()) {
2125                         LOG.debug("getCreditMemoEncumbrance() difference: " + logItmNbr + " " + difference);
2126                     }
2127 
2128                     SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine();
2129                     KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
2130                     if (amount == null) {
2131                         encumbranceAccountMap.put(acctString, difference);
2132                     } else {
2133                         encumbranceAccountMap.put(acctString, amount.add(difference));
2134                     }
2135                     lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference));
2136                 }
2137             }
2138         }
2139 
2140         List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
2141         for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) {
2142             SourceAccountingLine acctString = (SourceAccountingLine) iter.next();
2143             KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString);
2144             if (amount.doubleValue() != 0) {
2145                 acctString.setAmount(amount);
2146                 encumbranceAccounts.add(acctString);
2147             }
2148         }
2149 
2150         // SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
2151         //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966
2152         SpringContext.getBean(BusinessObjectService.class).save(po);
2153 
2154         return encumbranceAccounts;
2155     }
2156 
2157     /**
2158      * Save the given general ledger entries
2159      *
2160      * @param glEntries List of GeneralLedgerPendingEntries to be saved
2161      */
2162     protected void saveGLEntries(List<GeneralLedgerPendingEntry> glEntries) {
2163         LOG.debug("saveGLEntries() started");
2164         businessObjectService.save(glEntries);
2165     }
2166 
2167     /**
2168      * Save the given accounts for the given document.
2169      *
2170      * @param summaryAccounts         Accounts to be saved
2171      * @param purapDocumentIdentifier Purap document id for accounts
2172      */
2173     protected void saveAccountsPayableSummaryAccounts(List<SummaryAccount> summaryAccounts, Integer purapDocumentIdentifier, String docType) {
2174         LOG.debug("saveAccountsPayableSummaryAccounts() started");
2175         purapAccountingService.deleteSummaryAccounts(purapDocumentIdentifier, docType);
2176         List<AccountsPayableSummaryAccount> apSummaryAccounts = new ArrayList();
2177         for (SummaryAccount summaryAccount : summaryAccounts) {
2178             apSummaryAccounts.add(new AccountsPayableSummaryAccount(summaryAccount.getAccount(), purapDocumentIdentifier, docType));
2179         }
2180         businessObjectService.save(apSummaryAccounts);
2181     }
2182 
2183     /**
2184      * Save the given accounts for the given document.
2185      *
2186      * @param summaryAccounts         Accounts to be saved
2187      * @param purapDocumentIdentifier Purap document id for accounts
2188      * @param docType                 Document Type Used
2189      */
2190     protected void saveInvoiceAccountsPayableSummaryAccounts(List<SummaryAccount> summaryAccounts, Integer purapDocumentIdentifier, String docType) {
2191         LOG.debug("saveAccountsPayableSummaryAccounts() started");
2192         purapAccountingService.deleteSummaryAccounts(purapDocumentIdentifier, docType);
2193         List<OleInvoiceAccountsPayableSummaryAccount> apSummaryAccounts = new ArrayList();
2194         for (SummaryAccount summaryAccount : summaryAccounts) {
2195             apSummaryAccounts.add(new OleInvoiceAccountsPayableSummaryAccount(summaryAccount.getAccount(), purapDocumentIdentifier, docType));
2196         }
2197         businessObjectService.save(apSummaryAccounts);
2198     }
2199 
2200     /**
2201      * Find item in PO based on given parameters. Must send either the line # or item type.
2202      *
2203      * @param po       Purchase Order containing list of items
2204      * @param nbr      Line # of desired item (could be null)
2205      * @param itemType Item type of desired item
2206      * @return PurcahseOrderItem found matching given criteria
2207      */
2208     protected PurchaseOrderItem getPoItem(PurchaseOrderDocument po, Integer nbr, ItemType itemType) {
2209         LOG.debug("getPoItem() started");
2210         for (Iterator iter = po.getItems().iterator(); iter.hasNext(); ) {
2211             PurchaseOrderItem element = (PurchaseOrderItem) iter.next();
2212             if (itemType.isLineItemIndicator()) {
2213                 if (ObjectUtils.isNotNull(nbr) && ObjectUtils.isNotNull(element.getItemLineNumber()) && (nbr.compareTo(element.getItemLineNumber()) == 0)) {
2214                     return element;
2215                 }
2216             } else {
2217                 if (element.getItemTypeCode().equals(itemType.getItemTypeCode())) {
2218                     return element;
2219                 }
2220             }
2221         }
2222         return null;
2223     }
2224 
2225     /**
2226      * Format description for general ledger entry. Currently making sure length is less than 40 char.
2227      *
2228      * @param description String to be formatted
2229      * @return Formatted String
2230      */
2231     protected String entryDescription(String description) {
2232         if (description != null && description.length() > 40) {
2233             return description.toString().substring(0, 39);
2234         } else {
2235             return description;
2236         }
2237     }
2238 
2239     /**
2240      * Calculate quantity change for creating Credit Memo entries
2241      *
2242      * @param cancel     Boolean indicating whether entries are for creation or cancellation of credit memo
2243      * @param poItem     Purchase Order Item
2244      * @param cmQuantity Quantity on credit memo item
2245      * @return Calculated change
2246      */
2247     protected KualiDecimal calculateQuantityChange(boolean cancel, PurchaseOrderItem poItem, KualiDecimal cmQuantity) {
2248         LOG.debug("calculateQuantityChange() started");
2249 
2250         // Calculate quantity change & adjust invoiced quantity & outstanding encumbered quantity
2251         KualiDecimal encumbranceQuantityChange = null;
2252         if (cancel) {
2253             encumbranceQuantityChange = cmQuantity.multiply(new KualiDecimal("-1"));
2254         } else {
2255             encumbranceQuantityChange = cmQuantity;
2256         }
2257         poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().subtract(encumbranceQuantityChange));
2258         poItem.setItemOutstandingEncumberedQuantity(poItem.getItemOutstandingEncumberedQuantity().add(encumbranceQuantityChange));
2259 
2260         // Check for overflows
2261         if (cancel) {
2262             if (poItem.getItemOutstandingEncumberedQuantity().doubleValue() < 0) {
2263                 LOG.debug("calculateQuantityChange() Cancel overflow");
2264                 KualiDecimal difference = poItem.getItemOutstandingEncumberedQuantity().abs();
2265                 poItem.setItemOutstandingEncumberedQuantity(ZERO);
2266                 poItem.setItemInvoicedTotalQuantity(poItem.getItemQuantity());
2267                 encumbranceQuantityChange = encumbranceQuantityChange.add(difference);
2268             }
2269         }
2270 // Coomented for JIRA:OLE-5162 as encumbrance get doubled here.
2271        /* else {
2272             if (poItem.getItemInvoicedTotalQuantity().doubleValue() < 0) {
2273                 LOG.debug("calculateQuantityChange() Create overflow");
2274                 KualiDecimal difference = poItem.getItemInvoicedTotalQuantity().abs();
2275                 poItem.setItemOutstandingEncumberedQuantity(poItem.getItemQuantity());
2276                 poItem.setItemInvoicedTotalQuantity(ZERO);
2277                 encumbranceQuantityChange = encumbranceQuantityChange.add(difference);
2278             }
2279         } */
2280         return encumbranceQuantityChange;
2281     }
2282 
2283     public void setDateTimeService(DateTimeService dateTimeService) {
2284         this.dateTimeService = dateTimeService;
2285     }
2286 
2287     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
2288         this.businessObjectService = businessObjectService;
2289     }
2290 
2291     public void setGeneralLedgerPendingEntryService(GeneralLedgerPendingEntryService generalLedgerPendingEntryService) {
2292         this.generalLedgerPendingEntryService = generalLedgerPendingEntryService;
2293     }
2294 
2295     public void setKualiRuleService(KualiRuleService kualiRuleService) {
2296         this.kualiRuleService = kualiRuleService;
2297     }
2298 
2299     public void setPurapAccountingService(PurapAccountingService purapAccountingService) {
2300         this.purapAccountingService = purapAccountingService;
2301     }
2302 
2303     public void setUniversityDateService(UniversityDateService universityDateService) {
2304         this.universityDateService = universityDateService;
2305     }
2306 
2307     public void setPurchaseOrderService(PurchaseOrderService purchaseOrderService) {
2308         this.purchaseOrderService = purchaseOrderService;
2309     }
2310 
2311     public void setObjectCodeService(ObjectCodeService objectCodeService) {
2312         this.objectCodeService = objectCodeService;
2313     }
2314 
2315     public void setSubObjectCodeService(SubObjectCodeService subObjectCodeService) {
2316         this.subObjectCodeService = subObjectCodeService;
2317     }
2318 
2319     public void setParameterService(ParameterService parameterService) {
2320         this.parameterService = parameterService;
2321     }
2322 
2323     public void setPaymentRequestService(PaymentRequestService paymentRequestService) {
2324         this.paymentRequestService = paymentRequestService;
2325     }
2326 
2327     /**
2328      * Sets the invoiceService attribute value.
2329      *
2330      * @param invoiceService The invoiceService to set.
2331      */
2332 
2333     public void setInvoiceService(InvoiceService invoiceService) {
2334         this.invoiceService = invoiceService;
2335     }
2336 
2337 
2338 }