001/**
002 * Copyright 2005-2018 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.krad.document;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
020import org.kuali.rice.coreservice.framework.parameter.ParameterService;
021import org.kuali.rice.kew.api.KewApiServiceLocator;
022import org.kuali.rice.kew.api.WorkflowDocument;
023import org.kuali.rice.kew.api.action.ActionRequest;
024import org.kuali.rice.kew.api.action.ActionRequestType;
025import org.kuali.rice.kew.api.action.ActionType;
026import org.kuali.rice.kew.api.document.DocumentStatus;
027import org.kuali.rice.krad.uif.view.RequestAuthorizationCache;
028import org.kuali.rice.krad.util.GlobalVariables;
029import org.kuali.rice.krad.util.KRADConstants;
030import org.kuali.rice.krad.util.KRADUtils;
031
032import java.io.Serializable;
033
034/**
035 * @author Kuali Rice Team (rice.collab@kuali.org)
036 */
037public class DocumentPresentationControllerBase implements DocumentPresentationController, Serializable {
038    private static final long serialVersionUID = -9181864754090276024L;
039
040    private static transient ParameterService parameterService;
041
042    private DocumentRequestAuthorizationCache documentRequestAuthorizationCache;
043
044    public boolean canInitiate(String documentTypeName) {
045        return true;
046    }
047
048    public boolean canEdit(Document document) {
049        boolean canEdit = false;
050
051        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
052                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
053
054        if (workflowDocumentInfo.isInitiated()
055                || workflowDocumentInfo.isSaved()
056                || workflowDocumentInfo.isEnroute()
057                || workflowDocumentInfo.isException()) {
058            canEdit = true;
059        }
060
061        return canEdit;
062    }
063
064    public boolean canAnnotate(Document document) {
065        return true;
066    }
067
068    public boolean canReload(Document document) {
069        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
070                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
071
072        return (canEdit(document) && !workflowDocumentInfo.isInitiated());
073
074    }
075
076    public boolean canClose(Document document) {
077        return false;
078    }
079
080    public boolean canSave(Document document) {
081        return canEdit(document);
082    }
083
084    public boolean canRoute(Document document) {
085        boolean canRoute = false;
086
087        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
088                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
089
090        if (workflowDocumentInfo.isInitiated() || workflowDocumentInfo.isSaved()) {
091            canRoute = true;
092        }
093
094        return canRoute;
095    }
096
097    public boolean canCancel(Document document) {
098        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
099                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
100
101        return workflowDocumentInfo.isValidAction(ActionType.CANCEL);
102    }
103
104    public boolean canRecall(Document document) {
105        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
106                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
107
108        return workflowDocumentInfo.isEnroute();
109    }
110
111    public boolean canCopy(Document document) {
112        boolean canCopy = false;
113        if (document.getAllowsCopy()) {
114            canCopy = true;
115        }
116        return canCopy;
117    }
118
119    @Override
120    public boolean canPerformRouteReport(Document document) {
121        return getParameterService().getParameterValueAsBoolean(KRADConstants.KNS_NAMESPACE,
122                KRADConstants.DetailTypes.DOCUMENT_DETAIL_TYPE,
123                KRADConstants.SystemGroupParameterNames.DEFAULT_CAN_PERFORM_ROUTE_REPORT_IND);
124    }
125
126    public boolean canAddAdhocRequests(Document document) {
127        return true;
128    }
129
130    public boolean canBlanketApprove(Document document) {
131        // check system parameter - if Y, use default workflow behavior: allow a user with the permission
132        // to perform the blanket approve action at any time
133        Boolean allowBlanketApproveNoRequest = getParameterService().getParameterValueAsBoolean(
134                KRADConstants.KNS_NAMESPACE, KRADConstants.DetailTypes.DOCUMENT_DETAIL_TYPE,
135                KRADConstants.SystemGroupParameterNames.ALLOW_ENROUTE_BLANKET_APPROVE_WITHOUT_APPROVAL_REQUEST_IND);
136        if (allowBlanketApproveNoRequest != null && allowBlanketApproveNoRequest.booleanValue()) {
137            return canEdit(document);
138        }
139
140        // otherwise, limit the display of the blanket approve button to only the initiator of the document
141        // (prior to routing)
142        WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
143        if (canRoute(document) && StringUtils.equals(workflowDocument.getInitiatorPrincipalId(),
144                GlobalVariables.getUserSession().getPrincipalId())) {
145            return true;
146        }
147
148        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
149                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
150
151        // or to a user with an approval action request
152        if (workflowDocumentInfo.isApprovalRequested()) {
153            return true;
154        }
155
156        return false;
157    }
158
159    public boolean canApprove(Document document) {
160        return !canComplete(document);
161    }
162
163    public boolean canDisapprove(Document document) {
164        // most of the time, a person who can approve can disapprove
165        return canApprove(document);
166    }
167
168    public boolean canSendAdhocRequests(Document document) {
169        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
170                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
171
172        return !(workflowDocumentInfo.isInitiated() || workflowDocumentInfo.isSaved());
173    }
174
175    public boolean canSendNoteFyi(Document document) {
176        return true;
177    }
178
179    public boolean canEditDocumentOverview(Document document) {
180        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
181                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
182
183        return (workflowDocumentInfo.isInitiated() || workflowDocumentInfo.isSaved());
184    }
185
186    public boolean canFyi(Document document) {
187        return true;
188    }
189
190    public boolean canAcknowledge(Document document) {
191        return true;
192    }
193
194    public boolean canComplete(Document document) {
195        DocumentRequestAuthorizationCache.WorkflowDocumentInfo workflowDocumentInfo =
196                getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo();
197
198        boolean docInInit = workflowDocumentInfo.isInitiated() || workflowDocumentInfo.isSaved();
199        boolean completionRequested = workflowDocumentInfo.isCompletionRequested();
200        if (completionRequested && !docInInit) {
201            return true;
202        }
203        return false;
204    }
205
206    /**
207     * {@inheritDoc}
208     */
209    @Override
210    public boolean canSuperUserTakeAction(Document document) {
211        return hasActionRequests(document) && canTakeAction(document);
212    }
213
214    /**
215     * {@inheritDoc}
216     */
217    @Override
218    public boolean canSuperUserApprove(Document document) {
219        return canApproveOrDisapprove(document);
220    }
221
222    /**
223     * {@inheritDoc}
224     */
225    @Override
226    public boolean canSuperUserDisapprove(Document document) {
227        return canApproveOrDisapprove(document);
228    }
229
230    /**
231     * Returns whether the {@code document} has any APPROVE or COMPLETE action requests.
232     *
233     * @param document the document to check
234     *
235     * @return true if the {@code document} has any APPROVE or COMPLETE action requests, false otherwise
236     */
237    protected boolean hasActionRequests(Document document) {
238        boolean hasActionRequests = false;
239
240        for (ActionRequest actionRequest : document.getActionRequests()) {
241            if  (StringUtils.equals(actionRequest.getActionRequested().getCode(), ActionRequestType.APPROVE.getCode())
242                    || StringUtils.equals(actionRequest.getActionRequested().getCode(), ActionRequestType.COMPLETE.getCode())) {
243                hasActionRequests = true;
244                break;
245            }
246        }
247
248        return hasActionRequests;
249    }
250
251    /**
252     * Returns whether a super user action can be taken on the {@code document}.
253     *
254     * <p>
255     * Typically, actions can only be taken on a document not in INITIATED, FINAL, or CANCELLED status.
256     * </p>
257     *
258     * @param document the document to check
259     *
260     * @return true if a super user action can be taken on the {@code document}, false otherwise
261     */
262    protected boolean canTakeAction(Document document) {
263        String documentNumber = document.getDocumentNumber();
264        DocumentStatus status = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(documentNumber);
265
266        return !isStateInitiatedFinalCancelled(status);
267    }
268
269    /**
270     * Returns whether a super user approve or disapprove action can be taken on the {@code document}.
271     *
272     * <p>
273     * Typically, actions can only be taken on a document not in INITIATED, SAVED, PROCESSED, DISAPPROVED, FINAL, or
274     * CANCELLED status.
275     * </p>
276     *
277     * @param document the document to check
278     * @return true if a super user approve or disapprove action can be taken on the {@code document}, false otherwise
279     */
280    protected boolean canApproveOrDisapprove(Document document) {
281        boolean canComplete = canComplete(document);
282        String documentNumber = document.getDocumentNumber();
283        DocumentStatus status = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(documentNumber);
284
285        return !canComplete && !isStateInitiatedFinalCancelled(status) && !isStateSaved(status)
286                && !isStateProcessedOrDisapproved(status);
287    }
288
289    /**
290     * Returns whether the {@code document} is in a INITIATED, FINAL, or CANCELLED state.
291     *
292     * @param status the document status
293     *
294     * @return true if the {@code document} is in a INITIATED, FINAL, or CANCELLED state, false otherwise
295     */
296    protected boolean isStateInitiatedFinalCancelled(DocumentStatus status) {
297        return (StringUtils.equals(status.getCode(), DocumentStatus.INITIATED.getCode()) ||
298                StringUtils.equals(status.getCode(), DocumentStatus.FINAL.getCode()) ||
299                StringUtils.equals(status.getCode(), DocumentStatus.CANCELED.getCode()));
300    }
301
302    /**
303     * Returns whether the {@code document} is in a SAVED state.
304     *
305     * @param status the document status
306     *
307     * @return true if the {@code document} is in a SAVED state, false otherwise
308     */
309    protected boolean isStateSaved(DocumentStatus status) {
310        return (StringUtils.equals(status.getCode(), DocumentStatus.SAVED.getCode()));
311    }
312
313    /**
314     * Returns whether the {@code document} is in a PROCESSED or DISAPPROVED state.
315     *
316     * @param status the document status
317     *
318     * @return true if the {@code document} is in a PROCESSED or DISAPPROVED state, false otherwise
319     */
320    protected boolean isStateProcessedOrDisapproved(DocumentStatus status) {
321        return (StringUtils.equals(status.getCode(), DocumentStatus.PROCESSED.getCode()) ||
322                StringUtils.equals(status.getCode(), DocumentStatus.DISAPPROVED.getCode()));
323    }
324
325    protected ParameterService getParameterService() {
326        if (parameterService == null) {
327            parameterService = CoreFrameworkServiceLocator.getParameterService();
328        }
329        return parameterService;
330    }
331
332    protected DocumentRequestAuthorizationCache getDocumentRequestAuthorizationCache(Document document) {
333        if (this.documentRequestAuthorizationCache == null) {
334            this.documentRequestAuthorizationCache = new DocumentRequestAuthorizationCache();
335        }
336
337        if (this.documentRequestAuthorizationCache.getWorkflowDocumentInfo() == null) {
338            this.documentRequestAuthorizationCache.createWorkflowDocumentInfo(
339                    document.getDocumentHeader().getWorkflowDocument());
340        }
341
342        return this.documentRequestAuthorizationCache;
343    }
344
345    /**
346     * {@inheritDoc}
347     */
348    @Override
349    public void setDocumentRequestAuthorizationCache(
350            DocumentRequestAuthorizationCache documentRequestAuthorizationCache) {
351         this.documentRequestAuthorizationCache = documentRequestAuthorizationCache;
352    }
353}