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 }