001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.kns.web.struts.form; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.struts.action.ActionErrors; 020import org.apache.struts.action.ActionMapping; 021import org.apache.struts.upload.FormFile; 022import org.kuali.rice.core.api.CoreApiServiceLocator; 023import org.kuali.rice.core.api.util.RiceKeyConstants; 024import org.kuali.rice.core.web.format.NoOpStringFormatter; 025import org.kuali.rice.core.web.format.TimestampAMPMFormatter; 026import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator; 027import org.kuali.rice.kew.api.KewApiServiceLocator; 028import org.kuali.rice.kew.api.WorkflowDocument; 029import org.kuali.rice.kew.api.WorkflowDocumentFactory; 030import org.kuali.rice.kew.api.action.ActionRequest; 031import org.kuali.rice.kew.api.action.ActionRequestType; 032import org.kuali.rice.kew.api.doctype.DocumentType; 033import org.kuali.rice.kew.api.document.DocumentStatus; 034import org.kuali.rice.kew.api.document.node.RouteNodeInstance; 035import org.kuali.rice.kew.api.exception.WorkflowException; 036import org.kuali.rice.kim.api.KimConstants; 037import org.kuali.rice.kim.api.identity.Person; 038import org.kuali.rice.kim.api.services.KimApiServiceLocator; 039import org.kuali.rice.kns.datadictionary.HeaderNavigation; 040import org.kuali.rice.kns.datadictionary.KNSDocumentEntry; 041import org.kuali.rice.kns.util.WebUtils; 042import org.kuali.rice.kns.web.derivedvaluesetter.DerivedValuesSetter; 043import org.kuali.rice.krad.UserSessionUtils; 044import org.kuali.rice.kns.web.ui.HeaderField; 045import org.kuali.rice.krad.bo.AdHocRoutePerson; 046import org.kuali.rice.krad.bo.AdHocRouteWorkgroup; 047import org.kuali.rice.krad.bo.Note; 048import org.kuali.rice.krad.datadictionary.DataDictionary; 049import org.kuali.rice.krad.document.Document; 050import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 051import org.kuali.rice.krad.service.ModuleService; 052import org.kuali.rice.krad.util.GlobalVariables; 053import org.kuali.rice.krad.util.KRADConstants; 054import org.kuali.rice.krad.util.MessageMap; 055import org.kuali.rice.krad.util.ObjectUtils; 056import org.kuali.rice.krad.util.UrlFactory; 057import org.springframework.util.AutoPopulatingList; 058 059import javax.servlet.http.HttpServletRequest; 060import java.io.Serializable; 061import java.util.ArrayList; 062import java.util.HashMap; 063import java.util.List; 064import java.util.Map; 065import java.util.Properties; 066 067/** 068 * TODO we should not be referencing kew constants from this class and wedding ourselves to that workflow application This class is 069 * the base action form for all documents. 070 * 071 * @deprecated Use {@link org.kuali.rice.krad.web.form.DocumentFormBase}. 072 */ 073@Deprecated 074public abstract class KualiDocumentFormBase extends KualiForm implements Serializable { 075 private static final long serialVersionUID = 916061016201941821L; 076 077 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiDocumentFormBase.class); 078 079 private Document document; 080 private String annotation = ""; 081 private String command; 082 083 private String docId; 084 private String docTypeName; 085 086 private List<String> additionalScriptFiles; 087 088 private AdHocRoutePerson newAdHocRoutePerson; 089 private AdHocRouteWorkgroup newAdHocRouteWorkgroup; 090 091 private Note newNote; 092 093 //TODO: is this still needed? I think it's obsolete now 094 private List boNotes; 095 096 protected FormFile attachmentFile = new BlankFormFile(); 097 098 protected Map editingMode; 099 protected Map documentActions; 100 protected boolean suppressAllButtons; 101 102 protected Map adHocActionRequestCodes; 103 private boolean returnToActionList; 104 105 // for session enhancement 106 private String formKey; 107 private String docNum; 108 109 private List<ActionRequest> actionRequests; 110 private List<String> selectedActionRequests; 111 private String superUserAnnotation; 112 113 114 /** 115 * Stores the error map from previous requests, so that we can continue to display error messages displayed during a previous request 116 */ 117 private MessageMap errorMapFromPreviousRequest; 118 119 /*** 120 * @see KualiForm#addRequiredNonEditableProperties() 121 */ 122 @Override 123 public void addRequiredNonEditableProperties(){ 124 super.addRequiredNonEditableProperties(); 125 registerRequiredNonEditableProperty(KRADConstants.DOCUMENT_TYPE_NAME); 126 registerRequiredNonEditableProperty(KRADConstants.FORM_KEY); 127 registerRequiredNonEditableProperty(KRADConstants.NEW_NOTE_NOTE_TYPE_CODE); 128 } 129 130 /** 131 * @return the docNum 132 */ 133 public String getDocNum() { 134 return this.docNum; 135 } 136 137 /** 138 * @param docNum 139 * the docNum to set 140 */ 141 public void setDocNum(String docNum) { 142 this.docNum = docNum; 143 } 144 145 /** 146 * no args constructor that just initializes things for us 147 */ 148 @SuppressWarnings("unchecked") 149 public KualiDocumentFormBase() { 150 super(); 151 152 instantiateDocument(); 153 newNote = new Note(); 154 this.editingMode = new HashMap(); 155 //this.additionalScriptFiles = new AutoPopulatingList(String.class); 156 this.additionalScriptFiles = new AutoPopulatingList<String>(String.class); 157 158 // set the initial record for persons up 159 newAdHocRoutePerson = new AdHocRoutePerson(); 160 161 // set the initial record for workgroups up 162 newAdHocRouteWorkgroup = new AdHocRouteWorkgroup(); 163 164 // to make sure it posts back the correct time 165 setFormatterType("document.documentHeader.note.finDocNotePostedDttmStamp", TimestampAMPMFormatter.class); 166 setFormatterType("document.documentHeader.note.attachment.finDocNotePostedDttmStamp", TimestampAMPMFormatter.class); 167 //TODO: Chris - Notes: remove the above and change the below from boNotes when notes are finished 168 //overriding note formatter to make sure they post back the full timestamp 169 setFormatterType("document.documentHeader.boNote.notePostedTimestamp",TimestampAMPMFormatter.class); 170 setFormatterType("document.documentBusinessObject.boNote.notePostedTimestamp",TimestampAMPMFormatter.class); 171 172 setFormatterType("editingMode", NoOpStringFormatter.class); 173 setFormatterType("editableAccounts", NoOpStringFormatter.class); 174 175 setDocumentActions(new HashMap()); 176 suppressAllButtons = false; 177 178 initializeHeaderNavigationTabs(); 179 } 180 181 /** 182 * Setup workflow doc in the document. 183 */ 184 @Override 185 public void populate(HttpServletRequest request) { 186 super.populate(request); 187 188 WorkflowDocument workflowDocument = null; 189 190 if (hasDocumentId()) { 191 // populate workflowDocument in documentHeader, if needed 192 // KULRICE-4444 Obtain Document Header using the Workflow Service to minimize overhead 193 try { 194 workflowDocument = UserSessionUtils.getWorkflowDocument(GlobalVariables.getUserSession(), getDocument().getDocumentNumber()); 195 if ( workflowDocument == null) 196 { 197 // gets the workflow document from doc service, doc service will also set the workflow document in the 198 // user's session 199 Person person = GlobalVariables.getUserSession().getPerson(); 200 if (ObjectUtils.isNull(person)) { 201 person = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(KRADConstants.SYSTEM_USER); 202 } 203 workflowDocument = KRADServiceLocatorWeb.getWorkflowDocumentService().loadWorkflowDocument(getDocument().getDocumentNumber(), person); 204 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument); 205 if (workflowDocument == null) 206 { 207 throw new WorkflowException("Unable to retrieve workflow document # " + getDocument().getDocumentNumber() + " from workflow document service createWorkflowDocument"); 208 } 209 else 210 { 211 LOG.debug("Retrieved workflow Document ID: " + workflowDocument.getDocumentId()); 212 } 213 } 214 215 getDocument().getDocumentHeader().setWorkflowDocument(workflowDocument); 216 } catch (WorkflowException e) { 217 LOG.warn("Error while instantiating workflowDoc", e); 218 throw new RuntimeException("error populating documentHeader.workflowDocument", e); 219 } 220 } 221 if (workflowDocument != null) { 222 //Populate Document Header attributes 223 populateHeaderFields(workflowDocument); 224 } 225 } 226 227 protected String getPersonInquiryUrlLink(Person user, String linkBody) { 228 StringBuffer urlBuffer = new StringBuffer(); 229 230 if(user != null && StringUtils.isNotEmpty(linkBody) ) { 231 ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(Person.class); 232 Map<String, String[]> parameters = new HashMap<String, String[]>(); 233 parameters.put(KimConstants.AttributeConstants.PRINCIPAL_ID, new String[] { user.getPrincipalId() }); 234 String inquiryUrl = moduleService.getExternalizableBusinessObjectInquiryUrl(Person.class, parameters); 235 if(!StringUtils.equals(KimConstants.EntityTypes.SYSTEM, user.getEntityTypeCode())){ 236 urlBuffer.append("<a href='"); 237 urlBuffer.append(inquiryUrl); 238 urlBuffer.append("' "); 239 urlBuffer.append("target='_blank'"); 240 urlBuffer.append("title='Person Inquiry'>"); 241 urlBuffer.append(linkBody); 242 urlBuffer.append("</a>"); 243 } else{ 244 urlBuffer.append(linkBody); 245 } 246 } 247 248 return urlBuffer.toString(); 249 } 250 251 protected String getDocumentHandlerUrl(String documentId) { 252 Properties parameters = new Properties(); 253 parameters.put(KRADConstants.PARAMETER_DOC_ID, documentId); 254 parameters.put(KRADConstants.PARAMETER_COMMAND, KRADConstants.METHOD_DISPLAY_DOC_SEARCH_VIEW); 255 return UrlFactory.parameterizeUrl( 256 CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString( 257 KRADConstants.WORKFLOW_URL_KEY) + "/" + KRADConstants.DOC_HANDLER_ACTION, parameters); 258 } 259 260 protected String buildHtmlLink(String url, String linkBody) { 261 StringBuffer urlBuffer = new StringBuffer(); 262 263 if(StringUtils.isNotEmpty(url) && StringUtils.isNotEmpty(linkBody) ) { 264 urlBuffer.append("<a href='").append(url).append("'>").append(linkBody).append("</a>"); 265 } 266 267 return urlBuffer.toString(); 268 } 269 270 /** 271 * This method is used to populate the list of header field objects (see {@link KualiForm#getDocInfo()}) displayed on 272 * the Kuali document form display pages. 273 * 274 * @param workflowDocument - the workflow document of the document being displayed (null is allowed) 275 */ 276 public void populateHeaderFields(WorkflowDocument workflowDocument) { 277 getDocInfo().clear(); 278 getDocInfo().addAll(getStandardHeaderFields(workflowDocument)); 279 } 280 281 /** 282 * This method returns a list of {@link HeaderField} objects that are used by default on Kuali document display pages. To 283 * use this list and override an individual {@link HeaderField} object the id constants from 284 * {@link org.kuali.rice.krad.util.KRADConstants.DocumentFormHeaderFieldIds} can be used to identify items from the list. 285 * 286 * @param workflowDocument - the workflow document of the document being displayed (null is allowed) 287 * @return a list of the standard fields displayed by default for all Kuali documents 288 */ 289 protected List<HeaderField> getStandardHeaderFields(WorkflowDocument workflowDocument) { 290 List<HeaderField> headerFields = new ArrayList<HeaderField>(); 291 setNumColumns(2); 292 // check for a document template number as that will dictate column numbering 293 HeaderField docTemplateNumber = null; 294 if ((ObjectUtils.isNotNull(getDocument())) && (ObjectUtils.isNotNull(getDocument().getDocumentHeader())) && (StringUtils.isNotBlank(getDocument().getDocumentHeader().getDocumentTemplateNumber()))) { 295 String templateDocumentNumber = getDocument().getDocumentHeader().getDocumentTemplateNumber(); 296 docTemplateNumber = new HeaderField(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_TEMPLATE_NUMBER, "DataDictionary.DocumentHeader.attributes.documentTemplateNumber", 297 templateDocumentNumber, buildHtmlLink(getDocumentHandlerUrl(templateDocumentNumber), templateDocumentNumber)); 298 } 299 //Document Number 300 HeaderField docNumber = new HeaderField("DataDictionary.DocumentHeader.attributes.documentNumber", workflowDocument != null? getDocument().getDocumentNumber() : null); 301 docNumber.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_NUMBER); 302 HeaderField docStatus = new HeaderField("DataDictionary.AttributeReference.attributes.workflowDocumentStatus", workflowDocument != null? workflowDocument.getStatus().getLabel() : null); 303 docStatus.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_WORKFLOW_STATUS); 304 String initiatorNetworkId = null; 305 Person user = null; 306 if (workflowDocument != null) { 307 if (getInitiator() == null) { 308 LOG.warn("User Not Found while attempting to build inquiry link for document header fields"); 309 } else { 310 user = getInitiator(); 311 initiatorNetworkId = getInitiator().getPrincipalName(); 312 } 313 } 314 String inquiryUrl = getPersonInquiryUrlLink(user, workflowDocument != null? initiatorNetworkId:null); 315 316 HeaderField docInitiator = new HeaderField(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_INITIATOR, "DataDictionary.AttributeReference.attributes.initiatorNetworkId", 317 workflowDocument != null? initiatorNetworkId : null, workflowDocument != null? inquiryUrl : null); 318 319 String createDateStr = null; 320 if(workflowDocument != null && workflowDocument.getDateCreated() != null) { 321 createDateStr = CoreApiServiceLocator.getDateTimeService().toString(workflowDocument.getDateCreated().toDate(), "hh:mm a MM/dd/yyyy"); 322 } 323 324 HeaderField docCreateDate = new HeaderField("DataDictionary.AttributeReference.attributes.createDate", createDateStr); 325 docCreateDate.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_CREATE_DATE); 326 if (ObjectUtils.isNotNull(docTemplateNumber)) { 327 setNumColumns(3); 328 } 329 330 headerFields.add(docNumber); 331 headerFields.add(docStatus); 332 if (ObjectUtils.isNotNull(docTemplateNumber)) { 333 headerFields.add(docTemplateNumber); 334 } 335 headerFields.add(docInitiator); 336 headerFields.add(docCreateDate); 337 if (ObjectUtils.isNotNull(docTemplateNumber)) { 338 // adding an empty field so implementors do not have to worry about additional fields being put on the wrong row 339 headerFields.add(HeaderField.EMPTY_FIELD); 340 } 341 return headerFields; 342 } 343 344 /** 345 * @see org.apache.struts.action.ActionForm#validate(org.apache.struts.action.ActionMapping, 346 * javax.servlet.http.HttpServletRequest) 347 */ 348 @Override 349 public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { 350 // check that annotation does not exceed 2000 characters 351 setAnnotation(StringUtils.stripToNull(getAnnotation())); 352 int diff = StringUtils.defaultString(getAnnotation()).length() - KRADConstants.DOCUMENT_ANNOTATION_MAX_LENGTH; 353 if (diff > 0) { 354 GlobalVariables.getMessageMap().putError("annotation", RiceKeyConstants.ERROR_DOCUMENT_ANNOTATION_MAX_LENGTH_EXCEEDED, new String[] { Integer.toString(KRADConstants.DOCUMENT_ANNOTATION_MAX_LENGTH), Integer.toString(diff) }); 355 } 356 return super.validate(mapping, request); 357 } 358 359 /** 360 * @return true if this document was properly initialized with a DocumentHeader and related KualiWorkflowDocument 361 */ 362 final public boolean isFormDocumentInitialized() { 363 boolean initialized = false; 364 365 if (document != null) { 366 if (document.getDocumentHeader() != null) { 367 initialized = document.getDocumentHeader().hasWorkflowDocument(); 368 } 369 } 370 371 return initialized; 372 } 373 374 375 /** 376 * @return Map of editingModes for this document, as set during the most recent call to 377 * populate(javax.servlet.http.HttpServletRequest) 378 */ 379 @SuppressWarnings("unchecked") 380 public Map getEditingMode() { 381 return editingMode; 382 } 383 384 /** 385 * Set editingMode for this document 386 */ 387 @SuppressWarnings("unchecked") 388 public void setEditingMode(Map editingMode) { 389 this.editingMode = editingMode; 390 } 391 392 /** 393 * @return the documentActions 394 */ 395 @SuppressWarnings("unchecked") 396 public Map getDocumentActions() { 397 return this.documentActions; 398 } 399 400 /** 401 * @param documentActions the documentActions to set 402 */ 403 @SuppressWarnings("unchecked") 404 public void setDocumentActions(Map documentActions) { 405 this.documentActions = documentActions; 406 } 407 408 409 410 /** 411 * @param adHocActionRequestCodes the adHocActionRequestCodes to set 412 */ 413 @SuppressWarnings("unchecked") 414 public void setAdHocActionRequestCodes(Map adHocActionRequestCodes) { 415 this.adHocActionRequestCodes = adHocActionRequestCodes; 416 } 417 418 /** 419 * @return a map of the possible action request codes that takes into account the users context on the document 420 */ 421 @SuppressWarnings("unchecked") 422 public Map getAdHocActionRequestCodes() { 423 //Map adHocActionRequestCodes = new HashMap(); 424 //KRADServiceLocatorInternal.getDocumentHelperService() 425 /*if (getWorkflowDocument() != null) { 426 if (getWorkflowDocument().isFYIRequested()) { 427 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL); 428 } 429 else if (getWorkflowDocument().isAcknowledgeRequested()) { 430 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ_LABEL); 431 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL); 432 } 433 else if (getWorkflowDocument().isApprovalRequested() || getWorkflowDocument().isCompletionRequested() || getWorkflowDocument().stateIsInitiated() || getWorkflowDocument().stateIsSaved()) { 434 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ_LABEL); 435 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL); 436 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, KewApiConstants.ACTION_REQUEST_APPROVE_REQ_LABEL); 437 } 438 }*/ 439 return adHocActionRequestCodes; 440 } 441 442 443 /** 444 * @return the list of ad hoc routing persons 445 */ 446 public List<AdHocRoutePerson> getAdHocRoutePersons() { 447 return document.getAdHocRoutePersons(); 448 } 449 450 451 /** 452 * @return attachmentFile 453 */ 454 public FormFile getAttachmentFile() { 455 return attachmentFile; 456 } 457 458 /** 459 * @param attachmentFile The attachmentFile to set. 460 */ 461 public void setAttachmentFile(FormFile attachmentFile) { 462 this.attachmentFile = attachmentFile; 463 } 464 465 466 /** 467 * set the ad hoc routing persons list 468 * 469 * @param adHocRouteRecipients 470 */ 471 public void setAdHocRoutePersons(List<AdHocRoutePerson> adHocRouteRecipients) { 472 document.setAdHocRoutePersons(adHocRouteRecipients); 473 } 474 475 /** 476 * get the ad hoc routing workgroup requests 477 * 478 * @return 479 */ 480 public List<AdHocRouteWorkgroup> getAdHocRouteWorkgroups() { 481 return document.getAdHocRouteWorkgroups(); 482 } 483 484 /** 485 * set the ad hoc routing workgroup requests 486 * 487 * @param adHocRouteWorkgroups 488 */ 489 public void setAdHocRouteWorkgroups(List<AdHocRouteWorkgroup> adHocRouteWorkgroups) { 490 document.setAdHocRouteWorkgroups(adHocRouteWorkgroups); 491 } 492 493 /** 494 * Special getter based on index to work with multi rows for ad hoc routing to persons struts page 495 * 496 * @param index 497 * @return 498 */ 499 public AdHocRoutePerson getAdHocRoutePerson(int index) { 500 while (getAdHocRoutePersons().size() <= index) { 501 getAdHocRoutePersons().add(new AdHocRoutePerson()); 502 } 503 return getAdHocRoutePersons().get(index); 504 } 505 506 /** 507 * Special getter based on index to work with multi rows for ad hoc routing to workgroups struts page 508 * 509 * @param index 510 * @return 511 */ 512 public AdHocRouteWorkgroup getAdHocRouteWorkgroup(int index) { 513 while (getAdHocRouteWorkgroups().size() <= index) { 514 getAdHocRouteWorkgroups().add(new AdHocRouteWorkgroup()); 515 } 516 return getAdHocRouteWorkgroups().get(index); 517 } 518 519 /** 520 * @return the new ad hoc route person object 521 */ 522 public AdHocRoutePerson getNewAdHocRoutePerson() { 523 return newAdHocRoutePerson; 524 } 525 526 /** 527 * set the new ad hoc route person object 528 * 529 * @param newAdHocRoutePerson 530 */ 531 public void setNewAdHocRoutePerson(AdHocRoutePerson newAdHocRoutePerson) { 532 this.newAdHocRoutePerson = newAdHocRoutePerson; 533 } 534 535 /** 536 * @return the new ad hoc route workgroup object 537 */ 538 public AdHocRouteWorkgroup getNewAdHocRouteWorkgroup() { 539 return newAdHocRouteWorkgroup; 540 } 541 542 /** 543 * set the new ad hoc route workgroup object 544 * 545 * @param newAdHocRouteWorkgroup 546 */ 547 public void setNewAdHocRouteWorkgroup(AdHocRouteWorkgroup newAdHocRouteWorkgroup) { 548 this.newAdHocRouteWorkgroup = newAdHocRouteWorkgroup; 549 } 550 551 /** 552 * @return Returns the Document 553 */ 554 public Document getDocument() { 555 return document; 556 } 557 558 /** 559 * @param document 560 */ 561 public void setDocument(Document document) { 562 this.document = document; 563 if(document != null && StringUtils.isNotEmpty(document.getDocumentNumber())) { 564 populateHeaderFields(document.getDocumentHeader().getWorkflowDocument()); 565 } 566 } 567 568 /** 569 * @return WorkflowDocument for this form's document 570 */ 571 public WorkflowDocument getWorkflowDocument() { 572 return getDocument().getDocumentHeader().getWorkflowDocument(); 573 } 574 575 /** 576 * Null-safe check to see if the workflow document object exists before attempting to retrieve it. 577 * (Which, if called, will throw an exception.) 578 */ 579 public boolean isHasWorkflowDocument() { 580 if ( getDocument() == null || getDocument().getDocumentHeader() == null ) { 581 return false; 582 } 583 return getDocument().getDocumentHeader().hasWorkflowDocument(); 584 } 585 586 /** 587 * TODO rk implemented to account for caps coming from kuali user service from workflow 588 */ 589 public boolean isUserDocumentInitiator() { 590 if (getWorkflowDocument() != null) { 591 return getWorkflowDocument().getInitiatorPrincipalId().equalsIgnoreCase( 592 GlobalVariables.getUserSession().getPrincipalId()); 593 } 594 return false; 595 } 596 597 public Person getInitiator() { 598 String initiatorPrincipalId = getWorkflowDocument().getInitiatorPrincipalId(); 599 return KimApiServiceLocator.getPersonService().getPerson(initiatorPrincipalId); 600 } 601 602 /** 603 * @return true if the workflowDocument associated with this form is currently enroute 604 */ 605 public boolean isDocumentEnRoute() { 606 return getWorkflowDocument().isEnroute(); 607 } 608 609 /** 610 * @param annotation The annotation to set. 611 */ 612 public void setAnnotation(String annotation) { 613 this.annotation = annotation; 614 } 615 616 /** 617 * @return Returns the annotation. 618 */ 619 public String getAnnotation() { 620 return annotation; 621 } 622 623 /** 624 * @return returns the command that was passed from workflow 625 */ 626 public String getCommand() { 627 return command; 628 } 629 630 /** 631 * setter for the command that was passed from workflow on the url 632 * 633 * @param command 634 */ 635 public void setCommand(String command) { 636 this.command = command; 637 } 638 639 /** 640 * @return returns the docId that was passed from workflow on the url 641 */ 642 public String getDocId() { 643 return docId; 644 } 645 646 /** 647 * setter for the docId that was passed from workflow on the url 648 * 649 * @param docId 650 */ 651 public void setDocId(String docId) { 652 this.docId = docId; 653 } 654 655 /** 656 * getter for the docTypeName that was passed from workflow on the url 657 * 658 * @return 659 */ 660 public String getDocTypeName() { 661 return docTypeName; 662 } 663 664 /** 665 * setter for the docTypeName that was passed from workflow on the url 666 * 667 * @param docTypeName 668 */ 669 public void setDocTypeName(String docTypeName) { 670 this.docTypeName = docTypeName; 671 } 672 673 /** 674 * getter for convenience that will return the initiators network id 675 * 676 * @return 677 */ 678 public String getInitiatorNetworkId() { 679 return this.getWorkflowDocument().getInitiatorPrincipalId(); 680 } 681 682 /** 683 * Gets the suppressAllButtons attribute. 684 * 685 * @return Returns the suppressAllButtons. 686 */ 687 public final boolean isSuppressAllButtons() { 688 return suppressAllButtons; 689 } 690 691 /** 692 * Sets the suppressAllButtons attribute value. 693 * 694 * @param suppressAllButtons The suppressAllButtons to set. 695 */ 696 public final void setSuppressAllButtons(boolean suppressAllButtons) { 697 this.suppressAllButtons = suppressAllButtons; 698 } 699 700 /** 701 * @return true if this form's getDocument() method returns a Document, and if that Document's getDocumentHeaderId method 702 * returns a non-null 703 */ 704 public boolean hasDocumentId() { 705 boolean hasDocId = false; 706 707 Document d = getDocument(); 708 if (d != null) { 709 String docHeaderId = d.getDocumentNumber(); 710 711 hasDocId = StringUtils.isNotBlank(docHeaderId); 712 } 713 714 return hasDocId; 715 } 716 717 /** 718 * Sets flag indicating whether upon completion of approve, blanketApprove, cancel, or disapprove, the user should be returned 719 * to the actionList instead of to the portal 720 * 721 * @param returnToActionList 722 */ 723 public void setReturnToActionList(boolean returnToActionList) { 724 this.returnToActionList = returnToActionList; 725 } 726 727 public boolean isReturnToActionList() { 728 return returnToActionList; 729 } 730 731 public List<String> getAdditionalScriptFiles() { 732 return additionalScriptFiles; 733 } 734 735 public void setAdditionalScriptFiles(List<String> additionalScriptFiles) { 736 this.additionalScriptFiles = additionalScriptFiles; 737 } 738 739 public void setAdditionalScriptFile( int index, String scriptFile ) { 740 additionalScriptFiles.set( index, scriptFile ); 741 } 742 743 public String getAdditionalScriptFile( int index ) { 744 return additionalScriptFiles.get( index ); 745 } 746 747 public Note getNewNote() { 748 return newNote; 749 } 750 751 public void setNewNote(Note newNote) { 752 this.newNote = newNote; 753 } 754 755 /** 756 * Gets the boNotes attribute. 757 * @return Returns the boNotes. 758 */ 759 @SuppressWarnings("unchecked") 760 public List getBoNotes() { 761 return boNotes; 762 } 763 764 /** 765 * Sets the boNotes attribute value. 766 * @param boNotes The boNotes to set. 767 */ 768 @SuppressWarnings("unchecked") 769 public void setBoNotes(List boNotes) { 770 this.boNotes = boNotes; 771 } 772 773 public String getFormKey() { 774 return this.formKey; 775 } 776 777 public void setFormKey(String formKey) { 778 this.formKey = formKey; 779 } 780 781 /* Reset method 782 * This is initially created for session document implementation 783 * @param mapping 784 * @param request 785 */ 786 @Override 787 public void reset(ActionMapping mapping, HttpServletRequest request) { 788 super.reset(mapping, request); 789 this.setMethodToCall(null); 790 this.setRefreshCaller(null); 791 this.setAnchor(null); 792 this.setCurrentTabIndex(0); 793 this.setSelectedActionRequests(new ArrayList<String>()); 794 } 795 796 797 /** 798 * Adds the attachment file size to the list of max file sizes. 799 * 800 * @see org.kuali.rice.krad.web.struts.pojo.PojoFormBase#customInitMaxUploadSizes() 801 */ 802 @Override 803 protected void customInitMaxUploadSizes() { 804 super.customInitMaxUploadSizes(); 805 String attachmentSize = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KRADConstants.KNS_NAMESPACE, KRADConstants.DetailTypes.DOCUMENT_DETAIL_TYPE, KRADConstants.ATTACHMENT_MAX_FILE_SIZE_PARM_NM); 806 if (StringUtils.isNotBlank(attachmentSize)) { 807 addMaxUploadSize(attachmentSize); 808 } 809 } 810 811 812 813 /** 814 * This overridden method ... 815 * IMPORTANT: any overrides of this method must ensure that nothing in the HTTP request will be used to determine whether document is in session 816 * 817 * @see org.kuali.rice.krad.web.struts.pojo.PojoFormBase#shouldPropertyBePopulatedInForm(java.lang.String, javax.servlet.http.HttpServletRequest) 818 */ 819 @Override 820 public boolean shouldPropertyBePopulatedInForm(String requestParameterName, HttpServletRequest request) { 821 for ( String prefix : KRADConstants.ALWAYS_VALID_PARAMETER_PREFIXES ) { 822 if (requestParameterName.startsWith(prefix)) { 823 return true; 824 } 825 } 826 827 if (StringUtils.equalsIgnoreCase(getMethodToCall(), KRADConstants.DOC_HANDLER_METHOD)) { 828 return true; 829 } 830 if (WebUtils.isDocumentSession(getDocument(), this)) { 831 return isPropertyEditable(requestParameterName) || isPropertyNonEditableButRequired(requestParameterName); 832 } 833 return true; 834 } 835 836 /** 837 * This overridden method ... 838 * 839 * @see KualiForm#shouldMethodToCallParameterBeUsed(java.lang.String, java.lang.String, javax.servlet.http.HttpServletRequest) 840 */ 841 @Override 842 public boolean shouldMethodToCallParameterBeUsed( 843 String methodToCallParameterName, 844 String methodToCallParameterValue, HttpServletRequest request) { 845 if (StringUtils.equals(methodToCallParameterName, KRADConstants.DISPATCH_REQUEST_PARAMETER) && 846 StringUtils.equals(methodToCallParameterValue, KRADConstants.DOC_HANDLER_METHOD)) { 847 return true; 848 } 849 return super.shouldMethodToCallParameterBeUsed(methodToCallParameterName, 850 methodToCallParameterValue, request); 851 } 852 853 public MessageMap getMessageMapFromPreviousRequest() { 854 return this.errorMapFromPreviousRequest; 855 } 856 857 public void setMessageMapFromPreviousRequest(MessageMap errorMapFromPreviousRequest) { 858 this.errorMapFromPreviousRequest = errorMapFromPreviousRequest; 859 } 860 861 @Override 862 public void setDerivedValuesOnForm(HttpServletRequest request) { 863 super.setDerivedValuesOnForm(request); 864 865 String docTypeName = getDocTypeName(); 866 if (StringUtils.isNotBlank(docTypeName)) { 867 DataDictionary dataDictionary = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary(); 868 869 Class<? extends DerivedValuesSetter> derivedValuesSetterClass = null; 870 KNSDocumentEntry documentEntry = (KNSDocumentEntry) dataDictionary.getDocumentEntry(docTypeName); 871 derivedValuesSetterClass = (documentEntry).getDerivedValuesSetterClass(); 872 873 if (derivedValuesSetterClass != null) { 874 DerivedValuesSetter derivedValuesSetter = null; 875 try { 876 derivedValuesSetter = derivedValuesSetterClass.newInstance(); 877 } 878 879 catch (Exception e) { 880 LOG.error("Unable to instantiate class " + derivedValuesSetterClass.getName(), e); 881 throw new RuntimeException("Unable to instantiate class " + derivedValuesSetterClass.getName(), e); 882 } 883 derivedValuesSetter.setDerivedValues(this, request); 884 } 885 } 886 } 887 888 protected String getDefaultDocumentTypeName() { 889 return ""; 890 } 891 892 /** will instatiate a new document setting it on the form if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value. */ 893 protected void instantiateDocument() { 894 if (document == null && StringUtils.isNotBlank(getDefaultDocumentTypeName())) { 895 Class<? extends Document> documentClass = getDocumentClass(); 896 try { 897 Document document = documentClass.newInstance(); 898 setDocument(document); 899 } catch (Exception e) { 900 LOG.error("Unable to instantiate document class " + documentClass.getName() + " document type " + getDefaultDocumentTypeName()); 901 throw new RuntimeException(e); 902 } 903 } 904 } 905 906 /** gets the document class from the datadictionary if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value otherwise behavior is nondeterministic. */ 907 private Class<? extends Document> getDocumentClass() { 908 return KRADServiceLocatorWeb.getDataDictionaryService().getDocumentClassByTypeName(getDefaultDocumentTypeName()); 909 } 910 911 /**initializes the header tabs from what is defined in the datadictionary if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value. */ 912 protected void initializeHeaderNavigationTabs() { 913 if (StringUtils.isNotBlank(getDefaultDocumentTypeName())) { 914 final KNSDocumentEntry docEntry = (KNSDocumentEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(getDocumentClass().getName()); 915 final List<HeaderNavigation> navList = docEntry.getHeaderNavigationList(); 916 final HeaderNavigation[] list = new HeaderNavigation[navList.size()]; 917 super.setHeaderNavigationTabs(navList.toArray(list)); 918 } 919 } 920 921 public List<ActionRequest> getActionRequests() { 922 return actionRequests; 923 } 924 925 public void setActionRequests(List<ActionRequest> actionRequests) { 926 this.actionRequests = actionRequests; 927 } 928 929 public List<String> getSelectedActionRequests() { 930 return selectedActionRequests; 931 } 932 933 public void setSelectedActionRequests(List<String> selectedActionRequests) { 934 this.selectedActionRequests = selectedActionRequests; 935 } 936 937 public List<ActionRequest> getActionRequestsRequiringApproval() { 938 List<ActionRequest> actionRequests = getActionRequests(); 939 List<ActionRequest> actionRequestsApprove = new ArrayList<ActionRequest>();; 940 941 for (ActionRequest actionRequest: actionRequests) { 942 if ((StringUtils.equals(actionRequest.getActionRequested().getCode(), ActionRequestType.APPROVE.getCode())) || 943 (StringUtils.equals(actionRequest.getActionRequested().getCode(), ActionRequestType.COMPLETE.getCode()))) { 944 actionRequestsApprove.add(actionRequest); 945 } 946 } 947 return actionRequestsApprove; 948 } 949 950 public String getSuperUserAnnotation() { 951 return superUserAnnotation; 952 } 953 954 public void setSuperUserAnnotation(String superUserAnnotation) { 955 this.superUserAnnotation = superUserAnnotation; 956 } 957 958 public boolean isSuperUserActionAvaliable() { 959 List<ActionRequest> actionRequests = getActionRequestsRequiringApproval(); 960 boolean hasSingleActionToTake = false; 961 boolean canSuperUserApprove = false; 962 boolean canSuperUserDisapprove = false; 963 964 hasSingleActionToTake = ( isSuperUserApproveSingleActionRequestAuthorized() && 965 isStateAllowsApproveSingleActionRequest() && 966 !actionRequests.isEmpty()); 967 if (!hasSingleActionToTake) { 968 canSuperUserApprove = (isSuperUserApproveDocumentAuthorized() && isStateAllowsApproveOrDisapprove()); 969 } 970 if (!canSuperUserApprove) { 971 canSuperUserDisapprove = (isSuperUserDisapproveDocumentAuthorized() && isStateAllowsApproveOrDisapprove()); 972 } 973 974 return (hasSingleActionToTake || canSuperUserApprove || canSuperUserDisapprove) ; 975 } 976 977 public boolean isSuperUserApproveSingleActionRequestAuthorized() { 978 String principalId = GlobalVariables.getUserSession().getPrincipalId(); 979 String docId = this.getDocId(); 980 DocumentType documentType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(docTypeName); 981 String docTypeId = null; 982 if (documentType != null) { 983 docTypeId = documentType.getId(); 984 } 985 if ( KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, docTypeId) ) { 986 return true; 987 } 988 List<RouteNodeInstance> routeNodeInstances= KewApiServiceLocator.getWorkflowDocumentService().getRouteNodeInstances(docId); 989 String documentStatus = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(docId).getCode(); 990 return KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveSingleActionRequest( 991 principalId, getDocTypeName(), routeNodeInstances, documentStatus); 992 } 993 994 public boolean isSuperUserApproveDocumentAuthorized() { 995 String principalId = GlobalVariables.getUserSession().getPrincipalId(); 996 String docId = this.getDocId(); 997 DocumentType documentType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(docTypeName); 998 String docTypeId = null; 999 if (documentType != null) { 1000 docTypeId = documentType.getId(); 1001 } 1002 if ( KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, docTypeId) ) { 1003 return true; 1004 } 1005 List<RouteNodeInstance> routeNodeInstances= KewApiServiceLocator.getWorkflowDocumentService().getRouteNodeInstances(docId); 1006 String documentStatus = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(docId).getCode(); 1007 return KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveDocument( 1008 principalId, this.getDocTypeName(), routeNodeInstances, documentStatus); 1009 } 1010 1011 public boolean isSuperUserDisapproveDocumentAuthorized() { 1012 String principalId = GlobalVariables.getUserSession().getPrincipalId(); 1013 String docId = this.getDocId(); 1014 DocumentType documentType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(docTypeName); 1015 String docTypeId = null; 1016 if (documentType != null) { 1017 docTypeId = documentType.getId(); 1018 } 1019 if ( KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, docTypeId) ) { 1020 return true; 1021 } 1022 List<RouteNodeInstance> routeNodeInstances= KewApiServiceLocator.getWorkflowDocumentService().getRouteNodeInstances(docId); 1023 String documentStatus = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(docId).getCode(); 1024 return KewApiServiceLocator.getDocumentTypeService().canSuperUserDisapproveDocument( 1025 principalId, this.getDocTypeName(), routeNodeInstances, documentStatus); 1026 } 1027 1028 public boolean isSuperUserAuthorized() { 1029 String docId = this.getDocId(); 1030 if (StringUtils.isBlank(docId) || ObjectUtils.isNull(docTypeName)) { 1031 return false; 1032 } 1033 1034 DocumentType documentType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(docTypeName); 1035 String docTypeId = null; 1036 if (documentType != null) { 1037 docTypeId = documentType.getId(); 1038 } 1039 String principalId = GlobalVariables.getUserSession().getPrincipalId(); 1040 if ( KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, docTypeId) ) { 1041 return true; 1042 } 1043 List<RouteNodeInstance> routeNodeInstances= KewApiServiceLocator.getWorkflowDocumentService().getRouteNodeInstances( 1044 docId); 1045 String documentStatus = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(docId).getCode(); 1046 return ((KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveSingleActionRequest( 1047 principalId, this.getDocTypeName(), routeNodeInstances, documentStatus)) || 1048 (KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveDocument( 1049 principalId, this.getDocTypeName(), routeNodeInstances, documentStatus)) || 1050 (KewApiServiceLocator.getDocumentTypeService().canSuperUserDisapproveDocument ( 1051 principalId, this.getDocTypeName(), routeNodeInstances, documentStatus))) ; 1052 } 1053 1054 public boolean isStateAllowsApproveOrDisapprove() { 1055 if(this.getDocument().getDocumentHeader().hasWorkflowDocument()) { 1056 DocumentStatus status = null; 1057 WorkflowDocument document = WorkflowDocumentFactory.loadDocument(GlobalVariables.getUserSession().getPrincipalId(), 1058 this.getDocument().getDocumentHeader().getWorkflowDocument().getDocumentId()); 1059 if (ObjectUtils.isNotNull(document)) { 1060 status = document.getStatus(); 1061 } else { 1062 status = this.getDocument().getDocumentHeader().getWorkflowDocument().getStatus(); 1063 } 1064 return !(isStateProcessedOrDisapproved(status) || 1065 isStateInitiatedFinalCancelled(status) || 1066 StringUtils.equals(status.getCode(), DocumentStatus.SAVED.getCode())); 1067 } else { 1068 return false; 1069 } 1070 } 1071 1072 public boolean isStateAllowsApproveSingleActionRequest() { 1073 if(this.getDocument().getDocumentHeader().hasWorkflowDocument()) { 1074 DocumentStatus status = null; 1075 WorkflowDocument document = WorkflowDocumentFactory.loadDocument(GlobalVariables.getUserSession().getPrincipalId(), 1076 this.getDocument().getDocumentHeader().getWorkflowDocument().getDocumentId()); 1077 if (ObjectUtils.isNotNull(document)) { 1078 status = document.getStatus(); 1079 } else { 1080 status = this.getDocument().getDocumentHeader().getWorkflowDocument().getStatus(); 1081 } 1082 return !(isStateInitiatedFinalCancelled(status)); 1083 } else { 1084 return false; 1085 } 1086 } 1087 1088 public boolean isStateProcessedOrDisapproved(DocumentStatus status) { 1089 return (StringUtils.equals(status.getCode(), DocumentStatus.PROCESSED.getCode()) || 1090 StringUtils.equals(status.getCode(), DocumentStatus.DISAPPROVED.getCode())); 1091 } 1092 1093 public boolean isStateInitiatedFinalCancelled(DocumentStatus status) { 1094 return (StringUtils.equals(status.getCode(), DocumentStatus.INITIATED.getCode()) || 1095 StringUtils.equals(status.getCode(), DocumentStatus.FINAL.getCode()) || 1096 StringUtils.equals(status.getCode(), DocumentStatus.CANCELED.getCode())); 1097 } 1098}