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.ArrayList;
019    import java.util.List;
020    import java.util.Set;
021    
022    import org.kuali.kfs.sys.KFSPropertyConstants;
023    import org.kuali.kfs.sys.KfsAuthorizationConstants;
024    import org.kuali.kfs.sys.businessobject.AccountingLine;
025    import org.kuali.kfs.sys.context.SpringContext;
026    import org.kuali.kfs.sys.document.AccountingDocument;
027    import org.kuali.kfs.sys.document.authorization.AccountingLineAuthorizer;
028    import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
029    import org.kuali.kfs.sys.document.validation.impl.AccountingLineAccessibleValidation;
030    import org.kuali.rice.kim.bo.Person;
031    import org.kuali.rice.kns.document.authorization.TransactionalDocumentAuthorizer;
032    import org.kuali.rice.kns.document.authorization.TransactionalDocumentPresentationController;
033    import org.kuali.rice.kns.service.DocumentHelperService;
034    import org.kuali.rice.kns.util.GlobalVariables;
035    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
036    
037    public class DisbursementVoucherAccountingLineAccessibleValidation extends AccountingLineAccessibleValidation {
038        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherAccountingLineAccessibleValidation.class);
039        protected AccountingLine oldAccountingLineForValidation;
040    
041        /**
042         * Validates that the given accounting line is accessible for editing by the current user. <strong>This method expects a
043         * document as the first parameter and an accounting line as the second</strong>
044         * 
045         * @see org.kuali.kfs.sys.document.validation.impl.AccountingLineAccessibleValidation#validate(org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent)
046         */
047        @Override
048        public boolean validate(AttributedDocumentEvent event) {
049            LOG.debug("validate start");
050    
051            Person financialSystemUser = GlobalVariables.getUserSession().getPerson();
052            AccountingDocument accountingDocument = this.getAccountingDocumentForValidation();
053            AccountingLine accountingLineForValidation = this.getAccountingLineForValidation();
054    
055            final AccountingLineAuthorizer accountingLineAuthorizer = lookupAccountingLineAuthorizer();
056            final boolean lineIsAccessible = accountingLineAuthorizer.hasEditPermissionOnAccountingLine(accountingDocument, accountingLineForValidation, getAccountingLineCollectionProperty(), financialSystemUser, true);
057            boolean isAccessible = accountingLineAuthorizer.hasEditPermissionOnField(accountingDocument, accountingLineForValidation, getAccountingLineCollectionProperty(), KFSPropertyConstants.ACCOUNT_NUMBER, lineIsAccessible, true, financialSystemUser);
058    
059            // get the authorizer class to check for special conditions routing and if the user is part of a particular workgroup
060            // but only if the document is enroute
061            KualiWorkflowDocument workflowDocument = accountingDocument.getDocumentHeader().getWorkflowDocument();
062            if (!isAccessible && workflowDocument.stateIsEnroute()) {
063                    
064                    if (oldAccountingLineForValidation == null || accountUnchanged(accountingLineForValidation, oldAccountingLineForValidation)) {
065                            isAccessible = true;
066                    } else {
067                    // if approval is requested and the user has required edit permission, then the line is accessible
068                    List<String> candidateEditModes = this.getCandidateEditModes();
069                    if (workflowDocument.isApprovalRequested() && this.hasRequiredEditMode(accountingDocument, financialSystemUser, candidateEditModes)) {
070                        isAccessible = true;
071                    }
072                    }
073            }
074    
075            // report errors if the current user can have no access to the account
076            if (!isAccessible) {
077                String accountNumber = accountingLineForValidation.getAccountNumber();
078                String principalName = GlobalVariables.getUserSession().getPerson().getPrincipalName();
079                String errorKey = this.convertEventToMessage(event);
080    
081                GlobalVariables.getMessageMap().putError(KFSPropertyConstants.ACCOUNT_NUMBER, errorKey, accountNumber, principalName);
082            }
083    
084            return isAccessible;
085        }
086    
087        /**
088         * determine whether the give user has permission to any edit mode defined in the given candidate edit modes
089         * 
090         * @param accountingDocument the given accounting document
091         * @param financialSystemUser the given user
092         * @param candidateEditEditModes the given candidate edit modes
093         * @return true if the give user has permission to any edit mode defined in the given candidate edit modes; otherwise, false
094         */
095        protected boolean hasRequiredEditMode(AccountingDocument accountingDocument, Person financialSystemUser, List<String> candidateEditModes) {
096            DocumentHelperService documentHelperService = SpringContext.getBean(DocumentHelperService.class);
097            TransactionalDocumentAuthorizer documentAuthorizer = (TransactionalDocumentAuthorizer) documentHelperService.getDocumentAuthorizer(accountingDocument);
098            TransactionalDocumentPresentationController presentationController = (TransactionalDocumentPresentationController) documentHelperService.getDocumentPresentationController(accountingDocument);
099    
100            Set<String> presentationControllerEditModes = presentationController.getEditModes(accountingDocument);
101            Set<String> editModes = documentAuthorizer.getEditModes(accountingDocument, financialSystemUser, presentationControllerEditModes);
102    
103            for (String editMode : candidateEditModes) {
104                if (editModes.contains(editMode)) {
105                    return true;
106                }
107            }
108    
109            return false;
110        }
111    
112        /**
113         * define the possibly desired edit modes
114         * 
115         * @return the possibly desired edit modes
116         */
117        protected List<String> getCandidateEditModes() {
118            List<String> candidateEdiModes = new ArrayList<String>();
119            candidateEdiModes.add(KfsAuthorizationConstants.DisbursementVoucherEditMode.TAX_ENTRY);
120            candidateEdiModes.add(KfsAuthorizationConstants.DisbursementVoucherEditMode.FRN_ENTRY);
121            candidateEdiModes.add(KfsAuthorizationConstants.DisbursementVoucherEditMode.TRAVEL_ENTRY);
122            candidateEdiModes.add(KfsAuthorizationConstants.DisbursementVoucherEditMode.WIRE_ENTRY);
123    
124            return candidateEdiModes;
125        }
126        
127        /**
128         * Determines if the two given accounting lines have not have their account changed
129         * @param pollux the first accounting line to check
130         * @param castor the second accounting line to check
131         * @return true if the account is the same for the two, false otherwise
132         */
133        protected boolean accountUnchanged(AccountingLine pollux, AccountingLine castor) {
134            return ((pollux.getChartOfAccountsCode() == null && castor.getChartOfAccountsCode() == null) || (pollux.getChartOfAccountsCode() != null && pollux.getChartOfAccountsCode().equals(castor.getChartOfAccountsCode()))) && ((pollux.getAccountNumber() == null && castor.getAccountNumber() == null) || (pollux.getAccountNumber() != null && pollux.getAccountNumber().equals(castor.getAccountNumber()))); 
135        }
136    
137        /**
138         * Sets the oldAccountingLineForValidation attribute value.
139         * @param oldAccountingLineForValidation The oldAccountingLineForValidation to set.
140         */
141        public void setOldAccountingLineForValidation(AccountingLine oldAccountingLineForValidation) {
142            this.oldAccountingLineForValidation = oldAccountingLineForValidation;
143        }
144    }