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