001/* 002 * Copyright 2007 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.ole.module.purap.service.impl; 017 018import org.kuali.ole.coa.businessobject.Account; 019import org.kuali.ole.coa.businessobject.ObjectCode; 020import org.kuali.ole.coa.businessobject.SubObjectCode; 021import org.kuali.ole.coa.service.ObjectCodeService; 022import org.kuali.ole.coa.service.SubObjectCodeService; 023import org.kuali.ole.module.purap.PurapConstants; 024import org.kuali.ole.module.purap.PurapConstants.PurapDocTypeCodes; 025import org.kuali.ole.module.purap.businessobject.*; 026import org.kuali.ole.module.purap.document.*; 027import org.kuali.ole.module.purap.document.InvoiceDocument; 028import org.kuali.ole.module.purap.document.service.InvoiceService; 029import org.kuali.ole.module.purap.document.service.PaymentRequestService; 030import org.kuali.ole.module.purap.document.service.PurapService; 031import org.kuali.ole.module.purap.document.service.PurchaseOrderService; 032import org.kuali.ole.module.purap.service.PurapAccountRevisionService; 033import org.kuali.ole.module.purap.service.PurapAccountingService; 034import org.kuali.ole.module.purap.service.PurapGeneralLedgerService; 035import org.kuali.ole.module.purap.util.SummaryAccount; 036import org.kuali.ole.module.purap.util.UseTaxContainer; 037import org.kuali.ole.select.businessobject.OleInvoiceAccountsPayableSummaryAccount; 038import org.kuali.ole.select.businessobject.OleInvoiceItem; 039import org.kuali.ole.select.businessobject.OlePaymentRequestItem; 040import org.kuali.ole.sys.OLEConstants; 041import org.kuali.ole.sys.businessobject.*; 042import org.kuali.ole.sys.context.SpringContext; 043import org.kuali.ole.sys.service.GeneralLedgerPendingEntryService; 044import org.kuali.ole.sys.service.UniversityDateService; 045import org.kuali.rice.core.api.datetime.DateTimeService; 046import org.kuali.rice.core.api.util.type.KualiDecimal; 047import org.kuali.rice.coreservice.framework.parameter.ParameterService; 048import org.kuali.rice.krad.service.BusinessObjectService; 049import org.kuali.rice.krad.service.KualiRuleService; 050import org.kuali.rice.krad.util.ObjectUtils; 051import org.springframework.transaction.annotation.Transactional; 052 053import java.math.BigDecimal; 054import java.util.*; 055 056import static org.kuali.ole.module.purap.PurapConstants.HUNDRED; 057import static org.kuali.ole.module.purap.PurapConstants.PURAP_ORIGIN_CODE; 058import static org.kuali.ole.sys.OLEConstants.*; 059import static org.kuali.rice.core.api.util.type.KualiDecimal.ZERO; 060 061@Transactional 062public class PurapGeneralLedgerServiceImpl implements PurapGeneralLedgerService { 063 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PurapGeneralLedgerServiceImpl.class); 064 065 private BusinessObjectService businessObjectService; 066 private DateTimeService dateTimeService; 067 private GeneralLedgerPendingEntryService generalLedgerPendingEntryService; 068 private KualiRuleService kualiRuleService; 069 private PaymentRequestService paymentRequestService; 070 private ParameterService parameterService; 071 private PurapAccountingService purapAccountingService; 072 private PurchaseOrderService purchaseOrderService; 073 private UniversityDateService universityDateService; 074 private ObjectCodeService objectCodeService; 075 private SubObjectCodeService subObjectCodeService; 076 private InvoiceService invoiceService; 077 078 /** 079 * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#customizeGeneralLedgerPendingEntry(org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument, 080 * org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry, 081 * java.lang.Integer, java.lang.String, java.lang.String, boolean) 082 */ 083 public void customizeGeneralLedgerPendingEntry(PurchasingAccountsPayableDocument purapDocument, AccountingLine accountingLine, GeneralLedgerPendingEntry explicitEntry, Integer referenceDocumentNumber, String debitCreditCode, String docType, boolean isEncumbrance) { 084 LOG.debug("customizeGeneralLedgerPendingEntry() started"); 085 086 explicitEntry.setDocumentNumber(purapDocument.getDocumentNumber()); 087 explicitEntry.setTransactionLedgerEntryDescription(entryDescription(purapDocument.getVendorName())); 088 explicitEntry.setFinancialSystemOriginationCode(PURAP_ORIGIN_CODE); 089 090 // Always make the referring document the PO for all PURAP docs except for CM against a vendor. 091 // This is required for encumbrance entries. It's not required for actual/liability 092 // entries, but it makes things easier to deal with. If vendor, leave referring stuff blank. 093 if (ObjectUtils.isNotNull(referenceDocumentNumber)) { 094 explicitEntry.setReferenceFinancialDocumentNumber(referenceDocumentNumber.toString()); 095 explicitEntry.setReferenceFinancialDocumentTypeCode(PurapDocTypeCodes.PO_DOCUMENT); 096 explicitEntry.setReferenceFinancialSystemOriginationCode(PURAP_ORIGIN_CODE); 097 } 098 099 // 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 978 // if invoice fields are null (as would be for new items), set fields to zero 979 item.setItemInvoicedTotalAmount(item.getItemInvoicedTotalAmount() == null ? ZERO : item.getItemInvoicedTotalAmount()); 980 item.setItemInvoicedTotalQuantity(item.getItemInvoicedTotalQuantity() == null ? ZERO : item.getItemInvoicedTotalQuantity()); 981 982 if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 983 item.getItemQuantity().subtract(item.getItemInvoicedTotalQuantity()); 984 item.setItemOutstandingEncumberedQuantity(item.getItemQuantity().subtract(item.getItemInvoicedTotalQuantity())); 985 if(item.getItemOutstandingEncumberedQuantity().isGreaterThan(new KualiDecimal(0))) { 986 item.setItemOutstandingEncumberedAmount(new KualiDecimal(item.getItemOutstandingEncumberedQuantity().bigDecimalValue().multiply(item.getItemUnitPrice()))); 987 } 988 else { 989 item.setItemOutstandingEncumberedAmount(new KualiDecimal(item.getItemQuantity().bigDecimalValue().multiply(item.getItemUnitPrice()))); 990 item.setItemOutstandingEncumberedQuantity(new KualiDecimal(item.getItemQuantity().bigDecimalValue())); 991 } 992 } else { 993 if((item.getTotalAmount().subtract(item.getItemInvoicedTotalAmount()).isGreaterThan(new KualiDecimal(0)))) { 994 item.setItemOutstandingEncumberedAmount(item.getTotalAmount().subtract(item.getItemInvoicedTotalAmount())); 995 } 996 else { 997 item.setItemOutstandingEncumberedAmount(item.getTotalAmount()); 998 item.setItemOutstandingEncumberedQuantity(new KualiDecimal(item.getItemQuantity().bigDecimalValue())); 999 } 1000 } 1001 List<PurApAccountingLine> sourceAccountingLines = item.getSourceAccountingLines(); 1002 for (PurApAccountingLine purApAccountingLine : sourceAccountingLines) { 1003 PurchaseOrderAccount account = (PurchaseOrderAccount) purApAccountingLine; 1004 account.setItemAccountOutstandingEncumbranceAmount(new KualiDecimal(item.getItemOutstandingEncumberedAmount().bigDecimalValue().multiply(account.getAccountLinePercent()).divide(OLEConstants.ONE_HUNDRED.bigDecimalValue()))); 1005 } 1006 }// endfor 1007 1008 // Set outstanding encumbered quantity/amount on items 1009 for (Iterator items = po.getItems().iterator(); items.hasNext(); ) { 1010 PurchaseOrderItem item = (PurchaseOrderItem) items.next(); 1011 1012 String logItmNbr = "Item # " + item.getItemLineNumber(); 1013 1014 if (!item.isItemActiveIndicator()) { 1015 continue; 1016 } 1017 1018 KualiDecimal itemAmount = null; 1019 if (item.getItemType().isAmountBasedGeneralLedgerIndicator()) { 1020 if (LOG.isDebugEnabled()) { 1021 LOG.debug("generateEntriesReopenPurchaseOrder() " + logItmNbr + " Calculate based on amounts"); 1022 } 1023 itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO : item.getItemOutstandingEncumberedAmount(); 1024 } else { 1025 if (LOG.isDebugEnabled()) { 1026 LOG.debug("generateEntriesReopenPurchaseOrder() " + logItmNbr + " Calculate based on quantities"); 1027 } 1028 //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits 1029 itemAmount = new KualiDecimal(item.getItemOutstandingEncumberedQuantity().bigDecimalValue().multiply(item.getItemUnitPrice())); 1030 } 1031 1032 KualiDecimal accountTotal = ZERO; 1033 PurchaseOrderAccount lastAccount = null; 1034 if (itemAmount.compareTo(ZERO) != 0) { 1035 // Sort accounts 1036 Collections.sort((List) item.getSourceAccountingLines()); 1037 1038 for (Iterator iterAcct = item.getSourceAccountingLines().iterator(); iterAcct.hasNext(); ) { 1039 PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct.next(); 1040 if (!acct.isEmpty()) { 1041 KualiDecimal acctAmount = itemAmount.multiply(new KualiDecimal(acct.getAccountLinePercent().toString())).divide(PurapConstants.HUNDRED); 1042 accountTotal = accountTotal.add(acctAmount); 1043 acct.setAlternateAmountForGLEntryCreation(acctAmount); 1044 lastAccount = acct; 1045 } 1046 } 1047 1048 // account for rounding by adjusting last account as needed 1049 if (lastAccount != null) { 1050 KualiDecimal difference = itemAmount.subtract(accountTotal); 1051 if (LOG.isDebugEnabled()) { 1052 LOG.debug("generateEntriesReopenPurchaseOrder() difference: " + logItmNbr + " " + difference); 1053 } 1054 1055 KualiDecimal amount = lastAccount.getAlternateAmountForGLEntryCreation(); 1056 if (ObjectUtils.isNotNull(amount)) { 1057 lastAccount.setAlternateAmountForGLEntryCreation(amount.add(difference)); 1058 } else { 1059 lastAccount.setAlternateAmountForGLEntryCreation(difference); 1060 } 1061 } 1062 1063 } 1064 }// endfor 1065 1066 po.setGlOnlySourceAccountingLines(purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly())); 1067 if (shouldGenerateGLPEForPurchaseOrder(po)) { 1068 generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po); 1069 saveGLEntries(po.getGeneralLedgerPendingEntries()); 1070 LOG.debug("generateEntriesReopenPurchaseOrder() gl entries created; exit method"); 1071 } 1072 LOG.debug("generateEntriesReopenPurchaseOrder() no gl entries created because the amount is 0; exit method"); 1073 } 1074 1075 /** 1076 * @see org.kuali.ole.module.purap.service.PurapGeneralLedgerService#generateEntriesVoidPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument) 1077 */ 1078 public void generateEntriesVoidPurchaseOrder(PurchaseOrderDocument po) { 1079 LOG.debug("generateEntriesVoidPurchaseOrder() started"); 1080 1081 // Set outstanding encumbered quantity/amount on items 1082 for (Iterator items = po.getItems().iterator(); items.hasNext(); ) { 1083 PurchaseOrderItem item = (PurchaseOrderItem) items.next(); 1084 1085 String logItmNbr = "Item # " + item.getItemLineNumber(); 1086 1087 if (!item.isItemActiveIndicator()) { 1088 continue; 1089 } 1090 1091 //just use the outstanding amount as recalculating here, particularly the item tax will cause 1092 //amounts to be over or under encumbered and the remaining encumbered amount should be unencumbered during a close 1093 if (LOG.isDebugEnabled()) { 1094 LOG.debug("generateEntriesVoidPurchaseOrder() " + logItmNbr + " Calculate based on amounts"); 1095 } 1096 KualiDecimal itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO : item.getItemOutstandingEncumberedAmount(); 1097 1098 KualiDecimal accountTotal = ZERO; 1099 PurchaseOrderAccount lastAccount = null; 1100 if (itemAmount.compareTo(ZERO) != 0) { 1101 // Sort accounts 1102 Collections.sort((List) item.getSourceAccountingLines()); 1103 1104 for (Iterator iterAcct = item.getSourceAccountingLines().iterator(); iterAcct.hasNext(); ) { 1105 PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct.next(); 1106 if (!acct.isEmpty()) { 1107 KualiDecimal acctAmount = itemAmount.multiply(new KualiDecimal(acct.getAccountLinePercent().toString())).divide(PurapConstants.HUNDRED); 1108 accountTotal = accountTotal.add(acctAmount); 1109 acct.setAlternateAmountForGLEntryCreation(acctAmount); 1110 lastAccount = acct; 1111 } 1112 } 1113 1114 // account for rounding by adjusting last account as needed 1115 if (lastAccount != null) { 1116 KualiDecimal difference = itemAmount.subtract(accountTotal); 1117 if (LOG.isDebugEnabled()) { 1118 LOG.debug("generateEntriesVoidPurchaseOrder() difference: " + logItmNbr + " " + difference); 1119 } 1120 1121 KualiDecimal amount = lastAccount.getAlternateAmountForGLEntryCreation(); 1122 if (ObjectUtils.isNotNull(amount)) { 1123 lastAccount.setAlternateAmountForGLEntryCreation(amount.add(difference)); 1124 } else { 1125 lastAccount.setAlternateAmountForGLEntryCreation(difference); 1126 } 1127 } 1128 1129 } 1130 }// endfor 1131 1132 po.setGlOnlySourceAccountingLines(purapAccountingService.generateSummaryWithNoZeroTotalsUsingAlternateAmount(po.getItemsActiveOnly())); 1133 generalLedgerPendingEntryService.generateGeneralLedgerPendingEntries(po); 1134 saveGLEntries(po.getGeneralLedgerPendingEntries()); 1135 LOG.debug("generateEntriesVoidPurchaseOrder() gl entries created; exit method"); 1136 } 1137 1138 /** 1139 * 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 1140 * the encumbrance values on the PO and saves the PO 1141 * 1142 * @param preq PREQ for invoice 1143 * @return List of accounting lines to use to create the pending general ledger entries 1144 */ 1145 protected List<SourceAccountingLine> relieveEncumbrance(PaymentRequestDocument preq) { 1146 LOG.debug("relieveEncumbrance() started"); 1147 1148 Map encumbranceAccountMap = new HashMap(); 1149 PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(preq.getPurchaseOrderIdentifier()); 1150 1151 // Get each item one by one 1152 for (Iterator items = preq.getItems().iterator(); items.hasNext(); ) { 1153 PaymentRequestItem preqItem = (PaymentRequestItem) items.next(); 1154 PurchaseOrderItem poItem = getPoItem(po, preqItem.getItemLineNumber(), preqItem.getItemType()); 1155 1156 boolean takeAll = false; // Set this true if we relieve the entire encumbrance 1157 KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item 1158 1159 String logItmNbr = "Item # " + preqItem.getItemLineNumber(); 1160 if (LOG.isDebugEnabled()) { 1161 LOG.debug("relieveEncumbrance() " + logItmNbr); 1162 } 1163 1164 // If there isn't a PO item or the extended price is 0, we don't need encumbrances 1165 if (poItem == null) { 1166 if (LOG.isDebugEnabled()) { 1167 LOG.debug("relieveEncumbrance() " + logItmNbr + " No encumbrances required because po item is null"); 1168 } 1169 } else { 1170 final KualiDecimal preqItemTotalAmount = (preqItem.getTotalAmount() == null) ? KualiDecimal.ZERO : preqItem.getTotalAmount(); 1171 if (ZERO.compareTo(preqItemTotalAmount) == 0) { 1172 /* 1173 * This is a specialized case where PREQ item being processed must adjust the PO item's outstanding encumbered 1174 * quantity. This kind of scenario is mostly seen on warranty type items. The following must be true to do this: 1175 * PREQ item Extended Price must be ZERO, PREQ item invoice quantity must be not empty and not ZERO, and PO item 1176 * is quantity based PO item unit cost is ZERO 1177 */ 1178 if (LOG.isDebugEnabled()) { 1179 LOG.debug("relieveEncumbrance() " + logItmNbr + " No GL encumbrances required because extended price is ZERO"); 1180 } 1181 if ((poItem.getItemQuantity() != null) && ((BigDecimal.ZERO.compareTo(poItem.getItemUnitPrice())) == 0)) { 1182 // po has order quantity and unit price is ZERO... reduce outstanding encumbered quantity 1183 if (LOG.isDebugEnabled()) { 1184 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate po oustanding encumbrance"); 1185 } 1186 1187 // Do encumbrance calculations based on quantity 1188 if ((preqItem.getItemQuantity() != null) && ((ZERO.compareTo(preqItem.getItemQuantity())) != 0)) { 1189 KualiDecimal invoiceQuantity = preqItem.getItemQuantity(); 1190 KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity(); 1191 1192 KualiDecimal encumbranceQuantity; 1193 if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) { 1194 // We bought more than the quantity on the PO 1195 if (LOG.isDebugEnabled()) { 1196 LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO"); 1197 } 1198 encumbranceQuantity = outstandingEncumberedQuantity; 1199 poItem.setItemOutstandingEncumberedQuantity(ZERO); 1200 } else { 1201 encumbranceQuantity = invoiceQuantity; 1202 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity)); 1203 if (LOG.isDebugEnabled()) { 1204 LOG.debug("relieveEncumbrance() " + logItmNbr + " adjusting oustanding encunbrance qty - encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity()); 1205 } 1206 } 1207 1208 if (poItem.getItemInvoicedTotalQuantity() == null) { 1209 poItem.setItemInvoicedTotalQuantity(invoiceQuantity); 1210 } else { 1211 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity)); 1212 } 1213 } 1214 } 1215 1216 1217 } else { 1218 if (LOG.isDebugEnabled()) { 1219 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries"); 1220 } 1221 1222 // Do we calculate the encumbrance amount based on quantity or amount? 1223 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 1224 if (LOG.isDebugEnabled()) { 1225 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity"); 1226 } 1227 1228 // Do encumbrance calculations based on quantity 1229 KualiDecimal invoiceQuantity = preqItem.getItemQuantity() == null ? ZERO : preqItem.getItemQuantity(); 1230 KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity(); 1231 1232 KualiDecimal encumbranceQuantity; 1233 1234 if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) { 1235 // We bought more than the quantity on the PO 1236 if (LOG.isDebugEnabled()) { 1237 LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO"); 1238 } 1239 encumbranceQuantity = outstandingEncumberedQuantity; 1240 poItem.setItemOutstandingEncumberedQuantity(ZERO); 1241 takeAll = true; 1242 } 1243 else if (outstandingEncumberedQuantity.isLessEqual(new KualiDecimal(0))) { 1244 // We bought more than the quantity on the PO 1245 // if (LOG.isDebugEnabled()) { 1246 LOG.info("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO"); 1247 // } 1248 encumbranceQuantity = poItem.getItemQuantity(); 1249 poItem.setItemOutstandingEncumberedQuantity(ZERO); 1250 takeAll = true; 1251 } 1252 1253 else { 1254 encumbranceQuantity = invoiceQuantity; 1255 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity)); 1256 if (ZERO.compareTo(poItem.getItemOutstandingEncumberedQuantity()) == 0) { 1257 takeAll = true; 1258 } 1259 if (LOG.isDebugEnabled()) { 1260 LOG.debug("relieveEncumbrance() " + logItmNbr + " encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity()); 1261 } 1262 } 1263 1264 if (poItem.getItemInvoicedTotalQuantity() == null) { 1265 poItem.setItemInvoicedTotalQuantity(invoiceQuantity); 1266 } else { 1267 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity)); 1268 } 1269 1270 itemDisEncumber = new KualiDecimal(encumbranceQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice())); 1271 1272 //add tax for encumbrance 1273 KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount(); 1274 KualiDecimal encumbranceTaxAmount = encumbranceQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount); 1275 itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount); 1276 } else { 1277 if (LOG.isDebugEnabled()) { 1278 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount"); 1279 } 1280 1281 // Do encumbrance calculations based on amount only 1282 if ((poItem.getItemOutstandingEncumberedAmount().bigDecimalValue().signum() == -1) && (preqItemTotalAmount.bigDecimalValue().signum() == -1)) { 1283 if (LOG.isDebugEnabled()) { 1284 LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is negative: " + poItem.getItemOutstandingEncumberedAmount()); 1285 } 1286 if (preqItemTotalAmount.compareTo(poItem.getItemOutstandingEncumberedAmount()) >= 0) { 1287 // extended price is equal to or greater than outstanding encumbered 1288 itemDisEncumber = preqItemTotalAmount; 1289 } 1290 else if (poItem.getItemOutstandingEncumberedAmount().isLessEqual(new KualiDecimal(0))) { 1291 // We bought more than the quantity on the PO 1292 // if (LOG.isDebugEnabled()) { 1293 LOG.info("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO"); 1294 // } 1295 itemDisEncumber = poItem.getItemQuantity().multiply(new KualiDecimal(poItem.getItemUnitPrice())); 1296 poItem.setItemOutstandingEncumberedQuantity(ZERO); 1297 takeAll = true; 1298 } 1299 1300 else { 1301 // extended price is less than outstanding encumbered 1302 takeAll = true; 1303 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount(); 1304 } 1305 } else { 1306 if (LOG.isDebugEnabled()) { 1307 LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is positive or ZERO: " + poItem.getItemOutstandingEncumberedAmount()); 1308 } 1309 if (poItem.getItemOutstandingEncumberedAmount().compareTo(preqItemTotalAmount) >= 0) { 1310 // outstanding amount is equal to or greater than extended price 1311 itemDisEncumber = preqItemTotalAmount; 1312 } else { 1313 // outstanding amount is less than extended price 1314 takeAll = true; 1315 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount(); 1316 } 1317 } 1318 } 1319 1320 if (LOG.isDebugEnabled()) { 1321 LOG.debug("relieveEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber); 1322 } 1323 1324 KualiDecimal newOutstandingEncumberedAmount = new KualiDecimal(0); 1325 if (poItem.getItemOutstandingEncumberedAmount().isLessEqual(new KualiDecimal(0))) { 1326 newOutstandingEncumberedAmount = itemDisEncumber; 1327 } 1328 else { 1329 newOutstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount().subtract(itemDisEncumber); 1330 } 1331 if (LOG.isDebugEnabled()) { 1332 LOG.debug("relieveEncumbrance() " + logItmNbr + " New Outstanding Encumbered amount is : " + newOutstandingEncumberedAmount); 1333 } 1334 poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount); 1335 1336 KualiDecimal newInvoicedTotalAmount = poItem.getItemInvoicedTotalAmount().add(preqItemTotalAmount); 1337 if (LOG.isDebugEnabled()) { 1338 LOG.debug("relieveEncumbrance() " + logItmNbr + " New Invoiced Total Amount is: " + newInvoicedTotalAmount); 1339 } 1340 poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount); 1341 1342 // Sort accounts 1343 Collections.sort((List) poItem.getSourceAccountingLines()); 1344 1345 // make the list of accounts for the disencumbrance entry 1346 PurchaseOrderAccount lastAccount = null; 1347 KualiDecimal accountTotal = ZERO; 1348 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) { 1349 PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next(); 1350 if (!account.isEmpty()) { 1351 KualiDecimal encumbranceAmount = null; 1352 SourceAccountingLine acctString = account.generateSourceAccountingLine(); 1353 if (takeAll) { 1354 // fully paid; remove remaining encumbrance 1355 encumbranceAmount = account.getItemAccountOutstandingEncumbranceAmount(); 1356 account.setItemAccountOutstandingEncumbranceAmount(ZERO); 1357 if (LOG.isDebugEnabled()) { 1358 LOG.debug("relieveEncumbrance() " + logItmNbr + " take all"); 1359 } 1360 } else { 1361 // amount = item disencumber * account percent / 100 1362 encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED); 1363 1364 account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().subtract(encumbranceAmount)); 1365 1366 // For rounding check at the end 1367 accountTotal = accountTotal.add(encumbranceAmount); 1368 1369 // If we are zeroing out the encumbrance, we don't need to adjust for rounding 1370 if (!takeAll) { 1371 lastAccount = account; 1372 } 1373 } 1374 1375 if (LOG.isDebugEnabled()) { 1376 LOG.debug("relieveEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount); 1377 } 1378 if (ObjectUtils.isNull(encumbranceAccountMap.get(acctString))) { 1379 encumbranceAccountMap.put(acctString, encumbranceAmount); 1380 } else { 1381 KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString); 1382 encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount)); 1383 } 1384 1385 } 1386 } 1387 1388 // account for rounding by adjusting last account as needed 1389 if (lastAccount != null) { 1390 KualiDecimal difference = itemDisEncumber.subtract(accountTotal); 1391 if (LOG.isDebugEnabled()) { 1392 LOG.debug("relieveEncumbrance() difference: " + logItmNbr + " " + difference); 1393 } 1394 1395 SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine(); 1396 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 1397 if (ObjectUtils.isNull(amount)) { 1398 encumbranceAccountMap.put(acctString, difference); 1399 } else { 1400 encumbranceAccountMap.put(acctString, amount.add(difference)); 1401 } 1402 1403 lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().subtract(difference)); 1404 } 1405 } 1406 } 1407 }// endfor 1408 1409 SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po); 1410 1411 List<SourceAccountingLine> encumbranceAccounts = new ArrayList(); 1412 for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) { 1413 SourceAccountingLine acctString = (SourceAccountingLine) iter.next(); 1414 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 1415 if (amount.doubleValue() != 0) { 1416 acctString.setAmount(amount); 1417 encumbranceAccounts.add(acctString); 1418 } 1419 } 1420 //SpringContext.getBean(BusinessObjectService.class).save(po); 1421 return encumbranceAccounts; 1422 } 1423 1424 1425 /** 1426 * 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 1427 * the encumbrance values on the PO and saves the PO 1428 * 1429 * @param inv inv for InvoiceDocument 1430 * @return List of accounting lines to use to create the pending general ledger entries 1431 */ 1432 protected List<SourceAccountingLine> relieveEncumbrance(InvoiceDocument inv) { 1433 LOG.debug("relieveEncumbrance() started"); 1434 1435 Map encumbranceAccountMap = new HashMap(); 1436 // PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(inv.getPurchaseOrderIdentifier()); 1437 for (PurchaseOrderDocument po : inv.getPurchaseOrderDocuments()) { 1438 // Get each item one by one 1439 for (Iterator items = inv.getItems().iterator(); items.hasNext(); ) { 1440 InvoiceItem invItem = (InvoiceItem) items.next(); 1441 PurchaseOrderItem poItem = getPoItem(po, invItem.getItemLineNumber(), invItem.getItemType()); 1442 1443 boolean takeAll = false; // Set this true if we relieve the entire encumbrance 1444 KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item 1445 1446 String logItmNbr = "Item # " + invItem.getItemLineNumber(); 1447 if (LOG.isDebugEnabled()) { 1448 LOG.debug("relieveEncumbrance() " + logItmNbr); 1449 } 1450 1451 // If there isn't a PO item or the extended price is 0, we don't need encumbrances 1452 if (poItem == null) { 1453 if (LOG.isDebugEnabled()) { 1454 LOG.debug("relieveEncumbrance() " + logItmNbr + " No encumbrances required because po item is null"); 1455 } 1456 } else { 1457 final KualiDecimal preqItemTotalAmount = (invItem.getTotalAmount() == null) ? KualiDecimal.ZERO : invItem.getTotalAmount(); 1458 if (ZERO.compareTo(preqItemTotalAmount) == 0) { 1459 /* 1460 * This is a specialized case where PREQ item being processed must adjust the PO item's outstanding encumbered 1461 * quantity. This kind of scenario is mostly seen on warranty type items. The following must be true to do this: 1462 * PREQ item Extended Price must be ZERO, PREQ item invoice quantity must be not empty and not ZERO, and PO item 1463 * is quantity based PO item unit cost is ZERO 1464 */ 1465 if (LOG.isDebugEnabled()) { 1466 LOG.debug("relieveEncumbrance() " + logItmNbr + " No GL encumbrances required because extended price is ZERO"); 1467 } 1468 if ((poItem.getItemQuantity() != null) && ((BigDecimal.ZERO.compareTo(poItem.getItemUnitPrice())) == 0)) { 1469 // po has order quantity and unit price is ZERO... reduce outstanding encumbered quantity 1470 if (LOG.isDebugEnabled()) { 1471 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate po oustanding encumbrance"); 1472 } 1473 1474 // Do encumbrance calculations based on quantity 1475 if ((invItem.getItemQuantity() != null) && ((ZERO.compareTo(invItem.getItemQuantity())) != 0)) { 1476 KualiDecimal invoiceQuantity = invItem.getItemQuantity(); 1477 KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity(); 1478 1479 KualiDecimal encumbranceQuantity; 1480 if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) { 1481 // We bought more than the quantity on the PO 1482 if (LOG.isDebugEnabled()) { 1483 LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO"); 1484 } 1485 encumbranceQuantity = outstandingEncumberedQuantity; 1486 poItem.setItemOutstandingEncumberedQuantity(ZERO); 1487 } else { 1488 encumbranceQuantity = invoiceQuantity; 1489 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity)); 1490 if (LOG.isDebugEnabled()) { 1491 LOG.debug("relieveEncumbrance() " + logItmNbr + " adjusting oustanding encunbrance qty - encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity()); 1492 } 1493 } 1494 1495 if (poItem.getItemInvoicedTotalQuantity() == null) { 1496 poItem.setItemInvoicedTotalQuantity(invoiceQuantity); 1497 } else { 1498 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity)); 1499 } 1500 } 1501 } 1502 1503 1504 } else { 1505 if (LOG.isDebugEnabled()) { 1506 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries"); 1507 } 1508 1509 // Do we calculate the encumbrance amount based on quantity or amount? 1510 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 1511 if (LOG.isDebugEnabled()) { 1512 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity"); 1513 } 1514 1515 // Do encumbrance calculations based on quantity 1516 KualiDecimal invoiceQuantity = invItem.getItemQuantity() == null ? ZERO : invItem.getItemQuantity(); 1517 KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity(); 1518 1519 KualiDecimal encumbranceQuantity; 1520 1521 if (invoiceQuantity.compareTo(outstandingEncumberedQuantity) > 0) { 1522 // We bought more than the quantity on the PO 1523 if (LOG.isDebugEnabled()) { 1524 LOG.debug("relieveEncumbrance() " + logItmNbr + " we bought more than the qty on the PO"); 1525 } 1526 encumbranceQuantity = outstandingEncumberedQuantity; 1527 poItem.setItemOutstandingEncumberedQuantity(ZERO); 1528 takeAll = true; 1529 } else { 1530 encumbranceQuantity = invoiceQuantity; 1531 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.subtract(encumbranceQuantity)); 1532 if (ZERO.compareTo(poItem.getItemOutstandingEncumberedQuantity()) == 0) { 1533 takeAll = true; 1534 } 1535 if (LOG.isDebugEnabled()) { 1536 LOG.debug("relieveEncumbrance() " + logItmNbr + " encumbranceQty " + encumbranceQuantity + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity()); 1537 } 1538 } 1539 1540 if (poItem.getItemInvoicedTotalQuantity() == null) { 1541 poItem.setItemInvoicedTotalQuantity(invoiceQuantity); 1542 } else { 1543 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().add(invoiceQuantity)); 1544 } 1545 1546 itemDisEncumber = new KualiDecimal(encumbranceQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice())); 1547 1548 //add tax for encumbrance 1549 KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount(); 1550 KualiDecimal encumbranceTaxAmount = encumbranceQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount); 1551 itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount); 1552 } else { 1553 if (LOG.isDebugEnabled()) { 1554 LOG.debug("relieveEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount"); 1555 } 1556 1557 // Do encumbrance calculations based on amount only 1558 if ((poItem.getItemOutstandingEncumberedAmount().bigDecimalValue().signum() == -1) && (preqItemTotalAmount.bigDecimalValue().signum() == -1)) { 1559 if (LOG.isDebugEnabled()) { 1560 LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is negative: " + poItem.getItemOutstandingEncumberedAmount()); 1561 } 1562 if (preqItemTotalAmount.compareTo(poItem.getItemOutstandingEncumberedAmount()) >= 0) { 1563 // extended price is equal to or greater than outstanding encumbered 1564 itemDisEncumber = preqItemTotalAmount; 1565 } else { 1566 // extended price is less than outstanding encumbered 1567 takeAll = true; 1568 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount(); 1569 } 1570 } else { 1571 if (LOG.isDebugEnabled()) { 1572 LOG.debug("relieveEncumbrance() " + logItmNbr + " Outstanding Encumbered amount is positive or ZERO: " + poItem.getItemOutstandingEncumberedAmount()); 1573 } 1574 if (poItem.getItemOutstandingEncumberedAmount().compareTo(preqItemTotalAmount) >= 0) { 1575 // outstanding amount is equal to or greater than extended price 1576 itemDisEncumber = preqItemTotalAmount; 1577 } else { 1578 // outstanding amount is less than extended price 1579 takeAll = true; 1580 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount(); 1581 } 1582 } 1583 } 1584 1585 if (LOG.isDebugEnabled()) { 1586 LOG.debug("relieveEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber); 1587 } 1588 1589 KualiDecimal newOutstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount().subtract(itemDisEncumber); 1590 if (LOG.isDebugEnabled()) { 1591 LOG.debug("relieveEncumbrance() " + logItmNbr + " New Outstanding Encumbered amount is : " + newOutstandingEncumberedAmount); 1592 } 1593 poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount); 1594 1595 KualiDecimal newInvoicedTotalAmount = poItem.getItemInvoicedTotalAmount().add(preqItemTotalAmount); 1596 if (LOG.isDebugEnabled()) { 1597 LOG.debug("relieveEncumbrance() " + logItmNbr + " New Invoiced Total Amount is: " + newInvoicedTotalAmount); 1598 } 1599 poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount); 1600 1601 // Sort accounts 1602 Collections.sort((List) poItem.getSourceAccountingLines()); 1603 1604 // make the list of accounts for the disencumbrance entry 1605 PurchaseOrderAccount lastAccount = null; 1606 KualiDecimal accountTotal = ZERO; 1607 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) { 1608 PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next(); 1609 if (!account.isEmpty()) { 1610 KualiDecimal encumbranceAmount = null; 1611 SourceAccountingLine acctString = account.generateSourceAccountingLine(); 1612 if (takeAll) { 1613 // fully paid; remove remaining encumbrance 1614 encumbranceAmount = account.getItemAccountOutstandingEncumbranceAmount(); 1615 account.setItemAccountOutstandingEncumbranceAmount(ZERO); 1616 if (LOG.isDebugEnabled()) { 1617 LOG.debug("relieveEncumbrance() " + logItmNbr + " take all"); 1618 } 1619 } else { 1620 // amount = item disencumber * account percent / 100 1621 encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED); 1622 1623 account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().subtract(encumbranceAmount)); 1624 1625 // For rounding check at the end 1626 accountTotal = accountTotal.add(encumbranceAmount); 1627 1628 // If we are zeroing out the encumbrance, we don't need to adjust for rounding 1629 if (!takeAll) { 1630 lastAccount = account; 1631 } 1632 } 1633 1634 if (LOG.isDebugEnabled()) { 1635 LOG.debug("relieveEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount); 1636 } 1637 if (ObjectUtils.isNull(encumbranceAccountMap.get(acctString))) { 1638 encumbranceAccountMap.put(acctString, encumbranceAmount); 1639 } else { 1640 KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString); 1641 encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount)); 1642 } 1643 1644 } 1645 } 1646 1647 // account for rounding by adjusting last account as needed 1648 if (lastAccount != null) { 1649 KualiDecimal difference = itemDisEncumber.subtract(accountTotal); 1650 if (LOG.isDebugEnabled()) { 1651 LOG.debug("relieveEncumbrance() difference: " + logItmNbr + " " + difference); 1652 } 1653 1654 SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine(); 1655 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 1656 if (ObjectUtils.isNull(amount)) { 1657 encumbranceAccountMap.put(acctString, difference); 1658 } else { 1659 encumbranceAccountMap.put(acctString, amount.add(difference)); 1660 } 1661 1662 lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().subtract(difference)); 1663 } 1664 } 1665 } 1666 }// endfor 1667 } 1668 1669 List<SourceAccountingLine> encumbranceAccounts = new ArrayList(); 1670 for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) { 1671 SourceAccountingLine acctString = (SourceAccountingLine) iter.next(); 1672 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 1673 if (amount.doubleValue() != 0) { 1674 acctString.setAmount(amount); 1675 encumbranceAccounts.add(acctString); 1676 } 1677 } 1678 1679 // SpringContext.getBean(BusinessObjectService.class).save(po); 1680 return encumbranceAccounts; 1681 } 1682 1683 1684 /** 1685 * 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 1686 * encumbrance values on the PO and saves the PO 1687 * 1688 * @param preq PREQ for invoice 1689 * @return List of accounting lines to use to create the pending general ledger entries 1690 */ 1691 protected List<SourceAccountingLine> reencumberEncumbrance(PaymentRequestDocument preq) { 1692 LOG.debug("reencumberEncumbrance() started"); 1693 1694 PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(preq.getPurchaseOrderIdentifier()); 1695 Map encumbranceAccountMap = new HashMap(); 1696 1697 // Get each item one by one 1698 for (Iterator items = preq.getItems().iterator(); items.hasNext(); ) { 1699 PaymentRequestItem payRequestItem = (PaymentRequestItem) items.next(); 1700 PurchaseOrderItem poItem = getPoItem(po, payRequestItem.getItemLineNumber(), payRequestItem.getItemType()); 1701 1702 KualiDecimal itemReEncumber = null; // Amount to reencumber for this item 1703 1704 String logItmNbr = "Item # " + payRequestItem.getItemLineNumber(); 1705 if (LOG.isDebugEnabled()) { 1706 LOG.debug("reencumberEncumbrance() " + logItmNbr); 1707 } 1708 1709 // If there isn't a PO item or the total amount is 0, we don't need encumbrances 1710 final KualiDecimal preqItemTotalAmount = (payRequestItem.getTotalAmount() == null) ? KualiDecimal.ZERO : payRequestItem.getTotalAmount(); 1711 if ((poItem == null) || (preqItemTotalAmount.doubleValue() == 0)) { 1712 if (LOG.isDebugEnabled()) { 1713 LOG.debug("reencumberEncumbrance() " + logItmNbr + " No encumbrances required"); 1714 } 1715 } else { 1716 if (LOG.isDebugEnabled()) { 1717 LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries"); 1718 } 1719 1720 // Do we calculate the encumbrance amount based on quantity or amount? 1721 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 1722 if (LOG.isDebugEnabled()) { 1723 LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity"); 1724 } 1725 1726 // Do disencumbrance calculations based on quantity 1727 KualiDecimal preqQuantity = payRequestItem.getItemQuantity() == null ? ZERO : payRequestItem.getItemQuantity(); 1728 KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity(); 1729 KualiDecimal invoicedTotal = poItem.getItemInvoicedTotalQuantity() == null ? ZERO : poItem.getItemInvoicedTotalQuantity(); 1730 1731 poItem.setItemInvoicedTotalQuantity(invoicedTotal.subtract(preqQuantity)); 1732 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.add(preqQuantity)); 1733 1734 //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits 1735 itemReEncumber = new KualiDecimal(preqQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice())); 1736 1737 //add tax for encumbrance 1738 KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount(); 1739 KualiDecimal encumbranceTaxAmount = preqQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount); 1740 itemReEncumber = itemReEncumber.add(encumbranceTaxAmount); 1741 1742 } else { 1743 if (LOG.isDebugEnabled()) { 1744 LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount"); 1745 } 1746 1747 itemReEncumber = preqItemTotalAmount; 1748 // if re-encumber amount is more than original PO ordered amount... do not exceed ordered amount 1749 // this prevents negative encumbrance 1750 if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() < 0)) { 1751 // po item extended cost is negative 1752 if ((poItem.getTotalAmount().compareTo(itemReEncumber)) > 0) { 1753 itemReEncumber = poItem.getTotalAmount(); 1754 } 1755 } else if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() >= 0)) { 1756 // po item extended cost is positive 1757 if ((poItem.getTotalAmount().compareTo(itemReEncumber)) < 0) { 1758 itemReEncumber = poItem.getTotalAmount(); 1759 } 1760 } 1761 } 1762 1763 if (LOG.isDebugEnabled()) { 1764 LOG.debug("reencumberEncumbrance() " + logItmNbr + " Amount to reencumber: " + itemReEncumber); 1765 } 1766 1767 KualiDecimal outstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount() == null ? ZERO : poItem.getItemOutstandingEncumberedAmount(); 1768 if (LOG.isDebugEnabled()) { 1769 LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Outstanding Encumbrance Amount set to: " + outstandingEncumberedAmount); 1770 } 1771 KualiDecimal newOutstandingEncumberedAmount = outstandingEncumberedAmount.add(itemReEncumber); 1772 if (LOG.isDebugEnabled()) { 1773 LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Outstanding Encumbrance Amount to set: " + newOutstandingEncumberedAmount); 1774 } 1775 poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount); 1776 1777 KualiDecimal invoicedTotalAmount = poItem.getItemInvoicedTotalAmount() == null ? ZERO : poItem.getItemInvoicedTotalAmount(); 1778 if (LOG.isDebugEnabled()) { 1779 LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Invoiced Total Amount set to: " + invoicedTotalAmount); 1780 } 1781 KualiDecimal newInvoicedTotalAmount = invoicedTotalAmount.subtract(preqItemTotalAmount); 1782 if (LOG.isDebugEnabled()) { 1783 LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Invoiced Total Amount to set: " + newInvoicedTotalAmount); 1784 } 1785 poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount); 1786 1787 // make the list of accounts for the reencumbrance entry 1788 PurchaseOrderAccount lastAccount = null; 1789 KualiDecimal accountTotal = ZERO; 1790 1791 // Sort accounts 1792 Collections.sort((List) poItem.getSourceAccountingLines()); 1793 1794 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) { 1795 PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next(); 1796 if (!account.isEmpty()) { 1797 SourceAccountingLine acctString = account.generateSourceAccountingLine(); 1798 1799 // amount = item reencumber * account percent / 100 1800 KualiDecimal reencumbranceAmount = itemReEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED); 1801 1802 account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(reencumbranceAmount)); 1803 1804 // For rounding check at the end 1805 accountTotal = accountTotal.add(reencumbranceAmount); 1806 1807 lastAccount = account; 1808 1809 if (LOG.isDebugEnabled()) { 1810 LOG.debug("reencumberEncumbrance() " + logItmNbr + " " + acctString + " = " + reencumbranceAmount); 1811 } 1812 if (encumbranceAccountMap.containsKey(acctString)) { 1813 KualiDecimal currentAmount = (KualiDecimal) encumbranceAccountMap.get(acctString); 1814 encumbranceAccountMap.put(acctString, reencumbranceAmount.add(currentAmount)); 1815 } else { 1816 encumbranceAccountMap.put(acctString, reencumbranceAmount); 1817 } 1818 } 1819 } 1820 1821 // account for rounding by adjusting last account as needed 1822 if (lastAccount != null) { 1823 KualiDecimal difference = itemReEncumber.subtract(accountTotal); 1824 if (LOG.isDebugEnabled()) { 1825 LOG.debug("reencumberEncumbrance() difference: " + logItmNbr + " " + difference); 1826 } 1827 1828 SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine(); 1829 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 1830 if (amount == null) { 1831 encumbranceAccountMap.put(acctString, difference); 1832 } else { 1833 encumbranceAccountMap.put(acctString, amount.add(difference)); 1834 } 1835 lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference)); 1836 } 1837 } 1838 } 1839 1840 //SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po); 1841 1842 //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966 1843 // SpringContext.getBean(BusinessObjectService.class).save(po); 1844 1845 List<SourceAccountingLine> encumbranceAccounts = new ArrayList<SourceAccountingLine>(); 1846 for (Iterator<SourceAccountingLine> iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) { 1847 SourceAccountingLine acctString = (SourceAccountingLine) iter.next(); 1848 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 1849 if (amount.doubleValue() != 0) { 1850 acctString.setAmount(amount); 1851 encumbranceAccounts.add(acctString); 1852 } 1853 } 1854 1855 SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po); 1856 return encumbranceAccounts; 1857 } 1858 1859 1860 protected List<SourceAccountingLine> reencumberEncumbrance(InvoiceDocument prqs) { 1861 LOG.debug("reencumberEncumbrance() started"); 1862 1863 PurchaseOrderDocument po = null; 1864 //purchaseOrderService.getCurrentPurchaseOrder(prqs.getPurchaseOrderIdentifier()); 1865 Map encumbranceAccountMap = new HashMap(); 1866 1867 // Get each item one by one 1868 for (Iterator items = prqs.getItems().iterator(); items.hasNext(); ) { 1869 InvoiceItem invItem = (InvoiceItem) items.next(); 1870 po = purchaseOrderService.getCurrentPurchaseOrder(invItem.getPurchaseOrderIdentifier()); 1871 PurchaseOrderItem poItem = null; 1872 if(po != null) { 1873 poItem = getPoItem(po, invItem.getItemLineNumber(), invItem.getItemType()); 1874 } 1875 1876 KualiDecimal itemReEncumber = null; // Amount to reencumber for this item 1877 1878 String logItmNbr = "Item # " + invItem.getItemLineNumber(); 1879 if (LOG.isDebugEnabled()) { 1880 LOG.debug("reencumberEncumbrance() " + logItmNbr); 1881 } 1882 1883 // If there isn't a PO item or the total amount is 0, we don't need encumbrances 1884 final KualiDecimal preqItemTotalAmount = (invItem.getTotalAmount() == null) ? KualiDecimal.ZERO : invItem.getTotalAmount(); 1885 if ((poItem == null) || (preqItemTotalAmount.doubleValue() == 0)) { 1886 if (LOG.isDebugEnabled()) { 1887 LOG.debug("reencumberEncumbrance() " + logItmNbr + " No encumbrances required"); 1888 } 1889 } else { 1890 if (LOG.isDebugEnabled()) { 1891 LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries"); 1892 } 1893 1894 // Do we calculate the encumbrance amount based on quantity or amount? 1895 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 1896 if (LOG.isDebugEnabled()) { 1897 LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity"); 1898 } 1899 1900 // Do disencumbrance calculations based on quantity 1901 KualiDecimal preqQuantity = invItem.getItemQuantity() == null ? ZERO : invItem.getItemQuantity(); 1902 KualiDecimal outstandingEncumberedQuantity = poItem.getItemOutstandingEncumberedQuantity() == null ? ZERO : poItem.getItemOutstandingEncumberedQuantity(); 1903 KualiDecimal invoicedTotal = poItem.getItemInvoicedTotalQuantity() == null ? ZERO : poItem.getItemInvoicedTotalQuantity(); 1904 1905 poItem.setItemInvoicedTotalQuantity(invoicedTotal.subtract(preqQuantity)); 1906 poItem.setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity.add(preqQuantity)); 1907 1908 //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits 1909 itemReEncumber = new KualiDecimal(preqQuantity.bigDecimalValue().multiply(poItem.getItemUnitPrice())); 1910 1911 //add tax for encumbrance 1912 KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount(); 1913 KualiDecimal encumbranceTaxAmount = preqQuantity.divide(poItem.getItemQuantity()).multiply(itemTaxAmount); 1914 itemReEncumber = itemReEncumber.add(encumbranceTaxAmount); 1915 1916 } else { 1917 if (LOG.isDebugEnabled()) { 1918 LOG.debug("reencumberEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount"); 1919 } 1920 1921 itemReEncumber = preqItemTotalAmount; 1922 // if re-encumber amount is more than original PO ordered amount... do not exceed ordered amount 1923 // this prevents negative encumbrance 1924 if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() < 0)) { 1925 // po item extended cost is negative 1926 if ((poItem.getTotalAmount().compareTo(itemReEncumber)) > 0) { 1927 itemReEncumber = poItem.getTotalAmount(); 1928 } 1929 } else if ((poItem.getTotalAmount() != null) && (poItem.getTotalAmount().bigDecimalValue().signum() >= 0)) { 1930 // po item extended cost is positive 1931 if ((poItem.getTotalAmount().compareTo(itemReEncumber)) < 0) { 1932 itemReEncumber = poItem.getTotalAmount(); 1933 } 1934 } 1935 } 1936 1937 if (LOG.isDebugEnabled()) { 1938 LOG.debug("reencumberEncumbrance() " + logItmNbr + " Amount to reencumber: " + itemReEncumber); 1939 } 1940 1941 KualiDecimal outstandingEncumberedAmount = poItem.getItemOutstandingEncumberedAmount() == null ? ZERO : poItem.getItemOutstandingEncumberedAmount(); 1942 if (LOG.isDebugEnabled()) { 1943 LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Outstanding Encumbrance Amount set to: " + outstandingEncumberedAmount); 1944 } 1945 KualiDecimal newOutstandingEncumberedAmount = outstandingEncumberedAmount.add(itemReEncumber); 1946 if (LOG.isDebugEnabled()) { 1947 LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Outstanding Encumbrance Amount to set: " + newOutstandingEncumberedAmount); 1948 } 1949 poItem.setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount); 1950 1951 KualiDecimal invoicedTotalAmount = poItem.getItemInvoicedTotalAmount() == null ? ZERO : poItem.getItemInvoicedTotalAmount(); 1952 if (LOG.isDebugEnabled()) { 1953 LOG.debug("reencumberEncumbrance() " + logItmNbr + " PO Item Invoiced Total Amount set to: " + invoicedTotalAmount); 1954 } 1955 KualiDecimal newInvoicedTotalAmount = invoicedTotalAmount.subtract(preqItemTotalAmount); 1956 if (LOG.isDebugEnabled()) { 1957 LOG.debug("reencumberEncumbrance() " + logItmNbr + " New PO Item Invoiced Total Amount to set: " + newInvoicedTotalAmount); 1958 } 1959 poItem.setItemInvoicedTotalAmount(newInvoicedTotalAmount); 1960 1961 // make the list of accounts for the reencumbrance entry 1962 PurchaseOrderAccount lastAccount = null; 1963 KualiDecimal accountTotal = ZERO; 1964 1965 // Sort accounts 1966 Collections.sort((List) poItem.getSourceAccountingLines()); 1967 1968 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) { 1969 PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next(); 1970 if (!account.isEmpty()) { 1971 SourceAccountingLine acctString = account.generateSourceAccountingLine(); 1972 1973 // amount = item reencumber * account percent / 100 1974 KualiDecimal reencumbranceAmount = itemReEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(HUNDRED); 1975 1976 account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(reencumbranceAmount)); 1977 1978 // For rounding check at the end 1979 accountTotal = accountTotal.add(reencumbranceAmount); 1980 1981 lastAccount = account; 1982 1983 if (LOG.isDebugEnabled()) { 1984 LOG.debug("reencumberEncumbrance() " + logItmNbr + " " + acctString + " = " + reencumbranceAmount); 1985 } 1986 if (encumbranceAccountMap.containsKey(acctString)) { 1987 KualiDecimal currentAmount = (KualiDecimal) encumbranceAccountMap.get(acctString); 1988 encumbranceAccountMap.put(acctString, reencumbranceAmount.add(currentAmount)); 1989 } else { 1990 encumbranceAccountMap.put(acctString, reencumbranceAmount); 1991 } 1992 } 1993 } 1994 1995 // account for rounding by adjusting last account as needed 1996 if (lastAccount != null) { 1997 KualiDecimal difference = itemReEncumber.subtract(accountTotal); 1998 if (LOG.isDebugEnabled()) { 1999 LOG.debug("reencumberEncumbrance() difference: " + logItmNbr + " " + difference); 2000 } 2001 2002 SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine(); 2003 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 2004 if (amount == null) { 2005 encumbranceAccountMap.put(acctString, difference); 2006 } else { 2007 encumbranceAccountMap.put(acctString, amount.add(difference)); 2008 } 2009 lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference)); 2010 } 2011 } 2012 } 2013 2014 //SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po); 2015 2016 //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966 2017 // SpringContext.getBean(BusinessObjectService.class).save(po); 2018 2019 List<SourceAccountingLine> encumbranceAccounts = new ArrayList<SourceAccountingLine>(); 2020 for (Iterator<SourceAccountingLine> iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) { 2021 SourceAccountingLine acctString = (SourceAccountingLine) iter.next(); 2022 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 2023 if (amount.doubleValue() != 0) { 2024 acctString.setAmount(amount); 2025 encumbranceAccounts.add(acctString); 2026 } 2027 } 2028 SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po); 2029 return encumbranceAccounts; 2030 } 2031 2032 2033 /** 2034 * 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 2035 * encumbrance values on the PO and saves the PO 2036 * 2037 * @param cm Credit Memo document 2038 * @param po Purchase Order document modify encumbrances 2039 * @return List of accounting lines to use to create the pending general ledger entries 2040 */ 2041 protected List<SourceAccountingLine> getCreditMemoEncumbrance(VendorCreditMemoDocument cm, PurchaseOrderDocument po, boolean cancel) { 2042 LOG.debug("getCreditMemoEncumbrance() started"); 2043 2044 if (ObjectUtils.isNull(po)) { 2045 return null; 2046 } 2047 2048 if (cancel) { 2049 LOG.debug("getCreditMemoEncumbrance() Receiving items back from vendor (cancelled CM)"); 2050 } else { 2051 LOG.debug("getCreditMemoEncumbrance() Returning items to vendor"); 2052 } 2053 2054 Map encumbranceAccountMap = new HashMap(); 2055 2056 // Get each item one by one 2057 for (Iterator items = cm.getItems().iterator(); items.hasNext(); ) { 2058 CreditMemoItem cmItem = (CreditMemoItem) items.next(); 2059 PurchaseOrderItem poItem = getPoItem(po, cmItem.getItemLineNumber(), cmItem.getItemType()); 2060 2061 KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item 2062 KualiDecimal itemAlterInvoiceAmt = null; // Amount to alter the invoicedAmt on the PO item 2063 2064 String logItmNbr = "Item # " + cmItem.getItemLineNumber(); 2065 if (LOG.isDebugEnabled()) { 2066 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr); 2067 } 2068 2069 final KualiDecimal cmItemTotalAmount = (cmItem.getTotalAmount() == null) ? KualiDecimal.ZERO : cmItem.getTotalAmount(); 2070 ; 2071 // If there isn't a PO item or the total amount is 0, we don't need encumbrances 2072 if ((poItem == null) || (cmItemTotalAmount == null) || (cmItemTotalAmount.doubleValue() == 0) || 2073 (cmItemTotalAmount!=null && !cmItemTotalAmount.isNegative())) { 2074 if (LOG.isDebugEnabled()) { 2075 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " No encumbrances required"); 2076 } 2077 } else { 2078 if (LOG.isDebugEnabled()) { 2079 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance GL entries"); 2080 } 2081 2082 // Do we calculate the encumbrance amount based on quantity or amount? 2083 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 2084 if (LOG.isDebugEnabled()) { 2085 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance based on quantity"); 2086 } 2087 2088 // Do encumbrance calculations based on quantity 2089 KualiDecimal cmQuantity = cmItem.getItemQuantity() == null ? ZERO : cmItem.getItemQuantity(); 2090 2091 KualiDecimal encumbranceQuantityChange = calculateQuantityChange(cancel, poItem, cmQuantity); 2092 2093 if (LOG.isDebugEnabled()) { 2094 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " encumbranceQtyChange " + encumbranceQuantityChange + " outstandingEncumberedQty " + poItem.getItemOutstandingEncumberedQuantity() + " invoicedTotalQuantity " + poItem.getItemInvoicedTotalQuantity()); 2095 } 2096 2097 //do math as big decimal as doing it as a KualiDecimal will cause the item price to round to 2 digits 2098 itemDisEncumber = new KualiDecimal(encumbranceQuantityChange.bigDecimalValue().multiply(poItem.getItemUnitPrice())); 2099 2100 //add tax for encumbrance 2101 KualiDecimal itemTaxAmount = poItem.getItemTaxAmount() == null ? ZERO : poItem.getItemTaxAmount(); 2102 KualiDecimal encumbranceTaxAmount = encumbranceQuantityChange.divide(poItem.getItemQuantity()).multiply(itemTaxAmount); 2103 itemDisEncumber = itemDisEncumber.add(encumbranceTaxAmount); 2104 2105 itemAlterInvoiceAmt = cmItemTotalAmount; 2106 if (cancel) { 2107 itemAlterInvoiceAmt = itemAlterInvoiceAmt.multiply(new KualiDecimal("-1")); 2108 } 2109 } else { 2110 if (LOG.isDebugEnabled()) { 2111 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Calculate encumbrance based on amount"); 2112 } 2113 2114 // Do encumbrance calculations based on amount only 2115 if (cancel) { 2116 // Decrease encumbrance 2117 itemDisEncumber = cmItemTotalAmount.multiply(new KualiDecimal("-1")); 2118 2119 if (poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber).doubleValue() < 0) { 2120 LOG.debug("getCreditMemoEncumbrance() Cancel overflow"); 2121 2122 itemDisEncumber = poItem.getItemOutstandingEncumberedAmount(); 2123 } 2124 } else { 2125 // Increase encumbrance 2126 itemDisEncumber = cmItemTotalAmount; 2127 2128 if (poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber).doubleValue() > poItem.getTotalAmount().doubleValue()) { 2129 LOG.debug("getCreditMemoEncumbrance() Create overflow"); 2130 2131 itemDisEncumber = poItem.getTotalAmount().subtract(poItem.getItemOutstandingEncumberedAmount()); 2132 } 2133 } 2134 itemAlterInvoiceAmt = itemDisEncumber; 2135 } 2136 2137 // alter the encumbrance based on what was originally encumbered 2138 poItem.setItemOutstandingEncumberedAmount(poItem.getItemOutstandingEncumberedAmount().add(itemDisEncumber)); 2139 2140 // alter the invoiced amt based on what was actually credited on the credit memo 2141 poItem.setItemInvoicedTotalAmount(poItem.getItemInvoicedTotalAmount().subtract(itemAlterInvoiceAmt)); 2142 if (poItem.getItemInvoicedTotalAmount().compareTo(ZERO) < 0) { 2143 poItem.setItemInvoicedTotalAmount(ZERO); 2144 } 2145 2146 2147 if (LOG.isDebugEnabled()) { 2148 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " Amount to disencumber: " + itemDisEncumber); 2149 } 2150 2151 // Sort accounts 2152 Collections.sort((List) poItem.getSourceAccountingLines()); 2153 2154 // make the list of accounts for the disencumbrance entry 2155 PurchaseOrderAccount lastAccount = null; 2156 KualiDecimal accountTotal = ZERO; 2157 // Collections.sort((List)poItem.getSourceAccountingLines()); 2158 for (Iterator accountIter = poItem.getSourceAccountingLines().iterator(); accountIter.hasNext(); ) { 2159 PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter.next(); 2160 if (!account.isEmpty()) { 2161 KualiDecimal encumbranceAmount = null; 2162 2163 SourceAccountingLine acctString = account.generateSourceAccountingLine(); 2164 // amount = item disencumber * account percent / 100 2165 encumbranceAmount = itemDisEncumber.multiply(new KualiDecimal(account.getAccountLinePercent().toString())).divide(new KualiDecimal(100)); 2166 2167 account.setItemAccountOutstandingEncumbranceAmount(account.getItemAccountOutstandingEncumbranceAmount().add(encumbranceAmount)); 2168 2169 // For rounding check at the end 2170 accountTotal = accountTotal.add(encumbranceAmount); 2171 2172 lastAccount = account; 2173 2174 if (LOG.isDebugEnabled()) { 2175 LOG.debug("getCreditMemoEncumbrance() " + logItmNbr + " " + acctString + " = " + encumbranceAmount); 2176 } 2177 2178 if (encumbranceAccountMap.get(acctString) == null) { 2179 encumbranceAccountMap.put(acctString, encumbranceAmount); 2180 } else { 2181 KualiDecimal amt = (KualiDecimal) encumbranceAccountMap.get(acctString); 2182 encumbranceAccountMap.put(acctString, amt.add(encumbranceAmount)); 2183 } 2184 } 2185 } 2186 2187 // account for rounding by adjusting last account as needed 2188 if (lastAccount != null) { 2189 KualiDecimal difference = itemDisEncumber.subtract(accountTotal); 2190 if (LOG.isDebugEnabled()) { 2191 LOG.debug("getCreditMemoEncumbrance() difference: " + logItmNbr + " " + difference); 2192 } 2193 2194 SourceAccountingLine acctString = lastAccount.generateSourceAccountingLine(); 2195 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 2196 if (amount == null) { 2197 encumbranceAccountMap.put(acctString, difference); 2198 } else { 2199 encumbranceAccountMap.put(acctString, amount.add(difference)); 2200 } 2201 lastAccount.setItemAccountOutstandingEncumbranceAmount(lastAccount.getItemAccountOutstandingEncumbranceAmount().add(difference)); 2202 } 2203 } 2204 } 2205 2206 List<SourceAccountingLine> encumbranceAccounts = new ArrayList(); 2207 for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter.hasNext(); ) { 2208 SourceAccountingLine acctString = (SourceAccountingLine) iter.next(); 2209 KualiDecimal amount = (KualiDecimal) encumbranceAccountMap.get(acctString); 2210 if (amount.doubleValue() != 0) { 2211 acctString.setAmount(amount); 2212 encumbranceAccounts.add(acctString); 2213 } 2214 } 2215 2216 SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po); 2217 //MSU Contribution OLEMI-8639 DTT-4009 OLECNTRB-966 2218 // SpringContext.getBean(BusinessObjectService.class).save(po); 2219 2220 return encumbranceAccounts; 2221 } 2222 2223 /** 2224 * Save the given general ledger entries 2225 * 2226 * @param glEntries List of GeneralLedgerPendingEntries to be saved 2227 */ 2228 protected void saveGLEntries(List<GeneralLedgerPendingEntry> glEntries) { 2229 LOG.debug("saveGLEntries() started"); 2230 businessObjectService.save(glEntries); 2231 } 2232 2233 /** 2234 * Save the given accounts for the given document. 2235 * 2236 * @param summaryAccounts Accounts to be saved 2237 * @param purapDocumentIdentifier Purap document id for accounts 2238 */ 2239 protected void saveAccountsPayableSummaryAccounts(List<SummaryAccount> summaryAccounts, Integer purapDocumentIdentifier, String docType) { 2240 LOG.debug("saveAccountsPayableSummaryAccounts() started"); 2241 purapAccountingService.deleteSummaryAccounts(purapDocumentIdentifier, docType); 2242 List<AccountsPayableSummaryAccount> apSummaryAccounts = new ArrayList(); 2243 for (SummaryAccount summaryAccount : summaryAccounts) { 2244 apSummaryAccounts.add(new AccountsPayableSummaryAccount(summaryAccount.getAccount(), purapDocumentIdentifier, docType)); 2245 } 2246 businessObjectService.save(apSummaryAccounts); 2247 } 2248 2249 /** 2250 * Save the given accounts for the given document. 2251 * 2252 * @param summaryAccounts Accounts to be saved 2253 * @param purapDocumentIdentifier Purap document id for accounts 2254 * @param docType Document Type Used 2255 */ 2256 protected void saveInvoiceAccountsPayableSummaryAccounts(List<SummaryAccount> summaryAccounts, Integer purapDocumentIdentifier, String docType) { 2257 LOG.debug("saveAccountsPayableSummaryAccounts() started"); 2258 purapAccountingService.deleteSummaryAccounts(purapDocumentIdentifier, docType); 2259 List<OleInvoiceAccountsPayableSummaryAccount> apSummaryAccounts = new ArrayList(); 2260 for (SummaryAccount summaryAccount : summaryAccounts) { 2261 apSummaryAccounts.add(new OleInvoiceAccountsPayableSummaryAccount(summaryAccount.getAccount(), purapDocumentIdentifier, docType)); 2262 } 2263 businessObjectService.save(apSummaryAccounts); 2264 } 2265 2266 /** 2267 * Find item in PO based on given parameters. Must send either the line # or item type. 2268 * 2269 * @param po Purchase Order containing list of items 2270 * @param nbr Line # of desired item (could be null) 2271 * @param itemType Item type of desired item 2272 * @return PurcahseOrderItem found matching given criteria 2273 */ 2274 protected PurchaseOrderItem getPoItem(PurchaseOrderDocument po, Integer nbr, ItemType itemType) { 2275 LOG.debug("getPoItem() started"); 2276 for (Iterator iter = po.getItems().iterator(); iter.hasNext(); ) { 2277 PurchaseOrderItem element = (PurchaseOrderItem) iter.next(); 2278 if (itemType.isLineItemIndicator()) { 2279 if (ObjectUtils.isNotNull(nbr) && ObjectUtils.isNotNull(element.getItemLineNumber()) && (nbr.compareTo(element.getItemLineNumber()) == 0)) { 2280 return element; 2281 } 2282 } else { 2283 if (element.getItemTypeCode().equals(itemType.getItemTypeCode())) { 2284 return element; 2285 } 2286 } 2287 } 2288 return null; 2289 } 2290 2291 /** 2292 * Format description for general ledger entry. Currently making sure length is less than 40 char. 2293 * 2294 * @param description String to be formatted 2295 * @return Formatted String 2296 */ 2297 protected String entryDescription(String description) { 2298 if (description != null && description.length() > 40) { 2299 return description.toString().substring(0, 39); 2300 } else { 2301 return description; 2302 } 2303 } 2304 2305 /** 2306 * Calculate quantity change for creating Credit Memo entries 2307 * 2308 * @param cancel Boolean indicating whether entries are for creation or cancellation of credit memo 2309 * @param poItem Purchase Order Item 2310 * @param cmQuantity Quantity on credit memo item 2311 * @return Calculated change 2312 */ 2313 protected KualiDecimal calculateQuantityChange(boolean cancel, PurchaseOrderItem poItem, KualiDecimal cmQuantity) { 2314 LOG.debug("calculateQuantityChange() started"); 2315 2316 // Calculate quantity change & adjust invoiced quantity & outstanding encumbered quantity 2317 KualiDecimal encumbranceQuantityChange = null; 2318 if (cancel) { 2319 encumbranceQuantityChange = cmQuantity.multiply(new KualiDecimal("-1")); 2320 } else { 2321 encumbranceQuantityChange = cmQuantity; 2322 } 2323 poItem.setItemInvoicedTotalQuantity(poItem.getItemInvoicedTotalQuantity().subtract(encumbranceQuantityChange)); 2324 poItem.setItemOutstandingEncumberedQuantity(poItem.getItemOutstandingEncumberedQuantity().add(encumbranceQuantityChange)); 2325 2326 // Check for overflows 2327 if (cancel) { 2328 if (poItem.getItemOutstandingEncumberedQuantity().doubleValue() < 0) { 2329 LOG.debug("calculateQuantityChange() Cancel overflow"); 2330 KualiDecimal difference = poItem.getItemOutstandingEncumberedQuantity().abs(); 2331 poItem.setItemOutstandingEncumberedQuantity(ZERO); 2332 poItem.setItemInvoicedTotalQuantity(poItem.getItemQuantity()); 2333 encumbranceQuantityChange = encumbranceQuantityChange.add(difference); 2334 } 2335 } 2336// Coomented for JIRA:OLE-5162 as encumbrance get doubled here. 2337 /* else { 2338 if (poItem.getItemInvoicedTotalQuantity().doubleValue() < 0) { 2339 LOG.debug("calculateQuantityChange() Create overflow"); 2340 KualiDecimal difference = poItem.getItemInvoicedTotalQuantity().abs(); 2341 poItem.setItemOutstandingEncumberedQuantity(poItem.getItemQuantity()); 2342 poItem.setItemInvoicedTotalQuantity(ZERO); 2343 encumbranceQuantityChange = encumbranceQuantityChange.add(difference); 2344 } 2345 } */ 2346 return encumbranceQuantityChange; 2347 } 2348 2349 public void setDateTimeService(DateTimeService dateTimeService) { 2350 this.dateTimeService = dateTimeService; 2351 } 2352 2353 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 2354 this.businessObjectService = businessObjectService; 2355 } 2356 2357 public void setGeneralLedgerPendingEntryService(GeneralLedgerPendingEntryService generalLedgerPendingEntryService) { 2358 this.generalLedgerPendingEntryService = generalLedgerPendingEntryService; 2359 } 2360 2361 public void setKualiRuleService(KualiRuleService kualiRuleService) { 2362 this.kualiRuleService = kualiRuleService; 2363 } 2364 2365 public void setPurapAccountingService(PurapAccountingService purapAccountingService) { 2366 this.purapAccountingService = purapAccountingService; 2367 } 2368 2369 public void setUniversityDateService(UniversityDateService universityDateService) { 2370 this.universityDateService = universityDateService; 2371 } 2372 2373 public void setPurchaseOrderService(PurchaseOrderService purchaseOrderService) { 2374 this.purchaseOrderService = purchaseOrderService; 2375 } 2376 2377 public void setObjectCodeService(ObjectCodeService objectCodeService) { 2378 this.objectCodeService = objectCodeService; 2379 } 2380 2381 public void setSubObjectCodeService(SubObjectCodeService subObjectCodeService) { 2382 this.subObjectCodeService = subObjectCodeService; 2383 } 2384 2385 public void setParameterService(ParameterService parameterService) { 2386 this.parameterService = parameterService; 2387 } 2388 2389 public void setPaymentRequestService(PaymentRequestService paymentRequestService) { 2390 this.paymentRequestService = paymentRequestService; 2391 } 2392 2393 /** 2394 * Sets the invoiceService attribute value. 2395 * 2396 * @param invoiceService The invoiceService to set. 2397 */ 2398 2399 public void setInvoiceService(InvoiceService invoiceService) { 2400 this.invoiceService = invoiceService; 2401 } 2402 2403 2404}