/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.module.purap.businessobject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.kuali.kfs.module.purap.PurapConstants;
import org.kuali.kfs.module.purap.PurapPropertyConstants;
import org.kuali.kfs.module.purap.document.PaymentRequestDocument;
import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
import org.kuali.kfs.module.purap.document.service.AccountsPayableService;
import org.kuali.kfs.module.purap.document.service.PurapService;
import org.kuali.kfs.module.purap.exception.PurError;
import org.kuali.kfs.module.purap.util.ExpiredOrClosedAccountEntry;
import org.kuali.kfs.module.purap.util.PurApItemUtils;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.util.ObjectPopulationUtils;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.krad.util.ObjectUtils;
/**
* Payment Request Item Business Object.
*/
public class PaymentRequestItem extends AccountsPayableItemBase {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentRequestItem.class);
private BigDecimal purchaseOrderItemUnitPrice;
private KualiDecimal itemOutstandingInvoiceQuantity;
private KualiDecimal itemOutstandingInvoiceAmount;
/**
* Default constructor.
*/
public PaymentRequestItem() {
}
/**
* preq item constructor - Delegate
*
* @param poi - purchase order item
* @param preq - payment request document
*/
public PaymentRequestItem(PurchaseOrderItem poi, PaymentRequestDocument preq) {
this(poi, preq, new HashMap<String, ExpiredOrClosedAccountEntry>());
}
/**
* Constructs a new payment request item, but also merges expired accounts.
*
* @param poi - purchase order item
* @param preq - payment request document
* @param expiredOrClosedAccountList - list of expired or closed accounts to merge
*/
public PaymentRequestItem(PurchaseOrderItem poi, PaymentRequestDocument preq, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
// copy base attributes w/ extra array of fields not to be copied
ObjectPopulationUtils.populateFromBaseClass(PurApItemBase.class, poi, this, PurapConstants.PREQ_ITEM_UNCOPYABLE_FIELDS);
setItemDescription(poi.getItemDescription());
//New Source Line should be set for PaymentRequestItem
resetAccount();
// set up accounts
List accounts = new ArrayList();
for (PurApAccountingLine account : poi.getSourceAccountingLines()) {
PurchaseOrderAccount poa = (PurchaseOrderAccount) account;
// check if this account is expired/closed and replace as needed
SpringContext.getBean(AccountsPayableService.class).processExpiredOrClosedAccount(poa, expiredOrClosedAccountList);
//KFSMI-4522 copy an accounting line with zero dollar amount if system parameter allows
if (poa.getAmount().isZero()) {
if (SpringContext.getBean(AccountsPayableService.class).canCopyAccountingLinesWithZeroAmount()) {
accounts.add(new PaymentRequestAccount(this, poa));
}
} else {
accounts.add(new PaymentRequestAccount(this, poa));
}
}
this.setSourceAccountingLines(accounts);
this.getUseTaxItems().clear();
//List<PurApItemUseTax> newUseTaxItems = new ArrayList<PurApItemUseTax>();
/// this.setUseTaxItems(newUseTaxItems);
//copy use tax items over, and blank out keys (useTaxId and itemIdentifier)
/*
this.getUseTaxItems().clear();
for (PurApItemUseTax useTaxItem : poi.getUseTaxItems()) {
PaymentRequestItemUseTax newItemUseTax = new PaymentRequestItemUseTax(useTaxItem);
this.getUseTaxItems().add(newItemUseTax);
}
*/
// clear amount and desc on below the line - we probably don't need that null
// itemType check but it's there just in case remove if it causes problems
// also do this if of type service
if ((ObjectUtils.isNotNull(this.getItemType()) && this.getItemType().isAmountBasedGeneralLedgerIndicator())) {
// setting unit price to be null to be more consistent with other below the line
this.setItemUnitPrice(null);
}
// copy custom
this.purchaseOrderItemUnitPrice = poi.getItemUnitPrice();
// this.purchaseOrderCommodityCode = poi.getPurchaseOrderCommodityCd();
// set doc fields
this.setPurapDocumentIdentifier(preq.getPurapDocumentIdentifier());
this.setPurapDocument(preq);
}
/**
* Retrieves a purchase order item by inspecting the item type to see if its above the line or below the line and returns the
* appropriate type.
*
* @return - purchase order item
*/
@Override
public PurchaseOrderItem getPurchaseOrderItem() {
if (ObjectUtils.isNotNull(this.getPurapDocumentIdentifier())) {
if (ObjectUtils.isNull(this.getPaymentRequest())) {
this.refreshReferenceObject(PurapPropertyConstants.PURAP_DOC);
}
}
// ideally we should do this a different way - maybe move it all into the service or save this info somehow (make sure and
// update though)
if (getPaymentRequest() != null) {
PurchaseOrderDocument po = getPaymentRequest().getPurchaseOrderDocument();
PurchaseOrderItem poi = null;
if (this.getItemType().isLineItemIndicator()) {
List items = po.getItems();
if (items != null) {
for (Object object : items) {
PurchaseOrderItem item = (PurchaseOrderItem) object;
if (item != null && item.getItemLineNumber().equals(this.getItemLineNumber())) {
poi = item;
break;
}
}
}
}
else {
poi = (PurchaseOrderItem) SpringContext.getBean(PurapService.class).getBelowTheLineByType(po, this.getItemType());
}
if (poi != null) {
return poi;
}
else {
if (LOG.isDebugEnabled()) {
LOG.debug("getPurchaseOrderItem() Returning null because PurchaseOrderItem object for line number" + getItemLineNumber() + "or itemType " + getItemTypeCode() + " is null");
}
return null;
}
}
else {
LOG.error("getPurchaseOrderItem() Returning null because paymentRequest object is null");
throw new PurError("Payment Request Object in Purchase Order item line number " + getItemLineNumber() + "or itemType " + getItemTypeCode() + " is null");
}
}
public KualiDecimal getPoOutstandingAmount() {
PurchaseOrderItem poi = getPurchaseOrderItem();
if(ObjectUtils.isNull(this.getPurchaseOrderItemUnitPrice()) || KualiDecimal.ZERO.equals(this.getPurchaseOrderItemUnitPrice())){
return null;
}else{
return this.getPoOutstandingAmount(poi);
}
}
private KualiDecimal getPoOutstandingAmount(PurchaseOrderItem poi) {
if (poi == null) {
return KualiDecimal.ZERO;
}
else {
return poi.getItemOutstandingEncumberedAmount();
}
}
public KualiDecimal getPoOriginalAmount() {
PurchaseOrderItem poi = getPurchaseOrderItem();
if (poi == null) {
return null;
}
else {
return poi.getExtendedPrice();
}
}
/**
* Exists due to a setter requirement by the htmlControlAttribute
* @deprecated
* @param amount - po outstanding amount
*/
@Deprecated
public void setPoOutstandingAmount(KualiDecimal amount) {
// do nothing
}
public KualiDecimal getPoOutstandingQuantity() {
PurchaseOrderItem poi = getPurchaseOrderItem();
if (poi == null) {
return null;
}
else {
if(PurapConstants.ItemTypeCodes.ITEM_TYPE_SERVICE_CODE.equals(this.getItemTypeCode())){
return null;
}else{
return poi.getOutstandingQuantity();
}
}
}
/**
* Exists due to a setter requirement by the htmlControlAttribute
* @deprecated
* @param amount - po outstanding quantity
*/
@Deprecated
public void setPoOutstandingQuantity(KualiDecimal qty) {
// do nothing
}
public BigDecimal getPurchaseOrderItemUnitPrice() {
return purchaseOrderItemUnitPrice;
}
public BigDecimal getOriginalAmountfromPO() {
return purchaseOrderItemUnitPrice;
}
public void setOriginalAmountfromPO(BigDecimal purchaseOrderItemUnitPrice) {
// Do nothing
}
public void setPurchaseOrderItemUnitPrice(BigDecimal purchaseOrderItemUnitPrice) {
this.purchaseOrderItemUnitPrice = purchaseOrderItemUnitPrice;
}
public KualiDecimal getItemOutstandingInvoiceAmount() {
return itemOutstandingInvoiceAmount;
}
public void setItemOutstandingInvoiceAmount(KualiDecimal itemOutstandingInvoiceAmount) {
this.itemOutstandingInvoiceAmount = itemOutstandingInvoiceAmount;
}
public KualiDecimal getItemOutstandingInvoiceQuantity() {
return itemOutstandingInvoiceQuantity;
}
public void setItemOutstandingInvoiceQuantity(KualiDecimal itemOutstandingInvoiceQuantity) {
this.itemOutstandingInvoiceQuantity = itemOutstandingInvoiceQuantity;
}
public PaymentRequestDocument getPaymentRequest() {
if (ObjectUtils.isNotNull(getPurapDocumentIdentifier())) {
if (ObjectUtils.isNull(getPurapDocument())) {
this.refreshReferenceObject(PurapPropertyConstants.PURAP_DOC);
}
}
return super.getPurapDocument();
}
public void setPaymentRequest(PaymentRequestDocument paymentRequest) {
this.setPurapDocument(paymentRequest);
}
public void generateAccountListFromPoItemAccounts(List<PurApAccountingLine> accounts) {
for (PurApAccountingLine line : accounts) {
PurchaseOrderAccount poa = (PurchaseOrderAccount) line;
if (!line.isEmpty()) {
getSourceAccountingLines().add(new PaymentRequestAccount(this, poa));
}
}
}
/**
* @see org.kuali.kfs.module.purap.businessobject.PurApItem#getAccountingLineClass()
*/
@Override
public Class getAccountingLineClass() {
return PaymentRequestAccount.class;
}
public boolean isDisplayOnPreq() {
PurchaseOrderItem poi = getPurchaseOrderItem();
if (ObjectUtils.isNull(poi)) {
LOG.debug("poi was null");
return false;
}
// if the po item is not active... skip it
if (!poi.isItemActiveIndicator()) {
if (LOG.isDebugEnabled()) {
LOG.debug("poi was not active: " + poi.toString());
}
return false;
}
ItemType poiType = poi.getItemType();
if (poiType.isQuantityBasedGeneralLedgerIndicator()) {
if (poi.getItemQuantity().isGreaterThan(poi.getItemInvoicedTotalQuantity())) {
return true;
}
else {
if (ObjectUtils.isNotNull(this.getItemQuantity()) && this.getItemQuantity().isGreaterThan(KualiDecimal.ZERO)) {
return true;
}
}
return false;
}
else { // not quantity based
if (poi.getItemOutstandingEncumberedAmount().isGreaterThan(KualiDecimal.ZERO)) {
return true;
}
else {
if (PurApItemUtils.isNonZeroExtended(this)) {
return true;
}
return false;
}
}
}
/**
* sets account line percentage to zero.
*
* @see org.kuali.kfs.module.purap.businessobject.PurApItem#resetAccount()
*/
@Override
public void resetAccount() {
super.resetAccount();
this.getNewSourceLine().setAmount(null);
this.getNewSourceLine().setAccountLinePercent(null);
}
/**
* Added for electronic invoice
*/
public void addToUnitPrice(BigDecimal addThisValue) {
if (getItemUnitPrice() == null) {
setItemUnitPrice(BigDecimal.ZERO);
}
BigDecimal addedPrice = getItemUnitPrice().add(addThisValue);
setItemUnitPrice(addedPrice);
}
public void addToExtendedPrice(KualiDecimal addThisValue) {
if (getExtendedPrice() == null) {
setExtendedPrice(KualiDecimal.ZERO);
}
KualiDecimal addedPrice = getExtendedPrice().add(addThisValue);
setExtendedPrice(addedPrice);
}
@Override
public Class getUseTaxClass() {
return PaymentRequestItemUseTax.class;
}
}