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.module.ld.document.validation.impl;
017    
018    import java.util.HashMap;
019    import java.util.Map;
020    import java.util.Set;
021    import java.util.Map.Entry;
022    
023    import org.kuali.kfs.module.ld.LaborConstants;
024    import org.kuali.kfs.module.ld.LaborKeyConstants;
025    import org.kuali.kfs.module.ld.document.SalaryExpenseTransferDocument;
026    import org.kuali.kfs.sys.KFSConstants;
027    import org.kuali.kfs.sys.KFSPropertyConstants;
028    import org.kuali.kfs.sys.businessobject.AccountingLine;
029    import org.kuali.kfs.sys.context.SpringContext;
030    import org.kuali.kfs.sys.document.AccountingDocument;
031    import org.kuali.kfs.sys.document.validation.GenericValidation;
032    import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
033    import org.kuali.kfs.sys.identity.KfsKimAttributes;
034    import org.kuali.rice.kns.document.Document;
035    import org.kuali.rice.kns.document.authorization.DocumentAuthorizer;
036    import org.kuali.rice.kns.service.DocumentHelperService;
037    import org.kuali.rice.kns.util.GlobalVariables;
038    import org.kuali.rice.kns.util.KualiDecimal;
039    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
040    
041    /**
042     * Validates that an accounting document's balances by object codes are unchanged
043     */
044    public class SalaryExpenseTransferValidAmountTransferredByObjectCodeValidation extends GenericValidation {
045        private Document documentForValidation;
046    
047        /**
048         * Validates that an accounting document's unbalanced object code balances exist <strong>Expects an accounting document as the
049         * first a parameter</strong>
050         * 
051         * @see org.kuali.kfs.validation.Validation#validate(java.lang.Object[])
052         */
053        public boolean validate(AttributedDocumentEvent event) {        
054            SalaryExpenseTransferDocument expenseTransferDocument = (SalaryExpenseTransferDocument) documentForValidation;
055            KualiWorkflowDocument workflowDocument = expenseTransferDocument.getDocumentHeader().getWorkflowDocument();
056            
057            // check if user is allowed to edit the object code.
058            if(this.hasEditPermissionOnObjectCode(expenseTransferDocument, workflowDocument)) {
059                return true;
060            }
061    
062            // if approving document, check the object code balances match when document was inititated, else check the balance
063            boolean isValid = true;
064            if (workflowDocument.isApprovalRequested()) {
065                if (!isObjectCodeBalancesUnchanged(expenseTransferDocument)) {
066                    GlobalVariables.getMessageMap().putError(KFSPropertyConstants.TARGET_ACCOUNTING_LINES, LaborKeyConstants.ERROR_TRANSFER_AMOUNT_BY_OBJECT_APPROVAL_CHANGE);
067                    isValid = false;
068                }
069            }
070            else {
071                if (!expenseTransferDocument.getUnbalancedObjectCodes().isEmpty()) {
072                    GlobalVariables.getMessageMap().putError(KFSPropertyConstants.TARGET_ACCOUNTING_LINES, LaborKeyConstants.ERROR_TRANSFER_AMOUNT_NOT_BALANCED_BY_OBJECT);
073                    isValid = false;
074                }
075            }
076    
077            return isValid;
078        }
079    
080        // check if user is allowed to edit the object code.
081        protected boolean hasEditPermissionOnObjectCode(SalaryExpenseTransferDocument expenseTransferDocument, KualiWorkflowDocument workflowDocument) {
082            String principalId = GlobalVariables.getUserSession().getPerson().getPrincipalId();
083            DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(expenseTransferDocument);
084            String templateName = KFSConstants.PermissionTemplate.MODIFY_ACCOUNTING_LINES.name;
085            
086            Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
087            additionalPermissionDetails.put(KfsKimAttributes.DOCUMENT_TYPE_NAME, workflowDocument.getDocumentType());
088            additionalPermissionDetails.put(KfsKimAttributes.PROPERTY_NAME, "targetAccountingLines.financialObjectCode");
089    
090            return documentAuthorizer.isAuthorizedByTemplate(expenseTransferDocument, KFSConstants.ParameterNamespaces.KFS, templateName, principalId, additionalPermissionDetails, null);
091        }
092    
093        /**
094         * Checks the current object code balance map of the document against the balances captured before the document was returned for
095         * approval.
096         * 
097         * @param accountingDocument SalaryExpenseTransferDocument to check
098         * @return true if the balances have not changed, false if they have
099         */
100        protected boolean isObjectCodeBalancesUnchanged(AccountingDocument accountingDocument) {
101            boolean isUnchanged = true;
102    
103            Map<String, KualiDecimal> initiatedObjectCodeBalances = ((SalaryExpenseTransferDocument) accountingDocument).getApprovalObjectCodeBalances();
104            Map<String, KualiDecimal> currentObjectCodeBalances = ((SalaryExpenseTransferDocument) accountingDocument).getUnbalancedObjectCodes();
105    
106            Set<Entry<String, KualiDecimal>> initiatedObjectCodes = initiatedObjectCodeBalances.entrySet();
107            Set<Entry<String, KualiDecimal>> currentObjectCodes = currentObjectCodeBalances.entrySet();
108    
109            if (initiatedObjectCodes == null) {
110                if (currentObjectCodes != null) {
111                    isUnchanged = false;
112                }
113            }
114            else {
115                if (!initiatedObjectCodes.equals(currentObjectCodes)) {
116                    isUnchanged = false;
117                }
118            }
119    
120            return isUnchanged;
121        }
122    
123        /**
124         * Sets the documentForValidation attribute value.
125         * 
126         * @param documentForValidation The documentForValidation to set.
127         */
128        public void setDocumentForValidation(Document documentForValidation) {
129            this.documentForValidation = documentForValidation;
130        }
131    }