0001: /*
0002: * Copyright 2007 The Kuali Foundation.
0003: *
0004: * Licensed under the Educational Community License, Version 1.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.opensource.org/licenses/ecl1.php
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.kuali.module.purap.service.impl;
0017:
0018: import static org.kuali.core.util.KualiDecimal.ZERO;
0019: import static org.kuali.kfs.KFSConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE;
0020: import static org.kuali.kfs.KFSConstants.ENCUMB_UPDT_DOCUMENT_CD;
0021: import static org.kuali.kfs.KFSConstants.ENCUMB_UPDT_REFERENCE_DOCUMENT_CD;
0022: import static org.kuali.kfs.KFSConstants.GL_CREDIT_CODE;
0023: import static org.kuali.kfs.KFSConstants.GL_DEBIT_CODE;
0024: import static org.kuali.module.purap.PurapConstants.HUNDRED;
0025: import static org.kuali.module.purap.PurapConstants.PURAP_ORIGIN_CODE;
0026:
0027: import java.math.BigDecimal;
0028: import java.util.ArrayList;
0029: import java.util.Collections;
0030: import java.util.HashMap;
0031: import java.util.Iterator;
0032: import java.util.List;
0033: import java.util.Map;
0034:
0035: import org.kuali.core.service.BusinessObjectService;
0036: import org.kuali.core.service.DateTimeService;
0037: import org.kuali.core.service.KualiConfigurationService;
0038: import org.kuali.core.service.KualiRuleService;
0039: import org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper;
0040: import org.kuali.core.util.KualiDecimal;
0041: import org.kuali.core.util.ObjectUtils;
0042: import org.kuali.kfs.bo.AccountingLine;
0043: import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
0044: import org.kuali.kfs.bo.SourceAccountingLine;
0045: import org.kuali.kfs.context.SpringContext;
0046: import org.kuali.kfs.rule.event.GenerateGeneralLedgerPendingEntriesEvent;
0047: import org.kuali.kfs.service.GeneralLedgerPendingEntryService;
0048: import org.kuali.module.chart.bo.ObjectCode;
0049: import org.kuali.module.chart.bo.SubObjCd;
0050: import org.kuali.module.chart.service.ObjectCodeService;
0051: import org.kuali.module.chart.service.SubObjectCodeService;
0052: import org.kuali.module.financial.service.UniversityDateService;
0053: import org.kuali.module.gl.bo.UniversityDate;
0054: import org.kuali.module.purap.PurapConstants;
0055: import org.kuali.module.purap.PurapPropertyConstants;
0056: import org.kuali.module.purap.PurapConstants.PurapDocTypeCodes;
0057: import org.kuali.module.purap.bo.CreditMemoItem;
0058: import org.kuali.module.purap.bo.ItemType;
0059: import org.kuali.module.purap.bo.PaymentRequestItem;
0060: import org.kuali.module.purap.bo.PaymentRequestSummaryAccount;
0061: import org.kuali.module.purap.bo.PurchaseOrderAccount;
0062: import org.kuali.module.purap.bo.PurchaseOrderItem;
0063: import org.kuali.module.purap.document.AccountsPayableDocument;
0064: import org.kuali.module.purap.document.CreditMemoDocument;
0065: import org.kuali.module.purap.document.PaymentRequestDocument;
0066: import org.kuali.module.purap.document.PurchaseOrderDocument;
0067: import org.kuali.module.purap.document.PurchasingAccountsPayableDocument;
0068: import org.kuali.module.purap.service.PaymentRequestService;
0069: import org.kuali.module.purap.service.PurapAccountingService;
0070: import org.kuali.module.purap.service.PurapGeneralLedgerService;
0071: import org.kuali.module.purap.service.PurchaseOrderService;
0072: import org.springframework.transaction.annotation.Transactional;
0073:
0074: @Transactional
0075: public class PurapGeneralLedgerServiceImpl implements
0076: PurapGeneralLedgerService {
0077: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0078: .getLogger(PurapGeneralLedgerServiceImpl.class);
0079:
0080: private BusinessObjectService businessObjectService;
0081: private DateTimeService dateTimeService;
0082: private GeneralLedgerPendingEntryService generalLedgerPendingEntryService;
0083: private KualiConfigurationService kualiConfigurationService;
0084: private KualiRuleService kualiRuleService;
0085: private PaymentRequestService paymentRequestService;
0086: private PurapAccountingService purapAccountingService;
0087: private PurchaseOrderService purchaseOrderService;
0088: private UniversityDateService universityDateService;
0089:
0090: /**
0091: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#customizeGeneralLedgerPendingEntry(org.kuali.module.purap.document.PurchasingAccountsPayableDocument,
0092: * org.kuali.kfs.bo.AccountingLine, org.kuali.kfs.bo.GeneralLedgerPendingEntry, java.lang.Integer, java.lang.String,
0093: * java.lang.String, boolean)
0094: */
0095: public void customizeGeneralLedgerPendingEntry(
0096: PurchasingAccountsPayableDocument purapDocument,
0097: AccountingLine accountingLine,
0098: GeneralLedgerPendingEntry explicitEntry,
0099: Integer referenceDocumentNumber, String debitCreditCode,
0100: String docType, boolean isEncumbrance) {
0101: LOG.debug("customizeGeneralLedgerPendingEntry() started");
0102:
0103: // USE CURRENT; don't use FY on doc in case it's a prior year
0104: UniversityDate uDate = universityDateService
0105: .getCurrentUniversityDate();
0106: explicitEntry.setUniversityFiscalYear(uDate
0107: .getUniversityFiscalYear());
0108: explicitEntry.setUniversityFiscalPeriodCode(uDate
0109: .getUniversityFiscalAccountingPeriod());
0110:
0111: explicitEntry.setDocumentNumber(purapDocument
0112: .getDocumentNumber());
0113: explicitEntry
0114: .setTransactionLedgerEntryDescription(entryDescription(purapDocument
0115: .getVendorName()));
0116: explicitEntry
0117: .setFinancialSystemOriginationCode(PURAP_ORIGIN_CODE);
0118:
0119: if (ObjectUtils.isNotNull(referenceDocumentNumber)) {
0120: explicitEntry
0121: .setReferenceFinancialDocumentNumber(referenceDocumentNumber
0122: .toString());
0123: explicitEntry
0124: .setReferenceFinancialDocumentTypeCode(PurapDocTypeCodes.PO_DOCUMENT);
0125: explicitEntry
0126: .setReferenceFinancialSystemOriginationCode(PURAP_ORIGIN_CODE);
0127: }
0128:
0129: ObjectCode objectCode = SpringContext.getBean(
0130: ObjectCodeService.class).getByPrimaryId(
0131: explicitEntry.getUniversityFiscalYear(),
0132: explicitEntry.getChartOfAccountsCode(),
0133: explicitEntry.getFinancialObjectCode());
0134: if (ObjectUtils.isNotNull(objectCode)) {
0135: explicitEntry.setFinancialObjectTypeCode(objectCode
0136: .getFinancialObjectTypeCode());
0137: }
0138:
0139: SubObjCd subObjectCode = SpringContext.getBean(
0140: SubObjectCodeService.class).getByPrimaryId(
0141: explicitEntry.getUniversityFiscalYear(),
0142: explicitEntry.getChartOfAccountsCode(),
0143: explicitEntry.getAccountNumber(),
0144: explicitEntry.getFinancialObjectCode(),
0145: explicitEntry.getFinancialSubObjectCode());
0146: if (ObjectUtils.isNotNull(subObjectCode)) {
0147: explicitEntry.setFinancialSubObjectCode(subObjectCode
0148: .getFinancialSubObjectCode());
0149: }
0150:
0151: if (isEncumbrance) {
0152: explicitEntry
0153: .setFinancialBalanceTypeCode(BALANCE_TYPE_EXTERNAL_ENCUMBRANCE);
0154:
0155: // D - means the encumbrance is based on the document number
0156: // R - means the encumbrance is based on the referring document number
0157: // Encumbrances are created on the PO. They are updated by PREQ's and CM's.
0158: // So PO encumbrances are D, PREQ & CM's are R.
0159: if (PurapDocTypeCodes.PO_DOCUMENT.equals(docType)) {
0160: explicitEntry
0161: .setTransactionEncumbranceUpdateCode(ENCUMB_UPDT_DOCUMENT_CD);
0162: } else {
0163: explicitEntry
0164: .setTransactionEncumbranceUpdateCode(ENCUMB_UPDT_REFERENCE_DOCUMENT_CD);
0165: }
0166: }
0167:
0168: // if the amount is negative, flip the D/C indicator
0169: if (accountingLine.getAmount().doubleValue() < 0) {
0170: if (GL_CREDIT_CODE.equals(debitCreditCode)) {
0171: explicitEntry
0172: .setTransactionDebitCreditCode(GL_DEBIT_CODE);
0173: } else {
0174: explicitEntry
0175: .setTransactionDebitCreditCode(GL_CREDIT_CODE);
0176: }
0177: } else {
0178: explicitEntry
0179: .setTransactionDebitCreditCode(debitCreditCode);
0180: }
0181:
0182: }// end purapCustomizeGeneralLedgerPendingEntry()
0183:
0184: /**
0185: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesCancelAccountsPayableDocument(org.kuali.module.purap.document.AccountsPayableDocument)
0186: */
0187: public void generateEntriesCancelAccountsPayableDocument(
0188: AccountsPayableDocument apDocument) {
0189: LOG
0190: .debug("generateEntriesCancelAccountsPayableDocument() started");
0191: if (apDocument instanceof PaymentRequestDocument) {
0192: LOG
0193: .info("generateEntriesCancelAccountsPayableDocument() cancel PaymentRequestDocument");
0194: generateEntriesCancelPaymentRequest((PaymentRequestDocument) apDocument);
0195: } else if (apDocument instanceof CreditMemoDocument) {
0196: LOG
0197: .info("generateEntriesCancelAccountsPayableDocument() cancel CreditMemoDocument");
0198: generateEntriesCancelCreditMemo((CreditMemoDocument) apDocument);
0199: } else {
0200: // doc not found
0201: }
0202: }
0203:
0204: /**
0205: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesCreatePaymentRequest(org.kuali.module.purap.document.PaymentRequestDocument)
0206: */
0207: public void generateEntriesCreatePaymentRequest(
0208: PaymentRequestDocument preq) {
0209: LOG.debug("generateEntriesCreatePaymentRequest() started");
0210: List encumbrances = relieveEncumbrance(preq);
0211: List accountingLines = purapAccountingService
0212: .generateSummaryWithNoZeroTotals(preq.getItems());
0213: generateEntriesPaymentRequest(preq, encumbrances,
0214: accountingLines, CREATE_PAYMENT_REQUEST);
0215: }
0216:
0217: /**
0218: * Called from generateEntriesCancelAccountsPayableDocument() for Payment Request Document
0219: *
0220: * @param preq Payment Request document to cancel
0221: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesCancelAccountsPayableDocument(org.kuali.module.purap.document.AccountsPayableDocument)
0222: */
0223: private void generateEntriesCancelPaymentRequest(
0224: PaymentRequestDocument preq) {
0225: LOG.debug("generateEntriesCreatePaymentRequest() started");
0226: List encumbrances = reencumberEncumbrance(preq);
0227: List accountingLines = purapAccountingService
0228: .generateSummaryWithNoZeroTotals(preq.getItems());
0229: generateEntriesPaymentRequest(preq, encumbrances,
0230: accountingLines, CANCEL_PAYMENT_REQUEST);
0231: }
0232:
0233: /**
0234: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesModifyPaymentRequest(org.kuali.module.purap.document.PaymentRequestDocument)
0235: */
0236: public void generateEntriesModifyPaymentRequest(
0237: PaymentRequestDocument preq) {
0238: LOG.debug("generateEntriesModifyPaymentRequest() started");
0239:
0240: Map actualsPositive = new HashMap();
0241: List<SourceAccountingLine> newAccountingLines = purapAccountingService
0242: .generateSummaryWithNoZeroTotals(preq.getItems());
0243: for (SourceAccountingLine newAccount : newAccountingLines) {
0244: actualsPositive.put(newAccount, newAccount.getAmount());
0245: LOG
0246: .debug("generateEntriesModifyPaymentRequest() actualsPositive: "
0247: + newAccount.getAccountNumber()
0248: + " = "
0249: + newAccount.getAmount());
0250: }
0251:
0252: Map actualsNegative = new HashMap();
0253: List<PaymentRequestSummaryAccount> oldAccountingLines = getPaymentRequestSummaryAccounts(preq
0254: .getPurapDocumentIdentifier());
0255:
0256: for (PaymentRequestSummaryAccount oldAccount : oldAccountingLines) {
0257: actualsNegative.put(oldAccount
0258: .generateSourceAccountingLine(), oldAccount
0259: .getAmount());
0260: LOG
0261: .debug("generateEntriesModifyPaymentRequest() actualsNegative: "
0262: + oldAccount.getAccountNumber()
0263: + " = "
0264: + oldAccount.getAmount());
0265: }
0266:
0267: // Add the positive entries and subtract the negative entries
0268: Map glEntries = new HashMap();
0269:
0270: // Combine the two maps (copy all the positive entries)
0271: LOG
0272: .debug("generateEntriesModifyPaymentRequest() Combine positive/negative entries");
0273: glEntries.putAll(actualsPositive);
0274:
0275: for (Iterator iter = actualsNegative.keySet().iterator(); iter
0276: .hasNext();) {
0277: SourceAccountingLine key = (SourceAccountingLine) iter
0278: .next();
0279:
0280: KualiDecimal amt;
0281: if (glEntries.containsKey(key)) {
0282: amt = (KualiDecimal) glEntries.get(key);
0283: amt = amt.subtract((KualiDecimal) actualsNegative
0284: .get(key));
0285: } else {
0286: amt = ZERO;
0287: amt = amt.subtract((KualiDecimal) actualsNegative
0288: .get(key));
0289: }
0290: glEntries.put(key, amt);
0291: }
0292:
0293: List<SourceAccountingLine> accounts = new ArrayList();
0294: for (Iterator iter = glEntries.keySet().iterator(); iter
0295: .hasNext();) {
0296: SourceAccountingLine account = (SourceAccountingLine) iter
0297: .next();
0298: KualiDecimal amount = (KualiDecimal) glEntries.get(account);
0299: if (ZERO.compareTo(amount) != 0) {
0300: account.setAmount(amount);
0301: accounts.add(account);
0302: }
0303: }
0304:
0305: LOG
0306: .debug("generateEntriesModifyPaymentRequest() Generate GL entries");
0307: generateEntriesPaymentRequest(preq, null, accounts,
0308: MODIFY_PAYMENT_REQUEST);
0309: }
0310:
0311: /**
0312: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesCreateCreditMemo(org.kuali.module.purap.document.CreditMemoDocument)
0313: */
0314: public void generateEntriesCreateCreditMemo(CreditMemoDocument cm) {
0315: LOG.debug("generateEntriesCreateCreditMemo() started");
0316: generateEntriesCreditMemo(cm, CREATE_CREDIT_MEMO);
0317: }
0318:
0319: /**
0320: * Called from generateEntriesCancelAccountsPayableDocument() for Payment Request Document
0321: *
0322: * @param preq Payment Request document to cancel
0323: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesCancelAccountsPayableDocument(org.kuali.module.purap.document.AccountsPayableDocument)
0324: */
0325: private void generateEntriesCancelCreditMemo(CreditMemoDocument cm) {
0326: LOG.debug("generateEntriesCancelCreditMemo() started");
0327: generateEntriesCreditMemo(cm, CANCEL_CREDIT_MEMO);
0328: }
0329:
0330: /**
0331: * Retrieves the next available sequence number from the general ledger pending entry table for this document
0332: *
0333: * @param documentNumber Document number to find next sequence number
0334: * @return Next available sequence number
0335: */
0336: private int getNextAvailableSequence(String documentNumber) {
0337: LOG.debug("getNextAvailableSequence() started");
0338: Map fieldValues = new HashMap();
0339: fieldValues.put("financialSystemOriginationCode",
0340: PURAP_ORIGIN_CODE);
0341: fieldValues.put("documentNumber", documentNumber);
0342: int count = businessObjectService.countMatching(
0343: GeneralLedgerPendingEntry.class, fieldValues);
0344: return count + 1;
0345: }
0346:
0347: /**
0348: * Creates the general ledger entries for Payment Request actions.
0349: *
0350: * @param preq Payment Request document to create entries
0351: * @param encumbrances List of encumbrance accounts if applies
0352: * @param accountingLines List of preq accounts to create entries
0353: * @param processType Type of process (create, modify, cancel)
0354: * @return Boolean returned indicating whether entry creation succeeded
0355: */
0356: private boolean generateEntriesPaymentRequest(
0357: PaymentRequestDocument preq, List encumbrances,
0358: List accountingLines, String processType) {
0359: LOG.debug("generateEntriesPaymentRequest() started");
0360: boolean success = true;
0361: preq.setGeneralLedgerPendingEntries(new ArrayList());
0362:
0363: /*
0364: * Can't let generalLedgerPendingEntryService just create all the entries because we need the sequenceHelper to carry over
0365: * from the encumbrances to the actuals and also because we need to tell the PaymentRequestDocumentRule customize entry
0366: * method how to customize differently based on if creating an encumbrance or actual.
0367: */
0368: GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper(
0369: getNextAvailableSequence(preq.getDocumentNumber()));
0370:
0371: if (encumbrances != null) {
0372: LOG
0373: .debug("generateEntriesPaymentRequest() generate encumbrance entries");
0374: if (CREATE_PAYMENT_REQUEST.equals(processType)) {
0375: // on create, use CREDIT code for encumbrances
0376: preq.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
0377: } else if (CANCEL_PAYMENT_REQUEST.equals(processType)) {
0378: // on cancel, use DEBIT code
0379: preq.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
0380: } else if (MODIFY_PAYMENT_REQUEST.equals(processType)) {
0381: // no encumbrances for modify
0382: }
0383:
0384: preq.setGenerateEncumbranceEntries(true);
0385: for (Iterator iter = encumbrances.iterator(); iter
0386: .hasNext();) {
0387: AccountingLine accountingLine = (AccountingLine) iter
0388: .next();
0389: GenerateGeneralLedgerPendingEntriesEvent glEvent = new GenerateGeneralLedgerPendingEntriesEvent(
0390: preq, accountingLine, sequenceHelper);
0391: success &= kualiRuleService.applyRules(glEvent);
0392: sequenceHelper.increment(); // increment for the next line
0393: }
0394: }
0395:
0396: if (ObjectUtils.isNotNull(accountingLines)
0397: && !accountingLines.isEmpty()) {
0398: LOG
0399: .debug("generateEntriesPaymentRequest() now book the actuals");
0400: preq.setGenerateEncumbranceEntries(false);
0401:
0402: if (CREATE_PAYMENT_REQUEST.equals(processType)
0403: || MODIFY_PAYMENT_REQUEST.equals(processType)) {
0404: // on create and modify, use DEBIT code
0405: preq.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
0406: } else if (CANCEL_PAYMENT_REQUEST.equals(processType)) {
0407: // on cancel, use CREDIT code
0408: preq.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
0409: }
0410:
0411: for (Iterator iter = accountingLines.iterator(); iter
0412: .hasNext();) {
0413: AccountingLine accountingLine = (AccountingLine) iter
0414: .next();
0415: GenerateGeneralLedgerPendingEntriesEvent glEvent = new GenerateGeneralLedgerPendingEntriesEvent(
0416: preq, accountingLine, sequenceHelper);
0417: success &= kualiRuleService.applyRules(glEvent);
0418: sequenceHelper.increment(); // increment for the next line
0419: }
0420:
0421: // Manually save summary accounts
0422: savePaymentRequestSummaryAccounts(accountingLines, preq
0423: .getPurapDocumentIdentifier());
0424: }
0425:
0426: // Manually save GL entries for Payment Request and encumbrances
0427: saveGLEntries(preq.getGeneralLedgerPendingEntries());
0428:
0429: return success;
0430: }
0431:
0432: /**
0433: * Creates the general ledger entries for Credit Memo actions.
0434: *
0435: * @param cm Credit Memo document to create entries
0436: * @param isCancel Indicates if request is a cancel or create
0437: * @return Boolean returned indicating whether entry creation succeeded
0438: */
0439: private boolean generateEntriesCreditMemo(CreditMemoDocument cm,
0440: boolean isCancel) {
0441: LOG.debug("generateEntriesCreditMemo() started");
0442:
0443: cm.setGeneralLedgerPendingEntries(new ArrayList());
0444:
0445: boolean success = true;
0446: GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper(
0447: getNextAvailableSequence(cm.getDocumentNumber()));
0448:
0449: if (!cm.isSourceVendor()) {
0450: LOG
0451: .debug("generateEntriesCreditMemo() create encumbrance entries for CM against a PO or PREQ (not vendor)");
0452: PurchaseOrderDocument po = null;
0453: if (cm.isSourceDocumentPurchaseOrder()) {
0454: LOG.debug("generateEntriesCreditMemo() PO type");
0455: po = purchaseOrderService.getCurrentPurchaseOrder(cm
0456: .getPurchaseOrderIdentifier());
0457: } else if (cm.isSourceDocumentPaymentRequest()) {
0458: LOG.debug("generateEntriesCreditMemo() PREQ type");
0459: po = purchaseOrderService.getCurrentPurchaseOrder(cm
0460: .getPaymentRequestDocument()
0461: .getPurchaseOrderIdentifier());
0462: }
0463:
0464: List encumbrances = getCreditMemoEncumbrance(cm, po,
0465: isCancel);
0466: if (encumbrances != null) {
0467: cm.setGenerateEncumbranceEntries(true);
0468:
0469: // even if generating encumbrance entries on cancel, call is the same because the method gets negative amounts from
0470: // the map so Debits on negatives = a credit
0471: cm.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
0472:
0473: for (Iterator iter = encumbrances.iterator(); iter
0474: .hasNext();) {
0475: AccountingLine accountingLine = (AccountingLine) iter
0476: .next();
0477: if (accountingLine.getAmount().compareTo(ZERO) != 0) {
0478: GenerateGeneralLedgerPendingEntriesEvent glEvent = new GenerateGeneralLedgerPendingEntriesEvent(
0479: cm, accountingLine, sequenceHelper);
0480: success &= kualiRuleService.applyRules(glEvent);
0481: sequenceHelper.increment(); // increment for the next line
0482: }
0483: }
0484: }
0485: }
0486:
0487: List<SourceAccountingLine> accountingLines = purapAccountingService
0488: .generateSummaryWithNoZeroTotals(cm.getItems());
0489: if (accountingLines != null) {
0490: LOG
0491: .debug("generateEntriesCreditMemo() now book the actuals");
0492: cm.setGenerateEncumbranceEntries(false);
0493:
0494: if (!isCancel) {
0495: // on create, use CREDIT code
0496: cm.setDebitCreditCodeForGLEntries(GL_CREDIT_CODE);
0497: } else {
0498: // on cancel, use DEBIT code
0499: cm.setDebitCreditCodeForGLEntries(GL_DEBIT_CODE);
0500: }
0501:
0502: for (Iterator iter = accountingLines.iterator(); iter
0503: .hasNext();) {
0504: AccountingLine accountingLine = (AccountingLine) iter
0505: .next();
0506: GenerateGeneralLedgerPendingEntriesEvent glEvent = new GenerateGeneralLedgerPendingEntriesEvent(
0507: cm, accountingLine, sequenceHelper);
0508: success &= kualiRuleService.applyRules(glEvent);
0509: sequenceHelper.increment(); // increment for the next line
0510: }
0511: }
0512:
0513: saveGLEntries(cm.getGeneralLedgerPendingEntries());
0514:
0515: LOG.debug("generateEntriesCreditMemo() ended");
0516: return success;
0517: }
0518:
0519: /**
0520: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesApproveAmendPurchaseOrder(org.kuali.module.purap.document.PurchaseOrderDocument)
0521: */
0522: public void generateEntriesApproveAmendPurchaseOrder(
0523: PurchaseOrderDocument po) {
0524: LOG.debug("generateEntriesApproveAmendPurchaseOrder() started");
0525:
0526: // Set outstanding encumbered quantity/amount on items
0527: for (Iterator items = po.getItems().iterator(); items.hasNext();) {
0528: PurchaseOrderItem item = (PurchaseOrderItem) items.next();
0529:
0530: // if invoice fields are null (as would be for new items), set fields to zero
0531: item.setItemInvoicedTotalAmount(item
0532: .getItemInvoicedTotalAmount() == null ? ZERO : item
0533: .getItemInvoicedTotalAmount());
0534: item.setItemInvoicedTotalQuantity(item
0535: .getItemInvoicedTotalQuantity() == null ? ZERO
0536: : item.getItemInvoicedTotalQuantity());
0537:
0538: if (!item.isItemActiveIndicator()) {
0539: // set outstanding encumbrance amounts to zero for inactive items
0540: item.setItemOutstandingEncumberedQuantity(ZERO);
0541: item.setItemOutstandingEncumberedAmount(ZERO);
0542:
0543: for (Iterator iter = item.getSourceAccountingLines()
0544: .iterator(); iter.hasNext();) {
0545: PurchaseOrderAccount account = (PurchaseOrderAccount) iter
0546: .next();
0547: account
0548: .setItemAccountOutstandingEncumbranceAmount(ZERO);
0549: account.setAlternateAmountForGLEntryCreation(ZERO);
0550: }
0551: } else {
0552: // Set quantities
0553: if (item.getItemQuantity() != null) {
0554: item
0555: .setItemOutstandingEncumberedQuantity(item
0556: .getItemQuantity()
0557: .subtract(
0558: item
0559: .getItemInvoicedTotalQuantity()));
0560: } else {
0561: // if order qty is null, outstanding encumbered qty should be null
0562: item.setItemOutstandingEncumberedQuantity(null);
0563: }
0564:
0565: // Set amount
0566: if (item.getItemOutstandingEncumberedQuantity() != null) {
0567: item.setItemOutstandingEncumberedAmount(item
0568: .getItemOutstandingEncumberedQuantity()
0569: .multiply(
0570: new KualiDecimal(item
0571: .getItemUnitPrice())));
0572: } else {
0573: if (item.getItemUnitPrice() != null) {
0574: item
0575: .setItemOutstandingEncumberedAmount(new KualiDecimal(
0576: item
0577: .getItemUnitPrice()
0578: .subtract(
0579: item
0580: .getItemInvoicedTotalAmount()
0581: .bigDecimalValue())));
0582: }
0583: }
0584:
0585: for (Iterator iter = item.getSourceAccountingLines()
0586: .iterator(); iter.hasNext();) {
0587: PurchaseOrderAccount account = (PurchaseOrderAccount) iter
0588: .next();
0589: BigDecimal percent = new BigDecimal(account
0590: .getAccountLinePercent().toString());
0591: percent = percent.divide(new BigDecimal("100"), 3,
0592: BigDecimal.ROUND_HALF_UP);
0593: account
0594: .setItemAccountOutstandingEncumbranceAmount(item
0595: .getItemOutstandingEncumberedAmount()
0596: .multiply(new KualiDecimal(percent)));
0597: account
0598: .setAlternateAmountForGLEntryCreation(account
0599: .getItemAccountOutstandingEncumbranceAmount());
0600: }
0601: }
0602: }
0603:
0604: PurchaseOrderDocument oldPO = SpringContext.getBean(
0605: PurchaseOrderService.class).getCurrentPurchaseOrder(
0606: po.getPurapDocumentIdentifier());
0607:
0608: if (oldPO == null) {
0609: throw new IllegalArgumentException(
0610: "Current Purchase Order not found - poId = "
0611: + oldPO.getPurapDocumentIdentifier());
0612: }
0613:
0614: List newAccounts = SpringContext.getBean(
0615: PurapAccountingService.class)
0616: .generateSummaryWithNoZeroTotalsUsingAlternateAmount(
0617: po.getItemsActiveOnly());
0618: List oldAccounts = SpringContext.getBean(
0619: PurapAccountingService.class)
0620: .generateSummaryWithNoZeroTotalsUsingAlternateAmount(
0621: oldPO.getItemsActiveOnlySetupAlternateAmount());
0622:
0623: Map combination = new HashMap();
0624:
0625: // Add amounts from the new PO
0626: for (Iterator iter = newAccounts.iterator(); iter.hasNext();) {
0627: SourceAccountingLine newAccount = (SourceAccountingLine) iter
0628: .next();
0629: combination.put(newAccount, newAccount.getAmount());
0630: }
0631:
0632: LOG
0633: .info("generateEntriesApproveAmendPurchaseOrder() combination after the add");
0634: for (Iterator iter = combination.keySet().iterator(); iter
0635: .hasNext();) {
0636: SourceAccountingLine element = (SourceAccountingLine) iter
0637: .next();
0638: LOG.info("generateEntriesApproveAmendPurchaseOrder() "
0639: + element
0640: + " = "
0641: + ((KualiDecimal) combination.get(element))
0642: .floatValue());
0643: }
0644:
0645: // Subtract the amounts from the old PO
0646: for (Iterator iter = oldAccounts.iterator(); iter.hasNext();) {
0647: SourceAccountingLine oldAccount = (SourceAccountingLine) iter
0648: .next();
0649: if (combination.containsKey(oldAccount)) {
0650: KualiDecimal amount = (KualiDecimal) combination
0651: .get(oldAccount);
0652: amount = amount.subtract(oldAccount.getAmount());
0653: combination.put(oldAccount, amount);
0654: } else {
0655: combination.put(oldAccount, ZERO.subtract(oldAccount
0656: .getAmount()));
0657: }
0658: }
0659:
0660: LOG
0661: .debug("generateEntriesApproveAmendPurchaseOrder() combination after the subtract");
0662: for (Iterator iter = combination.keySet().iterator(); iter
0663: .hasNext();) {
0664: SourceAccountingLine element = (SourceAccountingLine) iter
0665: .next();
0666: LOG.info("generateEntriesApproveAmendPurchaseOrder() "
0667: + element
0668: + " = "
0669: + ((KualiDecimal) combination.get(element))
0670: .floatValue());
0671: }
0672:
0673: List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
0674: for (Iterator iter = combination.keySet().iterator(); iter
0675: .hasNext();) {
0676: SourceAccountingLine account = (SourceAccountingLine) iter
0677: .next();
0678: KualiDecimal amount = (KualiDecimal) combination
0679: .get(account);
0680: if (ZERO.compareTo(amount) != 0) {
0681: account.setAmount(amount);
0682: encumbranceAccounts.add(account);
0683: }
0684: }
0685:
0686: po.setSourceAccountingLines(encumbranceAccounts);
0687: generalLedgerPendingEntryService
0688: .generateGeneralLedgerPendingEntries(po);
0689: saveGLEntries(po.getGeneralLedgerPendingEntries());
0690: LOG
0691: .debug("generateEntriesApproveAmendPo() gl entries created; exit method");
0692: }
0693:
0694: /**
0695: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesClosePurchaseOrder(org.kuali.module.purap.document.PurchaseOrderDocument)
0696: */
0697: public void generateEntriesClosePurchaseOrder(
0698: PurchaseOrderDocument po) {
0699: LOG.debug("generateEntriesClosePurchaseOrder() started");
0700:
0701: // Set outstanding encumbered quantity/amount on items
0702: for (Iterator items = po.getItems().iterator(); items.hasNext();) {
0703: PurchaseOrderItem item = (PurchaseOrderItem) items.next();
0704:
0705: String logItmNbr = "Item # " + item.getItemLineNumber();
0706:
0707: if (!item.isItemActiveIndicator()) {
0708: continue;
0709: }
0710:
0711: KualiDecimal itemAmount = null;
0712: if (!item.getItemType()
0713: .isQuantityBasedGeneralLedgerIndicator()) {
0714: LOG.debug("generateEntriesClosePurchaseOrder() "
0715: + logItmNbr + " Calculate based on amounts");
0716: itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO
0717: : item.getItemOutstandingEncumberedAmount();
0718: } else {
0719: LOG.debug("generateEntriesClosePurchaseOrder() "
0720: + logItmNbr + " Calculate based on quantities");
0721: itemAmount = item
0722: .getItemOutstandingEncumberedQuantity()
0723: .multiply(
0724: new KualiDecimal(item
0725: .getItemUnitPrice()));
0726: }
0727:
0728: KualiDecimal accountTotal = ZERO;
0729: PurchaseOrderAccount lastAccount = null;
0730: if (itemAmount.compareTo(ZERO) != 0) {
0731: // Sort accounts
0732: Collections
0733: .sort((List) item.getSourceAccountingLines());
0734:
0735: for (Iterator iterAcct = item
0736: .getSourceAccountingLines().iterator(); iterAcct
0737: .hasNext();) {
0738: PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct
0739: .next();
0740: if (!acct.isEmpty()) {
0741: KualiDecimal acctAmount = itemAmount.multiply(
0742: new KualiDecimal(acct
0743: .getAccountLinePercent()
0744: .toString())).divide(
0745: PurapConstants.HUNDRED);
0746: accountTotal = accountTotal.add(acctAmount);
0747: acct
0748: .setAlternateAmountForGLEntryCreation(acctAmount);
0749: lastAccount = acct;
0750: }
0751: }
0752:
0753: // account for rounding by adjusting last account as needed
0754: if (lastAccount != null) {
0755: KualiDecimal difference = itemAmount
0756: .subtract(accountTotal);
0757: LOG
0758: .debug("generateEntriesClosePurchaseOrder() difference: "
0759: + logItmNbr + " " + difference);
0760:
0761: KualiDecimal amount = lastAccount
0762: .getAlternateAmountForGLEntryCreation();
0763: if (ObjectUtils.isNotNull(amount)) {
0764: lastAccount
0765: .setAlternateAmountForGLEntryCreation(amount
0766: .add(difference));
0767: } else {
0768: lastAccount
0769: .setAlternateAmountForGLEntryCreation(difference);
0770: }
0771: }
0772:
0773: }
0774: }// endfor
0775:
0776: po.setSourceAccountingLines(purapAccountingService
0777: .generateSummaryWithNoZeroTotalsUsingAlternateAmount(po
0778: .getItemsActiveOnly()));
0779: generalLedgerPendingEntryService
0780: .generateGeneralLedgerPendingEntries(po);
0781: saveGLEntries(po.getGeneralLedgerPendingEntries());
0782: LOG
0783: .debug("generateEntriesClosePurchaseOrder() gl entries created; exit method");
0784: }
0785:
0786: /**
0787: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesReopenPurchaseOrder(org.kuali.module.purap.document.PurchaseOrderDocument)
0788: */
0789: public void generateEntriesReopenPurchaseOrder(
0790: PurchaseOrderDocument po) {
0791: LOG.debug("generateEntriesReopenPurchaseOrder() started");
0792:
0793: // Set outstanding encumbered quantity/amount on items
0794: for (Iterator items = po.getItems().iterator(); items.hasNext();) {
0795: PurchaseOrderItem item = (PurchaseOrderItem) items.next();
0796:
0797: String logItmNbr = "Item # " + item.getItemLineNumber();
0798:
0799: if (!item.isItemActiveIndicator()) {
0800: continue;
0801: }
0802:
0803: KualiDecimal itemAmount = null;
0804: if (!item.getItemType()
0805: .isQuantityBasedGeneralLedgerIndicator()) {
0806: LOG.debug("generateEntriesReopenPurchaseOrder() "
0807: + logItmNbr + " Calculate based on amounts");
0808: itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO
0809: : item.getItemOutstandingEncumberedAmount();
0810: } else {
0811: LOG.debug("generateEntriesReopenPurchaseOrder() "
0812: + logItmNbr + " Calculate based on quantities");
0813: itemAmount = item
0814: .getItemOutstandingEncumberedQuantity()
0815: .multiply(
0816: new KualiDecimal(item
0817: .getItemUnitPrice()));
0818: }
0819:
0820: KualiDecimal accountTotal = ZERO;
0821: PurchaseOrderAccount lastAccount = null;
0822: if (itemAmount.compareTo(ZERO) != 0) {
0823: // Sort accounts
0824: Collections
0825: .sort((List) item.getSourceAccountingLines());
0826:
0827: for (Iterator iterAcct = item
0828: .getSourceAccountingLines().iterator(); iterAcct
0829: .hasNext();) {
0830: PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct
0831: .next();
0832: if (!acct.isEmpty()) {
0833: KualiDecimal acctAmount = itemAmount.multiply(
0834: new KualiDecimal(acct
0835: .getAccountLinePercent()
0836: .toString())).divide(
0837: PurapConstants.HUNDRED);
0838: accountTotal = accountTotal.add(acctAmount);
0839: acct
0840: .setAlternateAmountForGLEntryCreation(acctAmount);
0841: lastAccount = acct;
0842: }
0843: }
0844:
0845: // account for rounding by adjusting last account as needed
0846: if (lastAccount != null) {
0847: KualiDecimal difference = itemAmount
0848: .subtract(accountTotal);
0849: LOG
0850: .debug("generateEntriesReopenPurchaseOrder() difference: "
0851: + logItmNbr + " " + difference);
0852:
0853: KualiDecimal amount = lastAccount
0854: .getAlternateAmountForGLEntryCreation();
0855: if (ObjectUtils.isNotNull(amount)) {
0856: lastAccount
0857: .setAlternateAmountForGLEntryCreation(amount
0858: .add(difference));
0859: } else {
0860: lastAccount
0861: .setAlternateAmountForGLEntryCreation(difference);
0862: }
0863: }
0864:
0865: }
0866: }// endfor
0867:
0868: po.setSourceAccountingLines(purapAccountingService
0869: .generateSummaryWithNoZeroTotalsUsingAlternateAmount(po
0870: .getItemsActiveOnly()));
0871: generalLedgerPendingEntryService
0872: .generateGeneralLedgerPendingEntries(po);
0873: saveGLEntries(po.getGeneralLedgerPendingEntries());
0874: LOG
0875: .debug("generateEntriesReopenPurchaseOrder() gl entries created; exit method");
0876: }
0877:
0878: /**
0879: * @see org.kuali.module.purap.service.PurapGeneralLedgerService#generateEntriesVoidPurchaseOrder(org.kuali.module.purap.document.PurchaseOrderDocument)
0880: */
0881: public void generateEntriesVoidPurchaseOrder(
0882: PurchaseOrderDocument po) {
0883: LOG.debug("generateEntriesVoidPurchaseOrder() started");
0884:
0885: // Set outstanding encumbered quantity/amount on items
0886: for (Iterator items = po.getItems().iterator(); items.hasNext();) {
0887: PurchaseOrderItem item = (PurchaseOrderItem) items.next();
0888:
0889: String logItmNbr = "Item # " + item.getItemLineNumber();
0890:
0891: if (!item.isItemActiveIndicator()) {
0892: continue;
0893: }
0894:
0895: KualiDecimal itemAmount = null;
0896: if (!item.getItemType()
0897: .isQuantityBasedGeneralLedgerIndicator()) {
0898: LOG.debug("generateEntriesVoidPurchaseOrder() "
0899: + logItmNbr + " Calculate based on amounts");
0900: itemAmount = item.getItemOutstandingEncumberedAmount() == null ? ZERO
0901: : item.getItemOutstandingEncumberedAmount();
0902: } else {
0903: LOG.debug("generateEntriesVoidPurchaseOrder() "
0904: + logItmNbr + " Calculate based on quantities");
0905: itemAmount = item
0906: .getItemOutstandingEncumberedQuantity()
0907: .multiply(
0908: new KualiDecimal(item
0909: .getItemUnitPrice()));
0910: }
0911:
0912: KualiDecimal accountTotal = ZERO;
0913: PurchaseOrderAccount lastAccount = null;
0914: if (itemAmount.compareTo(ZERO) != 0) {
0915: // Sort accounts
0916: Collections
0917: .sort((List) item.getSourceAccountingLines());
0918:
0919: for (Iterator iterAcct = item
0920: .getSourceAccountingLines().iterator(); iterAcct
0921: .hasNext();) {
0922: PurchaseOrderAccount acct = (PurchaseOrderAccount) iterAcct
0923: .next();
0924: if (!acct.isEmpty()) {
0925: KualiDecimal acctAmount = itemAmount.multiply(
0926: new KualiDecimal(acct
0927: .getAccountLinePercent()
0928: .toString())).divide(
0929: PurapConstants.HUNDRED);
0930: accountTotal = accountTotal.add(acctAmount);
0931: acct
0932: .setAlternateAmountForGLEntryCreation(acctAmount);
0933: lastAccount = acct;
0934: }
0935: }
0936:
0937: // account for rounding by adjusting last account as needed
0938: if (lastAccount != null) {
0939: KualiDecimal difference = itemAmount
0940: .subtract(accountTotal);
0941: LOG
0942: .debug("generateEntriesVoidPurchaseOrder() difference: "
0943: + logItmNbr + " " + difference);
0944:
0945: KualiDecimal amount = lastAccount
0946: .getAlternateAmountForGLEntryCreation();
0947: if (ObjectUtils.isNotNull(amount)) {
0948: lastAccount
0949: .setAlternateAmountForGLEntryCreation(amount
0950: .add(difference));
0951: } else {
0952: lastAccount
0953: .setAlternateAmountForGLEntryCreation(difference);
0954: }
0955: }
0956:
0957: }
0958: }// endfor
0959:
0960: po.setSourceAccountingLines(purapAccountingService
0961: .generateSummaryWithNoZeroTotalsUsingAlternateAmount(po
0962: .getItemsActiveOnly()));
0963: generalLedgerPendingEntryService
0964: .generateGeneralLedgerPendingEntries(po);
0965: saveGLEntries(po.getGeneralLedgerPendingEntries());
0966: LOG
0967: .debug("generateEntriesVoidPurchaseOrder() gl entries created; exit method");
0968: }
0969:
0970: /**
0971: * 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
0972: * the encumbrance values on the PO and saves the PO
0973: *
0974: * @param preq PREQ for invoice
0975: * @return List of accounting lines to use to create the pending general ledger entries
0976: */
0977: private List<SourceAccountingLine> relieveEncumbrance(
0978: PaymentRequestDocument preq) {
0979: LOG.debug("relieveEncumbrance() started");
0980:
0981: Map encumbranceAccountMap = new HashMap();
0982: PurchaseOrderDocument po = purchaseOrderService
0983: .getCurrentPurchaseOrder(preq
0984: .getPurchaseOrderIdentifier());
0985:
0986: // Get each item one by one
0987: for (Iterator items = preq.getItems().iterator(); items
0988: .hasNext();) {
0989: PaymentRequestItem preqItem = (PaymentRequestItem) items
0990: .next();
0991: PurchaseOrderItem poItem = getPoItem(po, preqItem
0992: .getItemLineNumber(), preqItem.getItemType());
0993:
0994: boolean takeAll = false; // Set this true if we relieve the entire encumbrance
0995: KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item
0996:
0997: String logItmNbr = "Item # " + preqItem.getItemLineNumber();
0998: LOG.debug("relieveEncumbrance() " + logItmNbr);
0999:
1000: // If there isn't a PO item or the extended price is 0, we don't need encumbrances
1001: if (poItem == null) {
1002: LOG
1003: .debug("relieveEncumbrance() "
1004: + logItmNbr
1005: + " No encumbrances required because po item is null");
1006: } else if (ZERO.compareTo(preqItem.getExtendedPrice()) == 0) {
1007: /*
1008: * This is a specialized case where PREQ item being processed must adjust the PO item's outstanding encumbered
1009: * quantity. This kind of scenario is mostly seen on warranty type items. The following must be true to do this:
1010: * PREQ item Extended Price must be ZERO, PREQ item invoice quantity must be not empty and not ZERO, and PO item is
1011: * quantity based PO item unit cost is ZERO
1012: */
1013: LOG
1014: .debug("relieveEncumbrance() "
1015: + logItmNbr
1016: + " No GL encumbrances required because extended price is ZERO");
1017: if ((poItem.getItemQuantity() != null)
1018: && ((BigDecimal.ZERO.compareTo(poItem
1019: .getItemUnitPrice())) == 0)) {
1020: // po has order quantity and unit price is ZERO... reduce outstanding encumbered quantity
1021: LOG.debug("relieveEncumbrance() " + logItmNbr
1022: + " Calculate po oustanding encumbrance");
1023:
1024: // Do encumbrance calculations based on quantity
1025: if ((preqItem.getItemQuantity() != null)
1026: && ((ZERO.compareTo(preqItem
1027: .getItemQuantity())) != 0)) {
1028: KualiDecimal invoiceQuantity = preqItem
1029: .getItemQuantity();
1030: KualiDecimal outstandingEncumberedQuantity = poItem
1031: .getItemOutstandingEncumberedQuantity() == null ? ZERO
1032: : poItem
1033: .getItemOutstandingEncumberedQuantity();
1034:
1035: KualiDecimal encumbranceQuantity;
1036: if (invoiceQuantity
1037: .compareTo(outstandingEncumberedQuantity) > 0) {
1038: // We bought more than the quantity on the PO
1039: LOG
1040: .debug("relieveEncumbrance() "
1041: + logItmNbr
1042: + " we bought more than the qty on the PO");
1043: encumbranceQuantity = outstandingEncumberedQuantity;
1044: poItem
1045: .setItemOutstandingEncumberedQuantity(ZERO);
1046: } else {
1047: encumbranceQuantity = invoiceQuantity;
1048: poItem
1049: .setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity
1050: .subtract(encumbranceQuantity));
1051: LOG
1052: .debug("relieveEncumbrance() "
1053: + logItmNbr
1054: + " adjusting oustanding encunbrance qty - encumbranceQty "
1055: + encumbranceQuantity
1056: + " outstandingEncumberedQty "
1057: + poItem
1058: .getItemOutstandingEncumberedQuantity());
1059: }
1060:
1061: if (poItem.getItemInvoicedTotalQuantity() == null) {
1062: poItem
1063: .setItemInvoicedTotalQuantity(invoiceQuantity);
1064: } else {
1065: poItem.setItemInvoicedTotalQuantity(poItem
1066: .getItemInvoicedTotalQuantity()
1067: .add(invoiceQuantity));
1068: }
1069: }
1070: }
1071:
1072: } else {
1073: LOG.debug("relieveEncumbrance() " + logItmNbr
1074: + " Calculate encumbrance GL entries");
1075:
1076: // Do we calculate the encumbrance amount based on quantity or amount?
1077: if (poItem.getItemType()
1078: .isQuantityBasedGeneralLedgerIndicator()) {
1079: LOG
1080: .debug("relieveEncumbrance() "
1081: + logItmNbr
1082: + " Calculate encumbrance based on quantity");
1083:
1084: // Do encumbrance calculations based on quantity
1085: KualiDecimal invoiceQuantity = preqItem
1086: .getItemQuantity() == null ? ZERO
1087: : preqItem.getItemQuantity();
1088: KualiDecimal outstandingEncumberedQuantity = poItem
1089: .getItemOutstandingEncumberedQuantity() == null ? ZERO
1090: : poItem
1091: .getItemOutstandingEncumberedQuantity();
1092:
1093: KualiDecimal encumbranceQuantity;
1094: if (invoiceQuantity
1095: .compareTo(outstandingEncumberedQuantity) > 0) {
1096: // We bought more than the quantity on the PO
1097: LOG
1098: .debug("relieveEncumbrance() "
1099: + logItmNbr
1100: + " we bought more than the qty on the PO");
1101: encumbranceQuantity = outstandingEncumberedQuantity;
1102: poItem
1103: .setItemOutstandingEncumberedQuantity(ZERO);
1104: takeAll = true;
1105: } else {
1106: encumbranceQuantity = invoiceQuantity;
1107: poItem
1108: .setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity
1109: .subtract(encumbranceQuantity));
1110: if (ZERO
1111: .compareTo(poItem
1112: .getItemOutstandingEncumberedQuantity()) == 0) {
1113: takeAll = true;
1114: }
1115: LOG
1116: .debug("relieveEncumbrance() "
1117: + logItmNbr
1118: + " encumbranceQty "
1119: + encumbranceQuantity
1120: + " outstandingEncumberedQty "
1121: + poItem
1122: .getItemOutstandingEncumberedQuantity());
1123: }
1124:
1125: if (poItem.getItemInvoicedTotalQuantity() == null) {
1126: poItem
1127: .setItemInvoicedTotalQuantity(invoiceQuantity);
1128: } else {
1129: poItem.setItemInvoicedTotalQuantity(poItem
1130: .getItemInvoicedTotalQuantity().add(
1131: invoiceQuantity));
1132: }
1133:
1134: itemDisEncumber = encumbranceQuantity
1135: .multiply(new KualiDecimal(poItem
1136: .getItemUnitPrice()));
1137: } else {
1138: LOG.debug("relieveEncumbrance() " + logItmNbr
1139: + " Calculate encumbrance based on amount");
1140:
1141: // Do encumbrance calculations based on amount only
1142: if ((poItem.getItemOutstandingEncumberedAmount()
1143: .bigDecimalValue().signum() == -1)
1144: && (preqItem.getExtendedPrice()
1145: .bigDecimalValue().signum() == -1)) {
1146: LOG
1147: .debug("relieveEncumbrance() "
1148: + logItmNbr
1149: + " Outstanding Encumbered amount is negative: "
1150: + poItem
1151: .getItemOutstandingEncumberedAmount());
1152: if (preqItem
1153: .getExtendedPrice()
1154: .compareTo(
1155: poItem
1156: .getItemOutstandingEncumberedAmount()) >= 0) {
1157: // extended price is equal to or greater than outstanding encumbered
1158: itemDisEncumber = preqItem
1159: .getExtendedPrice();
1160: } else {
1161: // extended price is less than outstanding encumbered
1162: takeAll = true;
1163: itemDisEncumber = poItem
1164: .getItemOutstandingEncumberedAmount();
1165: }
1166: } else {
1167: LOG
1168: .debug("relieveEncumbrance() "
1169: + logItmNbr
1170: + " Outstanding Encumbered amount is positive or ZERO: "
1171: + poItem
1172: .getItemOutstandingEncumberedAmount());
1173: if (poItem.getItemOutstandingEncumberedAmount()
1174: .compareTo(preqItem.getExtendedPrice()) >= 0) {
1175: // outstanding amount is equal to or greater than extended price
1176: itemDisEncumber = preqItem
1177: .getExtendedPrice();
1178: } else {
1179: // outstanding amount is less than extended price
1180: takeAll = true;
1181: itemDisEncumber = poItem
1182: .getItemOutstandingEncumberedAmount();
1183: }
1184: }
1185: }
1186:
1187: LOG.debug("relieveEncumbrance() " + logItmNbr
1188: + " Amount to disencumber: " + itemDisEncumber);
1189:
1190: KualiDecimal newOutstandingEncumberedAmount = poItem
1191: .getItemOutstandingEncumberedAmount().subtract(
1192: itemDisEncumber);
1193: LOG.debug("relieveEncumbrance() " + logItmNbr
1194: + " New Outstanding Encumbered amount is : "
1195: + newOutstandingEncumberedAmount);
1196: poItem
1197: .setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1198:
1199: KualiDecimal newInvoicedTotalAmount = poItem
1200: .getItemInvoicedTotalAmount().add(
1201: preqItem.getExtendedPrice());
1202: LOG.debug("relieveEncumbrance() " + logItmNbr
1203: + " New Invoiced Total Amount is: "
1204: + newInvoicedTotalAmount);
1205: poItem
1206: .setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1207:
1208: // Sort accounts
1209: Collections.sort((List) poItem
1210: .getSourceAccountingLines());
1211:
1212: // make the list of accounts for the disencumbrance entry
1213: PurchaseOrderAccount lastAccount = null;
1214: KualiDecimal accountTotal = ZERO;
1215: for (Iterator accountIter = poItem
1216: .getSourceAccountingLines().iterator(); accountIter
1217: .hasNext();) {
1218: PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter
1219: .next();
1220: if (!account.isEmpty()) {
1221: KualiDecimal encumbranceAmount = null;
1222: SourceAccountingLine acctString = account
1223: .generateSourceAccountingLine();
1224: if (takeAll) {
1225: // fully paid; remove remaining encumbrance
1226: encumbranceAmount = account
1227: .getItemAccountOutstandingEncumbranceAmount();
1228: account
1229: .setItemAccountOutstandingEncumbranceAmount(ZERO);
1230: LOG.debug("relieveEncumbrance() "
1231: + logItmNbr + " take all");
1232: } else {
1233: // amount = item disencumber * account percent / 100
1234: encumbranceAmount = itemDisEncumber
1235: .multiply(
1236: new KualiDecimal(
1237: account
1238: .getAccountLinePercent()
1239: .toString()))
1240: .divide(HUNDRED);
1241:
1242: account
1243: .setItemAccountOutstandingEncumbranceAmount(account
1244: .getItemAccountOutstandingEncumbranceAmount()
1245: .subtract(encumbranceAmount));
1246:
1247: // For rounding check at the end
1248: accountTotal = accountTotal
1249: .add(encumbranceAmount);
1250:
1251: // If we are zeroing out the encumbrance, we don't need to adjust for rounding
1252: if (!takeAll) {
1253: lastAccount = account;
1254: }
1255: }
1256:
1257: LOG.debug("relieveEncumbrance() " + logItmNbr
1258: + " " + acctString + " = "
1259: + encumbranceAmount);
1260: if (ObjectUtils.isNull(encumbranceAccountMap
1261: .get(acctString))) {
1262: encumbranceAccountMap.put(acctString,
1263: encumbranceAmount);
1264: } else {
1265: KualiDecimal amt = (KualiDecimal) encumbranceAccountMap
1266: .get(acctString);
1267: encumbranceAccountMap.put(acctString, amt
1268: .add(encumbranceAmount));
1269: }
1270:
1271: }
1272: }
1273:
1274: // account for rounding by adjusting last account as needed
1275: if (lastAccount != null) {
1276: KualiDecimal difference = itemDisEncumber
1277: .subtract(accountTotal);
1278: LOG.debug("relieveEncumbrance() difference: "
1279: + logItmNbr + " " + difference);
1280:
1281: SourceAccountingLine acctString = lastAccount
1282: .generateSourceAccountingLine();
1283: KualiDecimal amount = (KualiDecimal) encumbranceAccountMap
1284: .get(acctString);
1285: if (ObjectUtils.isNull(amount)) {
1286: encumbranceAccountMap.put(acctString,
1287: difference);
1288: } else {
1289: encumbranceAccountMap.put(acctString, amount
1290: .add(difference));
1291: }
1292:
1293: lastAccount
1294: .setItemAccountOutstandingEncumbranceAmount(lastAccount
1295: .getItemAccountOutstandingEncumbranceAmount()
1296: .subtract(difference));
1297: }
1298: }
1299: }// endfor
1300:
1301: List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
1302: for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter
1303: .hasNext();) {
1304: SourceAccountingLine acctString = (SourceAccountingLine) iter
1305: .next();
1306: KualiDecimal amount = (KualiDecimal) encumbranceAccountMap
1307: .get(acctString);
1308: if (amount.doubleValue() != 0) {
1309: acctString.setAmount(amount);
1310: encumbranceAccounts.add(acctString);
1311: }
1312: }
1313:
1314: purchaseOrderService.saveDocumentNoValidation(po);
1315:
1316: return encumbranceAccounts;
1317: }
1318:
1319: /**
1320: * 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
1321: * encumbrance values on the PO and saves the PO
1322: *
1323: * @param preq PREQ for invoice
1324: * @return List of accounting lines to use to create the pending general ledger entries
1325: */
1326: private List reencumberEncumbrance(PaymentRequestDocument preq) {
1327: LOG.debug("reencumberEncumbrance() started");
1328:
1329: PurchaseOrderDocument po = purchaseOrderService
1330: .getCurrentPurchaseOrder(preq
1331: .getPurchaseOrderIdentifier());
1332: Map encumbranceAccountMap = new HashMap();
1333:
1334: // Get each item one by one
1335: for (Iterator items = preq.getItems().iterator(); items
1336: .hasNext();) {
1337: PaymentRequestItem payRequestItem = (PaymentRequestItem) items
1338: .next();
1339: PurchaseOrderItem poItem = getPoItem(po, payRequestItem
1340: .getItemLineNumber(), payRequestItem.getItemType());
1341:
1342: KualiDecimal itemReEncumber = null; // Amount to reencumber for this item
1343:
1344: String logItmNbr = "Item # "
1345: + payRequestItem.getItemLineNumber();
1346: LOG.debug("reencumberEncumbrance() " + logItmNbr);
1347:
1348: // If there isn't a PO item or the extended price is 0, we don't need encumbrances
1349: if ((poItem == null)
1350: || (payRequestItem.getExtendedPrice().doubleValue() == 0)) {
1351: LOG.debug("reencumberEncumbrance() " + logItmNbr
1352: + " No encumbrances required");
1353: } else {
1354: LOG.debug("reencumberEncumbrance() " + logItmNbr
1355: + " Calculate encumbrance GL entries");
1356:
1357: // Do we calculate the encumbrance amount based on quantity or amount?
1358: if (poItem.getItemType()
1359: .isQuantityBasedGeneralLedgerIndicator()) {
1360: LOG
1361: .debug("reencumberEncumbrance() "
1362: + logItmNbr
1363: + " Calculate encumbrance based on quantity");
1364:
1365: // Do disencumbrance calculations based on quantity
1366: KualiDecimal preqQuantity = payRequestItem
1367: .getItemQuantity() == null ? ZERO
1368: : payRequestItem.getItemQuantity();
1369: KualiDecimal outstandingEncumberedQuantity = poItem
1370: .getItemOutstandingEncumberedQuantity() == null ? ZERO
1371: : poItem
1372: .getItemOutstandingEncumberedQuantity();
1373: KualiDecimal invoicedTotal = poItem
1374: .getItemInvoicedTotalQuantity() == null ? ZERO
1375: : poItem.getItemInvoicedTotalQuantity();
1376:
1377: poItem.setItemInvoicedTotalQuantity(invoicedTotal
1378: .subtract(preqQuantity));
1379: poItem
1380: .setItemOutstandingEncumberedQuantity(outstandingEncumberedQuantity
1381: .add(preqQuantity));
1382:
1383: itemReEncumber = preqQuantity
1384: .multiply(new KualiDecimal(poItem
1385: .getItemUnitPrice()));
1386: } else {
1387: LOG.debug("reencumberEncumbrance() " + logItmNbr
1388: + " Calculate encumbrance based on amount");
1389:
1390: itemReEncumber = payRequestItem.getExtendedPrice();
1391: // if re-encumber amount is more than original PO ordered amount... do not exceed ordered amount
1392: // this prevents negative encumbrance
1393: if ((poItem.getExtendedPrice() != null)
1394: && (poItem.getExtendedPrice()
1395: .bigDecimalValue().signum() < 0)) {
1396: // po item extended cost is negative
1397: if ((poItem.getExtendedPrice()
1398: .compareTo(itemReEncumber)) > 0) {
1399: itemReEncumber = poItem.getExtendedPrice();
1400: }
1401: } else if ((poItem.getExtendedPrice() != null)
1402: && (poItem.getExtendedPrice()
1403: .bigDecimalValue().signum() >= 0)) {
1404: // po item extended cost is positive
1405: if ((poItem.getExtendedPrice()
1406: .compareTo(itemReEncumber)) < 0) {
1407: itemReEncumber = poItem.getExtendedPrice();
1408: }
1409: }
1410: }
1411:
1412: LOG.debug("reencumberEncumbrance() " + logItmNbr
1413: + " Amount to reencumber: " + itemReEncumber);
1414:
1415: KualiDecimal outstandingEncumberedAmount = poItem
1416: .getItemOutstandingEncumberedAmount() == null ? ZERO
1417: : poItem.getItemOutstandingEncumberedAmount();
1418: LOG
1419: .debug("reencumberEncumbrance() "
1420: + logItmNbr
1421: + " PO Item Outstanding Encumbrance Amount set to: "
1422: + outstandingEncumberedAmount);
1423: KualiDecimal newOutstandingEncumberedAmount = outstandingEncumberedAmount
1424: .add(itemReEncumber);
1425: LOG
1426: .debug("reencumberEncumbrance() "
1427: + logItmNbr
1428: + " New PO Item Outstanding Encumbrance Amount to set: "
1429: + newOutstandingEncumberedAmount);
1430: poItem
1431: .setItemOutstandingEncumberedAmount(newOutstandingEncumberedAmount);
1432:
1433: KualiDecimal invoicedTotalAmount = poItem
1434: .getItemInvoicedTotalAmount() == null ? ZERO
1435: : poItem.getItemInvoicedTotalAmount();
1436: LOG.debug("reencumberEncumbrance() " + logItmNbr
1437: + " PO Item Invoiced Total Amount set to: "
1438: + invoicedTotalAmount);
1439: KualiDecimal newInvoicedTotalAmount = invoicedTotalAmount
1440: .subtract(payRequestItem.getExtendedPrice());
1441: LOG.debug("reencumberEncumbrance() " + logItmNbr
1442: + " New PO Item Invoiced Total Amount to set: "
1443: + newInvoicedTotalAmount);
1444: poItem
1445: .setItemInvoicedTotalAmount(newInvoicedTotalAmount);
1446:
1447: // make the list of accounts for the reencumbrance entry
1448: PurchaseOrderAccount lastAccount = null;
1449: KualiDecimal accountTotal = ZERO;
1450:
1451: // Sort accounts
1452: Collections.sort((List) poItem
1453: .getSourceAccountingLines());
1454:
1455: for (Iterator accountIter = poItem
1456: .getSourceAccountingLines().iterator(); accountIter
1457: .hasNext();) {
1458: PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter
1459: .next();
1460: if (!account.isEmpty()) {
1461: SourceAccountingLine acctString = account
1462: .generateSourceAccountingLine();
1463:
1464: // amount = item reencumber * account percent / 100
1465: KualiDecimal reencumbranceAmount = itemReEncumber
1466: .multiply(
1467: new KualiDecimal(
1468: account
1469: .getAccountLinePercent()
1470: .toString()))
1471: .divide(HUNDRED);
1472:
1473: account
1474: .setItemAccountOutstandingEncumbranceAmount(account
1475: .getItemAccountOutstandingEncumbranceAmount()
1476: .add(reencumbranceAmount));
1477:
1478: // For rounding check at the end
1479: accountTotal = accountTotal
1480: .add(reencumbranceAmount);
1481:
1482: lastAccount = account;
1483:
1484: LOG.debug("reencumberEncumbrance() "
1485: + logItmNbr + " " + acctString + " = "
1486: + reencumbranceAmount);
1487: if (encumbranceAccountMap
1488: .containsKey(acctString)) {
1489: KualiDecimal currentAmount = (KualiDecimal) encumbranceAccountMap
1490: .get(acctString);
1491: encumbranceAccountMap.put(acctString,
1492: reencumbranceAmount
1493: .add(currentAmount));
1494: } else {
1495: encumbranceAccountMap.put(acctString,
1496: reencumbranceAmount);
1497: }
1498: }
1499: }
1500:
1501: // account for rounding by adjusting last account as needed
1502: if (lastAccount != null) {
1503: KualiDecimal difference = itemReEncumber
1504: .subtract(accountTotal);
1505: LOG.debug("reencumberEncumbrance() difference: "
1506: + logItmNbr + " " + difference);
1507:
1508: SourceAccountingLine acctString = lastAccount
1509: .generateSourceAccountingLine();
1510: KualiDecimal amount = (KualiDecimal) encumbranceAccountMap
1511: .get(acctString);
1512: if (amount == null) {
1513: encumbranceAccountMap.put(acctString,
1514: difference);
1515: } else {
1516: encumbranceAccountMap.put(acctString, amount
1517: .add(difference));
1518: }
1519: lastAccount
1520: .setItemAccountOutstandingEncumbranceAmount(lastAccount
1521: .getItemAccountOutstandingEncumbranceAmount()
1522: .add(difference));
1523: }
1524: }
1525: }
1526:
1527: purchaseOrderService.saveDocumentNoValidation(po);
1528:
1529: List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
1530: for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter
1531: .hasNext();) {
1532: SourceAccountingLine acctString = (SourceAccountingLine) iter
1533: .next();
1534: KualiDecimal amount = (KualiDecimal) encumbranceAccountMap
1535: .get(acctString);
1536: if (amount.doubleValue() != 0) {
1537: acctString.setAmount(amount);
1538: encumbranceAccounts.add(acctString);
1539: }
1540: }
1541:
1542: return encumbranceAccounts;
1543: }
1544:
1545: /**
1546: * 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
1547: * encumbrance values on the PO and saves the PO
1548: *
1549: * @param cm Credit Memo document
1550: * @param po Purchase Order document modify encumbrances
1551: * @return List of accounting lines to use to create the pending general ledger entries
1552: */
1553: private List<SourceAccountingLine> getCreditMemoEncumbrance(
1554: CreditMemoDocument cm, PurchaseOrderDocument po,
1555: boolean cancel) {
1556: LOG.debug("getCreditMemoEncumbrance() started");
1557:
1558: if (ObjectUtils.isNull(po)) {
1559: return null;
1560: }
1561:
1562: if (cancel) {
1563: LOG
1564: .debug("getCreditMemoEncumbrance() Receiving items back from vendor (cancelled CM)");
1565: } else {
1566: LOG
1567: .debug("getCreditMemoEncumbrance() Returning items to vendor");
1568: }
1569:
1570: Map encumbranceAccountMap = new HashMap();
1571:
1572: // Get each item one by one
1573: for (Iterator items = cm.getItems().iterator(); items.hasNext();) {
1574: CreditMemoItem cmItem = (CreditMemoItem) items.next();
1575: PurchaseOrderItem poItem = getPoItem(po, cmItem
1576: .getItemLineNumber(), cmItem.getItemType());
1577:
1578: KualiDecimal itemDisEncumber = null; // Amount to disencumber for this item
1579:
1580: String logItmNbr = "Item # " + cmItem.getItemLineNumber();
1581: LOG.debug("getCreditMemoEncumbrance() " + logItmNbr);
1582:
1583: // If there isn't a PO item or the extended price is 0, we don't need encumbrances
1584: if ((poItem == null) || (cmItem.getExtendedPrice() == null)
1585: || (cmItem.getExtendedPrice().doubleValue() == 0)) {
1586: LOG.debug("getCreditMemoEncumbrance() " + logItmNbr
1587: + " No encumbrances required");
1588: } else {
1589: LOG.debug("getCreditMemoEncumbrance() " + logItmNbr
1590: + " Calculate encumbrance GL entries");
1591:
1592: // Do we calculate the encumbrance amount based on quantity or amount?
1593: if (poItem.getItemType()
1594: .isQuantityBasedGeneralLedgerIndicator()) {
1595: LOG
1596: .debug("getCreditMemoEncumbrance() "
1597: + logItmNbr
1598: + " Calculate encumbrance based on quantity");
1599:
1600: // Do encumbrance calculations based on quantity
1601: KualiDecimal cmQuantity = cmItem.getItemQuantity() == null ? ZERO
1602: : cmItem.getItemQuantity();
1603:
1604: KualiDecimal encumbranceQuantityChange = calculateQuantityChange(
1605: cancel, poItem, cmQuantity);
1606:
1607: LOG
1608: .debug("getCreditMemoEncumbrance() "
1609: + logItmNbr
1610: + " encumbranceQtyChange "
1611: + encumbranceQuantityChange
1612: + " outstandingEncumberedQty "
1613: + poItem
1614: .getItemOutstandingEncumberedQuantity()
1615: + " invoicedTotalQuantity "
1616: + poItem
1617: .getItemInvoicedTotalQuantity());
1618:
1619: itemDisEncumber = encumbranceQuantityChange
1620: .multiply(new KualiDecimal(poItem
1621: .getItemUnitPrice()));
1622: } else {
1623: LOG.debug("getCreditMemoEncumbrance() " + logItmNbr
1624: + " Calculate encumbrance based on amount");
1625:
1626: // Do encumbrance calculations based on amount only
1627: if (cancel) {
1628: // Decrease encumbrance
1629: itemDisEncumber = cmItem.getExtendedPrice()
1630: .multiply(new KualiDecimal("-1"));
1631:
1632: if (poItem.getItemOutstandingEncumberedAmount()
1633: .add(itemDisEncumber).doubleValue() < 0) {
1634: LOG
1635: .debug("getCreditMemoEncumbrance() Cancel overflow");
1636:
1637: itemDisEncumber = poItem
1638: .getItemOutstandingEncumberedAmount();
1639: }
1640: } else {
1641: // Increase encumbrance
1642: itemDisEncumber = cmItem.getExtendedPrice();
1643:
1644: if (poItem.getItemOutstandingEncumberedAmount()
1645: .add(itemDisEncumber).doubleValue() > poItem
1646: .getExtendedPrice().doubleValue()) {
1647: LOG
1648: .debug("getCreditMemoEncumbrance() Create overflow");
1649:
1650: itemDisEncumber = poItem
1651: .getExtendedPrice()
1652: .subtract(
1653: poItem
1654: .getItemOutstandingEncumberedAmount());
1655: }
1656: }
1657: }
1658:
1659: poItem.setItemOutstandingEncumberedAmount(poItem
1660: .getItemOutstandingEncumberedAmount().add(
1661: itemDisEncumber));
1662: poItem.setItemInvoicedTotalAmount(poItem
1663: .getItemInvoicedTotalAmount().subtract(
1664: itemDisEncumber));
1665:
1666: LOG.debug("getCreditMemoEncumbrance() " + logItmNbr
1667: + " Amount to disencumber: " + itemDisEncumber);
1668:
1669: // Sort accounts
1670: Collections.sort((List) poItem
1671: .getSourceAccountingLines());
1672:
1673: // make the list of accounts for the disencumbrance entry
1674: PurchaseOrderAccount lastAccount = null;
1675: KualiDecimal accountTotal = ZERO;
1676: // Collections.sort((List)poItem.getSourceAccountingLines());
1677: for (Iterator accountIter = poItem
1678: .getSourceAccountingLines().iterator(); accountIter
1679: .hasNext();) {
1680: PurchaseOrderAccount account = (PurchaseOrderAccount) accountIter
1681: .next();
1682: if (!account.isEmpty()) {
1683: KualiDecimal encumbranceAmount = null;
1684:
1685: SourceAccountingLine acctString = account
1686: .generateSourceAccountingLine();
1687: // amount = item disencumber * account percent / 100
1688: encumbranceAmount = itemDisEncumber.multiply(
1689: new KualiDecimal(account
1690: .getAccountLinePercent()
1691: .toString())).divide(
1692: new KualiDecimal(100));
1693:
1694: account
1695: .setItemAccountOutstandingEncumbranceAmount(account
1696: .getItemAccountOutstandingEncumbranceAmount()
1697: .add(encumbranceAmount));
1698:
1699: // For rounding check at the end
1700: accountTotal = accountTotal
1701: .add(encumbranceAmount);
1702:
1703: lastAccount = account;
1704:
1705: LOG.debug("getCreditMemoEncumbrance() "
1706: + logItmNbr + " " + acctString + " = "
1707: + encumbranceAmount);
1708:
1709: if (encumbranceAccountMap.get(acctString) == null) {
1710: encumbranceAccountMap.put(acctString,
1711: encumbranceAmount);
1712: } else {
1713: KualiDecimal amt = (KualiDecimal) encumbranceAccountMap
1714: .get(acctString);
1715: encumbranceAccountMap.put(acctString, amt
1716: .add(encumbranceAmount));
1717: }
1718: }
1719: }
1720:
1721: // account for rounding by adjusting last account as needed
1722: if (lastAccount != null) {
1723: KualiDecimal difference = itemDisEncumber
1724: .subtract(accountTotal);
1725: LOG.debug("getCreditMemoEncumbrance() difference: "
1726: + logItmNbr + " " + difference);
1727:
1728: SourceAccountingLine acctString = lastAccount
1729: .generateSourceAccountingLine();
1730: KualiDecimal amount = (KualiDecimal) encumbranceAccountMap
1731: .get(acctString);
1732: if (amount == null) {
1733: encumbranceAccountMap.put(acctString,
1734: difference);
1735: } else {
1736: encumbranceAccountMap.put(acctString, amount
1737: .add(difference));
1738: }
1739: lastAccount
1740: .setItemAccountOutstandingEncumbranceAmount(lastAccount
1741: .getItemAccountOutstandingEncumbranceAmount()
1742: .add(difference));
1743: }
1744: }
1745: }
1746:
1747: List<SourceAccountingLine> encumbranceAccounts = new ArrayList();
1748: for (Iterator iter = encumbranceAccountMap.keySet().iterator(); iter
1749: .hasNext();) {
1750: SourceAccountingLine acctString = (SourceAccountingLine) iter
1751: .next();
1752: KualiDecimal amount = (KualiDecimal) encumbranceAccountMap
1753: .get(acctString);
1754: if (amount.doubleValue() != 0) {
1755: acctString.setAmount(amount);
1756: encumbranceAccounts.add(acctString);
1757: }
1758: }
1759:
1760: purchaseOrderService.saveDocumentNoValidation(po);
1761:
1762: return encumbranceAccounts;
1763: }
1764:
1765: /**
1766: * Save the given general ledger entries
1767: *
1768: * @param glEntries List of GeneralLedgerPendingEntries to be saved
1769: */
1770: private void saveGLEntries(List<GeneralLedgerPendingEntry> glEntries) {
1771: LOG.debug("saveGLEntries() started");
1772: businessObjectService.save(glEntries);
1773: }
1774:
1775: /**
1776: * Save the given accounts for the given document.
1777: *
1778: * @param sourceLines Accounts to be saved
1779: * @param purapDocumentIdentifier Purap document id for accounts
1780: */
1781: private void savePaymentRequestSummaryAccounts(
1782: List<SourceAccountingLine> sourceLines,
1783: Integer purapDocumentIdentifier) {
1784: LOG.debug("savePaymentRequestSummaryAccounts() started");
1785: paymentRequestService
1786: .deleteSummaryAccounts(purapDocumentIdentifier);
1787: List<PaymentRequestSummaryAccount> summaryAccounts = new ArrayList();
1788: for (SourceAccountingLine account : sourceLines) {
1789: summaryAccounts.add(new PaymentRequestSummaryAccount(
1790: account, purapDocumentIdentifier));
1791: }
1792: businessObjectService.save(summaryAccounts);
1793: }
1794:
1795: /**
1796: * Retrieve summary accounts based on given purap document id
1797: *
1798: * @param purapDocumentIdentifier Purap document id for accounts
1799: * @return List of summary accounts
1800: */
1801: private List getPaymentRequestSummaryAccounts(
1802: Integer purapDocumentIdentifier) {
1803: LOG.debug("getPaymentRequestSummaryAccounts() started");
1804: Map fieldValues = new HashMap();
1805: fieldValues.put(PurapPropertyConstants.PURAP_DOC_ID,
1806: purapDocumentIdentifier);
1807: return new ArrayList(businessObjectService.findMatching(
1808: PaymentRequestSummaryAccount.class, fieldValues));
1809: }
1810:
1811: /**
1812: * Find item in PO based on given parameters. Must send either the line # or item type.
1813: *
1814: * @param po Purchase Order containing list of items
1815: * @param nbr Line # of desired item (could be null)
1816: * @param itemType Item type of desired item
1817: * @return PurcahseOrderItem found matching given criteria
1818: */
1819: private PurchaseOrderItem getPoItem(PurchaseOrderDocument po,
1820: Integer nbr, ItemType itemType) {
1821: LOG.debug("getPoItem() started");
1822: for (Iterator iter = po.getItems().iterator(); iter.hasNext();) {
1823: PurchaseOrderItem element = (PurchaseOrderItem) iter.next();
1824: if (itemType.isItemTypeAboveTheLineIndicator()) {
1825: if (ObjectUtils.isNotNull(nbr)
1826: && ObjectUtils.isNotNull(element
1827: .getItemLineNumber())
1828: && (nbr.compareTo(element.getItemLineNumber()) == 0)) {
1829: return element;
1830: }
1831: } else {
1832: if (element.getItemTypeCode().equals(
1833: itemType.getItemTypeCode())) {
1834: return element;
1835: }
1836: }
1837: }
1838: return null;
1839: }
1840:
1841: /**
1842: * Format description for general ledger entry. Currently making sure length is less than 40 char.
1843: *
1844: * @param description String to be formatted
1845: * @return Formatted String
1846: */
1847: private String entryDescription(String description) {
1848: if (description != null && description.length() > 40) {
1849: return description.toString().substring(0, 39);
1850: } else {
1851: return description;
1852: }
1853: }
1854:
1855: /**
1856: * Calculate quantity change for creating Credit Memo entries
1857: *
1858: * @param cancel Boolean indicating whether entries are for creation or cancellation of credit memo
1859: * @param poItem Purchase Order Item
1860: * @param cmQuantity Quantity on credit memo item
1861: * @return Calculated change
1862: */
1863: private KualiDecimal calculateQuantityChange(boolean cancel,
1864: PurchaseOrderItem poItem, KualiDecimal cmQuantity) {
1865: LOG.debug("calculateQuantityChange() started");
1866:
1867: // Calculate quantity change & adjust invoiced quantity & outstanding encumbered quantity
1868: KualiDecimal encumbranceQuantityChange = null;
1869: if (cancel) {
1870: encumbranceQuantityChange = cmQuantity
1871: .multiply(new KualiDecimal("-1"));
1872: } else {
1873: encumbranceQuantityChange = cmQuantity;
1874: }
1875: poItem.setItemInvoicedTotalQuantity(poItem
1876: .getItemInvoicedTotalQuantity().subtract(
1877: encumbranceQuantityChange));
1878: poItem.setItemOutstandingEncumberedQuantity(poItem
1879: .getItemOutstandingEncumberedQuantity().add(
1880: encumbranceQuantityChange));
1881:
1882: // Check for overflows
1883: if (cancel) {
1884: if (poItem.getItemOutstandingEncumberedQuantity()
1885: .doubleValue() < 0) {
1886: LOG.debug("calculateQuantityChange() Cancel overflow");
1887: KualiDecimal difference = poItem
1888: .getItemOutstandingEncumberedQuantity().abs();
1889: poItem.setItemOutstandingEncumberedQuantity(ZERO);
1890: poItem.setItemInvoicedTotalQuantity(poItem
1891: .getItemQuantity());
1892: encumbranceQuantityChange = encumbranceQuantityChange
1893: .add(difference);
1894: }
1895: } else {
1896: if (poItem.getItemInvoicedTotalQuantity().doubleValue() < 0) {
1897: LOG.debug("calculateQuantityChange() Create overflow");
1898: KualiDecimal difference = poItem
1899: .getItemInvoicedTotalQuantity().abs();
1900: poItem.setItemOutstandingEncumberedQuantity(poItem
1901: .getItemQuantity());
1902: poItem.setItemInvoicedTotalQuantity(ZERO);
1903: encumbranceQuantityChange = encumbranceQuantityChange
1904: .add(difference);
1905: }
1906: }
1907: return encumbranceQuantityChange;
1908: }
1909:
1910: public void setDateTimeService(DateTimeService dateTimeService) {
1911: this .dateTimeService = dateTimeService;
1912: }
1913:
1914: public void setBusinessObjectService(
1915: BusinessObjectService businessObjectService) {
1916: this .businessObjectService = businessObjectService;
1917: }
1918:
1919: public void setGeneralLedgerPendingEntryService(
1920: GeneralLedgerPendingEntryService generalLedgerPendingEntryService) {
1921: this .generalLedgerPendingEntryService = generalLedgerPendingEntryService;
1922: }
1923:
1924: public void setKualiRuleService(KualiRuleService kualiRuleService) {
1925: this .kualiRuleService = kualiRuleService;
1926: }
1927:
1928: public void setPurapAccountingService(
1929: PurapAccountingService purapAccountingService) {
1930: this .purapAccountingService = purapAccountingService;
1931: }
1932:
1933: public void setKualiConfigurationService(
1934: KualiConfigurationService kualiConfigurationService) {
1935: this .kualiConfigurationService = kualiConfigurationService;
1936: }
1937:
1938: public void setUniversityDateService(
1939: UniversityDateService universityDateService) {
1940: this .universityDateService = universityDateService;
1941: }
1942:
1943: public void setPaymentRequestService(
1944: PaymentRequestService paymentRequestService) {
1945: this .paymentRequestService = paymentRequestService;
1946: }
1947:
1948: public void setPurchaseOrderService(
1949: PurchaseOrderService purchaseOrderService) {
1950: this.purchaseOrderService = purchaseOrderService;
1951: }
1952: }
|