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    package org.kuali.kfs.module.purap.document;
017    
018    import java.math.BigDecimal;
019    import java.text.MessageFormat;
020    import java.util.ArrayList;
021    import java.util.Arrays;
022    import java.util.Iterator;
023    import java.util.LinkedHashMap;
024    import java.util.List;
025    
026    import org.apache.commons.lang.ArrayUtils;
027    import org.apache.commons.lang.StringUtils;
028    import org.kuali.kfs.module.purap.PurapConstants;
029    import org.kuali.kfs.module.purap.PurapParameterConstants;
030    import org.kuali.kfs.module.purap.PurapPropertyConstants;
031    import org.kuali.kfs.module.purap.PurapWorkflowConstants.NodeDetails;
032    import org.kuali.kfs.module.purap.businessobject.ItemType;
033    import org.kuali.kfs.module.purap.businessobject.PurApAccountingLine;
034    import org.kuali.kfs.module.purap.businessobject.PurApItem;
035    import org.kuali.kfs.module.purap.businessobject.PurApItemBase;
036    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderView;
037    import org.kuali.kfs.module.purap.businessobject.SensitiveData;
038    import org.kuali.kfs.module.purap.businessobject.Status;
039    import org.kuali.kfs.module.purap.document.service.PurapService;
040    import org.kuali.kfs.module.purap.document.service.impl.PurapServiceImpl;
041    import org.kuali.kfs.module.purap.service.PurapAccountingService;
042    import org.kuali.kfs.module.purap.service.SensitiveDataService;
043    import org.kuali.kfs.module.purap.util.PurApRelatedViews;
044    import org.kuali.kfs.sys.KFSConstants.AdHocPaymentIndicator;
045    import org.kuali.kfs.sys.businessobject.AccountingLine;
046    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
047    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
048    import org.kuali.kfs.sys.businessobject.SourceAccountingLine;
049    import org.kuali.kfs.sys.context.SpringContext;
050    import org.kuali.kfs.sys.document.AccountingDocumentBase;
051    import org.kuali.kfs.sys.document.AmountTotaling;
052    import org.kuali.kfs.sys.service.UniversityDateService;
053    import org.kuali.kfs.vnd.businessobject.VendorAddress;
054    import org.kuali.kfs.vnd.businessobject.VendorDetail;
055    import org.kuali.kfs.vnd.document.service.VendorService;
056    import org.kuali.rice.kew.exception.WorkflowException;
057    import org.kuali.rice.kns.bo.Country;
058    import org.kuali.rice.kns.rule.event.ApproveDocumentEvent;
059    import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
060    import org.kuali.rice.kns.rule.event.RouteDocumentEvent;
061    import org.kuali.rice.kns.service.CountryService;
062    import org.kuali.rice.kns.service.ParameterService;
063    import org.kuali.rice.kns.util.KualiDecimal;
064    import org.kuali.rice.kns.util.ObjectUtils;
065    import org.kuali.rice.kns.util.TypedArrayList;
066    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
067    
068    /**
069     * Base class for Purchasing-Accounts Payable Documents.
070     */
071    public abstract class PurchasingAccountsPayableDocumentBase extends AccountingDocumentBase implements PurchasingAccountsPayableDocument, AmountTotaling {
072    
073        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PurchasingAccountsPayableDocumentBase.class);
074    
075        // SHARED FIELDS BETWEEN REQUISITION, PURCHASE ORDER, PAYMENT REQUEST, AND CREDIT MEMO
076        protected Integer purapDocumentIdentifier;
077        protected String statusCode;
078        protected Integer vendorHeaderGeneratedIdentifier;
079        protected Integer vendorDetailAssignedIdentifier;
080        protected String vendorCustomerNumber;
081        protected String vendorName;
082        protected String vendorLine1Address;
083        protected String vendorLine2Address;
084        protected String vendorCityName;
085        protected String vendorStateCode;
086        protected String vendorAddressInternationalProvinceName;
087        protected String vendorPostalCode;
088        protected String vendorCountryCode;
089        protected Integer accountsPayablePurchasingDocumentLinkIdentifier;
090        protected boolean useTaxIndicator;
091        protected String vendorAttentionName;
092        
093        // NOT PERSISTED IN DB
094        protected String vendorNumber;
095        protected Integer vendorAddressGeneratedIdentifier;
096        protected Boolean overrideWorkflowButtons = null;
097        protected transient PurApRelatedViews relatedViews;   
098        protected boolean sensitive;
099        
100        // COLLECTIONS
101        protected List<PurApItem> items;
102        protected List<SourceAccountingLine> accountsForRouting; // don't use me for anything else!!
103        
104        // REFERENCE OBJECTS
105        protected Status status;
106        protected VendorDetail vendorDetail;
107        protected Country vendorCountry;
108    
109        // STATIC
110        public transient String[] belowTheLineTypes;
111    
112        // workaround for purapOjbCollectionHelper - remove when merged into rice
113        public boolean allowDeleteAwareCollection = true;
114        
115    
116        /**
117         * Default constructor to be overridden.
118         */
119        public PurchasingAccountsPayableDocumentBase() {
120            items = new TypedArrayList(getItemClass());
121        }
122    
123        protected GeneralLedgerPendingEntry getFirstPendingGLEntry() {
124            if (ObjectUtils.isNotNull(getGeneralLedgerPendingEntries()) && !getGeneralLedgerPendingEntries().isEmpty()) {
125                return (GeneralLedgerPendingEntry)getGeneralLedgerPendingEntries().get(0);
126            }
127            return null;
128        }
129        
130        public Integer getPostingYearFromPendingGLEntries() {
131            GeneralLedgerPendingEntry glpe = getFirstPendingGLEntry();
132            if (ObjectUtils.isNotNull(glpe)) {
133                return glpe.getUniversityFiscalYear();
134            }
135            return null;
136        }
137        
138        public String getPostingPeriodCodeFromPendingGLEntries() {
139            GeneralLedgerPendingEntry glpe = getFirstPendingGLEntry();
140            if (ObjectUtils.isNotNull(glpe)) {
141                return glpe.getUniversityFiscalPeriodCode();
142            }
143            return null;
144        }
145    
146        public List<SourceAccountingLine> getAccountsForRouting() {
147            if (accountsForRouting == null) {
148                populateAccountsForRouting();
149            }
150            return accountsForRouting;
151        }
152    
153        public void setAccountsForRouting(List<SourceAccountingLine> accountsForRouting) {
154            this.accountsForRouting = accountsForRouting;
155        }
156    
157        /**
158         * Makes sure that accounts for routing has been generated, so that other information can be retrieved from that
159         */
160        protected void populateAccountsForRouting() {
161            SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(this);
162            setAccountsForRouting(SpringContext.getBean(PurapAccountingService.class).generateSummary(getItems()));
163            // need to refresh to get the references for the searchable attributes (ie status) and for invoking route levels (ie account
164            // objects) -hjs
165            refreshNonUpdateableReferences();
166            for (SourceAccountingLine sourceLine : getAccountsForRouting()) {
167                sourceLine.refreshNonUpdateableReferences();
168            }
169        }
170        
171        public boolean isSensitive() {
172            List<SensitiveData> sensitiveData = SpringContext.getBean(SensitiveDataService.class).getSensitiveDatasAssignedByRelatedDocId(getAccountsPayablePurchasingDocumentLinkIdentifier());
173            if (ObjectUtils.isNotNull(sensitiveData) && !sensitiveData.isEmpty()) {
174                return true;
175            }
176            return false;
177        }
178    
179        /**
180         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#isInquiryRendered()
181         */
182        public boolean isInquiryRendered() {
183            return isPostingYearPrior();    
184        }
185        
186        /**
187         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#isPostingYearNext()
188         */
189        public boolean isPostingYearNext() {
190            Integer currentFY = SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
191            return (getPostingYear().compareTo(currentFY) > 0);
192        }
193    
194        /**
195         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#isPostingYearPrior()
196         */
197        public boolean isPostingYearPrior() {
198            Integer currentFY = SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
199            return (getPostingYear().compareTo(currentFY) < 0);
200        }
201        
202        
203        /**
204         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getPostingYearNextOrCurrent()
205         */
206        public Integer getPostingYearNextOrCurrent() {
207            if (isPostingYearNext()) {
208                //FY is set to next; use it
209                return getPostingYear();
210            }
211            //FY is NOT set to next; use CURRENT
212            return SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
213        }
214        
215        /**
216         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getItemClass()
217         */
218        @SuppressWarnings("rawtypes")
219        public abstract Class getItemClass();
220    
221        @SuppressWarnings("rawtypes")
222        public abstract Class getItemUseTaxClass();
223        
224        /**
225         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getPurApSourceDocumentIfPossible()
226         */
227        public abstract PurchasingAccountsPayableDocument getPurApSourceDocumentIfPossible();
228    
229        /**
230         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getPurApSourceDocumentLabelIfPossible()
231         */
232        public abstract String getPurApSourceDocumentLabelIfPossible();
233    
234        /**
235         * @see org.kuali.rice.kns.document.DocumentBase#prepareForSave()
236         */
237        @Override
238        public void prepareForSave(KualiDocumentEvent event) {
239            customPrepareForSave(event);
240            super.prepareForSave(event);
241            fixItemReferences();
242        }
243    
244        /**
245         * PURAP documents are all overriding this method to return false because sufficient funds checking should not be performed on
246         * route of any PURAP documents. Only the Purchase Order performs a sufficient funds check and it is manually forced during
247         * routing.
248         * 
249         * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase#documentPerformsSufficientFundsCheck()
250         */
251        @Override
252        public boolean documentPerformsSufficientFundsCheck() {
253            return false;
254        }
255    
256        /**
257         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#isDocumentStoppedInRouteNode(NodeDetails nodeDetails)
258         */
259        public boolean isDocumentStoppedInRouteNode(NodeDetails nodeDetails) {
260            List<String> currentRouteLevels = new ArrayList<String>();
261            try {
262                KualiWorkflowDocument workflowDoc = getDocumentHeader().getWorkflowDocument();
263                currentRouteLevels = Arrays.asList(getDocumentHeader().getWorkflowDocument().getNodeNames());
264                if (currentRouteLevels.contains(nodeDetails.getName()) && workflowDoc.isApprovalRequested()) {
265                    return true;
266                }
267                return false;
268            }
269            catch (WorkflowException e) {
270                throw new RuntimeException(e);
271            }
272        }
273    
274        /**
275         * Records the specified error message into the Log file and throws a runtime exception.
276         * 
277         * @param errorMessage the error message to be logged.
278         */
279        protected void logAndThrowRuntimeException(String errorMessage) {
280            this.logAndThrowRuntimeException(errorMessage, null);
281        }
282    
283        /**
284         * Records the specified error message into the Log file and throws the specified runtime exception.
285         * 
286         * @param errorMessage the specified error message.
287         * @param e the specified runtime exception.
288         */
289        protected void logAndThrowRuntimeException(String errorMessage, Exception e) {
290            if (ObjectUtils.isNotNull(e)) {
291                LOG.error(errorMessage, e);
292                throw new RuntimeException(errorMessage, e);
293            }
294            else {
295                LOG.error(errorMessage);
296                throw new RuntimeException(errorMessage);
297            }
298        }
299    
300        /**
301         * Allows child PO classes to customize the prepareForSave method. Most of the subclasses need to call the super's method to get
302         * the GL entry creation, but they each need to do different things to prepare for those entries to be created. This is only for
303         * PO since it has children classes that need different prep work for GL creation.
304         * 
305         * @param event the event involved in this action.
306         */
307        public void customPrepareForSave(KualiDocumentEvent event) {
308            // Need this here so that it happens before the GL work is done
309            SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(this);
310    
311            if (event instanceof RouteDocumentEvent || event instanceof ApproveDocumentEvent) {
312                if (this instanceof VendorCreditMemoDocument && ((VendorCreditMemoDocument)this).isSourceVendor()){
313                    return;
314                }
315                SpringContext.getBean(PurapServiceImpl.class).calculateTax(this);
316            }
317            // These next 5 lines are temporary changes so that we can use PurApOjbCollectionHelper for release 2.
318            // But these 5 lines will not be necessary anymore if the changes in PurApOjbCollectionHelper is
319            // merge into Rice. 
320    //        this.allowDeleteAwareCollection = true;
321    //        DocumentDaoOjb docDao = SpringContext.getBean(DocumentDaoOjb.class);
322    //        PurchasingAccountsPayableDocumentBase retrievedDocument = (PurchasingAccountsPayableDocumentBase) docDao.findByDocumentHeaderId(this.getClass(), this.getDocumentNumber());
323    //        if (retrievedDocument != null) {
324    //            retrievedDocument.allowDeleteAwareCollection = true;
325    //        }
326    //
327    //        SpringContext.getBean(PurApOjbCollectionHelper.class).processCollections(docDao, this, retrievedDocument);
328    //        this.allowDeleteAwareCollection = false;
329    //        if (retrievedDocument != null) {
330    //            retrievedDocument.allowDeleteAwareCollection = false;
331    //        }
332        }
333    
334        /**
335         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#buildListOfDeletionAwareLists()
336         */
337        @SuppressWarnings("rawtypes")
338        @Override
339        public List buildListOfDeletionAwareLists() {
340            List managedLists = new ArrayList<List>();
341            managedLists.add(getDeletionAwareAccountingLines());
342            if (allowDeleteAwareCollection) {            
343                //From now on, the list of accounting lines would have been added when the 
344                //super.buildListOfDeletionAwareLists() is executed when it calls getSourceAccountingLines(). 
345                //So we can remove the old codes that used to exist here to add the accounts to the
346                //managedLists and just use the one from the super.buildListOfDeletionAwareLists()
347                List<PurApItemBase> subManageList = this.getItems();
348                List useTaxItems = new ArrayList();
349                    for (PurApItemBase subManage : subManageList) {
350                            useTaxItems.addAll(subManage.getUseTaxItems());
351                    }
352            
353                managedLists.add(this.getItems());
354                managedLists.add(useTaxItems);
355            }
356            return managedLists;
357        }   
358        
359        /**
360         * Build deletion list of accounting lines for PurAp generic use.
361         * 
362         * @return
363         */
364        @SuppressWarnings("rawtypes")
365        protected List getDeletionAwareAccountingLines() {
366            List<PurApAccountingLine> deletionAwareAccountingLines = new ArrayList<PurApAccountingLine>();
367            for (Object itemAsObject : this.getItems()) {
368                final PurApItem item = (PurApItem)itemAsObject;
369                for (PurApAccountingLine accountingLine : item.getSourceAccountingLines()) {
370                    deletionAwareAccountingLines.add(accountingLine);
371                }
372            }
373            return deletionAwareAccountingLines;      
374        }
375        
376        /**
377         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#buildListOfDeletionAwareLists()
378         *
379        @Override
380        public List buildListOfDeletionAwareLists() {
381            List managedLists = new ArrayList();
382            if (allowDeleteAwareCollection) {            
383                List<PurApAccountingLine> purapAccountsList = new ArrayList<PurApAccountingLine>();
384                for (Object itemAsObject : this.getItems()) {
385                    final PurApItem item = (PurApItem)itemAsObject;
386                    purapAccountsList.addAll(item.getSourceAccountingLines());
387                }
388                managedLists.add(purapAccountsList);
389                managedLists.add(this.getItems());
390            }
391            return managedLists;
392        }
393        */
394        
395        /**
396         * @see org.kuali.rice.kns.bo.BusinessObjectBase#toStringMapper()
397         */
398        @SuppressWarnings("rawtypes")
399        @Override
400        protected LinkedHashMap toStringMapper() {
401            LinkedHashMap m = new LinkedHashMap();
402            m.put("purapDocumentIdentifier", this.purapDocumentIdentifier);
403            return m;
404        }
405    
406        @Override
407        public void processAfterRetrieve() {
408            super.processAfterRetrieve();
409    
410            refreshNonUpdateableReferences();
411        }
412        
413        /**
414         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#addItem(PurApItem item)
415         */
416        public void addItem(PurApItem item) {
417            int itemLinePosition = getItemLinePosition();
418            if (ObjectUtils.isNotNull(item.getItemLineNumber()) && (item.getItemLineNumber() > 0) && (item.getItemLineNumber() <= itemLinePosition)) {
419                itemLinePosition = item.getItemLineNumber().intValue() - 1;
420            }
421            
422            item.setPurapDocumentIdentifier(this.purapDocumentIdentifier);
423            item.setPurapDocument(this);
424            
425            items.add(itemLinePosition, item);
426            renumberItems(itemLinePosition);
427        }
428    
429        /**
430         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#deleteItem(int lineNum)
431         */
432        public void deleteItem(int lineNum) {
433            if (items.remove(lineNum) == null) {
434                // throw error here
435            }
436            renumberItems(lineNum);
437        }
438    
439        /**
440         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#renumberItems(int start)
441         */
442        public void renumberItems(int start) {
443            for (int i = start; i < items.size(); i++) {
444                PurApItem item = (PurApItem) items.get(i);
445                // only set the item line number for above the line items
446                if (item.getItemType().isLineItemIndicator()) {
447                    item.setItemLineNumber(new Integer(i + 1));
448                }
449            }
450        }
451    
452        /**
453         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#itemSwap(int positionFrom, int positionTo)
454         */
455        public void itemSwap(int positionFrom, int positionTo) {
456            // if out of range do nothing
457            if ((positionTo < 0) || (positionTo >= getItemLinePosition())) {
458                return;
459            }
460            PurApItem item1 = this.getItem(positionFrom);
461            PurApItem item2 = this.getItem(positionTo);
462            Integer oldFirstPos = item1.getItemLineNumber();
463            // swap line numbers
464            item1.setItemLineNumber(item2.getItemLineNumber());
465            item2.setItemLineNumber(oldFirstPos);
466            // fix ordering in list
467            items.remove(positionFrom);
468            items.add(positionTo, item1);
469        }
470    
471        /**
472         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getItemLinePosition()
473         */
474        public int getItemLinePosition() {
475            int belowTheLineCount = 0;
476            for (PurApItem item : items) {
477                if (item.getItemType().isAdditionalChargeIndicator()) {
478                    belowTheLineCount++;
479                }
480            }
481            return items.size() - belowTheLineCount;
482        }
483    
484        /**
485         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getItem(int pos)
486         */
487        public PurApItem getItem(int pos) {
488            return (PurApItem) items.get(pos);
489        }
490    
491        /**
492         * Iterates through the items of the document and returns the item with the line number equal to the number given, or null if a
493         * match is not found.
494         * 
495         * @param lineNumber line number to match on.
496         * @return the PurchasingAp Item if a match is found, else null.
497         */
498        @SuppressWarnings("rawtypes")
499        public PurApItem getItemByLineNumber(int lineNumber) {
500            for (Iterator iter = items.iterator(); iter.hasNext();) {
501                PurApItem item = (PurApItem) iter.next();
502                if (item.getItemLineNumber().intValue() == lineNumber) {
503                    return item;
504                }
505            }
506            return null;
507        }
508    
509        /**
510         * Find the item in the document via its string identifier.
511         * @param itemStrID the string identifier of the item being searched for
512         * @return the item being searched for
513         */
514        @SuppressWarnings("rawtypes")
515        public PurApItem getItemByStringIdentifier(String itemStrID) {
516            for (Iterator iter = items.iterator(); iter.hasNext();) {
517                PurApItem item = (PurApItem) iter.next();
518                if (StringUtils.equalsIgnoreCase(item.getItemIdentifierString(), itemStrID)) {
519                    return item;
520                }
521            }
522            return null;
523        }
524        
525        /**
526         * Find the item in the document via its identifier.
527         * @param itemID the string identifier of the item being searched for
528         * @return the item being searched for
529         */
530        @SuppressWarnings("rawtypes")
531        public PurApItem getItemByItemIdentifier(Integer itemID) {
532            for (Iterator iter = items.iterator(); iter.hasNext();) {
533                PurApItem item = (PurApItem) iter.next();
534                if (item.getItemIdentifier() == itemID) {
535                    return item;
536                }
537            }
538            return null;
539        }
540    
541        /**
542         * Overriding the parent method so that we can just set the posting year without the other stuff that the parent does to the
543         * accounting period. We only store the posting year on the doc and don't want the other stuff.
544         * 
545         * @see org.kuali.kfs.sys.document.LedgerPostingDocumentBase#setPostingYear(java.lang.Integer)
546         */
547        @Override
548        public void setPostingYear(Integer postingYear) {
549            this.postingYear = postingYear;
550        }
551    
552        /**
553         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getTotalDollarAmount()
554         */
555        @Override
556        public KualiDecimal getTotalDollarAmount() {
557            return getTotalDollarAmountAllItems(null);
558        }
559    
560        /**
561         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#setTotalDollarAmount(KualiDecimal amount)
562         */
563        public void setTotalDollarAmount(KualiDecimal amount) {
564            // do nothing, this is so that the jsp won't complain about totalDollarAmount have no setter method.
565        }
566    
567        /**
568         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getTotalDollarAmountAllItems(String[] excludedTypes)
569         */
570        public KualiDecimal getTotalDollarAmountAllItems(String[] excludedTypes) {
571            return getTotalDollarAmountWithExclusions(excludedTypes, true);
572        }
573    
574        /**
575         * Computes the total dollar amount of all above the line items.
576         * 
577         * @return the total dollar amount of all above the line items.
578         */
579        public KualiDecimal getTotalDollarAmountAboveLineItems() {
580            return getTotalDollarAmountAboveLineItems(null);
581        }
582    
583        /**
584         * Computes the total dollar amount of all above the line items with the specified item types excluded.
585         * 
586         * @param excludedTypes the types of items to be excluded.
587         * @return the total dollar amount of all above the line items with the specified item types excluded..
588         */
589        public KualiDecimal getTotalDollarAmountAboveLineItems(String[] excludedTypes) {
590            return getTotalDollarAmountWithExclusions(excludedTypes, false);
591        }
592    
593        /**
594         * Computes the total dollar amount with the specified item types and possibly below the line items excluded.
595         * 
596         * @param excludedTypes the types of items to be excluded.
597         * @param includeBelowTheLine indicates whether below the line items shall be included.
598         * @return the total dollar amount with the specified item types excluded.
599         */
600        public KualiDecimal getTotalDollarAmountWithExclusions(String[] excludedTypes, boolean includeBelowTheLine) {
601            List<PurApItem> itemsForTotal = (List<PurApItem>) getItems();
602            
603            return getTotalDollarAmountWithExclusionsSubsetItems(excludedTypes, includeBelowTheLine, itemsForTotal);
604        }
605    
606        /**
607         * This method...
608         * @param excludedTypes
609         * @param includeBelowTheLine
610         * @param itemsForTotal
611         * @return
612         */
613        protected KualiDecimal getTotalDollarAmountWithExclusionsSubsetItems(String[] excludedTypes, boolean includeBelowTheLine, List<PurApItem> itemsForTotal) {
614            if (excludedTypes == null) {
615                excludedTypes = new String[] {};
616            }
617    
618            KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
619            for (PurApItem item : itemsForTotal) {
620                item.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
621                ItemType it = item.getItemType();
622                if ((includeBelowTheLine || it.isLineItemIndicator()) && !ArrayUtils.contains(excludedTypes, it.getItemTypeCode())) {
623                    KualiDecimal totalAmount = item.getTotalAmount();
624                    KualiDecimal itemTotal = (totalAmount != null) ? totalAmount : KualiDecimal.ZERO;
625                    total = total.add(itemTotal);
626                }
627            }
628            return total;
629        }
630    
631        public KualiDecimal getTotalDollarAmountForTradeIn() {
632            List<PurApItem> tradeInItems = getTradeInItems();
633            return getTotalDollarAmountWithExclusionsSubsetItems(null,false,tradeInItems);
634        }
635    
636        /**
637         * This method...
638         * @param tradeInItems
639         */
640        public List<PurApItem> getTradeInItems() {
641            List<PurApItem> tradeInItems = new ArrayList<PurApItem>();
642            for (PurApItem purApItem : (List<PurApItem>)getItems()) {
643                if(purApItem.getItemAssignedToTradeInIndicator()) {
644                    tradeInItems.add(purApItem);
645                }
646            }
647            return tradeInItems;
648        }
649    
650        /**
651         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getTotalPreTaxDollarAmount()
652         */
653        public KualiDecimal getTotalPreTaxDollarAmount() {
654            return getTotalPreTaxDollarAmountAllItems(null);
655        }
656    
657        /**
658         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#setTotalPreTaxDollarAmount(org.kuali.rice.kns.util.KualiDecimal)
659         */
660        public void setTotalPreTaxDollarAmount(KualiDecimal amount) {
661            // do nothing, this is so that the jsp won't complain about totalDollarAmount have no setter method.
662        }
663    
664        /**
665         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getTotalPreTaxDollarAmountAllItems(java.lang.String[])
666         */
667        public KualiDecimal getTotalPreTaxDollarAmountAllItems(String[] excludedTypes) {
668            return getTotalPreTaxDollarAmountWithExclusions(excludedTypes, true);
669        }
670    
671        /**
672         * Computes the total dollar amount of all above the line items.
673         * 
674         * @return the total dollar amount of all above the line items.
675         */
676        public KualiDecimal getTotalPreTaxDollarAmountAboveLineItems() {
677            return getTotalPreTaxDollarAmountAboveLineItems(null);
678        }
679    
680        /**
681         * Computes the total dollar amount of all above the line items with the specified item types excluded.
682         * 
683         * @param excludedTypes the types of items to be excluded.
684         * @return the total dollar amount of all above the line items with the specified item types excluded..
685         */
686        public KualiDecimal getTotalPreTaxDollarAmountAboveLineItems(String[] excludedTypes) {
687            return getTotalPreTaxDollarAmountWithExclusions(excludedTypes, false);
688        }
689    
690        /**
691         * Computes the total dollar amount with the specified item types and possibly below the line items excluded.
692         * 
693         * @param excludedTypes the types of items to be excluded.
694         * @param includeBelowTheLine indicates whether below the line items shall be included.
695         * @return the total dollar amount with the specified item types excluded.
696         */
697        public KualiDecimal getTotalPreTaxDollarAmountWithExclusions(String[] excludedTypes, boolean includeBelowTheLine) {
698            if (excludedTypes == null) {
699                excludedTypes = new String[] {};
700            }
701    
702            KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
703            for (PurApItem item : (List<PurApItem>) getItems()) {
704                item.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
705                ItemType it = item.getItemType();
706                if ((includeBelowTheLine || it.isLineItemIndicator()) && !ArrayUtils.contains(excludedTypes, it.getItemTypeCode())) {
707                    KualiDecimal extendedPrice = item.getExtendedPrice();
708                    KualiDecimal itemTotal = (extendedPrice != null) ? extendedPrice : KualiDecimal.ZERO;
709                    total = total.add(itemTotal);
710                }
711            }
712            return total;
713        }
714    
715        public KualiDecimal getTotalTaxAmount() {
716            return getTotalTaxAmountAllItems(null);
717        }
718    
719        public void setTotalTaxAmount(KualiDecimal amount) {
720            // do nothing, this is so that the jsp won't complain about totalTaxAmount have no setter method.
721        }
722    
723        public KualiDecimal getTotalTaxAmountAllItems(String[] excludedTypes) {
724            return getTotalTaxAmountWithExclusions(excludedTypes, true);
725        }
726    
727        public KualiDecimal getTotalTaxAmountAboveLineItems() {
728            return getTotalTaxAmountAboveLineItems(null);
729        }
730    
731        public KualiDecimal getTotalTaxAmountAboveLineItems(String[] excludedTypes) {
732            return getTotalTaxAmountWithExclusions(excludedTypes, false);
733        }
734    
735        public KualiDecimal getTotalTaxAmountWithExclusions(String[] excludedTypes, boolean includeBelowTheLine) {
736            if (excludedTypes == null) {
737                excludedTypes = new String[] {};
738            }
739    
740            KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
741            for (PurApItem item : (List<PurApItem>) getItems()) {
742                item.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
743                ItemType it = item.getItemType();
744                if ((includeBelowTheLine || it.isLineItemIndicator()) && !ArrayUtils.contains(excludedTypes, it.getItemTypeCode())) {
745                    KualiDecimal taxAmount = item.getItemTaxAmount();
746                    KualiDecimal itemTotal = (taxAmount != null) ? taxAmount : KualiDecimal.ZERO;
747                    total = total.add(itemTotal);
748                }
749            }
750            return total;
751        }
752    
753        public boolean isUseTaxIndicator() {
754            return useTaxIndicator;
755        }
756    
757        public void setUseTaxIndicator(boolean useTaxIndicator) {
758            this.useTaxIndicator = useTaxIndicator;
759        }
760    
761        /**
762         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#templateVendorAddress(VendorAddress)
763         */
764        public void templateVendorAddress(VendorAddress vendorAddress) {
765            if (vendorAddress == null) {
766                return;
767            }
768            this.setVendorLine1Address(vendorAddress.getVendorLine1Address());
769            this.setVendorLine2Address(vendorAddress.getVendorLine2Address());
770            this.setVendorCityName(vendorAddress.getVendorCityName());
771            this.setVendorStateCode(vendorAddress.getVendorStateCode());
772            this.setVendorPostalCode(vendorAddress.getVendorZipCode());
773            this.setVendorCountryCode(vendorAddress.getVendorCountryCode());
774        }
775    
776        /**
777         * Returns the vendor number for this document.
778         * 
779         * @return the vendor number for this document.
780         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument#getVendorNumber()
781         */
782        public String getVendorNumber() {
783            if (StringUtils.isNotEmpty(vendorNumber)) {
784                return vendorNumber;
785            }
786            else if (ObjectUtils.isNotNull(vendorDetail)) {
787                return vendorDetail.getVendorNumber();
788            }
789            else
790                return "";
791        }
792    
793        public void setVendorNumber(String vendorNumber) {
794            this.vendorNumber = vendorNumber;
795        }
796    
797        public Boolean getOverrideWorkflowButtons() {
798            return overrideWorkflowButtons;
799        }
800    
801        public void setOverrideWorkflowButtons(Boolean overrideWorkflowButtons) {
802            this.overrideWorkflowButtons = overrideWorkflowButtons;
803        }
804    
805        public Integer getVendorHeaderGeneratedIdentifier() {
806            return vendorHeaderGeneratedIdentifier;
807        }
808    
809        public void setVendorHeaderGeneratedIdentifier(Integer vendorHeaderGeneratedIdentifier) {
810            this.vendorHeaderGeneratedIdentifier = vendorHeaderGeneratedIdentifier;
811        }
812    
813        public Integer getVendorDetailAssignedIdentifier() {
814            return vendorDetailAssignedIdentifier;
815        }
816    
817        public void setVendorDetailAssignedIdentifier(Integer vendorDetailAssignedIdentifier) {
818            this.vendorDetailAssignedIdentifier = vendorDetailAssignedIdentifier;
819        }
820    
821        public String getVendorCustomerNumber() {
822            return vendorCustomerNumber;
823        }
824    
825        public void setVendorCustomerNumber(String vendorCustomerNumber) {
826            this.vendorCustomerNumber = vendorCustomerNumber;
827        }
828    
829        public Integer getPurapDocumentIdentifier() {
830            return purapDocumentIdentifier;
831        }
832    
833        public void setPurapDocumentIdentifier(Integer identifier) {
834            this.purapDocumentIdentifier = identifier;
835        }
836    
837        public Status getStatus() {
838            if (ObjectUtils.isNull(this.status) && StringUtils.isNotEmpty(this.getStatusCode()))  {
839                this.refreshReferenceObject(PurapPropertyConstants.STATUS);
840            }
841            else if (ObjectUtils.isNotNull(status) && StringUtils.isNotEmpty(getStatusCode()) && !status.getStatusCode().equals(getStatusCode())) {
842                this.refreshReferenceObject(PurapPropertyConstants.STATUS);
843            }
844            return status;
845        }
846    
847        public void setStatus(Status status) {
848            this.status = status;
849        }
850    
851        public String getStatusCode() {
852            return statusCode;
853        }
854    
855        public void setStatusCode(String statusCode) {
856            this.statusCode = statusCode;
857        }
858    
859        public VendorDetail getVendorDetail() {
860            return vendorDetail;
861        }
862    
863        public void setVendorDetail(VendorDetail vendorDetail) {
864            this.vendorDetail = vendorDetail;
865        }
866    
867        @SuppressWarnings("rawtypes")
868        public List getItems() {
869            return items;
870        }
871    
872        @SuppressWarnings("rawtypes")
873        public void setItems(List items) {
874            this.items = items;
875        }
876    
877        public String getVendorCityName() {
878            return vendorCityName;
879        }
880    
881        public void setVendorCityName(String vendorCityName) {
882            this.vendorCityName = vendorCityName;
883        }
884    
885        public String getVendorCountryCode() {
886            return vendorCountryCode;
887        }
888    
889        public void setVendorCountryCode(String vendorCountryCode) {
890            this.vendorCountryCode = vendorCountryCode;
891        }
892    
893        public String getVendorLine1Address() {
894            return vendorLine1Address;
895        }
896    
897        public void setVendorLine1Address(String vendorLine1Address) {
898            this.vendorLine1Address = vendorLine1Address;
899        }
900    
901        public String getVendorLine2Address() {
902            return vendorLine2Address;
903        }
904    
905        public void setVendorLine2Address(String vendorLine2Address) {
906            this.vendorLine2Address = vendorLine2Address;
907        }
908    
909        public String getVendorName() {
910            return vendorName;
911        }
912    
913        public void setVendorName(String vendorName) {
914            this.vendorName = vendorName;
915        }
916    
917        public String getVendorPostalCode() {
918            return vendorPostalCode;
919        }
920    
921        public void setVendorPostalCode(String vendorPostalCode) {
922            this.vendorPostalCode = vendorPostalCode;
923        }
924    
925        public String getVendorStateCode() {
926            return vendorStateCode;
927        }
928    
929        public void setVendorStateCode(String vendorStateCode) {
930            this.vendorStateCode = vendorStateCode;
931        }
932        
933        public String getVendorAddressInternationalProvinceName() {
934            return vendorAddressInternationalProvinceName;
935        }
936    
937        public void setVendorAddressInternationalProvinceName(String vendorAddressInternationalProvinceName) {
938            this.vendorAddressInternationalProvinceName = vendorAddressInternationalProvinceName;
939        }
940    
941        public Integer getVendorAddressGeneratedIdentifier() {
942            return vendorAddressGeneratedIdentifier;
943        }
944    
945        public void setVendorAddressGeneratedIdentifier(Integer vendorAddressGeneratedIdentifier) {
946            this.vendorAddressGeneratedIdentifier = vendorAddressGeneratedIdentifier;
947        }
948    
949        public Integer getAccountsPayablePurchasingDocumentLinkIdentifier() {
950            return accountsPayablePurchasingDocumentLinkIdentifier;
951        }
952    
953        public void setAccountsPayablePurchasingDocumentLinkIdentifier(Integer accountsPayablePurchasingDocumentLinkIdentifier) {
954            this.accountsPayablePurchasingDocumentLinkIdentifier = accountsPayablePurchasingDocumentLinkIdentifier;
955        }
956    
957        public String[] getBelowTheLineTypes() {
958            if (this.belowTheLineTypes == null) {
959                this.belowTheLineTypes = SpringContext.getBean(PurapService.class).getBelowTheLineForDocument(this);
960            }
961            return belowTheLineTypes;
962        }
963    
964        public Country getVendorCountry() {
965            vendorCountry = SpringContext.getBean(CountryService.class).getByPrimaryIdIfNecessary(vendorCountryCode, vendorCountry);
966            return vendorCountry;
967        }
968    
969        /**
970         * Added only to allow for {@link org.kuali.kfs.module.purap.util.PurApObjectUtils} class to work correctly.
971         * 
972         * @deprecated
973         */
974        public void setVendorCountry(Country vendorCountry) {
975            this.vendorCountry = vendorCountry;
976        }
977        
978        public String getVendorAttentionName() {
979            return vendorAttentionName;
980        }
981    
982        public void setVendorAttentionName(String vendorAttentionName) {
983            this.vendorAttentionName = vendorAttentionName;
984        }
985        
986        /**
987         * Determines whether the account is debit. It always returns false.
988         * 
989         * @param financialDocument The document containing the account to be validated.
990         * @param accountingLine The account to be validated.
991         * @return boolean false.
992         * @see org.kuali.kfs.sys.document.validation.AccountingLineRule#isDebit(org.kuali.kfs.sys.document.AccountingDocument,
993         *      org.kuali.kfs.sys.businessobject.AccountingLine)
994         */
995        public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) {
996            return false;
997        }
998        
999        public PurApRelatedViews getRelatedViews() {
1000            if (relatedViews == null) {
1001                relatedViews = new PurApRelatedViews(this.documentNumber, this.accountsPayablePurchasingDocumentLinkIdentifier);
1002            }
1003            return relatedViews;
1004        }
1005    
1006        public void setRelatedViews(PurApRelatedViews relatedViews) {
1007            this.relatedViews = relatedViews;
1008        }
1009        
1010        public String getStatusCodeForMultiboxSearching() {
1011            return statusCode;
1012        }
1013            
1014        @Override
1015        public void refreshNonUpdateableReferences() {
1016    
1017            super.refreshNonUpdateableReferences();
1018            fixItemReferences();
1019        }
1020    
1021        /**
1022         * This method fixes the item references in this document if it's new
1023         */
1024        public void fixItemReferences() {
1025            //fix item and account references in case this is a new doc (since they will be lost)
1026            if(ObjectUtils.isNull(this.purapDocumentIdentifier)) {
1027                for (PurApItem item : (List<PurApItem>)this.getItems()) {
1028                    item.setPurapDocument(this);
1029                    item.fixAccountReferences();
1030                }
1031            }
1032        }
1033        
1034        /**
1035         * Returns the trade in item of the document.
1036         * 
1037         * @return
1038         */
1039        public PurApItem getTradeInItem() {
1040            for (PurApItem item : (List<PurApItem>)getItems()) {
1041                if (item.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)) {
1042                    return item;
1043                }
1044            }
1045            return null;
1046        }
1047        
1048        /**
1049         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument.getIsATypeOfPurAPRecDoc().
1050         */
1051        public boolean getIsATypeOfPurAPRecDoc() {
1052            return true;
1053        }
1054        
1055        /**
1056         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument.getIsATypeOfPurDoc().
1057         */
1058        public boolean getIsATypeOfPurDoc() {
1059            if (this instanceof PurchasingDocumentBase) 
1060                return true;
1061            else
1062                return false;
1063        }
1064        
1065        /**
1066         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument.getIsATypeOfPODoc().
1067         */
1068        public boolean getIsATypeOfPODoc() {
1069            if (this instanceof PurchaseOrderDocument) 
1070                return true;
1071            else
1072                return false;
1073        }
1074        
1075        /**
1076         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument.getIsPODoc().
1077         */
1078        public boolean getIsPODoc() {
1079            if ( (this instanceof PurchaseOrderDocument) && 
1080                !(this instanceof PurchaseOrderAmendmentDocument) &&
1081                !(this instanceof PurchaseOrderCloseDocument) &&
1082                !(this instanceof PurchaseOrderPaymentHoldDocument) &&
1083                !(this instanceof PurchaseOrderRemoveHoldDocument) &&
1084                !(this instanceof PurchaseOrderReopenDocument) && 
1085                !(this instanceof PurchaseOrderRetransmitDocument) && 
1086                !(this instanceof PurchaseOrderSplitDocument) &&
1087                !(this instanceof PurchaseOrderVoidDocument)) 
1088                return true;
1089            else
1090                return false;
1091        }
1092        
1093        /**
1094         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument.getIsATypeOfREQSDoc().
1095         */
1096        public boolean getIsReqsDoc() {
1097            if (this instanceof RequisitionDocument) 
1098                return true;
1099            else
1100                return false;
1101        }
1102        
1103        /**
1104         * build document title based on the properties of current document
1105         * 
1106         * @param the default document title
1107         * @return the combine information of the given title and additional payment indicators 
1108         */ 
1109        protected String buildDocumentTitle(String title) { 
1110            if(this.getVendorDetail() == null) {
1111               return title; 
1112            }
1113            
1114            Integer vendorHeaderGeneratedIdentifier = this.getVendorDetail().getVendorHeaderGeneratedIdentifier();
1115            VendorService vendorService = SpringContext.getBean(VendorService.class);
1116         
1117            Object[] indicators = new String[2];
1118            
1119            boolean isEmployeeVendor = vendorService.isVendorInstitutionEmployee(vendorHeaderGeneratedIdentifier);
1120            indicators[0] = isEmployeeVendor ? AdHocPaymentIndicator.EMPLOYEE_VENDOR : AdHocPaymentIndicator.OTHER;
1121            
1122            boolean isVendorForeign = vendorService.isVendorForeign(vendorHeaderGeneratedIdentifier);
1123            indicators[1] = isVendorForeign ? AdHocPaymentIndicator.ALIEN_VENDOR : AdHocPaymentIndicator.OTHER;
1124            
1125            for(Object indicator : indicators) {
1126                if(!AdHocPaymentIndicator.OTHER.equals(indicator)) {
1127                    String titlePattern = title + " [{0}:{1}]";
1128                    return MessageFormat.format(titlePattern, indicators);
1129                }
1130            }
1131        
1132            return title;
1133        }
1134    
1135        /**
1136         * Overridden to return the source lines of all of the items
1137         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getSourceAccountingLines()
1138         */
1139        @SuppressWarnings("rawtypes")
1140        @Override
1141        public List getSourceAccountingLines() {
1142            if (ObjectUtils.isNotNull(sourceAccountingLines) && !sourceAccountingLines.isEmpty()) {
1143                // do nothing because acct lines have already been set
1144                return sourceAccountingLines;
1145            }
1146            else {
1147                /*
1148                SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(this);
1149                return SpringContext.getBean(PurapAccountingService.class).generateSummary(getItems());
1150                */
1151                List<AccountingLine> sourceAccountingLines = new ArrayList<AccountingLine>();
1152                for (Object itemAsObject : this.getItems()) {
1153                    final PurApItem item = (PurApItem)itemAsObject;
1154                    for (PurApAccountingLine accountingLine : item.getSourceAccountingLines()) {
1155                        sourceAccountingLines.add(accountingLine);
1156                    }
1157                }
1158                return sourceAccountingLines;            
1159            }
1160        }
1161        
1162        /**
1163         * Checks whether the related purchase order views need a warning to be displayed, 
1164         * i.e. if at least one of the purchase orders has never been opened.
1165         * @return true if at least one related purchase order needs a warning; false otherwise
1166         */
1167        public boolean getNeedWarningRelatedPOs() {
1168            List<PurchaseOrderView> poViews = getRelatedViews().getRelatedPurchaseOrderViews();
1169            for (PurchaseOrderView poView : poViews) {
1170                if (poView.getNeedWarning())
1171                    return true;
1172            }
1173            return false;
1174        }
1175        
1176        /**
1177         * Accounting lines that are read-only should skip validation
1178         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getPersistedSourceAccountingLinesForComparison()
1179         */
1180        @SuppressWarnings("rawtypes")
1181        @Override
1182        protected List getPersistedSourceAccountingLinesForComparison() {
1183            LOG.info("Checking persisted source accounting lines for read-only fields");
1184            List<String> restrictedItemTypesList = new ArrayList<String>();
1185            try {
1186                restrictedItemTypesList = SpringContext.getBean(ParameterService.class).getParameterValues(this.getClass(), PurapParameterConstants.PURAP_ITEM_TYPES_RESTRICTING_ACCOUNT_EDIT);
1187            } catch (IllegalArgumentException iae) {
1188                // do nothing, not a problem if no restricted types are defined
1189            }
1190    
1191            PurapAccountingService purApAccountingService = SpringContext.getBean(PurapAccountingService.class);
1192            List persistedSourceLines = new ArrayList();
1193    
1194            for (PurApItem item : (List<PurApItem>) this.getItems()) {
1195                // only check items that already have been persisted since last save
1196                if (ObjectUtils.isNotNull(item.getItemIdentifier())) {
1197                    // Disable validation if the item is read-only
1198                    final boolean isNotReadOnly = !((restrictedItemTypesList != null) && restrictedItemTypesList.contains(item.getItemTypeCode()));
1199                    if (isNotReadOnly) {
1200                        persistedSourceLines.addAll(purApAccountingService.getAccountsFromItem(item));
1201                    }
1202                }
1203            }
1204            return persistedSourceLines;
1205        }
1206    
1207        /**
1208         * Accounting lines that are read-only should skip validation
1209         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getSourceAccountingLinesForComparison()
1210         */
1211        @SuppressWarnings("rawtypes")
1212        @Override
1213        protected List getSourceAccountingLinesForComparison() {
1214            LOG.info("Checking source accounting lines for read-only fields");
1215            List<String> restrictedItemTypesList = new ArrayList<String>();
1216            try {
1217                restrictedItemTypesList = SpringContext.getBean(ParameterService.class).getParameterValues(this.getClass(), PurapParameterConstants.PURAP_ITEM_TYPES_RESTRICTING_ACCOUNT_EDIT);
1218            } catch (IllegalArgumentException iae) {
1219                // do nothing, not a problem if no restricted types are defined
1220            }
1221            PurapAccountingService purApAccountingService = SpringContext.getBean(PurapAccountingService.class);
1222            List currentSourceLines = new ArrayList();
1223            for (PurApItem item : (List<PurApItem>) this.getItems()) {
1224                // Disable validation if the item is read-only
1225                final boolean isNotReadOnly = !((restrictedItemTypesList != null) && restrictedItemTypesList.contains(item.getItemTypeCode()));
1226                if (isNotReadOnly) {
1227                    currentSourceLines.addAll(item.getSourceAccountingLines());
1228                }
1229            }
1230            return currentSourceLines;
1231        }
1232    
1233    }