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