001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.module.gl.batch.closing.year.service.impl.helper;
017:
018: import java.util.List;
019:
020: import org.apache.commons.lang.ArrayUtils;
021: import org.kuali.core.service.KualiConfigurationService;
022: import org.kuali.kfs.KFSConstants;
023: import org.kuali.kfs.context.SpringContext;
024: import org.kuali.module.chart.bo.A21SubAccount;
025: import org.kuali.module.chart.bo.PriorYearAccount;
026: import org.kuali.module.chart.bo.SubFundGroup;
027: import org.kuali.module.chart.service.A21SubAccountService;
028: import org.kuali.module.chart.service.ObjectTypeService;
029: import org.kuali.module.chart.service.PriorYearAccountService;
030: import org.kuali.module.chart.service.SubFundGroupService;
031: import org.kuali.module.gl.bo.Encumbrance;
032: import org.kuali.module.gl.bo.OriginEntryFull;
033: import org.kuali.module.gl.util.FatalErrorException;
034: import org.kuali.module.gl.util.ObjectHelper;
035:
036: /**
037: * A helper class which contains the more complicated logic involved in the year end encumbrance closing process. This logic is
038: * likely going to need to be modular which is why it's in its own class.
039: */
040: public class EncumbranceClosingRuleHelper {
041:
042: static private org.apache.log4j.Logger LOG = org.apache.log4j.Logger
043: .getLogger(EncumbranceClosingRuleHelper.class);
044:
045: private A21SubAccountService a21SubAccountService;
046: private PriorYearAccountService priorYearAccountService;
047: private SubFundGroupService subFundGroupService;
048: private KualiConfigurationService kualiConfigurationService;
049:
050: /**
051: * Field accessor for A21SubAccountService.
052: *
053: * @param a21SubAccountService
054: */
055: public void setA21SubAccountService(
056: A21SubAccountService a21SubAccountService) {
057: this .a21SubAccountService = a21SubAccountService;
058: }
059:
060: /**
061: * Field accessor for PriorYearAccountService.
062: *
063: * @param priorYearAccountService
064: */
065: public void setPriorYearAccountService(
066: PriorYearAccountService priorYearAccountService) {
067: this .priorYearAccountService = priorYearAccountService;
068: }
069:
070: /**
071: * Field accessor for SubFundGroupService.
072: *
073: * @param subFundGroupService
074: */
075: public void setSubFundGroupService(
076: SubFundGroupService subFundGroupService) {
077: this .subFundGroupService = subFundGroupService;
078: }
079:
080: /**
081: * Determine whether or not an encumbrance should be carried forward from one fiscal year to the next.
082: *
083: * @param encumbrance the encumbrance to qualify
084: * @return true if the encumbrance should be rolled forward from the closing fiscal year to the opening fiscal year.
085: */
086: public boolean anEntryShouldBeCreatedForThisEncumbrance(
087: Encumbrance encumbrance) {
088:
089: // null guard
090: if (null == encumbrance) {
091: return false;
092: }
093:
094: if (encumbrance.getAccountLineEncumbranceAmount().equals(
095: encumbrance.getAccountLineEncumbranceClosedAmount())) {
096: return false;
097: }
098:
099: if (ObjectHelper.isOneOf(encumbrance.getBalanceTypeCode(),
100: new String[] {
101: KFSConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE,
102: KFSConstants.BALANCE_TYPE_INTERNAL_ENCUMBRANCE,
103: KFSConstants.BALANCE_TYPE_PRE_ENCUMBRANCE })) {
104: // internal encumbrances are forwarded, unless they are labor distribution
105: if (KFSConstants.BALANCE_TYPE_INTERNAL_ENCUMBRANCE
106: .equals(encumbrance.getBalanceTypeCode())) {
107: if (KFSConstants.LABOR_DISTRIBUTION_ORIGIN_CODE
108: .equals(encumbrance.getOriginCode())) {
109: return false;
110: } else {
111: return true;
112: }
113: } else if (KFSConstants.BALANCE_TYPE_PRE_ENCUMBRANCE
114: .equals(encumbrance.getBalanceTypeCode())) {
115: // pre-encumbrances are forwarded, but only if they're related to contracts and grants accounts
116: PriorYearAccount priorYearAccount = priorYearAccountService
117: .getByPrimaryKey(encumbrance
118: .getChartOfAccountsCode(), encumbrance
119: .getAccountNumber());
120: // the account on the encumbrance must be valid
121: if (null == priorYearAccount) {
122: LOG.info("No prior year account for chart \""
123: + encumbrance.getChartOfAccountsCode()
124: + "\" and account \""
125: + encumbrance.getAccountNumber() + "\"");
126: return false;
127: }
128: // the sub fund group must exist for the prior year account and the
129: // encumbrance must not be closed.
130: if (priorYearAccount.isForContractsAndGrants()) {
131: return true;
132: } else {
133: return false;
134: }
135: } else {
136: // we're still here? because we're an external encumbrance, and we always get forwarded
137: return true;
138: }
139: }
140:
141: // we're still here? because we're not of a valid encumbrance balance type; we don't get forwarded
142: return false;
143:
144: }
145:
146: /**
147: * Determine whether or not the encumbrance has been fully relieved.
148: *
149: * @param encumbrance the encumbrance to qualify
150: * @return true if the amount closed on the encumbrance is NOT equal to the amount of the encumbrance itself, e.g. if the
151: * encumbrance has not yet been paid off.
152: */
153: private boolean isEncumbranceClosed(Encumbrance encumbrance) {
154: if (encumbrance.getAccountLineEncumbranceAmount().doubleValue() == encumbrance
155: .getAccountLineEncumbranceClosedAmount().doubleValue()) {
156: return false;
157: }
158: return true;
159: }
160:
161: /**
162: * Do some validation and make sure that the encumbrance A21SubAccount is a cost share sub-account.
163: *
164: * @param entry not used in this implementation
165: * @param offset not used in this implementation
166: * @param encumbrance the encumbrance whose A21SubAccount must be qualified
167: * @param objectTypeCode the object type code of the generated entries
168: * @return true if the encumbrance is eligible for cost share.
169: * @throws FatalErrorException thrown if a given A21SubAccount, SubFundGroup, or PriorYearAccount record is not found in the database
170: */
171: public boolean isEncumbranceEligibleForCostShare(
172: OriginEntryFull entry, OriginEntryFull offset,
173: Encumbrance encumbrance, String objectTypeCode)
174: throws FatalErrorException {
175: PriorYearAccount priorYearAccount = priorYearAccountService
176: .getByPrimaryKey(encumbrance.getChartOfAccountsCode(),
177: encumbrance.getAccountNumber());
178:
179: // the sub fund group for the prior year account must exist.
180: String subFundGroupCode = null;
181: if (null != priorYearAccount) {
182:
183: subFundGroupCode = priorYearAccount.getSubFundGroupCode();
184:
185: } else {
186:
187: // this message was carried over from the cobol.
188: throw new FatalErrorException(
189: "ERROR ACCESSING PRIOR YR ACCT TABLE FOR "
190: + encumbrance.getAccountNumber());
191:
192: }
193:
194: SubFundGroup subFundGroup = subFundGroupService
195: .getByPrimaryId(subFundGroupCode);
196:
197: if (null != subFundGroup) {
198:
199: if (!priorYearAccount.isForContractsAndGrants()) {
200:
201: return false;
202:
203: }
204:
205: } else {
206:
207: throw new FatalErrorException(
208: "ERROR ACCESSING SUB FUND GROUP TABLE FOR "
209: + subFundGroupCode);
210:
211: }
212:
213: // I think this is redundant to the statement a few lines above here.
214: // In any case, the sub fund group must not be contracts and grants.
215: if (!priorYearAccount.isForContractsAndGrants()) {
216:
217: return false;
218:
219: }
220:
221: ObjectTypeService objectTypeService = (ObjectTypeService) SpringContext
222: .getBean(ObjectTypeService.class);
223: List<String> expenseObjectCodeTypes = objectTypeService
224: .getCurrentYearExpenseObjectTypes();
225:
226: String[] encumbranceBalanceTypeCodes = new String[] {
227: KFSConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE,
228: KFSConstants.BALANCE_TYPE_INTERNAL_ENCUMBRANCE,
229: KFSConstants.BALANCE_TYPE_PRE_ENCUMBRANCE };
230:
231: // the object type code must be an expense and the encumbrance balance type code must correspond to an internal, external or
232: // pre-encumbrance
233: if (!expenseObjectCodeTypes.contains(objectTypeCode)
234: || !ArrayUtils.contains(encumbranceBalanceTypeCodes,
235: encumbrance.getBalanceTypeCode())) {
236:
237: return false;
238:
239: } else if (!encumbrance.getSubAccountNumber().equals(
240: KFSConstants.getDashSubAccountNumber())) {
241:
242: A21SubAccount a21SubAccount = a21SubAccountService
243: .getByPrimaryKey(encumbrance
244: .getChartOfAccountsCode(), encumbrance
245: .getAccountNumber(), encumbrance
246: .getSubAccountNumber());
247:
248: if (null == a21SubAccount) {
249:
250: // Error message carried over from cobol. not very well descriptive.
251: // Just indicates that the a21 sub account doesn't exist.
252: throw new FatalErrorException(
253: "ERROR ACCESSING A21 SUB ACCOUNT TABLE FOR ENCUMBRANCE "
254: + encumbrance.getChartOfAccountsCode()
255: + "-" + encumbrance.getAccountNumber()
256: + " "
257: + encumbrance.getSubAccountNumber());
258:
259: }
260:
261: // everything is valid, return true if the a21 sub account is a cost share sub-account
262: return KFSConstants.COST_SHARE.equals(a21SubAccount
263: .getSubAccountTypeCode());
264:
265: } else {
266: return false;
267: }
268:
269: }
270:
271: public void setKualiConfigurationService(
272: KualiConfigurationService kualiConfigurationService) {
273: this.kualiConfigurationService = kualiConfigurationService;
274: }
275:
276: }
|