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.fp.document.DisbursementVoucherDocument;
023    import org.kuali.kfs.sys.KFSKeyConstants;
024    import org.kuali.kfs.sys.KFSPropertyConstants;
025    import org.kuali.kfs.sys.KfsAuthorizationConstants.DisbursementVoucherEditMode;
026    import org.kuali.kfs.sys.context.SpringContext;
027    import org.kuali.kfs.sys.document.AccountingDocument;
028    import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
029    import org.kuali.kfs.sys.document.validation.impl.AccountingLineGroupTotalsUnchangedValidation;
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 DisbursementVoucherAccountingLineTotalsValidation extends AccountingLineGroupTotalsUnchangedValidation {
038        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherAccountingLineTotalsValidation.class);
039    
040        /**
041         * @see org.kuali.kfs.sys.document.validation.impl.AccountingLineGroupTotalsUnchangedValidation#validate(org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent)
042         */
043        @Override
044        public boolean validate(AttributedDocumentEvent event) {
045            if (LOG.isDebugEnabled()) {
046                LOG.debug("validate start");
047            }
048    
049            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) event.getDocument();
050            
051            
052            Person financialSystemUser = GlobalVariables.getUserSession().getPerson();
053            final Set<String> currentEditModes = getEditModesFromDocument(dvDocument, financialSystemUser);
054            
055            // amounts can only decrease
056            List<String> candidateEditModes = this.getCandidateEditModes();
057            if (this.hasRequiredEditMode(currentEditModes, candidateEditModes)) {
058    
059                //users in foreign or wire workgroup can increase or decrease amounts because of currency conversion            
060                List<String> foreignDraftAndWireTransferEditModes = this.getForeignDraftAndWireTransferEditModes(dvDocument);
061                if (!this.hasRequiredEditMode(currentEditModes, foreignDraftAndWireTransferEditModes)) {
062                    DisbursementVoucherDocument persistedDocument = (DisbursementVoucherDocument) retrievePersistedDocument(dvDocument);
063                    if (persistedDocument == null) {
064                        handleNonExistentDocumentWhenApproving(dvDocument);
065                        return true;
066                    }
067                    // KFSMI- 5183
068                    if (persistedDocument.getDocumentHeader().getWorkflowDocument().stateIsSaved() && persistedDocument.getDisbVchrCheckTotalAmount().isZero()) return true;
069                                       
070                    // check total cannot decrease
071                    if (persistedDocument.getDisbVchrCheckTotalAmount().isLessThan(dvDocument.getDisbVchrCheckTotalAmount())) {
072                        GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.DISB_VCHR_CHECK_TOTAL_AMOUNT, KFSKeyConstants.ERROR_DV_CHECK_TOTAL_CHANGE);
073                        return false;
074                    }
075                }
076    
077                return true;
078            }
079    
080            return super.validate(event);
081        }
082    
083        /**
084         * determine whether the give user has permission to any edit mode defined in the given candidate edit modes
085         * 
086         * @param currentEditModes the edit modes currently available to the given user on the document
087         * @param candidateEditEditModes the given candidate edit modes
088         * @return true if the give user has permission to any edit mode defined in the given candidate edit modes; otherwise, false
089         */
090        protected boolean hasRequiredEditMode(Set<String> currentEditModes, List<String> candidateEditModes) {
091            for (String editMode : candidateEditModes) {
092                if (currentEditModes.contains(editMode)) {
093                    return true;
094                }
095            }
096    
097            return false;
098        }
099        
100        /**
101         * Retrieves the current edit modes from the document
102         * @param accountingDocument the document to find edit modes of
103         * @param financialSystemUser the user requesting the edit modes
104         * @return the Set of current edit modes
105         */
106        protected Set<String> getEditModesFromDocument(AccountingDocument accountingDocument, Person financialSystemUser) {
107            final DocumentHelperService documentHelperService = SpringContext.getBean(DocumentHelperService.class);
108            final TransactionalDocumentAuthorizer documentAuthorizer = (TransactionalDocumentAuthorizer) documentHelperService.getDocumentAuthorizer(accountingDocument);
109            final TransactionalDocumentPresentationController presentationController = (TransactionalDocumentPresentationController) documentHelperService.getDocumentPresentationController(accountingDocument);
110    
111            final Set<String> presentationControllerEditModes = presentationController.getEditModes(accountingDocument);
112            final Set<String> editModes = documentAuthorizer.getEditModes(accountingDocument, financialSystemUser, presentationControllerEditModes);
113            
114            return editModes;
115        }
116    
117        /**
118         * define the possibly desired edit modes
119         * 
120         * @return the possibly desired edit modes
121         */
122        protected List<String> getCandidateEditModes() {
123            List<String> candidateEdiModes = new ArrayList<String>();
124            candidateEdiModes.add(DisbursementVoucherEditMode.TAX_ENTRY);
125            candidateEdiModes.add(DisbursementVoucherEditMode.FRN_ENTRY);
126            candidateEdiModes.add(DisbursementVoucherEditMode.TRAVEL_ENTRY);
127            candidateEdiModes.add(DisbursementVoucherEditMode.WIRE_ENTRY);
128    
129            return candidateEdiModes;
130        }
131        
132        /**
133         * get foreign draft And wire transfer edit mode names, as well as tax if the payee is a non-resident alien
134         * @param dvDocument the document we're validating 
135         * @return foreign draft And wire transfer edit mode names
136         */
137        protected List<String> getForeignDraftAndWireTransferEditModes(DisbursementVoucherDocument dvDocument) {
138            List<String> foreignDraftAndWireTransferEditModes = new ArrayList<String>();
139            foreignDraftAndWireTransferEditModes.add(DisbursementVoucherEditMode.FRN_ENTRY);
140            foreignDraftAndWireTransferEditModes.add(DisbursementVoucherEditMode.WIRE_ENTRY);
141            
142            if (includeTaxAsTotalChangingMode(dvDocument)) {
143                foreignDraftAndWireTransferEditModes.add(DisbursementVoucherEditMode.TAX_ENTRY);
144            }
145    
146            return foreignDraftAndWireTransferEditModes;
147        }
148        
149        /**
150         * Determines whether the tax edit mode should be allowed to change the accounting line totals,
151         * based on whether the payee is a non-resident alient or not
152         * @param dvDocument the document to check
153         * @return true if the tax entry mode can change accounting line totals, false otherwise
154         */
155        protected boolean includeTaxAsTotalChangingMode(DisbursementVoucherDocument dvDocument) {
156            return dvDocument.getDvPayeeDetail().isDisbVchrAlienPaymentCode();
157        }
158    }