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 }