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    }