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.AccountGlobalDetail;
022 import org.kuali.kfs.sys.KFSKeyConstants;
023 import org.kuali.kfs.sys.document.validation.impl.KfsMaintenanceDocumentRuleBase;
024 import org.kuali.rice.kns.util.GlobalVariables;
025
026 /**
027 * This class contains common Business Rule functionality for Global Documents.
028 */
029 public class GlobalDocumentRuleBase extends KfsMaintenanceDocumentRuleBase {
030
031 /**
032 * Constructs a GlobalDocumentRuleBase.java.
033 */
034 public GlobalDocumentRuleBase() {
035 super();
036 }
037
038 /**
039 * This method checks whether the set of Account Change Detail records on this document all are under the same Chart of
040 * Accounts. It will set the appropriate field error if it did fail, and return the result.
041 *
042 * @param accountGlobalDetails
043 * @return True if the test passed with no errors, False if any errors occurred.
044 */
045 protected boolean checkOnlyOneChartErrorWrapper(List<AccountGlobalDetail> accountGlobalDetails) {
046 CheckOnlyOneChartResult result = checkOnlyOneChart(accountGlobalDetails);
047 if (!result.success) {
048 putFieldError("accountGlobalDetails[" + result.firstLineNumber + "].chartOfAccountsCode", KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_ONE_CHART_ONLY);
049 putFieldError("accountGlobalDetails[" + result.failedLineNumber + "].chartOfAccountsCode", KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_ONE_CHART_ONLY);
050 }
051 return result.success;
052 }
053
054 /**
055 * This method checks whether the set of Account Change Detail records on this document all are under the same Chart of
056 * Accounts. It will return a failed CheckOnlyOneChartResult if so. Note that this method doesnt actually set any errors, it
057 * just returns whether or not the test succeeded, and where it failed if it failed.
058 *
059 * @param accountGlobalDetails The popualted accountGlobalDocument to test.
060 * @return A populated CheckOnlyOneChartResult object. This will contain whether the test succeeded or failed, and if failed,
061 * what lines the failures occurred on.
062 */
063 protected CheckOnlyOneChartResult checkOnlyOneChart(List<AccountGlobalDetail> accountGlobalDetails) {
064 // if there is not enough information to do the test, then exit happily with no failure
065 if (accountGlobalDetails == null) {
066 return new CheckOnlyOneChartResult(true);
067 }
068 if (accountGlobalDetails.isEmpty()) {
069 return new CheckOnlyOneChartResult(true);
070 }
071
072 // test to see if there is more than one chart listed, ignores blank chartcodes
073 int compareLineNumber = 0;
074 int firstChartLineNumber = 0;
075 String firstChart = "";
076 for (AccountGlobalDetail account : accountGlobalDetails) {
077 if (StringUtils.isBlank(firstChart)) {
078 if (StringUtils.isNotBlank(account.getChartOfAccountsCode())) {
079 firstChart = account.getChartOfAccountsCode();
080 firstChartLineNumber = compareLineNumber;
081 }
082 }
083 else {
084 if (StringUtils.isNotBlank(account.getChartOfAccountsCode())) {
085 if (!firstChart.equalsIgnoreCase(account.getChartOfAccountsCode())) {
086 return new CheckOnlyOneChartResult(false, firstChartLineNumber, compareLineNumber);
087 }
088 }
089 }
090 compareLineNumber++;
091 }
092 return new CheckOnlyOneChartResult(true);
093 }
094
095 /**
096 * This class is used internally to represent the result of the CheckOnlyOneChart method.
097 */
098 protected class CheckOnlyOneChartResult {
099
100 public int firstLineNumber;
101 public int failedLineNumber;
102 public boolean success;
103
104 /**
105 * Constructs a CheckOnlyOneChartResult
106 */
107 public CheckOnlyOneChartResult() {
108 firstLineNumber = -1;
109 failedLineNumber = -1;
110 success = true;
111 }
112
113 /**
114 * Constructs a CheckOnlyOneChartResult
115 *
116 * @param success
117 */
118 public CheckOnlyOneChartResult(boolean success) {
119 this();
120 this.success = success;
121 }
122
123 /**
124 * Constructs a CheckOnlyOneChartResult
125 *
126 * @param success
127 * @param firstLineNumber
128 * @param failedLineNumber
129 */
130 public CheckOnlyOneChartResult(boolean success, int firstLineNumber, int failedLineNumber) {
131 this.success = success;
132 this.firstLineNumber = firstLineNumber;
133 this.failedLineNumber = failedLineNumber;
134 }
135
136 }
137
138 /**
139 * This method tests whether the line being added has a different Chart of Accounts Code from any of the existing lines. It will
140 * set an Error and return false if this is the case.
141 *
142 * @param newAccountLine
143 * @param accountGlobalDetails
144 * @return True if the line being added has the exact same chart as all the existing lines, False if not.
145 */
146 protected boolean checkOnlyOneChartAddLineErrorWrapper(AccountGlobalDetail newAccountLine, List<AccountGlobalDetail> accountGlobalDetails) {
147 boolean success = checkOnlyOneChartAddLine(newAccountLine, accountGlobalDetails);
148 if (!success) {
149 // putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_ONE_CHART_ONLY_ADDNEW);
150 // TODO: KULCOA-1091 Need to add this error to the add line, but this doesn't work right, as the
151 // error message comes out at the bottom, and the field doesn't get highlighted.
152 // putFieldError("newAccountGlobalDetail.chartOfAccountsCode",
153 // KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_ONE_CHART_ONLY);
154
155 // added to prevent error from showing at the top of the document, but rather in the Account Detail Edit section
156 GlobalVariables.getMessageMap().putError("chartOfAccountsCode", KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_ONE_CHART_ONLY_ADDNEW);
157 }
158 return success;
159 }
160
161 /**
162 * This method tests whether a new line can be added, based on the rule that says all the accounts being used must belong to the
163 * same chart. If the line being added differs from any existing line's Chart code, it will return false. Note that this
164 * document does not actually set any errors, it just reports success or failure.
165 *
166 * @param newAccountLine
167 * @param accountGlobalDetails
168 * @return True if no errors are found, False if the line being added has a different Chart code than any of the existing lines.
169 */
170 protected boolean checkOnlyOneChartAddLine(AccountGlobalDetail newAccountLine, List<AccountGlobalDetail> accountGlobalDetails) {
171 if (newAccountLine == null || accountGlobalDetails == null) {
172 return true;
173 }
174 if (accountGlobalDetails.isEmpty()) {
175 return true;
176 }
177 String newChart = newAccountLine.getChartOfAccountsCode();
178 if (StringUtils.isBlank(newChart)) {
179 return true;
180 }
181 for (AccountGlobalDetail account : accountGlobalDetails) {
182 if (StringUtils.isNotBlank(account.getChartOfAccountsCode())) {
183 if (!newChart.equalsIgnoreCase(account.getChartOfAccountsCode())) {
184 return false;
185 }
186 }
187 }
188 return true;
189 }
190
191 }