001 /* 002 * Copyright 2011 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 */ 016 017 package org.kuali.kfs.module.purap.businessobject; 018 019 import java.math.BigDecimal; 020 import java.util.ArrayList; 021 import java.util.HashMap; 022 import java.util.List; 023 024 import org.kuali.kfs.module.purap.PurapConstants; 025 import org.kuali.kfs.module.purap.PurapPropertyConstants; 026 import org.kuali.kfs.module.purap.document.PaymentRequestDocument; 027 import org.kuali.kfs.module.purap.document.PurchaseOrderDocument; 028 import org.kuali.kfs.module.purap.document.service.AccountsPayableService; 029 import org.kuali.kfs.module.purap.document.service.PurapService; 030 import org.kuali.kfs.module.purap.exception.PurError; 031 import org.kuali.kfs.module.purap.util.ExpiredOrClosedAccountEntry; 032 import org.kuali.kfs.module.purap.util.PurApItemUtils; 033 import org.kuali.kfs.module.purap.util.PurApObjectUtils; 034 import org.kuali.kfs.sys.context.SpringContext; 035 import org.kuali.rice.kns.util.KualiDecimal; 036 import org.kuali.rice.kns.util.ObjectUtils; 037 038 /** 039 * Payment Request Item Business Object. 040 */ 041 public class PaymentRequestItem extends AccountsPayableItemBase { 042 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentRequestItem.class); 043 044 private BigDecimal purchaseOrderItemUnitPrice; 045 private KualiDecimal itemOutstandingInvoiceQuantity; 046 private KualiDecimal itemOutstandingInvoiceAmount; 047 048 /** 049 * Default constructor. 050 */ 051 public PaymentRequestItem() { 052 053 } 054 055 /** 056 * preq item constructor - Delegate 057 * 058 * @param poi - purchase order item 059 * @param preq - payment request document 060 */ 061 public PaymentRequestItem(PurchaseOrderItem poi, PaymentRequestDocument preq) { 062 this(poi, preq, new HashMap<String, ExpiredOrClosedAccountEntry>()); 063 } 064 065 /** 066 * Constructs a new payment request item, but also merges expired accounts. 067 * 068 * @param poi - purchase order item 069 * @param preq - payment request document 070 * @param expiredOrClosedAccountList - list of expired or closed accounts to merge 071 */ 072 public PaymentRequestItem(PurchaseOrderItem poi, PaymentRequestDocument preq, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) { 073 074 // copy base attributes w/ extra array of fields not to be copied 075 PurApObjectUtils.populateFromBaseClass(PurApItemBase.class, poi, this, PurapConstants.PREQ_ITEM_UNCOPYABLE_FIELDS); 076 077 setItemDescription(poi.getItemDescription()); 078 079 //New Source Line should be set for PaymentRequestItem 080 resetAccount(); 081 082 // set up accounts 083 List accounts = new ArrayList(); 084 for (PurApAccountingLine account : poi.getSourceAccountingLines()) { 085 PurchaseOrderAccount poa = (PurchaseOrderAccount) account; 086 087 // check if this account is expired/closed and replace as needed 088 SpringContext.getBean(AccountsPayableService.class).processExpiredOrClosedAccount(poa, expiredOrClosedAccountList); 089 090 accounts.add(new PaymentRequestAccount(this, poa)); 091 } 092 this.setSourceAccountingLines(accounts); 093 this.getUseTaxItems().clear(); 094 //List<PurApItemUseTax> newUseTaxItems = new ArrayList<PurApItemUseTax>(); 095 /// this.setUseTaxItems(newUseTaxItems); 096 //copy use tax items over, and blank out keys (useTaxId and itemIdentifier) 097 /* 098 this.getUseTaxItems().clear(); 099 for (PurApItemUseTax useTaxItem : poi.getUseTaxItems()) { 100 PaymentRequestItemUseTax newItemUseTax = new PaymentRequestItemUseTax(useTaxItem); 101 this.getUseTaxItems().add(newItemUseTax); 102 103 } 104 */ 105 106 // clear amount and desc on below the line - we probably don't need that null 107 // itemType check but it's there just in case remove if it causes problems 108 // also do this if of type service 109 if ((ObjectUtils.isNotNull(this.getItemType()) && this.getItemType().isAmountBasedGeneralLedgerIndicator())) { 110 // setting unit price to be null to be more consistent with other below the line 111 this.setItemUnitPrice(null); 112 } 113 114 // copy custom 115 this.purchaseOrderItemUnitPrice = poi.getItemUnitPrice(); 116 // this.purchaseOrderCommodityCode = poi.getPurchaseOrderCommodityCd(); 117 118 // set doc fields 119 this.setPurapDocumentIdentifier(preq.getPurapDocumentIdentifier()); 120 this.setPurapDocument(preq); 121 } 122 123 /** 124 * Retreives a purchase order item by inspecting the item type to see if its above the line or below the line and returns the 125 * appropriate type. 126 * 127 * @return - purchase order item 128 */ 129 public PurchaseOrderItem getPurchaseOrderItem() { 130 if (ObjectUtils.isNotNull(this.getPurapDocumentIdentifier())) { 131 if (ObjectUtils.isNull(this.getPaymentRequest())) { 132 this.refreshReferenceObject(PurapPropertyConstants.PURAP_DOC); 133 } 134 } 135 // ideally we should do this a different way - maybe move it all into the service or save this info somehow (make sure and 136 // update though) 137 if (getPaymentRequest() != null) { 138 PurchaseOrderDocument po = getPaymentRequest().getPurchaseOrderDocument(); 139 PurchaseOrderItem poi = null; 140 if (this.getItemType().isLineItemIndicator()) { 141 poi = (PurchaseOrderItem) po.getItem(this.getItemLineNumber().intValue() - 1); 142 // throw error if line numbers don't match 143 } 144 else { 145 poi = (PurchaseOrderItem) SpringContext.getBean(PurapService.class).getBelowTheLineByType(po, this.getItemType()); 146 } 147 if (poi != null) { 148 return poi; 149 } 150 else { 151 LOG.debug("getPurchaseOrderItem() Returning null because PurchaseOrderItem object for line number" + getItemLineNumber() + "or itemType " + getItemTypeCode() + " is null"); 152 return null; 153 } 154 } 155 else { 156 157 LOG.error("getPurchaseOrderItem() Returning null because paymentRequest object is null"); 158 throw new PurError("Payment Request Object in Purchase Order item line number " + getItemLineNumber() + "or itemType " + getItemTypeCode() + " is null"); 159 } 160 } 161 162 public KualiDecimal getPoOutstandingAmount() { 163 PurchaseOrderItem poi = getPurchaseOrderItem(); 164 if(ObjectUtils.isNull(this.getPurchaseOrderItemUnitPrice()) || KualiDecimal.ZERO.equals(this.getPurchaseOrderItemUnitPrice())){ 165 return null; 166 }else{ 167 return this.getPoOutstandingAmount(poi); 168 } 169 } 170 171 private KualiDecimal getPoOutstandingAmount(PurchaseOrderItem poi) { 172 if (poi == null) { 173 return KualiDecimal.ZERO; 174 } 175 else { 176 return poi.getItemOutstandingEncumberedAmount(); 177 } 178 } 179 180 public KualiDecimal getPoOriginalAmount() { 181 PurchaseOrderItem poi = getPurchaseOrderItem(); 182 if (poi == null) { 183 return null; 184 } 185 else { 186 return poi.getExtendedPrice(); 187 } 188 } 189 190 /** 191 * Exists due to a setter requirement by the htmlControlAttribute 192 * @deprecated 193 * @param amount - po outstanding amount 194 */ 195 public void setPoOutstandingAmount(KualiDecimal amount) { 196 // do nothing 197 } 198 199 200 public KualiDecimal getPoOutstandingQuantity() { 201 PurchaseOrderItem poi = getPurchaseOrderItem(); 202 if (poi == null) { 203 return null; 204 } 205 else { 206 if(PurapConstants.ItemTypeCodes.ITEM_TYPE_SERVICE_CODE.equals(this.getItemTypeCode())){ 207 return null; 208 }else{ 209 return poi.getOutstandingQuantity(); 210 } 211 } 212 } 213 214 /** 215 * Exists due to a setter requirement by the htmlControlAttribute 216 * @deprecated 217 * @param amount - po outstanding quantity 218 */ 219 public void setPoOutstandingQuantity(KualiDecimal qty) { 220 // do nothing 221 } 222 223 public BigDecimal getPurchaseOrderItemUnitPrice() { 224 return purchaseOrderItemUnitPrice; 225 } 226 227 public BigDecimal getOriginalAmountfromPO() { 228 return purchaseOrderItemUnitPrice; 229 } 230 231 public void setOriginalAmountfromPO(BigDecimal purchaseOrderItemUnitPrice) { 232 // Do nothing 233 } 234 235 public void setPurchaseOrderItemUnitPrice(BigDecimal purchaseOrderItemUnitPrice) { 236 this.purchaseOrderItemUnitPrice = purchaseOrderItemUnitPrice; 237 } 238 239 public KualiDecimal getItemOutstandingInvoiceAmount() { 240 return itemOutstandingInvoiceAmount; 241 } 242 243 public void setItemOutstandingInvoiceAmount(KualiDecimal itemOutstandingInvoiceAmount) { 244 this.itemOutstandingInvoiceAmount = itemOutstandingInvoiceAmount; 245 } 246 247 public KualiDecimal getItemOutstandingInvoiceQuantity() { 248 return itemOutstandingInvoiceQuantity; 249 } 250 251 public void setItemOutstandingInvoiceQuantity(KualiDecimal itemOutstandingInvoiceQuantity) { 252 this.itemOutstandingInvoiceQuantity = itemOutstandingInvoiceQuantity; 253 } 254 255 public PaymentRequestDocument getPaymentRequest() { 256 if (ObjectUtils.isNotNull(getPurapDocumentIdentifier())) { 257 if (ObjectUtils.isNull(getPurapDocument())) { 258 this.refreshReferenceObject(PurapPropertyConstants.PURAP_DOC); 259 } 260 } 261 return super.getPurapDocument(); 262 } 263 264 public void setPaymentRequest(PaymentRequestDocument paymentRequest) { 265 this.setPurapDocument(paymentRequest); 266 } 267 268 public void generateAccountListFromPoItemAccounts(List<PurApAccountingLine> accounts) { 269 for (PurApAccountingLine line : accounts) { 270 PurchaseOrderAccount poa = (PurchaseOrderAccount) line; 271 if (!line.isEmpty()) { 272 getSourceAccountingLines().add(new PaymentRequestAccount(this, poa)); 273 } 274 } 275 } 276 277 /** 278 * @see org.kuali.kfs.module.purap.businessobject.PurApItem#getAccountingLineClass() 279 */ 280 public Class getAccountingLineClass() { 281 return PaymentRequestAccount.class; 282 } 283 284 public boolean isDisplayOnPreq() { 285 PurchaseOrderItem poi = getPurchaseOrderItem(); 286 if (ObjectUtils.isNull(poi)) { 287 LOG.debug("poi was null"); 288 return false; 289 } 290 291 // if the po item is not active... skip it 292 if (!poi.isItemActiveIndicator()) { 293 LOG.debug("poi was not active: " + poi.toString()); 294 return false; 295 } 296 297 ItemType poiType = poi.getItemType(); 298 299 if (poiType.isQuantityBasedGeneralLedgerIndicator()) { 300 if (poi.getItemQuantity().isGreaterThan(poi.getItemInvoicedTotalQuantity())) { 301 return true; 302 } 303 else { 304 if (ObjectUtils.isNotNull(this.getItemQuantity()) && this.getItemQuantity().isGreaterThan(KualiDecimal.ZERO)) { 305 return true; 306 } 307 } 308 309 return false; 310 } 311 else { // not quantity based 312 if (poi.getItemOutstandingEncumberedAmount().isGreaterThan(KualiDecimal.ZERO)) { 313 return true; 314 } 315 else { 316 if (PurApItemUtils.isNonZeroExtended(this)) { 317 return true; 318 } 319 return false; 320 } 321 322 } 323 } 324 325 /** 326 * sets account line percentage to zero. 327 * 328 * @see org.kuali.kfs.module.purap.businessobject.PurApItem#resetAccount() 329 */ 330 @Override 331 public void resetAccount() { 332 super.resetAccount(); 333 this.getNewSourceLine().setAccountLinePercent(new BigDecimal(0)); 334 } 335 336 /** 337 * Added for electronic invoice 338 */ 339 public void addToUnitPrice(BigDecimal addThisValue) { 340 if (getItemUnitPrice() == null) { 341 setItemUnitPrice(BigDecimal.ZERO); 342 } 343 BigDecimal addedPrice = getItemUnitPrice().add(addThisValue); 344 setItemUnitPrice(addedPrice); 345 } 346 347 public void addToExtendedPrice(KualiDecimal addThisValue) { 348 if (getExtendedPrice() == null) { 349 setExtendedPrice(KualiDecimal.ZERO); 350 } 351 KualiDecimal addedPrice = getExtendedPrice().add(addThisValue); 352 setExtendedPrice(addedPrice); 353 } 354 355 @Override 356 public Class getUseTaxClass() { 357 return PaymentRequestItemUseTax.class; 358 } 359 360 361 }