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.module.ec.document.validation.impl;
017
018 import java.util.Collection;
019 import java.util.List;
020 import java.util.Map;
021 import java.util.Set;
022
023 import org.kuali.kfs.coa.businessobject.Account;
024 import org.kuali.kfs.coa.businessobject.Organization;
025 import org.kuali.kfs.coa.businessobject.SubFundGroup;
026 import org.kuali.kfs.integration.cg.ContractsAndGrantsModuleService;
027 import org.kuali.kfs.integration.ld.LaborLedgerBalance;
028 import org.kuali.kfs.module.ec.EffortConstants;
029 import org.kuali.kfs.module.ec.EffortKeyConstants;
030 import org.kuali.kfs.module.ec.util.LedgerBalanceConsolidationHelper;
031 import org.kuali.kfs.sys.Message;
032 import org.kuali.kfs.sys.MessageBuilder;
033 import org.kuali.kfs.sys.context.SpringContext;
034 import org.kuali.rice.kns.util.KualiDecimal;
035 import org.kuali.rice.kns.util.ObjectUtils;
036
037 /**
038 * The validator provides a set of facilities to determine whether the given ledger balances meet the specified requirements. As a
039 * pattern, null would be returned if the requirements are met; otherwise, return an error message.
040 */
041 public class LedgerBalanceFieldValidator {
042
043 /**
044 * check if the given ledger balance has an account qualified for effort reporting
045 *
046 * @param ledgerBalance the given ledger balance
047 * @return null if the given ledger balance has an account qualified for effort reporting; otherwise, a message
048 */
049 public static Message hasValidAccount(LaborLedgerBalance ledgerBalance) {
050 if (ObjectUtils.isNull(ledgerBalance.getAccount())) {
051 String account = new StringBuilder(ledgerBalance.getChartOfAccountsCode()).append(EffortConstants.VALUE_SEPARATOR).append(ledgerBalance.getAccountNumber()).toString();
052 return MessageBuilder.buildMessage(EffortKeyConstants.ERROR_ACCOUNT_NUMBER_NOT_FOUND, account);
053 }
054 return null;
055 }
056
057 /**
058 * detetermine if the fund group code associated with the given ledger balance is in the given fund group codes
059 *
060 * @param ledgerBalance the given ledger balance
061 * @param fundGroupCodes the given fund group codes
062 * @return null if the fund group code associated with the given ledger balance is in the given fund group codes; otherwise, a
063 * message
064 */
065 public static Message isInFundGroups(LaborLedgerBalance ledgerBalance, List<String> fundGroupCodes) {
066 SubFundGroup subFundGroup = getSubFundGroup(ledgerBalance);
067
068 if (ObjectUtils.isNull(subFundGroup) || !fundGroupCodes.contains(subFundGroup.getFundGroupCode())) {
069 return MessageBuilder.buildMessage(EffortKeyConstants.ERROR_FUND_GROUP_NOT_FOUND, subFundGroup.getFundGroupCode());
070 }
071 return null;
072 }
073
074 /**
075 * detetermine if the sub fund group code associated with the given ledger balance is in the given sub fund group codes
076 *
077 * @param ledgerBalance the given ledger balance
078 * @param subFundGroupCodes the given sub fund group codes
079 * @return null if the sub fund group code associated with the given ledger balance is in the given sub fund group codes;
080 * otherwise, an error message
081 */
082 public static Message isInSubFundGroups(LaborLedgerBalance ledgerBalance, List<String> subFundGroupCodes) {
083 SubFundGroup subFundGroup = getSubFundGroup(ledgerBalance);
084
085 if (ObjectUtils.isNull(subFundGroup) || !subFundGroupCodes.contains(subFundGroup.getSubFundGroupCode())) {
086 return MessageBuilder.buildMessage(EffortKeyConstants.ERROR_FUND_GROUP_NOT_FOUND, subFundGroup.getSubFundGroupCode());
087 }
088 return null;
089 }
090
091 /**
092 * determine if the total amount within the specified periods of the given ledger balance is ZERO
093 *
094 * @param ledgerBalance the given ledger balance
095 * @param reportPeriods the specified periods
096 * @return null the total amount within the specified periods of the given ledger balance is NOT ZERO; otherwise, a message
097 * message
098 */
099 public static Message isNonZeroAmountBalanceWithinReportPeriod(LaborLedgerBalance ledgerBalance, Map<Integer, Set<String>> reportPeriods) {
100 KualiDecimal totalAmount = LedgerBalanceConsolidationHelper.calculateTotalAmountWithinReportPeriod(ledgerBalance, reportPeriods);
101
102 if (totalAmount.isZero()) {
103 return MessageBuilder.buildMessage(EffortKeyConstants.ERROR_ZERO_PAYROLL_AMOUNT, Message.TYPE_FATAL);
104 }
105 return null;
106 }
107
108 /**
109 * determine if the total amount within the specified periods of the given ledger balances is positive
110 *
111 * @param ledgerBalance the given ledger balance
112 * @param reportPeriods the specified periods
113 * @return null the total amount within the specified periods of the given ledger balance is positive; otherwise, a message
114 * message
115 */
116 public static Message isTotalAmountPositive(Collection<LaborLedgerBalance> ledgerBalances, Map<Integer, Set<String>> reportPeriods) {
117 KualiDecimal totalAmount = LedgerBalanceConsolidationHelper.calculateTotalAmountWithinReportPeriod(ledgerBalances, reportPeriods);
118
119 if (!totalAmount.isPositive()) {
120 return MessageBuilder.buildMessage(EffortKeyConstants.ERROR_NONPOSITIVE_PAYROLL_AMOUNT, totalAmount.toString());
121 }
122 return null;
123 }
124
125 /**
126 * check if there is at least one account of the given ledger balances that has a fund group code or subfund group code that is
127 * in the specifed group codes. If fundGroupDenotesCGIndictor is ture, only examine the fund group code associated with the
128 * ledger balances; otherwise, the sub fund group code.
129 *
130 * @param ledgerBalances the given ledger balances
131 * @return null if one of the group codes associated with the ledger balances is in the specified codes; otherwise, a message
132 * message
133 */
134 public static Message hasGrantAccount(Collection<LaborLedgerBalance> ledgerBalances) {
135 for (LaborLedgerBalance balance : ledgerBalances) {
136 if (balance.getAccount().isForContractsAndGrants()) {
137 return null;
138 }
139 }
140
141 return MessageBuilder.buildMessage(EffortKeyConstants.ERROR_NOT_PAID_BY_GRANT_ACCOUNT, Message.TYPE_FATAL);
142 }
143
144 /**
145 * determine whether there is at least one account of the given ledger balances that is funded by a federal grant. The award
146 * associated with the account must be one of the given federal agency types or have an enabled federal pass through flag.
147 *
148 * @param the given labor ledger balances
149 * @param federalAgencyTypeCodes the given federal agency type codes
150 * @return null if there is at least one account with federal funding; otherwise, a message
151 */
152 public static Message hasFederalFunds(Collection<LaborLedgerBalance> ledgerBalances, List<String> federalAgencyTypeCodes) {
153 for (LaborLedgerBalance balance : ledgerBalances) {
154 Account account = balance.getAccount();
155 if (SpringContext.getBean(ContractsAndGrantsModuleService.class).isAwardedByFederalAgency(account.getChartOfAccountsCode(), account.getAccountNumber(), federalAgencyTypeCodes)) {
156 return null;
157 }
158 }
159 return MessageBuilder.buildMessage(EffortKeyConstants.ERROR_NOT_PAID_BY_FEDERAL_FUNDS, Message.TYPE_FATAL);
160 }
161
162 /**
163 * determine if the given ledger balances have the accounts that belong to multiple organizations
164 *
165 * @param ledgerBalance the given ledger balance
166 * @return null if the given ledger balances have the accounts that belong to a single organization; otherwise, a message
167 */
168 public static Message isFromSingleOrganization(Collection<LaborLedgerBalance> ledgerBalances) {
169 Organization tempOrganization = null;
170
171 boolean isFirstTime = true;
172 for (LaborLedgerBalance balance : ledgerBalances) {
173 Organization organization = balance.getAccount().getOrganization();
174
175 if (isFirstTime) {
176 tempOrganization = organization;
177 isFirstTime = false;
178 }
179
180 if (!organization.equals(tempOrganization)) {
181 return MessageBuilder.buildMessage(EffortKeyConstants.ERROR_MULTIPLE_ORGANIZATIONS_FOUND, Message.TYPE_FATAL);
182 }
183 }
184 return null;
185 }
186
187 /**
188 * get the sub fund group associated with the given ledger balance
189 *
190 * @param ledgerBalance the given ledger balance
191 * @return the sub fund group associated with the given ledger balance
192 */
193 public static SubFundGroup getSubFundGroup(LaborLedgerBalance ledgerBalance) {
194 SubFundGroup subFundGroup = null;
195 try {
196 subFundGroup = ledgerBalance.getAccount().getSubFundGroup();
197 }
198 catch (NullPointerException npe) {
199 return null;
200 }
201 return subFundGroup;
202 }
203 }