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