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 }