View Javadoc
1   /*
2    * Copyright 2005 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.coa.document.validation.impl;
17  
18  import java.math.BigDecimal;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.kuali.ole.coa.businessobject.A21IndirectCostRecoveryAccount;
25  import org.kuali.ole.coa.businessobject.Account;
26  import org.kuali.ole.coa.businessobject.Chart;
27  import org.kuali.ole.coa.businessobject.IndirectCostRecoveryAccount;
28  import org.kuali.ole.sys.OLEKeyConstants;
29  import org.kuali.ole.sys.OLEPropertyConstants;
30  import org.kuali.ole.sys.context.SpringContext;
31  import org.kuali.ole.sys.document.validation.impl.KfsMaintenanceDocumentRuleBase;
32  import org.kuali.rice.kns.document.MaintenanceDocument;
33  import org.kuali.rice.kns.service.DictionaryValidationService;
34  import org.kuali.rice.krad.bo.PersistableBusinessObject;
35  import org.kuali.rice.krad.service.BusinessObjectService;
36  import org.kuali.rice.krad.util.GlobalVariables;
37  import org.kuali.rice.krad.util.ObjectUtils;
38  
39  /**
40   * Business rule(s) applicable to AccountMaintenance documents.
41   */
42  abstract public class IndirectCostRecoveryAccountsRule extends KfsMaintenanceDocumentRuleBase {
43  
44      protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(IndirectCostRecoveryAccountsRule.class);
45  
46      protected static final BigDecimal BD100 = new BigDecimal(100);
47      private List<? extends IndirectCostRecoveryAccount> activeIndirectCostRecoveryAccountList;
48      protected String boFieldPath;
49      
50      /**
51       * Custom processing for adding collection lines
52       * 
53       * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument, java.lang.String, org.kuali.rice.krad.bo.PersistableBusinessObject)
54       */
55      public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject bo) {
56          boolean success = true;
57  
58          // this incoming bo needs to be refreshed because it doesn't have its subobjects setup
59          bo.refreshNonUpdateableReferences();
60  
61          if (bo instanceof IndirectCostRecoveryAccount || bo instanceof A21IndirectCostRecoveryAccount) {
62              IndirectCostRecoveryAccount account = (IndirectCostRecoveryAccount) bo;
63              success &= checkIndirectCostRecoveryAccount(account);
64          }
65          return success;
66      }
67  
68      /**
69       * This method calls the rule: OLEPropertyConstants.INDIRECT_COST_RECOVERY_ACCOUNT
70       * 
71       * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
72       */
73      protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
74          boolean success = true;
75          return success = checkIndirectCostRecoveryAccountDistributions();
76      }
77      
78      /**
79       * This method checks if the ICR collection should or should not be filled
80       * error message is not handled in the function 
81       * 
82       * @param expectFilled
83       * @return
84       */
85      protected boolean checkICRCollectionExist(boolean expectFilled) {
86          boolean success = true;
87          
88          success = expectFilled != activeIndirectCostRecoveryAccountList.isEmpty();
89          
90          //double check each of the account/coa codes are not blank
91          if (!success && expectFilled){
92              for (IndirectCostRecoveryAccount account : activeIndirectCostRecoveryAccountList){
93                  success &= StringUtils.isNotBlank(account.getIndirectCostRecoveryAccountNumber())
94                      && StringUtils.isNotBlank(account.getIndirectCostRecoveryFinCoaCode());
95              }
96          }
97          
98          return success;
99      }
100     
101 
102     /**
103      * This method checks if the ICR collection should or should not be filled
104      * add error message if validation is not successful
105      * 
106      * @param expectFilled
107      * @param errorMessage
108      * @param args
109      * @return
110      */
111     protected boolean checkICRCollectionExistWithErrorMessage(boolean expectFilled, String errorMessage, String args) {
112         boolean success = true;
113         success = checkICRCollectionExist(expectFilled);
114         if (!success){
115             putFieldError(boFieldPath, errorMessage, args);
116         }
117         return success;
118     }
119     
120     /**
121      * Check valid IndirectCostRecovery Account
122      * 
123      * @return
124      */
125     protected boolean checkIndirectCostRecoveryAccount(IndirectCostRecoveryAccount icrAccount) {
126         
127         boolean success = true;
128         
129         //check for empty values on the ICR account
130         
131         // The chart and account  must exist in the database.
132         String chartOfAccountsCode = icrAccount.getIndirectCostRecoveryFinCoaCode();
133         String accountNumber = icrAccount.getIndirectCostRecoveryAccountNumber();
134         BigDecimal icraAccountLinePercentage = ObjectUtils.isNotNull(icrAccount.getAccountLinePercent()) ? icrAccount.getAccountLinePercent() : BigDecimal.ZERO;
135         return checkIndirectCostRecoveryAccount(chartOfAccountsCode, accountNumber, icraAccountLinePercentage);
136     }
137         
138     protected boolean checkIndirectCostRecoveryAccount(String chartOfAccountsCode, String accountNumber, BigDecimal icraAccountLinePercentage) {
139         boolean success = true;
140         if (StringUtils.isBlank(chartOfAccountsCode)) {
141             GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ICR_CHART_OF_ACCOUNTS_CODE, OLEKeyConstants.ERROR_REQUIRED, 
142                     getDDAttributeLabel(OLEPropertyConstants.ICR_CHART_OF_ACCOUNTS_CODE));
143             success &= false;
144         }
145         
146         if (StringUtils.isBlank(accountNumber)) {
147             GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ICR_ACCOUNT_NUMBER, OLEKeyConstants.ERROR_REQUIRED,
148                     getDDAttributeLabel(OLEPropertyConstants.ICR_ACCOUNT_NUMBER));
149             success &= false;
150         }
151         
152         if (StringUtils.isNotBlank(chartOfAccountsCode) && StringUtils.isNotBlank(accountNumber)) {
153             Map<String, String> chartAccountMap = new HashMap<String, String>();
154             chartAccountMap.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode);
155             if (SpringContext.getBean(BusinessObjectService.class).countMatching(Chart.class, chartAccountMap) < 1) {
156                 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ICR_CHART_OF_ACCOUNTS_CODE, OLEKeyConstants.ERROR_EXISTENCE, chartOfAccountsCode);
157                 success &= false;
158             }
159             chartAccountMap.put(OLEPropertyConstants.ACCOUNT_NUMBER, accountNumber);
160             if (SpringContext.getBean(BusinessObjectService.class).countMatching(Account.class, chartAccountMap) < 1) {
161                 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ICR_ACCOUNT_NUMBER, OLEKeyConstants.ERROR_EXISTENCE, chartOfAccountsCode + "-" + accountNumber);
162                 success &= false;
163             }
164         }
165         
166         
167         //check the percent line
168         if (icraAccountLinePercentage.compareTo(BigDecimal.ZERO) <= 0 || icraAccountLinePercentage.compareTo(BD100) == 1){
169             GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ICR_ACCOUNT_LINE_PERCENT, 
170                     OLEKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_ACCOUNT_INVALID_LINE_PERCENT);
171             success &= false;
172         }
173         
174         return success;
175     }
176 
177     /**
178      * Check the collection list of indirect cost recovery account
179      * 
180      * 1. Check each account with rule: checkIndirectCostRecoveryAccount
181      * 2. Total distributions from all the account should be 100
182      * 
183      * @param document
184      * @return
185      */
186     protected boolean checkIndirectCostRecoveryAccountDistributions() {
187         
188         boolean result = true;
189         if (ObjectUtils.isNull(activeIndirectCostRecoveryAccountList) || (activeIndirectCostRecoveryAccountList.size() == 0)) {
190             return result;
191         }
192         
193         DictionaryValidationService dvService = super.getDictionaryValidationService();
194         
195         int i=0;
196         BigDecimal totalDistribution = BigDecimal.ZERO;
197        
198         for (IndirectCostRecoveryAccount icra : activeIndirectCostRecoveryAccountList){
199             String errorPath = MAINTAINABLE_ERROR_PREFIX + boFieldPath + "[" + i++ + "]";
200             GlobalVariables.getMessageMap().addToErrorPath(errorPath);
201             checkIndirectCostRecoveryAccount(icra);
202             GlobalVariables.getMessageMap().removeFromErrorPath(errorPath);
203             
204             totalDistribution = totalDistribution.add(icra.getAccountLinePercent());
205         }
206         
207         //check the total distribution is 100
208         if (totalDistribution.compareTo(BD100) != 0){
209             putFieldError(boFieldPath, OLEKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_ACCOUNT_TOTAL_NOT_100_PERCENT);
210             result &= false;
211         }
212         
213         return result;
214     }
215     
216     /**
217      * Get the attribute label from DataDictionary
218      * @param attribute
219      * @return
220      */
221     protected String getDDAttributeLabel(String attribute){
222         return ddService.getAttributeLabel(IndirectCostRecoveryAccount.class, attribute);
223     }
224     
225     public List<? extends IndirectCostRecoveryAccount> getActiveIndirectCostRecoveryAccountList() {
226         return activeIndirectCostRecoveryAccountList;
227     }
228 
229     public void setActiveIndirectCostRecoveryAccountList(List<? extends IndirectCostRecoveryAccount> indirectCostRecoveryAccountList) {
230         this.activeIndirectCostRecoveryAccountList = indirectCostRecoveryAccountList;
231     }
232     
233     public String getBoFieldPath() {
234         return boFieldPath;
235     }
236 
237     public void setBoFieldPath(String boFieldPath) {
238         this.boFieldPath = boFieldPath;
239     }
240 
241 }
242