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.HashMap;
019    import java.util.Map;
020    
021    import org.apache.commons.lang.StringUtils;
022    import org.kuali.kfs.coa.businessobject.Account;
023    import org.kuali.kfs.coa.businessobject.SubAccount;
024    import org.kuali.kfs.coa.businessobject.SubObjectCode;
025    import org.kuali.kfs.fp.businessobject.CreditCardVendor;
026    import org.kuali.kfs.sys.KFSKeyConstants;
027    import org.kuali.rice.kns.document.MaintenanceDocument;
028    import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
029    import org.kuali.rice.kns.util.ObjectUtils;
030    
031    /**
032     * This class represents business rules for the credit card vendor maintenance document
033     */
034    public class CreditCardVendorRule extends MaintenanceDocumentRuleBase {
035    
036        protected CreditCardVendor newCreditCardVendor;
037    
038        /**
039         *  Sets up a CreditCardVendor convenience objects to make sure all possible sub-objects are populated
040         * 
041         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#setupConvenienceObjects()
042         */
043        public void setupConvenienceObjects() {
044    
045            newCreditCardVendor = (CreditCardVendor) super.getNewBo();
046        }
047    
048        /**
049         * Return true if rules for processing a save for the credit card maintenance document are are valid.
050         * 
051         * @param document maintenance document
052         * @return true credit card vendor number is valid
053         * 
054         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
055         */
056        protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
057            // default to success
058            boolean success = true;
059            setupConvenienceObjects();
060    
061            // check valid Credit Card Vendor Number (numeric, minimum length)
062            success &= checkCreditCardVendorNumber();
063    
064            return success;
065        }
066    
067        /**
068         * Returns value from processCustomRouteDocumentBusinessRules(document)
069         * 
070         * @param document maintenance document
071         * @return value from processCustomRouteDocumentBusinessRules(document)
072         * 
073         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomApproveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
074         */
075        protected boolean processCustomApproveDocumentBusinessRules(MaintenanceDocument document) {
076    
077            return processCustomRouteDocumentBusinessRules(document);
078        }
079    
080        /**
081         * Returns true credit card vendor maintenance document is routed successfully
082         * 
083         * @param document submitted credit card maintenance document
084         * @return true if credit card vendor number, income/expense account numbers, income/expense sub-account numbers, and income/expense sub-object codes are valid
085         * 
086         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
087         */
088        protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
089            // default to success
090            boolean success = true;
091    
092            setupConvenienceObjects();
093    
094            // check valid Credit Card Vendor Number (numeric, minimum length)
095            success &= checkCreditCardVendorNumber();
096    
097            // check Income Account Number business rule
098            if (newCreditCardVendor.getIncomeAccountNumber() != null) {
099                success &= checkExistingActiveAccount(newCreditCardVendor.getIncomeAccountNumber(), "incomeAccountNumber", "Income Account Number");
100            }
101    
102            // check Expense Account Number business rule
103            if (newCreditCardVendor.getExpenseAccountNumber() != null) {
104                success &= checkExistingActiveAccount(newCreditCardVendor.getExpenseAccountNumber(), "expenseAccountNumber", "Expense Account Number");
105            }
106    
107            // check Income Sub-Account business rule
108            if (newCreditCardVendor.getIncomeSubAccountNumber() != null) {
109    
110                // check required fields to validate Sub-Account
111                if (checkRequiredSubAccount("Income")) {
112                    SubAccount existenceSubAccount = checkExistenceSubAccount("Income");
113    
114                    // check existence of Sub-Account
115                    if (existenceSubAccount == null) {
116                        putFieldError("incomeSubAccountNumber", KFSKeyConstants.ERROR_CCV_INVALIDSUBACCOUNT, "Income Sub-Account Number, " + newCreditCardVendor.getIncomeSubAccountNumber());
117                    }
118                    else
119    
120                    // check the Sub-Account is active
121                    if (!existenceSubAccount.isActive()) {
122                        putFieldError("incomeSubAccountNumber", KFSKeyConstants.ERROR_INACTIVE, "Income Sub-Account");
123                    }
124                }
125            }
126    
127            // check Expense Sub-Account business rule
128            if (newCreditCardVendor.getExpenseSubAccountNumber() != null) {
129                if (checkRequiredSubAccount("Expense")) {
130    
131                    // check existence of Sub-Account
132                    SubAccount existenceSubAccount = checkExistenceSubAccount("Expense");
133                    if (existenceSubAccount == null) {
134                        putFieldError("expenseSubAccountNumber", KFSKeyConstants.ERROR_CCV_INVALIDSUBACCOUNT, "Expense Sub-Account Number, " + newCreditCardVendor.getExpenseSubAccountNumber());
135    
136                    }
137                    else
138    
139                    // check the Sub-Account is active
140                    if (!existenceSubAccount.isActive()) {
141                        putFieldError("expenseSubAccountNumber", KFSKeyConstants.ERROR_INACTIVE, "Expense Sub-Account");
142                    }
143                }
144            }
145    
146            // check Income Sub-Object Code business rule
147            if (newCreditCardVendor.getIncomeFinancialSubObjectCode() != null) {
148                if (checkRequiredSubObjectCode("Income")) {
149    
150                    // check existence of Sub-Object
151                    SubObjectCode existenceSubObj = checkExistenceSubObj("Income");
152                    if (existenceSubObj == null) {
153                        putFieldError("incomeFinancialSubObjectCode", KFSKeyConstants.ERROR_CCV_INVALIDSUBOBJECT, "Income Sub-Object Code, " + newCreditCardVendor.getIncomeFinancialSubObjectCode());
154                    }
155                    else
156                    // check the Sub-Object is active
157                    if (!existenceSubObj.isActive()) {
158                        putFieldError("incomeFinancialSubObjectCode", KFSKeyConstants.ERROR_INACTIVE, "Income Sub-Object");
159                    }
160    
161                }
162            }
163    
164            // check Expense Sub-Object Code business rule
165            if (newCreditCardVendor.getExpenseFinancialSubObjectCode() != null) {
166                if (checkRequiredSubObjectCode("Expense")) {
167    
168                    // check existence of Sub-Object
169                    SubObjectCode existenceSubObj = checkExistenceSubObj("Expense");
170                    if (existenceSubObj == null) {
171                        putFieldError("expenseFinancialSubObjectCode", KFSKeyConstants.ERROR_CCV_INVALIDSUBOBJECT, "Expense Sub-Object Code, " + newCreditCardVendor.getExpenseFinancialSubObjectCode());
172                    }
173                    else
174                    // check the Sub-Object is active
175                    if (!existenceSubObj.isActive()) {
176                        putFieldError("expenseFinancialSubObjectCode", KFSKeyConstants.ERROR_INACTIVE, "Expense Sub-Object");
177                    }
178                }
179            }
180    
181    
182            return success;
183        }
184    
185    
186        /**
187         * Returns true if credit card vendor number is valid (i.e. numeric and at least 5 digits)
188         * 
189         * @return true if credit card vendor number is valid (i.e. numeric and at least 5 digits)
190         */
191        protected boolean checkCreditCardVendorNumber() {
192            String ccvNumber = newCreditCardVendor.getFinancialDocumentCreditCardVendorNumber();
193    
194            if (ccvNumber == null) {
195                return false;
196            }
197            else if (!StringUtils.isNumeric(ccvNumber)) {
198                putFieldError("financialDocumentCreditCardVendorNumber", KFSKeyConstants.ERROR_NUMERIC, "Vendor Credit Card Number");
199                return false;
200            }
201            else if (ccvNumber.length() < 5) {
202                String errorMessage[] = null;
203                errorMessage = new String[] { "Vendor Credit Card Number", "5" };
204                putFieldError("financialDocumentCreditCardVendorNumber", KFSKeyConstants.ERROR_MIN_LENGTH, errorMessage);
205                return false;
206            }
207    
208            return true;
209        }
210    
211    
212        /**
213         * Returns true if account is active (i.e. exists and is not expired or closed)
214         * 
215         * @param accountNumber account number
216         * @param fieldName field name to place error for
217         * @param errorMessage error message to display
218         * @return true if account is active (i.e. exists and is not expired or closed)
219         */
220        protected boolean checkExistingActiveAccount(String accountNumber, String fieldName, String errorMessage) {
221            boolean result = false;
222            Account account;
223            Map pkMap = new HashMap();
224            pkMap.put("accountNumber", accountNumber);
225            account = (Account) super.getBoService().findByPrimaryKey(Account.class, pkMap);
226    
227            // if the object doesnt exist, then we cant continue, so exit
228            if (ObjectUtils.isNull(account)) {
229                putFieldError(fieldName, KFSKeyConstants.ERROR_EXISTENCE, errorMessage);
230                return result;
231            }
232    
233            // check whether expired or not
234            if (account.isExpired()) {
235                putFieldError(fieldName, KFSKeyConstants.ERROR_EXPIRED, errorMessage);
236                return result;
237            }
238    
239            // check whether closed or not
240            if (!account.isActive()) {
241                putFieldError(fieldName, KFSKeyConstants.ERROR_CLOSED, errorMessage);
242                return result;
243            }
244    
245    
246            return true;
247        }
248    
249        /**
250         * Returns true if income/expense financial chart of accounts code and account number exist. Income or expense is determined by
251         * the "Income" value or the "Expense" value passed in to the method as a string
252         * 
253         * @param string determines whether or not to check income or expense sub account information (valid values include "Income" or "Expense")
254         * @return true if corresponding sub account values exist
255         */
256        protected boolean checkRequiredSubAccount(String string) {
257            boolean returnVal = true;
258            if (string.equals("Income")) {
259                if (newCreditCardVendor.getIncomeFinancialChartOfAccountsCode() == null) {
260                    putFieldError("incomeFinancialChartOfAccountsCode", KFSKeyConstants.ERROR_CCV_INCOME_SUBACCOUNT_REQUIRED, "Income Chart");
261                    returnVal = false;
262                }
263    
264                if (newCreditCardVendor.getIncomeAccountNumber() == null) {
265                    putFieldError("incomeAccountNumber", KFSKeyConstants.ERROR_CCV_INCOME_SUBACCOUNT_REQUIRED, "Income Account Number");
266                    returnVal = false;
267                }
268            }
269    
270    
271            if (string.equals("Expense")) {
272                if (newCreditCardVendor.getExpenseFinancialChartOfAccountsCode() == null) {
273                    putFieldError("expenseFinancialChartOfAccountsCode", KFSKeyConstants.ERROR_CCV_EXPENSE_SUBACCOUNT_REQUIRED, "Expense Chart");
274                    returnVal = false;
275                }
276    
277                if (newCreditCardVendor.getExpenseAccountNumber() == null) {
278                    putFieldError("expenseAccountNumber", KFSKeyConstants.ERROR_CCV_EXPENSE_SUBACCOUNT_REQUIRED, "Expense Account Number");
279                    returnVal = false;
280                }
281            }
282    
283    
284            return returnVal;
285        }
286    
287    
288        /**
289         * Returns a SubAccount object if SubAccount object exists for "Income" or "Expense"
290         * 
291         * @param string determines whether or not to retrieve a income or expense sub account (valid values include "Income" or "Expense")
292         * @return SubAccount Income/Expense SubAccount object
293         */
294        protected SubAccount checkExistenceSubAccount(String string) {
295    
296            SubAccount subAccount = null;
297    
298            if (string.equals("Income")) {
299                Map pkMap = new HashMap();
300                pkMap.put("chartOfAccountsCode", newCreditCardVendor.getIncomeFinancialChartOfAccountsCode());
301                pkMap.put("accountNumber", newCreditCardVendor.getIncomeAccountNumber());
302                pkMap.put("subAccountNumber", newCreditCardVendor.getIncomeSubAccountNumber());
303                subAccount = (SubAccount) super.getBoService().findByPrimaryKey(SubAccount.class, pkMap);
304            }
305    
306            if (string.equals("Expense")) {
307                Map pkMap = new HashMap();
308                pkMap.put("chartOfAccountsCode", newCreditCardVendor.getExpenseFinancialChartOfAccountsCode());
309                pkMap.put("accountNumber", newCreditCardVendor.getExpenseAccountNumber());
310                pkMap.put("subAccountNumber", newCreditCardVendor.getExpenseSubAccountNumber());
311                subAccount = (SubAccount) super.getBoService().findByPrimaryKey(SubAccount.class, pkMap);
312            }
313    
314            return subAccount;
315        }
316    
317    
318        /**
319         * Returns a true sub-object code exists for "Income" or "Expense"
320         * 
321         * @param string determines whether or not to check for an income or expense sub-object code (valid values include "Income" or "Expense")
322         * @return true if income/expense chart of account code, account number, and financial object code exist
323         */
324        protected boolean checkRequiredSubObjectCode(String string) {
325    
326            boolean returnVal = true;
327            if (string.equals("Income")) {
328                if (newCreditCardVendor.getIncomeFinancialChartOfAccountsCode() == null) {
329                    putFieldError("incomeFinancialChartOfAccountsCode", KFSKeyConstants.ERROR_CCV_INCOME_SUBOBJ_REQUIRED, "Income Chart");
330                    returnVal = false;
331                }
332    
333                if (newCreditCardVendor.getIncomeAccountNumber() == null) {
334                    putFieldError("incomeAccountNumber", KFSKeyConstants.ERROR_CCV_INCOME_SUBOBJ_REQUIRED, "Income Account Number");
335                    returnVal = false;
336                }
337    
338                if (newCreditCardVendor.getIncomeFinancialObjectCode() == null) {
339                    putFieldError("incomeFinancialObjectCode", KFSKeyConstants.ERROR_CCV_INCOME_SUBOBJ_REQUIRED, "Income Object Code");
340                    returnVal = false;
341                }
342    
343            }
344    
345    
346            if (string.equals("Expense")) {
347                if (newCreditCardVendor.getExpenseFinancialChartOfAccountsCode() == null) {
348                    putFieldError("expenseFinancialChartOfAccountsCode", KFSKeyConstants.ERROR_CCV_EXPENSE_SUBOBJ_REQUIRED, "Expense Chart");
349                    returnVal = false;
350                }
351    
352                if (newCreditCardVendor.getExpenseAccountNumber() == null) {
353                    putFieldError("expenseAccountNumber", KFSKeyConstants.ERROR_CCV_EXPENSE_SUBOBJ_REQUIRED, "Expense Account Number");
354                    returnVal = false;
355                }
356    
357                if (newCreditCardVendor.getExpenseFinancialObjectCode() == null) {
358                    putFieldError("expenseFinancialObjectCode", KFSKeyConstants.ERROR_CCV_EXPENSE_SUBOBJ_REQUIRED, "Expense Object Code");
359                    returnVal = false;
360                }
361    
362            }
363    
364    
365            return returnVal;
366        }
367    
368    
369        /**
370         * Returns a SubObjCd object if SubObjCd object exists for "Income" or "Expense"
371         * 
372         * @param string determines whether or not to retrieve a income or expense sub object (valid values include "Income" or "Expense")
373         * @return SubAccount Income/Expense SubObjCd object
374         */
375        protected SubObjectCode checkExistenceSubObj(String string) {
376    
377            SubObjectCode subObjCd = null;
378    
379            if (string.equals("Income")) {
380                Map pkMap = new HashMap();
381                pkMap.put("chartOfAccountsCode", newCreditCardVendor.getIncomeFinancialChartOfAccountsCode());
382                pkMap.put("accountNumber", newCreditCardVendor.getIncomeAccountNumber());
383                pkMap.put("financialObjectCode", newCreditCardVendor.getIncomeFinancialObjectCode());
384                pkMap.put("financialSubObjectCode", newCreditCardVendor.getIncomeFinancialSubObjectCode());
385                subObjCd = (SubObjectCode) super.getBoService().findByPrimaryKey(SubObjectCode.class, pkMap);
386            }
387    
388            if (string.equals("Expense")) {
389                Map pkMap = new HashMap();
390                pkMap.put("chartOfAccountsCode", newCreditCardVendor.getExpenseFinancialChartOfAccountsCode());
391                pkMap.put("accountNumber", newCreditCardVendor.getExpenseAccountNumber());
392                pkMap.put("financialObjectCode", newCreditCardVendor.getExpenseFinancialObjectCode());
393                pkMap.put("financialSubObjectCode", newCreditCardVendor.getExpenseFinancialSubObjectCode());
394                subObjCd = (SubObjectCode) super.getBoService().findByPrimaryKey(SubObjectCode.class, pkMap);
395            }
396    
397            return subObjCd;
398        }
399    
400    }