001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.fp.document.validation.impl;
017    
018    import java.util.Arrays;
019    import java.util.List;
020    
021    import org.kuali.kfs.fp.document.DisbursementVoucherConstants;
022    import org.kuali.kfs.fp.document.DisbursementVoucherDocument;
023    import org.kuali.kfs.sys.KFSKeyConstants;
024    import org.kuali.kfs.sys.document.validation.GenericValidation;
025    import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
026    import org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBaseConstants;
027    import org.kuali.rice.kew.dto.ActionRequestDTO;
028    import org.kuali.rice.kew.exception.WorkflowException;
029    import org.kuali.rice.kew.service.WorkflowInfo;
030    import org.kuali.rice.kns.bo.Note;
031    import org.kuali.rice.kns.service.DocumentService;
032    import org.kuali.rice.kns.util.GlobalVariables;
033    
034    /**
035     * Validates that if a disbursement voucher had special handling turned off at the campus node, an extra note explaining that change has been added.
036     */
037    public class DisbursementVoucherCampusSpecialHandlingValidation extends GenericValidation {
038        private DisbursementVoucherDocument disbursementVoucherDocumentForValidation;
039        private DocumentService documentService;
040        private WorkflowInfo workflowInfo;
041        
042        public static final String DOCUMENT_EDITOR_ROLE_NAME = "Document Editor";
043    
044        /**
045         * Carries out the validation
046         * @see org.kuali.kfs.sys.document.validation.Validation#validate(org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent)
047         */
048        public boolean validate(AttributedDocumentEvent event) {
049            boolean result = true;
050            
051            if (isAtNodeToCheck()) {
052                final DisbursementVoucherDocument persistedDocument = getPersistedDisbursementVoucherDocument();
053                if (isSpecialHandlingChanged(persistedDocument) && !isNoteAdded()) {
054                    result = false;
055                    GlobalVariables.getMessageMap().putError(AccountingDocumentRuleBaseConstants.ERROR_PATH.DOCUMENT_ERROR_PREFIX+"disbVchrSpecialHandlingCode", KFSKeyConstants.ERROR_DV_CAMPUS_TURNED_OFF_SPECIAL_HANDLING_WITHOUT_EXPLANATORY_NOTE, new String[] {});
056                }
057            }
058            
059            return result;
060        }
061    
062        /**
063         * Determines if the DisbursementVoucherDocumentForValidation is at the Campus route node 
064         * @return true if the document is at the campus route node, false otherwise
065         */
066        protected boolean isAtNodeToCheck() {
067            try {
068                List<String> currentNodes = Arrays.asList(getDisbursementVoucherDocumentForValidation().getDocumentHeader().getWorkflowDocument().getNodeNames());
069                return (!currentNodes.contains(DisbursementVoucherConstants.RouteLevelNames.PURCHASING));
070            }
071            catch (WorkflowException we) {
072                throw new RuntimeException("Workflow Exception while attempting to check route levels", we);
073            }
074        }
075        
076        /**
077         * Retrieves from the persistence store the persisted version of the given document
078         * @param document the document to find the persisted version of
079         * @return the persisted version of that document
080         */
081        protected DisbursementVoucherDocument getPersistedDisbursementVoucherDocument() {
082            try {
083                return (DisbursementVoucherDocument)getDocumentService().getByDocumentHeaderId(getDisbursementVoucherDocumentForValidation().getDocumentNumber());
084            }
085            catch (WorkflowException we) {
086                throw new RuntimeException("Could not retrieve persisted version of document "+getDisbursementVoucherDocumentForValidation().getDocumentNumber()+" for Special Handling validation", we);
087            }
088        }
089        
090        /**
091         * Determines if special handling was turned off from the DisbursementVoucherDocumentForValidation
092         * @param persistedDocument the persisted version of the document
093         * @return true if special handling was turned off, false otherwise
094         */
095        protected boolean isSpecialHandlingChanged(DisbursementVoucherDocument persistedDocument) {
096            return persistedDocument.isDisbVchrSpecialHandlingCode() != getDisbursementVoucherDocumentForValidation().isDisbVchrSpecialHandlingCode();
097        }
098        
099        /**
100         * Determines if another note was added from the time the DisbursementVoucherDocumentForValidation was persisted
101         * @param persistedDocument the persisted version of the document
102         * @return true if an extra note was added, false otherwise
103         */
104        protected boolean isNoteAdded() {
105           boolean foundNoteByCurrentApprover = false;
106           int count = 0;
107           final int noteCount = getDisbursementVoucherDocumentForValidation().getDocumentHeader().getBoNotes().size();
108           while (!foundNoteByCurrentApprover && count < noteCount) {
109               foundNoteByCurrentApprover |= noteAddedByApproverForCurrentNode(getDisbursementVoucherDocumentForValidation().getDocumentHeader().getBoNote(count));
110               count += 1;
111           }
112           return foundNoteByCurrentApprover;
113        }
114        
115        /**
116         * Determines if the given note was added by the current approver
117         * @param note the note to see added
118         * @return true if the note was added by the current approver, false otherwise
119         */
120        protected boolean noteAddedByApproverForCurrentNode(Note note) {
121            ActionRequestDTO[] actionRequests = null;
122            try {
123                actionRequests = getWorkflowInfo().getActionRequests(new Long(getDisbursementVoucherDocumentForValidation().getDocumentNumber()), getDisbursementVoucherDocumentForValidation().getDocumentHeader().getWorkflowDocument().getCurrentRouteNodeNames(), note.getAuthorUniversalIdentifier());
124            }
125            catch (NumberFormatException nfe) {
126                throw new RuntimeException("Could not convert Disbursement Voucher document number "+getDisbursementVoucherDocumentForValidation().getDocumentNumber()+" to long", nfe);
127            }
128            catch (WorkflowException we) {
129                throw new RuntimeException("D'oh!  Workflow Exception!", we);
130            }
131            return actionRequests != null && actionRequests.length > 0;
132        }
133        
134        /**
135         * Determines the count of notes on the given document
136         * @param dvDoc a document to find the count of notes on
137         * @return the count of notes on the document
138         */
139        protected int getNoteCount(DisbursementVoucherDocument dvDoc) {
140            return dvDoc.getDocumentHeader().getBoNotes().size();
141        }
142    
143        /**
144         * Gets the disbursementVoucherDocumentForValidation attribute. 
145         * @return Returns the disbursementVoucherDocumentForValidation.
146         */
147        public DisbursementVoucherDocument getDisbursementVoucherDocumentForValidation() {
148            return disbursementVoucherDocumentForValidation;
149        }
150    
151        /**
152         * Sets the disbursementVoucherDocumentForValidation attribute value.
153         * @param disbursementVoucherDocumentForValidation The disbursementVoucherDocumentForValidation to set.
154         */
155        public void setDisbursementVoucherDocumentForValidation(DisbursementVoucherDocument disbursementVoucherDocumentForValidation) {
156            this.disbursementVoucherDocumentForValidation = disbursementVoucherDocumentForValidation;
157        }
158    
159        /**
160         * Gets the workflowInfo attribute. 
161         * @return Returns the workflowInfo.
162         */
163        public WorkflowInfo getWorkflowInfo() {
164            if (workflowInfo == null) {
165                workflowInfo = new WorkflowInfo();
166            }
167            return workflowInfo;
168        }
169    
170        /**
171         * Sets the workflowInfo attribute value.
172         * @param workflowInfo The workflowInfo to set.
173         */
174        public void setWorkflowInfo(WorkflowInfo workflowInfo) {
175            this.workflowInfo = workflowInfo;
176        }
177    
178        /**
179         * Gets the documentService attribute. 
180         * @return Returns the documentService.
181         */
182        public DocumentService getDocumentService() {
183            return documentService;
184        }
185    
186        /**
187         * Sets the documentService attribute value.
188         * @param documentService The documentService to set.
189         */
190        public void setDocumentService(DocumentService documentService) {
191            this.documentService = documentService;
192        }
193    }