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.document;
018    
019    import java.util.ArrayList;
020    import java.util.Calendar;
021    import java.util.Date;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    import java.util.Set;
026    
027    import org.apache.commons.lang.StringUtils;
028    import org.kuali.kfs.module.purap.PurapConstants;
029    import org.kuali.kfs.module.purap.PurapKeyConstants;
030    import org.kuali.kfs.module.purap.PurapParameterConstants;
031    import org.kuali.kfs.module.purap.PurapWorkflowConstants;
032    import org.kuali.kfs.module.purap.PurapConstants.RequisitionStatuses;
033    import org.kuali.kfs.module.purap.PurapWorkflowConstants.NodeDetails;
034    import org.kuali.kfs.module.purap.PurapWorkflowConstants.RequisitionDocument.NodeDetailEnum;
035    import org.kuali.kfs.module.purap.businessobject.BillingAddress;
036    import org.kuali.kfs.module.purap.businessobject.DefaultPrincipalAddress;
037    import org.kuali.kfs.module.purap.businessobject.PurApAccountingLine;
038    import org.kuali.kfs.module.purap.businessobject.PurchaseRequisitionItemUseTax;
039    import org.kuali.kfs.module.purap.businessobject.RequisitionAccount;
040    import org.kuali.kfs.module.purap.businessobject.RequisitionCapitalAssetItem;
041    import org.kuali.kfs.module.purap.businessobject.RequisitionCapitalAssetSystem;
042    import org.kuali.kfs.module.purap.businessobject.RequisitionItem;
043    import org.kuali.kfs.module.purap.document.service.PurapService;
044    import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
045    import org.kuali.kfs.module.purap.document.service.PurchasingDocumentSpecificService;
046    import org.kuali.kfs.module.purap.document.service.PurchasingService;
047    import org.kuali.kfs.module.purap.document.service.RequisitionService;
048    import org.kuali.kfs.sys.KFSConstants;
049    import org.kuali.kfs.sys.businessobject.Building;
050    import org.kuali.kfs.sys.businessobject.ChartOrgHolder;
051    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
052    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
053    import org.kuali.kfs.sys.context.SpringContext;
054    import org.kuali.kfs.sys.service.FinancialSystemUserService;
055    import org.kuali.kfs.sys.service.UniversityDateService;
056    import org.kuali.kfs.vnd.businessobject.VendorContract;
057    import org.kuali.kfs.vnd.businessobject.VendorDetail;
058    import org.kuali.kfs.vnd.document.service.VendorService;
059    import org.kuali.kfs.vnd.service.PhoneNumberService;
060    import org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO;
061    import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
062    import org.kuali.rice.kew.dto.ReportCriteriaDTO;
063    import org.kuali.rice.kew.exception.WorkflowException;
064    import org.kuali.rice.kew.util.KEWConstants;
065    import org.kuali.rice.kim.bo.Person;
066    import org.kuali.rice.kim.service.KIMServiceLocator;
067    import org.kuali.rice.kns.document.Copyable;
068    import org.kuali.rice.kns.exception.ValidationException;
069    import org.kuali.rice.kns.service.BusinessObjectService;
070    import org.kuali.rice.kns.service.DateTimeService;
071    import org.kuali.rice.kns.service.KualiConfigurationService;
072    import org.kuali.rice.kns.service.ParameterService;
073    import org.kuali.rice.kns.service.PersistenceService;
074    import org.kuali.rice.kns.util.GlobalVariables;
075    import org.kuali.rice.kns.util.KualiDecimal;
076    import org.kuali.rice.kns.util.ObjectUtils;
077    import org.kuali.rice.kns.workflow.service.KualiWorkflowInfo;
078    import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
079    
080    /**
081     * Document class for the Requisition.
082     */
083    public class RequisitionDocument extends PurchasingDocumentBase implements Copyable {
084        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RequisitionDocument.class);
085    
086        protected String requisitionOrganizationReference1Text;
087        protected String requisitionOrganizationReference2Text;
088        protected String requisitionOrganizationReference3Text;
089        protected String alternate1VendorName;
090        protected String alternate2VendorName;
091        protected String alternate3VendorName;
092        protected String alternate4VendorName;
093        protected String alternate5VendorName;
094        protected KualiDecimal organizationAutomaticPurchaseOrderLimit;
095        
096        // non-persistent property used for controlling validation for accounting lines when doc is request for blanket approve.
097        protected boolean isBlanketApproveRequest = false;
098        
099        /**
100         * Default constructor.
101         */
102        public RequisitionDocument() {
103            super();
104        }
105    
106        @Override
107        public PurchasingDocumentSpecificService getDocumentSpecificService() {
108            return SpringContext.getBean(RequisitionService.class);
109        }
110        /**
111         * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#isBoNotesSupport()
112         */
113        @Override
114        public boolean isBoNotesSupport() {
115            return true;
116        }
117    
118        /**
119         * Provides answers to the following splits:
120         * AmountRequiresSeparationOfDutiesReview
121         * 
122         * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
123         */
124        @Override
125        public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
126            if (nodeName.equals(PurapWorkflowConstants.HAS_ACCOUNTING_LINES)) return !isMissingAccountingLines();
127            if (nodeName.equals(PurapWorkflowConstants.AMOUNT_REQUIRES_SEPARATION_OF_DUTIES_REVIEW_SPLIT)) return isSeparationOfDutiesReviewRequired();
128            throw new UnsupportedOperationException("Cannot answer split question for this node you call \""+nodeName+"\"");
129        }
130    
131        protected boolean isMissingAccountingLines() {
132            for (Iterator iterator = getItems().iterator(); iterator.hasNext();) {
133                RequisitionItem item = (RequisitionItem) iterator.next();
134                if (item.isConsideredEntered() && item.isAccountListEmpty()) {
135                    return true;
136                }
137            }
138            
139            return false;
140        }
141        
142        protected boolean isSeparationOfDutiesReviewRequired() {
143            try {
144                Set<Person> priorApprovers = getDocumentHeader().getWorkflowDocument().getAllPriorApprovers();
145                
146                // The initiator cannot be the approver
147                String initiatorPrincipalId = getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId();
148                Person initiator = KIMServiceLocator.getPersonService().getPerson(initiatorPrincipalId);
149                // If there is only one approver, and that approver is also the initiator, then Separation of Duties is required.
150                boolean priorApproverIsInitiator = priorApprovers.contains(initiator);
151                boolean onlyOneApprover = (priorApprovers.size() == 1);
152                if ( priorApproverIsInitiator && onlyOneApprover) {
153                    return true;
154                }
155                
156                // if there are more than 0 prior approvers which means there had been at least another approver than the current approver
157                // then no need for separation of duties
158                if (priorApprovers.size() > 0) {
159                    return false;
160                }
161            }catch (WorkflowException we) {
162                LOG.error("Exception while attempting to retrieve all prior approvers from workflow: " + we);
163            }
164            ParameterService parameterService = SpringContext.getBean(ParameterService.class);
165            KualiDecimal maxAllowedAmount = new KualiDecimal(parameterService.getParameterValue(RequisitionDocument.class, PurapParameterConstants.SEPARATION_OF_DUTIES_DOLLAR_AMOUNT));
166            // if app param amount is greater than or equal to documentTotalAmount... no need for separation of duties
167            KualiDecimal totalAmount = documentHeader.getFinancialDocumentTotalAmount();
168            if (ObjectUtils.isNotNull(maxAllowedAmount) && ObjectUtils.isNotNull(totalAmount) && (maxAllowedAmount.compareTo(totalAmount) >= 0)) {
169                return false;
170            }
171            else {
172                return true;
173            }
174        }
175    
176        
177        /**
178         * Overrides the method in PurchasingAccountsPayableDocumentBase to add the criteria
179         * specific to Requisition Document.
180         * 
181         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#isInquiryRendered()
182         */
183        @Override
184        public boolean isInquiryRendered() {
185            if ( isPostingYearPrior() && 
186                 ( getStatusCode().equals(PurapConstants.RequisitionStatuses.CLOSED) || 
187                   getStatusCode().equals(PurapConstants.RequisitionStatuses.CANCELLED) ) )  {
188                   return false;            
189            }
190            else {
191                return true;
192            }
193        }
194        
195        /**
196         * Performs logic needed to initiate Requisition Document.
197         */
198        public void initiateDocument() {
199            this.setRequisitionSourceCode(PurapConstants.RequisitionSources.STANDARD_ORDER);
200            this.setStatusCode(PurapConstants.RequisitionStatuses.IN_PROCESS);
201            this.setPurchaseOrderCostSourceCode(PurapConstants.POCostSources.ESTIMATE);
202            this.setPurchaseOrderTransmissionMethodCode(determinePurchaseOrderTransmissionMethod());
203            this.setDocumentFundingSourceCode(SpringContext.getBean(ParameterService.class).getParameterValue(RequisitionDocument.class, PurapParameterConstants.DEFAULT_FUNDING_SOURCE));
204            this.setUseTaxIndicator(SpringContext.getBean(PurchasingService.class).getDefaultUseTaxIndicatorValue(this));
205                
206            Person currentUser = GlobalVariables.getUserSession().getPerson();
207            ChartOrgHolder purapChartOrg = SpringContext.getBean(FinancialSystemUserService.class).getPrimaryOrganization(currentUser, PurapConstants.PURAP_NAMESPACE);
208            if (ObjectUtils.isNotNull(purapChartOrg)) {
209            this.setChartOfAccountsCode(purapChartOrg.getChartOfAccountsCode());
210            this.setOrganizationCode(purapChartOrg.getOrganizationCode());
211            }
212            this.setDeliveryCampusCode(currentUser.getCampusCode());
213            this.setDeliveryToName(currentUser.getName());
214            this.setDeliveryToEmailAddress(currentUser.getEmailAddressUnmasked());
215            this.setDeliveryToPhoneNumber(SpringContext.getBean(PhoneNumberService.class).formatNumberIfPossible(currentUser.getPhoneNumber()));
216            this.setRequestorPersonName(currentUser.getName());
217            this.setRequestorPersonEmailAddress(currentUser.getEmailAddressUnmasked());
218            this.setRequestorPersonPhoneNumber(SpringContext.getBean(PhoneNumberService.class).formatNumberIfPossible(currentUser.getPhoneNumber()));
219    
220            DefaultPrincipalAddress defaultPrincipalAddress = new DefaultPrincipalAddress(currentUser.getPrincipalId());
221            Map addressKeys = SpringContext.getBean(PersistenceService.class).getPrimaryKeyFieldValues(defaultPrincipalAddress);
222            defaultPrincipalAddress = (DefaultPrincipalAddress) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(DefaultPrincipalAddress.class, addressKeys);
223            if (ObjectUtils.isNotNull(defaultPrincipalAddress) && ObjectUtils.isNotNull(defaultPrincipalAddress.getBuilding())) {
224                if (defaultPrincipalAddress.getBuilding().isActive()) {
225                    this.setDeliveryCampusCode(defaultPrincipalAddress.getCampusCode());
226                    this.templateBuildingToDeliveryAddress(defaultPrincipalAddress.getBuilding());
227                    this.setDeliveryBuildingRoomNumber(defaultPrincipalAddress.getBuildingRoomNumber());
228                }
229                else {
230                    //since building is now inactive, delete default building record
231                    SpringContext.getBean(BusinessObjectService.class).delete(defaultPrincipalAddress);
232                }
233            }
234            
235            // set the APO limit
236            this.setOrganizationAutomaticPurchaseOrderLimit(SpringContext.getBean(PurapService.class).getApoLimit(this.getVendorContractGeneratedIdentifier(), this.getChartOfAccountsCode(), this.getOrganizationCode()));
237    
238            // populate billing address
239            BillingAddress billingAddress = new BillingAddress();
240            billingAddress.setBillingCampusCode(this.getDeliveryCampusCode());
241            Map keys = SpringContext.getBean(PersistenceService.class).getPrimaryKeyFieldValues(billingAddress);
242            billingAddress = (BillingAddress) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(BillingAddress.class, keys);
243            this.templateBillingAddress(billingAddress);
244            
245            // populate receiving address with the default one for the chart/org
246            loadReceivingAddress();
247            
248            SpringContext.getBean(PurapService.class).addBelowLineItems(this);
249            this.refreshNonUpdateableReferences();
250        }
251    
252        public void templateBuildingToDeliveryAddress(Building building) {
253            if (ObjectUtils.isNotNull(building)) {
254                setDeliveryBuildingCode(building.getBuildingCode());
255                setDeliveryBuildingName(building.getBuildingName());
256                setDeliveryBuildingLine1Address(building.getBuildingStreetAddress());
257                setDeliveryCityName(building.getBuildingAddressCityName());
258                setDeliveryStateCode(building.getBuildingAddressStateCode());
259                setDeliveryPostalCode(building.getBuildingAddressZipCode());
260                setDeliveryCountryCode(building.getBuildingAddressCountryCode());
261            }
262        }
263    
264        /**
265         * Determines what PO transmission method to use.
266         * 
267         * @return the PO PO transmission method to use.
268         */
269        protected String determinePurchaseOrderTransmissionMethod() {
270            
271            return SpringContext.getBean(ParameterService.class).getParameterValue(RequisitionDocument.class, PurapParameterConstants.PURAP_DEFAULT_PO_TRANSMISSION_CODE);
272        }
273    
274        /**
275         * Checks whether copying of this document should be allowed. Copying is not allowed if this is a B2B requistion, and more than
276         * a set number of days have passed since the document's creation.
277         * 
278         * @return True if copying of this requisition is allowed.
279         * @see org.kuali.rice.kns.document.Document#getAllowsCopy()
280         */
281        @Override
282        public boolean getAllowsCopy() {
283            boolean allowsCopy = super.getAllowsCopy();
284            if (PurapConstants.RequisitionSources.B2B.equals(getRequisitionSourceCode())) {
285                DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
286                Calendar c = Calendar.getInstance();
287    
288                // The allowed copy date is the document creation date plus a set number of days.
289                Date createDate = getDocumentHeader().getWorkflowDocument().getCreateDate();
290                c.setTime(createDate);
291                String allowedCopyDays = SpringContext.getBean(ParameterService.class).getParameterValue(RequisitionDocument.class, PurapParameterConstants.B2B_ALLOW_COPY_DAYS);
292                c.add(Calendar.DATE, Integer.parseInt(allowedCopyDays));
293                Date allowedCopyDate = c.getTime();
294                Date currentDate = dateTimeService.getCurrentDate();
295    
296                // Return true if the current time is before the allowed copy date.
297                allowsCopy = (dateTimeService.dateDiff(currentDate, allowedCopyDate, false) > 0);
298            }
299            return allowsCopy;
300        }
301    
302        /**
303         * Performs logic needed to copy Requisition Document.
304         * 
305         * @see org.kuali.rice.kns.document.Document#toCopy()
306         */
307        @Override
308        public void toCopy() throws WorkflowException, ValidationException {
309            super.toCopy();
310    
311            // Clear related views
312            this.setAccountsPayablePurchasingDocumentLinkIdentifier(null);
313            this.setRelatedViews(null);
314            
315            Person currentUser = GlobalVariables.getUserSession().getPerson();
316            ChartOrgHolder purapChartOrg = SpringContext.getBean(FinancialSystemUserService.class).getPrimaryOrganization(currentUser, PurapConstants.PURAP_NAMESPACE);
317            this.setPurapDocumentIdentifier(null);
318    
319            // Set req status to INPR.
320            this.setStatusCode(PurapConstants.RequisitionStatuses.IN_PROCESS);
321    
322            // Set fields from the user.
323            if (ObjectUtils.isNotNull(purapChartOrg)) {
324            this.setChartOfAccountsCode(purapChartOrg.getChartOfAccountsCode());
325            this.setOrganizationCode(purapChartOrg.getOrganizationCode());
326            }
327            this.setPostingYear(SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear());
328    
329            boolean activeVendor = true;
330            boolean activeContract = true;
331            Date today = SpringContext.getBean(DateTimeService.class).getCurrentDate();
332            VendorContract vendorContract = new VendorContract();
333            vendorContract.setVendorContractGeneratedIdentifier(this.getVendorContractGeneratedIdentifier());
334            Map keys = SpringContext.getBean(PersistenceService.class).getPrimaryKeyFieldValues(vendorContract);
335            vendorContract = (VendorContract) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(VendorContract.class, keys);
336            if (!(vendorContract != null && today.after(vendorContract.getVendorContractBeginningDate()) && today.before(vendorContract.getVendorContractEndDate()))) {
337                activeContract = false;
338            }
339    
340            VendorDetail vendorDetail = SpringContext.getBean(VendorService.class).getVendorDetail(this.getVendorHeaderGeneratedIdentifier(), this.getVendorDetailAssignedIdentifier());
341            if (!(vendorDetail != null && vendorDetail.isActiveIndicator())) {
342                activeVendor = false;
343            }
344    
345            // B2B - only copy if contract and vendor are both active (throw separate errors to print to screen)
346            if (this.getRequisitionSourceCode().equals(PurapConstants.RequisitionSources.B2B)) {
347                if (!activeContract) {
348                    throw new ValidationException(PurapKeyConstants.ERROR_REQ_COPY_EXPIRED_CONTRACT);
349                }
350                if (!activeVendor) {
351                    throw new ValidationException(PurapKeyConstants.ERROR_REQ_COPY_INACTIVE_VENDOR);
352                }
353            }
354    
355            if (!activeVendor) {
356                this.setVendorContractGeneratedIdentifier(null);
357            }
358            if (!activeContract) {
359                this.setVendorContractGeneratedIdentifier(null);
360            }
361    
362            // These fields should not be set in this method; force to be null
363            this.setOrganizationAutomaticPurchaseOrderLimit(null);
364            this.setPurchaseOrderAutomaticIndicator(false);
365    
366            // Fill the BO Notes with an empty List.
367            this.setBoNotes(new ArrayList());
368    
369            for (Iterator iter = this.getItems().iterator(); iter.hasNext();) {
370                RequisitionItem item = (RequisitionItem) iter.next();
371                item.setPurapDocumentIdentifier(null);
372                item.setItemIdentifier(null);
373                for (Iterator acctIter = item.getSourceAccountingLines().iterator(); acctIter.hasNext();) {
374                    RequisitionAccount account = (RequisitionAccount) acctIter.next();
375                    account.setAccountIdentifier(null);
376                    account.setItemIdentifier(null);
377                }
378            }
379    
380            if (!PurapConstants.RequisitionSources.B2B.equals(this.getRequisitionSourceCode())) {
381                SpringContext.getBean(PurapService.class).addBelowLineItems(this);
382            }
383            this.setOrganizationAutomaticPurchaseOrderLimit(SpringContext.getBean(PurapService.class).getApoLimit(this.getVendorContractGeneratedIdentifier(), this.getChartOfAccountsCode(), this.getOrganizationCode()));
384            clearCapitalAssetFields();
385            SpringContext.getBean(PurapService.class).clearTax(this, this.isUseTaxIndicator());
386            
387            this.refreshNonUpdateableReferences();
388        }
389        
390        /**
391         * Updates status of this document and saves it.
392         * 
393         * @param statusCode the status code of the current status.
394         */
395        protected void updateStatusAndSave(String statusCode) {
396            SpringContext.getBean(PurapService.class).updateStatus(this, statusCode);
397            SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
398        }
399    
400        @Override
401        public List<Long> getWorkflowEngineDocumentIdsToLock() {
402            List<String> docIdStrings = new ArrayList<String>();
403            docIdStrings.add(getDocumentNumber());
404            
405            //  PROCESSED
406            if (getDocumentHeader().getWorkflowDocument().stateIsProcessed()) {
407                // creates a new PO but no way to know what the docID will be ahead of time
408            }
409            
410            //  convert our easy to use List<String> to a Long[]
411            List<Long> docIds = new ArrayList<Long>();
412            for (int i = 0; i < docIdStrings.size(); i++) {
413                docIds.add(new Long(docIdStrings.get(i)));
414            }
415            return docIds;
416        }
417    
418        /**
419         * @see org.kuali.rice.kns.document.DocumentBase#doRouteStatusChange()
420         */
421        @Override
422        public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
423            LOG.debug("doRouteStatusChange() started");
424            super.doRouteStatusChange(statusChangeEvent);
425            try {
426                // DOCUMENT PROCESSED
427                if (this.getDocumentHeader().getWorkflowDocument().stateIsProcessed()) {
428                    String newRequisitionStatus = PurapConstants.RequisitionStatuses.AWAIT_CONTRACT_MANAGER_ASSGN;
429                    if (SpringContext.getBean(RequisitionService.class).isAutomaticPurchaseOrderAllowed(this)) {
430                        newRequisitionStatus = PurapConstants.RequisitionStatuses.CLOSED;
431                        SpringContext.getBean(PurchaseOrderService.class).createAutomaticPurchaseOrderDocument(this);
432                    }
433                    updateStatusAndSave(newRequisitionStatus);
434                }
435                // DOCUMENT DISAPPROVED
436                else if (this.getDocumentHeader().getWorkflowDocument().stateIsDisapproved()) {
437                    String nodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(getDocumentHeader().getWorkflowDocument());
438                    NodeDetails currentNode = NodeDetailEnum.getNodeDetailEnumByName(nodeName);
439                    if (ObjectUtils.isNotNull(currentNode)) {
440                        if (StringUtils.isNotBlank(currentNode.getDisapprovedStatusCode())) {
441                            updateStatusAndSave(currentNode.getDisapprovedStatusCode());
442                            return;
443                        }
444                    }
445                    logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + nodeName + "'");
446                }
447                // DOCUMENT CANCELED
448                else if (this.getDocumentHeader().getWorkflowDocument().stateIsCanceled()) {
449                    updateStatusAndSave(RequisitionStatuses.CANCELLED);
450                }
451            }
452            catch (WorkflowException e) {
453                logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e);
454            }
455            LOG.debug("doRouteStatusChange() ending");
456        }
457    
458        /**
459         * @see org.kuali.rice.kns.document.DocumentBase#handleRouteLevelChange(org.kuali.rice.kew.clientapp.vo.DocumentRouteLevelChangeDTO)
460         */
461        @Override
462        public void doRouteLevelChange(DocumentRouteLevelChangeDTO change) {
463            LOG.debug("handleRouteLevelChange() started");
464            super.doRouteLevelChange(change);
465            try {
466                String newNodeName = change.getNewNodeName();
467                if (StringUtils.isNotBlank(newNodeName)) {
468                    ReportCriteriaDTO reportCriteriaDTO = new ReportCriteriaDTO(Long.valueOf(getDocumentNumber()));
469                    reportCriteriaDTO.setTargetNodeName(newNodeName);
470                    if (SpringContext.getBean(KualiWorkflowInfo.class).documentWillHaveAtLeastOneActionRequest(reportCriteriaDTO, new String[] { KEWConstants.ACTION_REQUEST_APPROVE_REQ, KEWConstants.ACTION_REQUEST_COMPLETE_REQ }, false)) {
471                        NodeDetails currentNode = NodeDetailEnum.getNodeDetailEnumByName(newNodeName);
472                        if (ObjectUtils.isNotNull(currentNode)) {
473                            if (StringUtils.isNotBlank(currentNode.getAwaitingStatusCode())) {
474                                updateStatusAndSave(currentNode.getAwaitingStatusCode());
475                            }
476                        }
477                    }
478                    else {
479                        LOG.debug("Document with id " + getDocumentNumber() + " will not stop in route node '" + newNodeName + "'");
480                    }
481                }
482            }
483            catch (WorkflowException e) {
484                String errorMsg = "Workflow Error found checking actions requests on document with id " + getDocumentNumber() + ". *** WILL NOT UPDATE PURAP STATUS ***";
485                LOG.warn(errorMsg, e);
486            }
487        }
488    
489        /**
490         * @see org.kuali.kfs.sys.document.AccountingDocument#getSourceAccountingLineClass()
491         */
492        @Override
493        public Class getSourceAccountingLineClass() {
494          //NOTE: do not do anything with this method as it is used by routing etc!
495            return super.getSourceAccountingLineClass();
496        } 
497        
498        public String getRequisitionOrganizationReference1Text() {
499            return requisitionOrganizationReference1Text;
500        }
501    
502        public void setRequisitionOrganizationReference1Text(String requisitionOrganizationReference1Text) {
503            this.requisitionOrganizationReference1Text = requisitionOrganizationReference1Text;
504        }
505    
506        public String getRequisitionOrganizationReference2Text() {
507            return requisitionOrganizationReference2Text;
508        }
509    
510        public void setRequisitionOrganizationReference2Text(String requisitionOrganizationReference2Text) {
511            this.requisitionOrganizationReference2Text = requisitionOrganizationReference2Text;
512        }
513    
514        public String getRequisitionOrganizationReference3Text() {
515            return requisitionOrganizationReference3Text;
516        }
517    
518        public void setRequisitionOrganizationReference3Text(String requisitionOrganizationReference3Text) {
519            this.requisitionOrganizationReference3Text = requisitionOrganizationReference3Text;
520        }
521    
522        public String getAlternate1VendorName() {
523            return alternate1VendorName;
524        }
525    
526        public void setAlternate1VendorName(String alternate1VendorName) {
527            this.alternate1VendorName = alternate1VendorName;
528        }
529    
530        public String getAlternate2VendorName() {
531            return alternate2VendorName;
532        }
533    
534        public void setAlternate2VendorName(String alternate2VendorName) {
535            this.alternate2VendorName = alternate2VendorName;
536        }
537    
538        public String getAlternate3VendorName() {
539            return alternate3VendorName;
540        }
541    
542        public void setAlternate3VendorName(String alternate3VendorName) {
543            this.alternate3VendorName = alternate3VendorName;
544        }
545    
546        public String getAlternate4VendorName() {
547            return alternate4VendorName;
548        }
549    
550        public void setAlternate4VendorName(String alternate4VendorName) {
551            this.alternate4VendorName = alternate4VendorName;
552        }
553    
554        public String getAlternate5VendorName() {
555            return alternate5VendorName;
556        }
557    
558        public void setAlternate5VendorName(String alternate5VendorName) {
559            this.alternate5VendorName = alternate5VendorName;
560        }
561    
562        public KualiDecimal getOrganizationAutomaticPurchaseOrderLimit() {
563            return organizationAutomaticPurchaseOrderLimit;
564        }
565    
566        public void setOrganizationAutomaticPurchaseOrderLimit(KualiDecimal organizationAutomaticPurchaseOrderLimit) {
567            this.organizationAutomaticPurchaseOrderLimit = organizationAutomaticPurchaseOrderLimit;
568        }
569    
570        /**
571         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass()
572         */
573        @Override
574        public Class getItemClass() {
575            return RequisitionItem.class;
576        }
577    
578        @Override
579        public Class getItemUseTaxClass() {
580            return PurchaseRequisitionItemUseTax.class;
581        }
582    
583        /**
584         * Returns null as requistion has no source document.
585         * 
586         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible()
587         */
588        @Override
589        public PurchasingAccountsPayableDocument getPurApSourceDocumentIfPossible() {
590            return null;
591        }
592    
593        /**
594         * Returns null as requistion has no source document.
595         * 
596         * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible()
597         */
598        @Override
599        public String getPurApSourceDocumentLabelIfPossible() {
600            return null;
601        }
602    
603        /**
604         * @see org.kuali.rice.kns.document.Document#getDocumentTitle()
605         */
606        @Override
607        public String getDocumentTitle() {
608            String title = "";
609            if (SpringContext.getBean(ParameterService.class).getIndicatorParameter(RequisitionDocument.class, PurapParameterConstants.PURAP_OVERRIDE_REQ_DOC_TITLE)) {
610                String docIdStr = "";
611                if ((this.getPurapDocumentIdentifier() != null) && (StringUtils.isNotBlank(this.getPurapDocumentIdentifier().toString()))) {
612                    docIdStr = "Requisition: " + this.getPurapDocumentIdentifier().toString();
613                }
614                String chartAcct = this.getFirstChartAccount();
615                String chartAcctStr = (chartAcct == null ? "" : " - Account Number:  " + chartAcct);
616                title = docIdStr + chartAcctStr;
617            }
618            else {
619                title = super.getDocumentTitle();
620            }
621            return title;
622        }
623    
624        /**
625         * Gets this requisition's Chart/Account of the first accounting line from the first item.
626         * 
627         * @return The first Chart and Account, or an empty string if there is none.
628         */
629        protected String getFirstChartAccount() {
630            String chartAcct = null;
631            RequisitionItem item = (RequisitionItem) this.getItem(0);
632            if (ObjectUtils.isNotNull(item)) {
633                if (item.getSourceAccountingLines().size() > 0) {
634                PurApAccountingLine accountLine = item.getSourceAccountingLine(0);
635                if (ObjectUtils.isNotNull(accountLine) && ObjectUtils.isNotNull(accountLine.getChartOfAccountsCode()) && ObjectUtils.isNotNull(accountLine.getAccountNumber())) {
636                    chartAcct = accountLine.getChartOfAccountsCode() + "-" + accountLine.getAccountNumber();
637                    }
638                }
639            }
640            return chartAcct;
641        }
642    
643        public Date getCreateDate() {
644            return this.getDocumentHeader().getWorkflowDocument().getCreateDate();
645        }
646    
647        public String getUrl() {
648            return SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.WORKFLOW_URL_KEY) + "/DocHandler.do?docId=" + getDocumentNumber() + "&command=displayDocSearchView";
649        }
650    
651        /**
652         * Used for routing only.
653         * 
654         * @deprecated
655         */
656        public String getStatusDescription() {
657            return "";
658        }
659    
660        /**
661         * Used for routing only.
662         * 
663         * @deprecated
664         */
665        public void setStatusDescription(String statusDescription) {
666        }
667        
668        /**
669         * This is a "do nothing" version of the method - it just won't create GLPEs
670         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#generateGeneralLedgerPendingEntries(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail, org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
671         */
672        @Override
673        public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
674            return true;
675        }
676    
677        @Override
678        public Class getPurchasingCapitalAssetItemClass() {
679            return RequisitionCapitalAssetItem.class;
680        }
681        
682        @Override
683        public Class getPurchasingCapitalAssetSystemClass() {
684            return RequisitionCapitalAssetSystem.class;
685        }
686        
687        @Override
688        public boolean shouldGiveErrorForEmptyAccountsProration() {
689            if (isDocumentStoppedInRouteNode(NodeDetailEnum.CONTENT_REVIEW) ||
690                getStatusCode().equals(PurapConstants.RequisitionStatuses.IN_PROCESS)) {
691                return false;
692            }
693            return true;
694        }
695        
696        public Date getCreateDateForResult() {
697            return this.getDocumentHeader().getWorkflowDocument().getCreateDate();
698        }
699    
700        /**
701         * Gets the isBlanketApproveRequest attribute. 
702         * @return Returns the isBlanketApproveRequest.
703         */
704        public boolean isBlanketApproveRequest() {
705            return isBlanketApproveRequest;
706        }
707    
708        /**
709         * Sets the isBlanketApproveRequest attribute value.
710         * @param isBlanketApproveRequest The isBlanketApproveRequest to set.
711         */
712        public void setBlanketApproveRequest(boolean isBlanketApproveRequest) {
713            this.isBlanketApproveRequest = isBlanketApproveRequest;
714        }
715        
716        
717    }
718