001/*
002 * Copyright 2008 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 */
016package org.kuali.ole.coa.document.validation.impl;
017
018import java.math.BigDecimal;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.commons.lang.StringUtils;
026import org.kuali.ole.coa.businessobject.Account;
027import org.kuali.ole.coa.businessobject.Chart;
028import org.kuali.ole.coa.businessobject.IndirectCostRecoveryRate;
029import org.kuali.ole.coa.businessobject.IndirectCostRecoveryRateDetail;
030import org.kuali.ole.coa.businessobject.ObjectCode;
031import org.kuali.ole.coa.businessobject.SubAccount;
032import org.kuali.ole.coa.businessobject.SubObjectCode;
033import org.kuali.ole.gl.GeneralLedgerConstants;
034import org.kuali.ole.sys.OLEConstants;
035import org.kuali.ole.sys.OLEKeyConstants;
036import org.kuali.ole.sys.OLEPropertyConstants;
037import org.kuali.ole.sys.businessobject.SystemOptions;
038import org.kuali.ole.sys.context.SpringContext;
039import org.kuali.rice.core.api.util.RiceKeyConstants;
040import org.kuali.rice.kns.document.MaintenanceDocument;
041import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
042import org.kuali.rice.kns.service.DataDictionaryService;
043import org.kuali.rice.krad.bo.PersistableBusinessObject;
044import org.kuali.rice.krad.util.GlobalVariables;
045import org.kuali.rice.krad.util.KRADConstants;
046
047
048public class IndirectCostRecoveryRateRule extends MaintenanceDocumentRuleBase {
049
050    protected static final String MAINTAINABLE_DETAIL_ERROR_PATH = KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + "indirectCostRecoveryRateDetails";
051    protected static final String MAINTAINABLE_DETAIL_ADDLINE_ERROR_PATH = "add.indirectCostRecoveryRateDetails";
052    
053    protected IndirectCostRecoveryRate indirectCostRecoveryRate;
054    protected IndirectCostRecoveryRateDetail indirectCostRecoveryRateDetail;
055    protected List<IndirectCostRecoveryRateDetail> indirectCostRecoveryRateDetails;
056    
057    public void setupConvenienceObjects() {
058        indirectCostRecoveryRate = (IndirectCostRecoveryRate) super.getNewBo();
059        indirectCostRecoveryRateDetails = indirectCostRecoveryRate.getIndirectCostRecoveryRateDetails();
060    }
061    
062    @Override
063    protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
064        boolean success = true;
065
066        BigDecimal awardIndrCostRcvyRatePctCredits = new BigDecimal(0);
067        BigDecimal awardIndrCostRcvyRatePctDebits = new BigDecimal(0);
068        
069        if (!processYear()) {
070            success = false;
071        }
072        else {
073            for(int i = 0;i<indirectCostRecoveryRateDetails.size();i++) {
074                if(indirectCostRecoveryRateDetails.get(i).isActive()) {
075                    GlobalVariables.getMessageMap().addToErrorPath(MAINTAINABLE_DETAIL_ERROR_PATH + "[" + i + "]");
076                    success &= processCollectionLine(indirectCostRecoveryRateDetails.get(i));
077                    GlobalVariables.getMessageMap().removeFromErrorPath(MAINTAINABLE_DETAIL_ERROR_PATH + "[" + i + "]");
078                    
079                    if(indirectCostRecoveryRateDetails.get(i).isActive()) {
080                        if(OLEConstants.GL_CREDIT_CODE.equals(indirectCostRecoveryRateDetails.get(i).getTransactionDebitIndicator())) {
081                            awardIndrCostRcvyRatePctCredits = awardIndrCostRcvyRatePctCredits.add(indirectCostRecoveryRateDetails.get(i).getAwardIndrCostRcvyRatePct());
082                        }
083                        if(OLEConstants.GL_DEBIT_CODE.equals(indirectCostRecoveryRateDetails.get(i).getTransactionDebitIndicator())) {
084                            awardIndrCostRcvyRatePctDebits = awardIndrCostRcvyRatePctDebits.add(indirectCostRecoveryRateDetails.get(i).getAwardIndrCostRcvyRatePct());
085                        }                    
086                    }
087                }
088            }
089        }
090        success &= checkCreditsAndDebits(awardIndrCostRcvyRatePctCredits, awardIndrCostRcvyRatePctDebits);
091        
092        return success;
093    }
094    
095    public boolean checkCreditsAndDebits(BigDecimal credits, BigDecimal debits) {
096        boolean success = true;
097
098        // global errors, in KeyConstants or KFSconstants or something, use one for the top of the page (mark doc once)
099        // include the key word active (informing that only active records are considered)
100        if(!(credits.compareTo(debits) == 0)) {
101            GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(KRADConstants.GLOBAL_ERRORS, OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_RATE_PERCENTS_NOT_EQUAL,
102                    SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.AWARD_INDR_COST_RCVY_RATE_PCT));
103            success = false;
104        }
105
106        return success;
107    }
108 
109    @Override
110    public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject line) {
111        boolean success = true;
112        IndirectCostRecoveryRateDetail item = (IndirectCostRecoveryRateDetail) line;
113        success &= processCollectionLine(item);
114        return success;
115    }
116    
117    public boolean processCollectionLine(IndirectCostRecoveryRateDetail item) {
118        boolean success = true;
119        
120        success &= validateWildcards(item);
121        if(success) {
122            success &= checkExistence(item) && checkRateFormat(item);
123        }
124                
125        return success;
126    }
127    
128    public boolean checkExistence(IndirectCostRecoveryRateDetail item) {
129        boolean success = 
130            processYear() && 
131            processChart(item) && 
132            processAccount(item) && 
133            processSubAccount(item) && 
134            processObjectCode(item) && 
135            processSubObjectCode(item);
136        return success;
137    }
138    
139    public boolean processYear() {
140        boolean success = true;
141        Map pkMap = new HashMap();
142        Integer year = indirectCostRecoveryRate.getUniversityFiscalYear();
143        pkMap.put(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
144        if(!checkExistenceFromTable(SystemOptions.class, pkMap)) {
145            GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR,
146                    RiceKeyConstants.ERROR_EXISTENCE, 
147                    SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRate.class, OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR));
148            success = false;
149        }
150        return success;
151    }
152    
153    protected boolean processChart(IndirectCostRecoveryRateDetail item) {
154        boolean success = true;
155        Map pkMap = new HashMap();
156        String chart = item.getChartOfAccountsCode();
157        if(StringUtils.isNotBlank(chart)) {
158            if(!propertyIsWildcard(chart)) {
159                pkMap.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chart);
160                if(!checkExistenceFromTable(Chart.class, pkMap)) {
161                    logErrorUtility(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, RiceKeyConstants.ERROR_EXISTENCE);
162                    success = false;
163                }
164            }
165        }
166        return success;
167    }
168    
169    protected boolean processAccount(IndirectCostRecoveryRateDetail item) {
170        boolean success = true;
171        Map pkMap = new HashMap();
172        String chart = item.getChartOfAccountsCode();
173        String acct = item.getAccountNumber();
174        if(StringUtils.isNotBlank(acct)) {
175            if(!propertyIsWildcard(chart)) {
176                pkMap.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chart);    
177            }
178            if(!propertyIsWildcard(acct)) {
179                pkMap.put(OLEPropertyConstants.ACCOUNT_NUMBER, acct);
180                if(!checkExistenceFromTable(Account.class, pkMap)) {
181                    logErrorUtility(OLEPropertyConstants.ACCOUNT_NUMBER, RiceKeyConstants.ERROR_EXISTENCE);
182                    success = false;
183                }
184            }
185        }
186        return success;
187    }
188    
189    protected boolean processSubAccount(IndirectCostRecoveryRateDetail item) {
190        boolean success = true;
191        Map pkMap = new HashMap();
192        String chart = item.getChartOfAccountsCode();
193        String acct = item.getAccountNumber();
194        String subAcct = item.getSubAccountNumber();
195        if(StringUtils.isNotBlank(subAcct) && !StringUtils.containsOnly(subAcct, "-")) { // if doesn't contain only dashes
196            if(!propertyIsWildcard(chart)) {
197                pkMap.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chart);    
198            }
199            if(!propertyIsWildcard(acct)) {
200                pkMap.put(OLEPropertyConstants.ACCOUNT_NUMBER, acct);    
201            }
202            if(!propertyIsWildcard(subAcct) && StringUtils.isNotBlank(subAcct) && !StringUtils.containsOnly(subAcct, "-")) {
203                pkMap.put(OLEPropertyConstants.SUB_ACCOUNT_NUMBER, subAcct);
204                if(!checkExistenceFromTable(SubAccount.class, pkMap)) {
205                    logErrorUtility(OLEPropertyConstants.SUB_ACCOUNT_NUMBER, RiceKeyConstants.ERROR_EXISTENCE);
206                    success = false;
207                }
208            }
209        }
210        return success;
211    }
212    
213    protected boolean processObjectCode(IndirectCostRecoveryRateDetail item) {
214        boolean success = true;
215        Map pkMap = new HashMap();
216        Integer year = indirectCostRecoveryRate.getUniversityFiscalYear();
217        String chart = item.getChartOfAccountsCode();
218        String objCd = item.getFinancialObjectCode();
219        pkMap.put(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
220        if(StringUtils.isNotBlank(objCd)) {
221            if(!propertyIsWildcard(chart)) {
222                pkMap.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chart);    
223            }
224            if(!propertyIsWildcard(objCd)) {
225                pkMap.put(OLEPropertyConstants.FINANCIAL_OBJECT_CODE, objCd);
226                if(!checkExistenceFromTable(ObjectCode.class, pkMap)) {
227                    logErrorUtility(OLEPropertyConstants.FINANCIAL_OBJECT_CODE, RiceKeyConstants.ERROR_EXISTENCE);
228                    success = false;
229                }
230            }
231        }
232        return success;
233    }
234    
235    protected boolean processSubObjectCode(IndirectCostRecoveryRateDetail item) { // chart being a wildcard implies account number being a wildcard, redundant checking?
236        boolean success = true;
237        Map pkMap = new HashMap();
238        Integer year = indirectCostRecoveryRate.getUniversityFiscalYear();
239        String chart = item.getChartOfAccountsCode();
240        String acct = item.getAccountNumber();
241        String objCd = item.getFinancialObjectCode();
242        String subObjCd = item.getFinancialSubObjectCode();
243        if(StringUtils.isNotBlank(subObjCd) && !propertyIsWildcard(subObjCd) && !StringUtils.containsOnly(subObjCd, "-")) {
244            pkMap.put(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
245            if(!propertyIsWildcard(chart)) {
246                pkMap.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chart);    
247            }
248            if(!propertyIsWildcard(acct)) {
249                pkMap.put(OLEPropertyConstants.ACCOUNT_NUMBER, acct);    
250            }
251            if(!propertyIsWildcard(objCd)) {
252                pkMap.put(OLEPropertyConstants.FINANCIAL_OBJECT_CODE, objCd);
253            }
254            pkMap.put(OLEPropertyConstants.FINANCIAL_SUB_OBJECT_CODE, subObjCd);
255            if(!GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(subObjCd) && !checkExistenceFromTable(SubObjectCode.class, pkMap)) {
256                logErrorUtility(OLEPropertyConstants.FINANCIAL_SUB_OBJECT_CODE, RiceKeyConstants.ERROR_EXISTENCE);
257                success = false;
258            }
259        }
260        return success;
261    }
262    
263    public boolean checkExistenceFromTable(Class clazz, Map fieldValues) {
264        return getBoService().countMatching(clazz, fieldValues) != 0;
265    }
266    
267    public boolean validateWildcards(IndirectCostRecoveryRateDetail item) {
268        boolean success = false;
269        if(!itemUsesWildcard(item) || (itemUsesWildcard(item) && itemPassesWildcardRules(item))) {
270            success = true;
271        }
272        return success;
273    }
274    
275    public boolean itemPassesWildcardRules(IndirectCostRecoveryRateDetail item) {
276        boolean success = false;
277        String[] wildcards = {GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY, GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT};
278        
279        success = !itemUsesWildcard(item) || checkWildcardRules(item);
280        
281        return success;
282    }
283    
284    public boolean itemUsesWildcard(IndirectCostRecoveryRateDetail item) {
285        boolean success = false;
286        String chart = item.getChartOfAccountsCode();
287        String acct = item.getAccountNumber();
288        String subAcct = item.getSubAccountNumber();
289        String objCd = item.getFinancialObjectCode();
290        String subObjCd = item.getFinancialSubObjectCode();
291        String[] fields = {chart,acct,subAcct,objCd,subObjCd};
292        
293        for(int i=0;i<fields.length;i++) {
294            success |= propertyIsWildcard(fields[i]);
295        }
296        
297        return success;
298    }
299    
300    public boolean propertyIsWildcard(String property) {
301        return GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(property) || GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT.equals(property);
302    }
303
304    protected boolean checkAccountNumberWildcardRules(IndirectCostRecoveryRateDetail item) {
305        String accountNumber = item.getAccountNumber();
306        boolean success = true;
307        if (!accountNumber.equals(item.getChartOfAccountsCode())) {
308            GlobalVariables.getMessageMap().putError(
309                    OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE,
310                    OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARDS_MUST_MATCH,
311                    SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.ACCOUNT_NUMBER),
312                    SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE)
313                    );
314            success = false;
315        }
316        
317        String subAccountNumber = item.getSubAccountNumber();
318        
319        // If # is entered on account, then # "must" be entered for chart and sub account "must" be dashes.
320        if (GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT.equals(accountNumber)) {
321            if (!GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT.equals(item.getChartOfAccountsCode()) && !StringUtils.containsOnly(subAccountNumber, OLEConstants.DASH)) {
322                GlobalVariables.getMessageMap().putError(
323                        OLEPropertyConstants.SUB_ACCOUNT_NUMBER, 
324                        OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_FIELD_MUST_BE_DASHES,
325                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.ACCOUNT_NUMBER),
326                        GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT,
327                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.SUB_ACCOUNT_NUMBER));
328                success = false;
329            }
330        }
331        
332        if (GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(accountNumber)) {
333            if (!(StringUtils.equals(GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY, subAccountNumber) || !StringUtils.containsOnly(subAccountNumber, OLEConstants.DASH))) {
334                GlobalVariables.getMessageMap().putError(OLEPropertyConstants.SUB_ACCOUNT_NUMBER, 
335                        OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_ACCOUNT_USE_EXPENDITURE_ENTRY_WILDCARD_RESTRICTION_ON_SUB_ACCOUNT);
336                success = false;
337            }
338        }
339        return success;
340    }
341    
342    protected boolean checkAccountNumberNotWildcardRules(IndirectCostRecoveryRateDetail item) {
343        boolean success = true;
344        if (propertyIsWildcard(item.getSubAccountNumber())) {
345            if (!GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT.equals(item.getSubAccountNumber())) {
346                GlobalVariables.getMessageMap().putError(OLEPropertyConstants.SUB_ACCOUNT_NUMBER, OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_CANNOT_BE_WILDCARD,
347                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.SUB_ACCOUNT_NUMBER),
348                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.ACCOUNT_NUMBER));
349                success = false;
350            }
351        }
352        return success;
353    }
354
355    protected boolean checkObjectCodeWildcardRules(IndirectCostRecoveryRateDetail item) {
356        String financialObjectCode = item.getFinancialObjectCode();
357        boolean success = true;
358        if (propertyIsWildcard(financialObjectCode)) {
359            if (GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT.equals(financialObjectCode)) {
360                GlobalVariables.getMessageMap().putError(
361                        OLEPropertyConstants.FINANCIAL_OBJECT_CODE,
362                        OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARD_NOT_VALID,
363                        GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT,
364                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.FINANCIAL_OBJECT_CODE),
365                        GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY
366                        );
367                success = false;
368            } 
369            else {
370                if (!GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(item.getChartOfAccountsCode())) {
371                    GlobalVariables.getMessageMap().putError(
372                            OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE,
373                            OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARDS_MUST_MATCH,
374                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.FINANCIAL_OBJECT_CODE),
375                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE)
376                            );
377                    success = false;
378                }
379            }
380        }
381        return success;
382    }
383    
384    protected boolean checkSubObjectWildcardRules(IndirectCostRecoveryRateDetail item) {
385        String financialSubObjectCode = item.getFinancialSubObjectCode();
386        boolean success = true;
387        if (propertyIsWildcard(financialSubObjectCode)) {
388            if (GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT.equals(financialSubObjectCode)) {
389                GlobalVariables.getMessageMap().putError(
390                        OLEPropertyConstants.FINANCIAL_SUB_OBJECT_CODE,
391                        OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARD_NOT_VALID,
392                        GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT,
393                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.FINANCIAL_SUB_OBJECT_CODE),
394                        GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY
395                        );
396                success = false;
397            }
398            else {
399                if (!GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(item.getChartOfAccountsCode())) {
400                    GlobalVariables.getMessageMap().putError(
401                            OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE,
402                            OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARDS_MUST_MATCH,
403                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.FINANCIAL_SUB_OBJECT_CODE),
404                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE)
405                            );
406                    success = false;
407                }
408                if (!GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(item.getAccountNumber())) {
409                    GlobalVariables.getMessageMap().putError(
410                            OLEPropertyConstants.ACCOUNT_NUMBER,
411                            OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARDS_MUST_MATCH,
412                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.FINANCIAL_SUB_OBJECT_CODE),
413                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.ACCOUNT_NUMBER)
414                            );
415                    success = false;
416                }
417                if (!GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(item.getFinancialObjectCode())) {
418                    GlobalVariables.getMessageMap().putError(
419                            OLEPropertyConstants.FINANCIAL_OBJECT_CODE,
420                            OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARDS_MUST_MATCH,
421                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.FINANCIAL_SUB_OBJECT_CODE),
422                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.FINANCIAL_OBJECT_CODE)
423                            );
424                    success = false;
425                }
426            }
427        }
428        return success;
429    }
430    
431    protected boolean checkSubAccountWildcardRules(IndirectCostRecoveryRateDetail item) {
432        boolean success = true;
433        String subAccountNumber = item.getSubAccountNumber();
434        if (GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT.equals(subAccountNumber)) {
435            GlobalVariables.getMessageMap().putError(
436                    OLEPropertyConstants.SUB_ACCOUNT_NUMBER,
437                    OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARD_NOT_VALID,
438                    GeneralLedgerConstants.PosterService.SYMBOL_USE_ICR_FROM_ACCOUNT,
439                    SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.SUB_ACCOUNT_NUMBER),
440                    GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY
441                    );
442            success = false;
443        }
444        else {
445            if (!GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(item.getChartOfAccountsCode())) {
446                GlobalVariables.getMessageMap().putError(
447                        OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE,
448                        OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARDS_MUST_MATCH,
449                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.SUB_ACCOUNT_NUMBER),
450                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE)
451                        );
452                success = false;
453            }
454            if (!GeneralLedgerConstants.PosterService.SYMBOL_USE_EXPENDITURE_ENTRY.equals(item.getAccountNumber())) {
455                GlobalVariables.getMessageMap().putError(
456                        OLEPropertyConstants.ACCOUNT_NUMBER,
457                        OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_WILDCARDS_MUST_MATCH,
458                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.SUB_ACCOUNT_NUMBER),
459                        SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.ACCOUNT_NUMBER)
460                        );
461                success = false;
462            }
463            
464        }
465        return success;
466    }
467    
468    /*
469     ** If @ is entered on chart, then @ "must" be entered for account and the sub account "must" be either @ or dashes. 
470     ** If @ is entered on account, then @ "must" be entered for chart and "may" be entered for sub account.
471     ** If @ is entered on sub account, then @ "must" be entered for chart and account.
472     ** If @ is entered on object code, then @ "must" be entered for chart and "may" be entered for account, sub account and sub object. 
473     * (This rule is the murkiest as enter @ in account, sub account, and sub object kicks of some of the other rules in this section).
474     ** If @ is entered on sub object code, then @ "must" be entered for chart, account, and object code and "may" be entered for sub account.
475
476     ** If # is entered on chart, then # "must" be entered for account and sub account "must" be dashes.
477     ** If # is entered on account, then # "must" be entered for chart and sub account "must" be dashes.
478     ** # can not be entered on the sub account.
479     ** # can not be entered on the object code.
480     ** # can not be entered on the sub object code.
481     * 
482     */
483    
484    public boolean checkWildcardRules(IndirectCostRecoveryRateDetail item) {
485        boolean success = checkAtMostOneWildcardUsed(item);
486        if (success) {
487            if (propertyIsWildcard(item.getFinancialObjectCode())) {
488                success &= checkObjectCodeWildcardRules(item); // verified
489            }
490            else {
491            }
492            if (propertyIsWildcard(item.getAccountNumber())) {
493                success &= checkAccountNumberWildcardRules(item); // verified
494            }
495            else {
496                success &= checkAccountNumberNotWildcardRules(item);
497            }
498            if (propertyIsWildcard(item.getFinancialSubObjectCode())) {
499                success &= checkSubObjectWildcardRules(item); // verified
500            }
501            
502            if (propertyIsWildcard(item.getSubAccountNumber())) {
503                success &= checkSubAccountWildcardRules(item); // verified
504            }
505            
506            if (!(propertyIsWildcard(item.getFinancialObjectCode()) || propertyIsWildcard(item.getAccountNumber()))) {
507                // chart code can't be the only wildcard on the item
508                if (success && propertyIsWildcard(item.getChartOfAccountsCode())) {
509                    success = false;
510                    GlobalVariables.getMessageMap().putError(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_CHART_CODE_NOT_ONLY_WILDCARD,
511                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE),
512                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.ACCOUNT_NUMBER),
513                            SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, OLEPropertyConstants.FINANCIAL_OBJECT_CODE));
514                }
515            }
516        }
517        return success;
518    }
519
520    protected boolean checkAtMostOneWildcardUsed(IndirectCostRecoveryRateDetail item) {
521        String chart = item.getChartOfAccountsCode();
522        String acct = item.getAccountNumber();
523        String subAcct = item.getSubAccountNumber();
524        String objCd = item.getFinancialObjectCode();
525        String subObjCd = item.getFinancialSubObjectCode();
526        
527        boolean success = true;
528        String errorPropertyName = null;
529        
530        Set<String> wildcards = new HashSet<String>();
531        if (propertyIsWildcard(chart)) {
532            wildcards.add(chart);
533            errorPropertyName = OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE;
534        }
535        if (success && propertyIsWildcard(acct)) {
536            wildcards.add(acct);
537            if (wildcards.size() > 1) {
538                success = false;
539                errorPropertyName = OLEPropertyConstants.ACCOUNT_NUMBER;
540            }
541        }
542        if (success && propertyIsWildcard(subAcct)) {
543            wildcards.add(subAcct);
544            if (wildcards.size() > 1) {
545                success = false;
546                errorPropertyName = OLEPropertyConstants.SUB_ACCOUNT_NUMBER;
547            }
548        }
549        if (success && propertyIsWildcard(objCd)) {
550            wildcards.add(objCd);
551            if (wildcards.size() > 1) {
552                success = false;
553                errorPropertyName = OLEPropertyConstants.FINANCIAL_OBJECT_CODE;
554            }
555        }
556        if (success && propertyIsWildcard(subObjCd)) {
557            wildcards.add(subObjCd);
558            if (wildcards.size() > 1) {
559                success = false;
560                errorPropertyName = OLEPropertyConstants.FINANCIAL_SUB_OBJECT_CODE;
561            }
562        }
563        
564        if (!success) {
565            GlobalVariables.getMessageMap().putError(
566                    errorPropertyName,
567                    OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_MULTIPLE_WILDCARDS_ON_ITEM);
568        }
569        return success;
570    }
571    
572    public boolean checkRateFormat(IndirectCostRecoveryRateDetail item) {
573        boolean success = true;
574        BigDecimal zero = new BigDecimal(0.00);
575        if(!(item.getAwardIndrCostRcvyRatePct() == null)) {
576            if(item.getAwardIndrCostRcvyRatePct().scale() > 3) {
577                logErrorUtility(OLEPropertyConstants.AWARD_INDR_COST_RCVY_RATE_PCT, OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_RATE_PERCENT_INVALID_FORMAT_SCALE);
578                success = false;
579            }
580            if(item.getAwardIndrCostRcvyRatePct().compareTo(zero) < 0) {
581                logErrorUtility(OLEPropertyConstants.AWARD_INDR_COST_RCVY_RATE_PCT, OLEKeyConstants.IndirectCostRecovery.ERROR_DOCUMENT_ICR_RATE_PERCENT_INVALID_FORMAT_ZERO);
582                success = false;
583            }            
584        } else {
585            
586        }
587        return success;
588    }
589    
590    public void logErrorUtility(String propertyName, String errorKey) {
591        GlobalVariables.getMessageMap().putError(propertyName, errorKey, SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(IndirectCostRecoveryRateDetail.class, propertyName));
592    }
593    
594}