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.coa.document.validation.impl;
017    
018    import java.util.List;
019    
020    import org.apache.commons.lang.StringUtils;
021    import org.kuali.kfs.coa.businessobject.AccountDelegateGlobal;
022    import org.kuali.kfs.coa.businessobject.AccountDelegateGlobalDetail;
023    import org.kuali.kfs.coa.businessobject.AccountGlobalDetail;
024    import org.kuali.kfs.sys.KFSConstants;
025    import org.kuali.kfs.sys.KFSKeyConstants;
026    import org.kuali.kfs.sys.KFSPropertyConstants;
027    import org.kuali.kfs.sys.context.SpringContext;
028    import org.kuali.kfs.sys.document.service.FinancialSystemDocumentService;
029    import org.kuali.kfs.sys.document.service.FinancialSystemDocumentTypeService;
030    import org.kuali.rice.kim.bo.Person;
031    import org.kuali.rice.kns.bo.PersistableBusinessObject;
032    import org.kuali.rice.kns.document.MaintenanceDocument;
033    import org.kuali.rice.kns.util.GlobalVariables;
034    import org.kuali.rice.kns.util.KualiDecimal;
035    import org.kuali.rice.kns.util.ObjectUtils;
036    
037    /**
038     * This class executes specific rules for the {@link DelegateGlobalMaintenanceDocument}
039     */
040    public class DelegateGlobalRule extends GlobalDocumentRuleBase {
041    
042        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DelegateGlobalRule.class);
043    
044        protected static final KualiDecimal ZERO = KualiDecimal.ZERO;
045        protected AccountDelegateGlobal newDelegateGlobal;
046        protected static final String DELEGATE_GLOBALS_PREFIX = "delegateGlobals";
047    
048        public DelegateGlobalRule() {
049            super();
050        }
051    
052        /**
053         * This method sets the convenience objects like newAccount and oldAccount, so you have short and easy handles to the new and
054         * old objects contained in the maintenance document. It also calls the BusinessObjectBase.refresh(), which will attempt to load
055         * all sub-objects from the DB by their primary keys, if available.
056         */
057        @Override
058        public void setupConvenienceObjects() {
059    
060            // setup newDelegateGlobal convenience objects,
061            // make sure all possible sub-objects are populated
062            newDelegateGlobal = (AccountDelegateGlobal) super.getNewBo();
063    
064            // forces refreshes on all the sub-objects in the lists
065            for (AccountDelegateGlobalDetail delegateGlobal : newDelegateGlobal.getDelegateGlobals()) {
066                delegateGlobal.refreshNonUpdateableReferences();
067            }
068            for (AccountGlobalDetail accountGlobalDetail : newDelegateGlobal.getAccountGlobalDetails()) {
069                accountGlobalDetail.refreshNonUpdateableReferences();
070            }
071        }
072    
073        /**
074         * This checks some basic rules for document approval Specifically it calls the following:
075         * <ul>
076         * <li>{@link DelegateGlobalRule#checkSimpleRulesAllLines()}</li>
077         * <li>{@link DelegateGlobalRule#checkOnlyOneChartErrorWrapper(List)}</li>
078         * <li>{@link DelegateGlobalRule#checkForPrimaryDelegateAllLines()}</li>
079         * </ul>
080         * fails if any rules fail
081         * 
082         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomApproveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
083         */
084        @Override
085        protected boolean processCustomApproveDocumentBusinessRules(MaintenanceDocument document) {
086            boolean success = true;
087            setupConvenienceObjects();
088            // check simple rules
089            success &= checkSimpleRulesAllLines(document);
090    
091            success &= checkOnlyOneChartErrorWrapper(newDelegateGlobal.getAccountGlobalDetails());
092    
093            // check for primary routing
094            success &= checkForPrimaryDelegateAllLines();
095            return success;
096        }
097    
098        /**
099         * This checks some basic rules for document routing Specifically it calls the following:
100         * <ul>
101         * <li>{@link DelegateGlobalRule#checkSimpleRulesAllLines()}</li>
102         * <li>{@link DelegateGlobalRule#checkAccountDetails(List)}</li>
103         * <li>{@link DelegateGlobalRule#checkForPrimaryDelegateAllLines()}</li>
104         * </ul>
105         * fails if any rules fail
106         * 
107         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
108         */
109        @Override
110        protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
111            boolean success = true;
112            setupConvenienceObjects();
113            // check simple rules
114            success &= checkSimpleRulesAllLines(document);
115    
116            success &= checkAccountDetails(newDelegateGlobal.getAccountGlobalDetails());
117    
118            // check for primary routing
119            success &= checkForPrimaryDelegateAllLines();
120            return success;
121        }
122    
123        /**
124         * This checks some basic rules for document saving Specifically it calls the following:
125         * <ul>
126         * <li>{@link DelegateGlobalRule#checkSimpleRulesAllLines()}</li>
127         * <li>{@link DelegateGlobalRule#checkOnlyOneChartErrorWrapper(List)}</li>
128         * <li>{@link DelegateGlobalRule#checkForPrimaryDelegateAllLines()}</li>
129         * </ul>
130         * fails if any rules fail
131         * 
132         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
133         */
134        @Override
135        protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
136            setupConvenienceObjects();
137            // check simple rules
138            checkSimpleRulesAllLines(document);
139    
140            checkOnlyOneChartErrorWrapper(newDelegateGlobal.getAccountGlobalDetails());
141    
142            // check for primary routing
143            checkForPrimaryDelegateAllLines();
144            return true;
145        }
146    
147        /**
148         * This checks to see if there are any accounts in the details collection if there are then it calls
149         * {@link DelegateGlobalRule#checkAccountDetails(AccountGlobalDetail)}
150         * 
151         * @param details - collection of {@link AccountGlobalDetail}s
152         * @return false if there are no objects in the collection or any one of the {@link AccountGlobalDetail} fail
153         */
154        public boolean checkAccountDetails(List<AccountGlobalDetail> details) {
155            boolean success = true;
156    
157            // check if there are any accounts
158            if (details.size() == 0) {
159                putFieldError(KFSConstants.MAINTENANCE_ADD_PREFIX + "accountGlobalDetails.accountNumber", KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_NO_ACCOUNTS);
160                success = false;
161            }
162            else {
163                // check each account
164                int index = 0;
165                for (AccountGlobalDetail dtl : details) {
166                    String errorPath = MAINTAINABLE_ERROR_PREFIX + "accountGlobalDetails[" + index + "]";
167                    GlobalVariables.getMessageMap().addToErrorPath(errorPath);
168                    success &= checkAccountDetails(dtl);
169                    GlobalVariables.getMessageMap().removeFromErrorPath(errorPath);
170                    index++;
171                }
172                success &= checkOnlyOneChartErrorWrapper(details);
173            }
174    
175            return success;
176        }
177    
178        /**
179         * This checks to make sure that each {@link AccountGlobalDetail} has a valid {@link Account}
180         * 
181         * @param dtl - the {@link AccountGlobalDetail}
182         * @return false if it does not have a valid {@link Account}
183         */
184        public boolean checkAccountDetails(AccountGlobalDetail dtl) {
185            boolean success = true;
186            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
187            getDictionaryValidationService().validateBusinessObject(dtl);
188            if (StringUtils.isNotBlank(dtl.getAccountNumber()) && StringUtils.isNotBlank(dtl.getChartOfAccountsCode())) {
189                dtl.refreshReferenceObject("account");
190                if (ObjectUtils.isNull(dtl.getAccount())) {
191                    GlobalVariables.getMessageMap().putError("accountNumber", KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_INVALID_ACCOUNT, new String[] { dtl.getChartOfAccountsCode(), dtl.getAccountNumber() });
192                }
193            }
194            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
195    
196            return success;
197        }
198    
199        /**
200         * This method checks the simple rules for all lines at once and gets called on save, submit, etc. but not on add Specifically
201         * it calls the following:
202         * <ul>
203         * <li>{@link DelegateGlobalRule#checkDelegateUserRules(DelegateGlobalDetail, int, boolean)}</li>
204         * <li>{@link DelegateGlobalRule#checkDelegateForNullToAmount(KualiDecimal, KualiDecimal, int, boolean)}</li>
205         * <li>{@link DelegateGlobalRule#checkDelegateToAmtGreaterThanFromAmt(KualiDecimal, KualiDecimal, int, boolean)}</li>
206         * <li>{@link DelegateGlobalRule#checkDelegateFromAmtGreaterThanEqualZero(KualiDecimal, int, boolean)}</li>
207         * <li>{@link DelegateGlobalRule#checkPrimaryRouteRules(List, DelegateGlobalDetail, Integer, boolean)}</li>
208         * </ul>
209         * 
210         * @return
211         */
212        protected boolean checkSimpleRulesAllLines(MaintenanceDocument document) {
213    
214            boolean success = true;
215            // check if there are any accounts
216            if (newDelegateGlobal.getDelegateGlobals().size() == 0) {
217                putFieldError(KFSConstants.MAINTENANCE_ADD_PREFIX + KFSPropertyConstants.DELEGATE_GLOBALS + "." + KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE, KFSKeyConstants.ERROR_DOCUMENT_DELEGATE_CHANGE_NO_DELEGATE);
218                success = false;
219            }
220            else {
221                // check each delegate
222                int i = 0;
223                final FinancialSystemDocumentTypeService documentService = SpringContext.getBean(FinancialSystemDocumentTypeService.class);
224                for (AccountDelegateGlobalDetail newDelegateGlobalDetail : newDelegateGlobal.getDelegateGlobals()) {
225                    KualiDecimal fromAmount = newDelegateGlobalDetail.getApprovalFromThisAmount();
226                    KualiDecimal toAmount = newDelegateGlobalDetail.getApprovalToThisAmount();
227    
228                    success &= checkDelegateUserRules(document, newDelegateGlobalDetail, i, false);
229    
230                    // FROM amount must be >= 0 (may not be negative)
231                    success &= checkDelegateFromAmtGreaterThanEqualZero(fromAmount, i, false);
232    
233                    // TO amount must be >= FROM amount or Zero
234                    success &= checkDelegateToAmtGreaterThanFromAmt(fromAmount, toAmount, i, false);
235    
236                    success &= checkDelegateDocumentTypeCode(newDelegateGlobalDetail.getFinancialDocumentTypeCode(), documentService);
237    
238                    // increment counter for delegate changes list
239                    i++;
240                }
241            }
242            return success;
243        }
244    
245    
246        /**
247         * This method will check through each delegate referenced in the DelegateGlobal to ensure that there is one and only primary
248         * for each account and doctype
249         * 
250         * @return false if there is more than one primary delegate
251         */
252        protected boolean checkForPrimaryDelegateAllLines() {
253            boolean success = true;
254            int i = 0;
255            for (AccountDelegateGlobalDetail newDelegateGlobalDetail : newDelegateGlobal.getDelegateGlobals()) {
256                success &= checkPrimaryRouteRules(newDelegateGlobal.getDelegateGlobals(), newDelegateGlobalDetail, new Integer(i), false);
257                i++;
258            }
259            return success;
260        }
261    
262        /**
263         * This method checks to see if the from amount is greater than zero
264         * 
265         * @param fromAmount
266         * @param lineNum
267         * @return false if from amount less than zero
268         */
269        protected boolean checkDelegateFromAmtGreaterThanEqualZero(KualiDecimal fromAmount, int lineNum, boolean add) {
270            boolean success = true;
271            if (ObjectUtils.isNotNull(fromAmount)) {
272                if (fromAmount.isLessThan(ZERO)) {
273                    String errorPath = KFSConstants.EMPTY_STRING;
274                    if (add) {
275                        errorPath = KFSConstants.MAINTENANCE_ADD_PREFIX + DELEGATE_GLOBALS_PREFIX + "." + "approvalFromThisAmount";
276                        putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_FROM_AMOUNT_NONNEGATIVE);
277                    }
278                    else {
279                        errorPath = DELEGATE_GLOBALS_PREFIX + "[" + lineNum + "]." + "approvalFromThisAmount";
280                        putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_FROM_AMOUNT_NONNEGATIVE);
281                    }
282                    success &= false;
283                }
284            }
285            return success;
286        }
287    
288        /**
289         * This method checks to see if the to Amount is greater than the from amount
290         * 
291         * @param fromAmount
292         * @param toAmount
293         * @param lineNum
294         * @return false if to amount less than from amount
295         */
296        protected boolean checkDelegateToAmtGreaterThanFromAmt(KualiDecimal fromAmount, KualiDecimal toAmount, int lineNum, boolean add) {
297            boolean success = true;
298            if (ObjectUtils.isNotNull(toAmount)) {
299    
300                if (!ObjectUtils.isNull(fromAmount)) {
301                    // case if FROM amount is non-null and positive, disallow TO amount being less if it is not ZERO (another indicator
302                    // of infinity)
303                    if (!toAmount.equals(ZERO) && toAmount.isLessThan(fromAmount)) {
304                        String errorPath = KFSConstants.EMPTY_STRING;
305                        if (add) {
306                            errorPath = KFSConstants.MAINTENANCE_ADD_PREFIX + DELEGATE_GLOBALS_PREFIX + "." + "approvalToThisAmount";
307                            putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_TO_AMOUNT_MORE_THAN_FROM_OR_ZERO);
308                        }
309                        else {
310                            errorPath = DELEGATE_GLOBALS_PREFIX + "[" + lineNum + "]." + "approvalToThisAmount";
311                            putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_TO_AMOUNT_MORE_THAN_FROM_OR_ZERO);
312                        }
313                        success &= false;
314                    }
315                }
316    
317                if (toAmount.isLessThan(KualiDecimal.ZERO)) {
318                    String errorPath = KFSConstants.EMPTY_STRING;
319                    if (add) {
320                        errorPath = KFSConstants.MAINTENANCE_ADD_PREFIX + DELEGATE_GLOBALS_PREFIX + "." + "approvalToThisAmount";
321                        putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_TO_AMOUNT_MORE_THAN_FROM_OR_ZERO);
322                    }
323                    else {
324                        errorPath = DELEGATE_GLOBALS_PREFIX + "[" + lineNum + "]." + "approvalToThisAmount";
325                        putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_TO_AMOUNT_MORE_THAN_FROM_OR_ZERO);
326                    }
327                    success &= false;
328                }
329            }
330            return success;
331        }
332    
333        /**
334         * Validates the document type code for the delegate, to make sure it is a Financial System document type code
335         * 
336         * @param documentTypeCode the document type code to check
337         * @param delegateService a helpful instance of the delegate service, so new ones don't have to be created all the time
338         * @return true if the document type code is valid, false otherwise
339         */
340        protected boolean checkDelegateDocumentTypeCode(String documentTypeCode, FinancialSystemDocumentTypeService documentService) {
341            if (!documentService.isFinancialSystemDocumentType(documentTypeCode)) {
342                String errorPath = KFSConstants.MAINTENANCE_ADD_PREFIX + DELEGATE_GLOBALS_PREFIX + "." + KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE;
343                putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_INVALID_DOC_TYPE, new String[] { documentTypeCode, KFSConstants.ROOT_DOCUMENT_TYPE });
344    
345                return false;
346            }
347            return true;
348        }
349    
350        /**
351         * This method validates the rule that says there can be only one PrimaryRoute delegate for each given docType. It checks the
352         * delegateGlobalToTest against the list, to determine whether adding this new delegateGlobalToTest would violate any
353         * PrimaryRoute business rule violations. If any of the incoming variables is null or empty, the method will do nothing, and
354         * return Null. It will only process the business rules if there is sufficient data to do so.
355         * 
356         * @param delegateGlobalToTest A delegateGlobal line that you want to test against the list.
357         * @param delegateGlobals A List of delegateGlobal items that is being tested against.
358         * @return Null if the business rule passes, or an Integer value greater than zero, representing the line that the new line is
359         *         conflicting with
360         */
361        protected Integer checkPrimaryRoutePerDocType(AccountDelegateGlobalDetail delegateGlobalToTest, List<AccountDelegateGlobalDetail> delegateGlobals, Integer testLineNum) {
362    
363            // exit immediately if the adding line isnt a Primary routing
364            if (delegateGlobalToTest == null || delegateGlobals == null || delegateGlobals.isEmpty()) {
365                return null;
366            }
367            if (!delegateGlobalToTest.getAccountDelegatePrimaryRoutingIndicator()) {
368                return null;
369            }
370            if (StringUtils.isBlank(delegateGlobalToTest.getFinancialDocumentTypeCode())) {
371                return null;
372            }
373    
374            // at this point, the delegateGlobal being added is a Primary for ALL docTypes, so we need to
375            // test whether any in the existing list are also Primary, regardless of docType
376            String docType = delegateGlobalToTest.getFinancialDocumentTypeCode();
377            AccountDelegateGlobalDetail delegateGlobal = null;
378            for (int lineNumber = 0; lineNumber < delegateGlobals.size(); lineNumber++) {
379                delegateGlobal = delegateGlobals.get(lineNumber);
380                if (delegateGlobal.getAccountDelegatePrimaryRoutingIndicator()) {
381                    if (docType.equalsIgnoreCase(delegateGlobal.getFinancialDocumentTypeCode())) {
382                        if (testLineNum == null) {
383                            return new Integer(lineNumber);
384                        }
385                        else if (!(testLineNum.intValue() == lineNumber)) {
386                            return new Integer(lineNumber);
387                        }
388                    }
389                }
390            }
391    
392            return null;
393        }
394    
395        /**
396         * This checks that the primary routing for delegates is correct, specifically that - there is not already a primary route
397         * delegate setup for this {@link Account}
398         * 
399         * @param delegateGlobals
400         * @param delegateGlobalToTest
401         * @param lineNum
402         * @param add
403         * @return
404         */
405        protected boolean checkPrimaryRouteRules(List<AccountDelegateGlobalDetail> delegateGlobals, AccountDelegateGlobalDetail delegateGlobalToTest, Integer lineNum, boolean add) {
406            boolean success = true;
407    
408            String errorPath = "";
409            Integer result = null;
410            for (AccountDelegateGlobalDetail delegateGlobal : delegateGlobals) {
411    
412                result = checkPrimaryRoutePerDocType(delegateGlobalToTest, delegateGlobals, lineNum);
413                if (result != null) {
414                    if (add) {
415                        errorPath = KFSConstants.MAINTENANCE_ADD_PREFIX + DELEGATE_GLOBALS_PREFIX + "." + "financialDocumentTypeCode";
416                        putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_DELEGATEMAINT_PRIMARY_ROUTE_ALREADY_EXISTS_FOR_DOCTYPE);
417                    }
418                    else {
419                        errorPath = DELEGATE_GLOBALS_PREFIX + "[" + lineNum.toString() + "]." + "financialDocumentTypeCode";
420                        putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_DELEGATEMAINT_PRIMARY_ROUTE_ALREADY_EXISTS_FOR_DOCTYPE);
421                    }
422                    success &= false;
423                }
424            }
425            return success;
426        }
427    
428        /**
429         * This checks that the delegate for this {@link Account} exists and is valid (active and a professional)
430         * 
431         * @param delegateGlobal
432         * @param lineNum
433         * @param add
434         * @return false if the delegate for the {@link Account} doesn't exist or isn't valid
435         */
436        protected boolean checkDelegateUserRules(MaintenanceDocument document, AccountDelegateGlobalDetail delegateGlobal, int lineNum, boolean add) {
437            boolean success = true;
438            String errorPath = KFSConstants.EMPTY_STRING;
439            
440            Person accountDelegate = delegateGlobal.getAccountDelegate();
441            if (StringUtils.isBlank(delegateGlobal.getAccountDelegateUniversalId()) || ObjectUtils.isNull(accountDelegate)) {
442                if (add) {
443                    errorPath = KFSConstants.MAINTENANCE_ADD_PREFIX + DELEGATE_GLOBALS_PREFIX + "." + "accountDelegate.principalName";
444                    putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_USER_DOESNT_EXIST);
445                }
446                else {
447                    errorPath = DELEGATE_GLOBALS_PREFIX + "[" + lineNum + "]." + "accountDelegate.principalName";
448                    putFieldError(errorPath, KFSKeyConstants.ERROR_DOCUMENT_ACCTDELEGATEMAINT_USER_DOESNT_EXIST);
449                }
450    
451                success &= false;
452            }
453            else if (!getDocumentHelperService().getDocumentAuthorizer(document).isAuthorized(document, KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_FISCAL_OFFICER_DELEGATE, accountDelegate.getPrincipalId())) {
454                if (add) {
455                    errorPath = KFSConstants.MAINTENANCE_ADD_PREFIX + DELEGATE_GLOBALS_PREFIX + "." + "accountDelegate.principalName";
456                    putFieldError(errorPath, KFSKeyConstants.ERROR_USER_MISSING_PERMISSION, new String[] { accountDelegate.getName(), KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_FISCAL_OFFICER_DELEGATE });
457                }
458                else {
459                    errorPath = DELEGATE_GLOBALS_PREFIX + "[" + lineNum + "]." + "accountDelegate.principalName";
460                    putFieldError(errorPath, KFSKeyConstants.ERROR_USER_MISSING_PERMISSION, new String[] { accountDelegate.getName(), KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_FISCAL_OFFICER_DELEGATE });
461                }
462                
463                success &= false;
464            }
465    
466            return success;
467        }
468    
469        /**
470         * This checks that when a new line is added (either {@link AccountGlobalDetail} or {@link DelegateGlobalDetail}) that the
471         * appropriate rules are run on the new lines being added on {@link AccountGlobalDetail}: - make sure that the account number
472         * and chart are entered
473         * <ul>
474         * <li>{@link DelegateGlobalRule#checkAccountDetails(AccountGlobalDetail)}</li>
475         * </ul>
476         * on {@link DelegateGlobalDetail}
477         * <ul>
478         * <li>{@link DelegateGlobalRule#checkDelegateFromAmtGreaterThanEqualZero(KualiDecimal, int, boolean)}</li>
479         * <li>{@link DelegateGlobalRule#checkDelegateForNullToAmount(KualiDecimal, KualiDecimal, int, boolean)}</li>
480         * <li>{@link DelegateGlobalRule#checkDelegateToAmtGreaterThanFromAmt(KualiDecimal, KualiDecimal, int, boolean)}</li>
481         * <li>{@link DelegateGlobalRule#checkDelegateUserRules(DelegateGlobalDetail, int, boolean)}</li>
482         * <li>{@link DelegateGlobalRule#checkPrimaryRouteRules(List, DelegateGlobalDetail, Integer, boolean)}</li>
483         * </ul>
484         * 
485         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument,
486         *      java.lang.String, org.kuali.rice.kns.bo.PersistableBusinessObject)
487         */
488        public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject bo) {
489            boolean success = true;
490            if (bo instanceof AccountGlobalDetail) {
491                AccountGlobalDetail detail = (AccountGlobalDetail) bo;
492                // make sure that both primary keys are available for this object
493                if (!checkEmptyValue(detail.getAccountNumber())) {
494                    // put an error about accountnumber
495                    GlobalVariables.getMessageMap().putError("accountNumber", KFSKeyConstants.ERROR_REQUIRED, "Account Number");
496                    success &= false;
497                }
498                if (!checkEmptyValue(detail.getChartOfAccountsCode())) {
499                    // put an error about chart code
500                    GlobalVariables.getMessageMap().putError("chartOfAccountsCode", KFSKeyConstants.ERROR_REQUIRED, "Chart of Accounts Code");
501                    success &= false;
502                }
503                success &= checkAccountDetails(detail);
504            }
505            else if (bo instanceof AccountDelegateGlobalDetail) {
506                AccountDelegateGlobalDetail detail = (AccountDelegateGlobalDetail) bo;
507                detail.refreshNonUpdateableReferences();
508                KualiDecimal fromAmount = detail.getApprovalFromThisAmount();
509                KualiDecimal toAmount = detail.getApprovalToThisAmount();
510    
511                // FROM amount must be >= 0 (may not be negative)
512                success &= checkDelegateFromAmtGreaterThanEqualZero(fromAmount, 0, true);
513    
514                // TO amount must be >= FROM amount or Zero
515                success &= checkDelegateToAmtGreaterThanFromAmt(fromAmount, toAmount, 0, true);
516    
517                // check the user that is being added
518                // TODO: add back in once the user issues have been fixed
519                success &= checkDelegateUserRules(document, detail, 0, true);
520    
521                // check the routing
522                success &= checkPrimaryRouteRules(newDelegateGlobal.getDelegateGlobals(), detail, null, true);
523    
524                final FinancialSystemDocumentTypeService documentService = SpringContext.getBean(FinancialSystemDocumentTypeService.class);
525                success &= checkDelegateDocumentTypeCode(detail.getFinancialDocumentTypeCode(), documentService);
526    
527            }
528            return success;
529        }
530    
531    }