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.sys.document.service.impl;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.apache.log4j.Logger;
020 import org.kuali.kfs.sys.KFSConstants;
021 import org.kuali.kfs.sys.businessobject.AccountingLine;
022 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
023 import org.kuali.kfs.sys.document.AccountingDocument;
024 import org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource;
025 import org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService;
026 import org.kuali.kfs.sys.document.service.DebitDeterminerService;
027 import org.kuali.kfs.sys.service.OptionsService;
028 import org.kuali.rice.kns.util.KualiDecimal;
029
030 /**
031 * Default implementation of the DebitDeterminerService.
032 */
033 public class DebitDeterminerServiceImpl implements DebitDeterminerService {
034 private static Logger LOG = Logger.getLogger(DebitDeterminerServiceImpl.class);
035 protected static final String isDebitCalculationIllegalStateExceptionMessage = "an invalid debit/credit check state was detected";
036 protected static final String isErrorCorrectionIllegalStateExceptionMessage = "invalid (error correction) document not allowed";
037 protected static final String isInvalidLineTypeIllegalArgumentExceptionMessage = "invalid accounting line type";
038
039 private AccountingDocumentRuleHelperService accountingDocumentRuleUtil;
040 private OptionsService optionsService;
041
042 /**
043 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#disallowErrorCorrectionDocumentCheck(org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource)
044 */
045 public void disallowErrorCorrectionDocumentCheck(GeneralLedgerPendingEntrySource poster) {
046 LOG.debug("disallowErrorCorrectionDocumentCheck(AccountingDocumentRuleBase, AccountingDocument) - start");
047
048 if (isErrorCorrection(poster)) {
049 throw new IllegalStateException(isErrorCorrectionIllegalStateExceptionMessage);
050 }
051
052 LOG.debug("disallowErrorCorrectionDocumentCheck(AccountingDocumentRuleBase, AccountingDocument) - end");
053 }
054
055 /**
056 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isAsset(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
057 */
058 public boolean isAsset(GeneralLedgerPendingEntrySourceDetail postable) {
059 LOG.debug("isAsset(AccountingLine) - start");
060
061 boolean returnboolean = isAssetTypeCode(accountingDocumentRuleUtil.getObjectCodeTypeCodeWithoutSideEffects(postable));
062 LOG.debug("isAsset(AccountingLine) - end");
063 return returnboolean;
064 }
065
066 /**
067 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isAssetTypeCode(java.lang.String)
068 */
069 public boolean isAssetTypeCode(String objectTypeCode) {
070 LOG.debug("isAssetTypeCode(String) - start");
071
072 boolean returnboolean = optionsService.getCurrentYearOptions().getFinancialObjectTypeAssetsCd().equals(objectTypeCode);
073 LOG.debug("isAssetTypeCode(String) - end");
074 return returnboolean;
075 }
076
077 /**
078 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isDebitCode(java.lang.String)
079 */
080 public boolean isDebitCode(String debitCreditCode) {
081 LOG.debug("isDebitCode(String) - start");
082
083 boolean returnboolean = StringUtils.equals(KFSConstants.GL_DEBIT_CODE, debitCreditCode);
084 LOG.debug("isDebitCode(String) - end");
085 return returnboolean;
086 }
087
088 /**
089 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isDebitConsideringNothingPositiveOnly(org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource, org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
090 */
091 public boolean isDebitConsideringNothingPositiveOnly(GeneralLedgerPendingEntrySource poster, GeneralLedgerPendingEntrySourceDetail postable) {
092 LOG.debug("isDebitConsideringNothingPositiveOnly(AccountingDocumentRuleBase, AccountingDocument, AccountingLine) - start");
093
094 boolean isDebit = false;
095 KualiDecimal amount = postable.getAmount();
096 boolean isPositiveAmount = amount.isPositive();
097 // isDebit if income/liability/expense/asset and line amount is positive
098 if (isPositiveAmount && (isIncomeOrLiability(postable) || isExpenseOrAsset(postable))) {
099 isDebit = true;
100 }
101 else {
102 // non error correction
103 if (!isErrorCorrection(poster)) {
104 throw new IllegalStateException(isDebitCalculationIllegalStateExceptionMessage);
105
106 }
107 // error correction
108 else {
109 isDebit = false;
110 }
111 }
112
113 LOG.debug("isDebitConsideringNothingPositiveOnly(AccountingDocumentRuleBase, AccountingDocument, AccountingLine) - end");
114 return isDebit;
115 }
116
117 /**
118 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isDebitConsideringSection(org.kuali.kfs.sys.document.AccountingDocument, org.kuali.kfs.sys.businessobject.AccountingLine)
119 */
120 public boolean isDebitConsideringSection(AccountingDocument accountingDocument, AccountingLine accountingLine) {
121 LOG.debug("isDebitConsideringSection(AccountingDocumentRuleBase, AccountingDocument, AccountingLine) - start");
122
123 KualiDecimal amount = accountingLine.getAmount();
124 // zero amounts are not allowed
125 if (amount.isZero()) {
126 throw new IllegalStateException(isDebitCalculationIllegalStateExceptionMessage);
127 }
128 boolean isDebit = false;
129 boolean isPositiveAmount = accountingLine.getAmount().isPositive();
130 // source line
131 if (accountingLine.isSourceAccountingLine()) {
132 // income/liability/expense/asset
133 if (isIncomeOrLiability(accountingLine) || isExpenseOrAsset(accountingLine)) {
134 isDebit = !isPositiveAmount;
135 }
136 else {
137 throw new IllegalStateException(isDebitCalculationIllegalStateExceptionMessage);
138 }
139 }
140 // target line
141 else {
142 if (accountingLine.isTargetAccountingLine()) {
143 if (isIncomeOrLiability(accountingLine) || isExpenseOrAsset(accountingLine)) {
144 isDebit = isPositiveAmount;
145 }
146 else {
147 throw new IllegalStateException(isDebitCalculationIllegalStateExceptionMessage);
148 }
149 }
150 else {
151 throw new IllegalArgumentException(isInvalidLineTypeIllegalArgumentExceptionMessage);
152 }
153 }
154
155 LOG.debug("isDebitConsideringSection(AccountingDocumentRuleBase, AccountingDocument, AccountingLine) - end");
156 return isDebit;
157 }
158
159 /**
160 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isDebitConsideringSectionAndTypePositiveOnly(org.kuali.kfs.sys.document.AccountingDocument, org.kuali.kfs.sys.businessobject.AccountingLine)
161 */
162 public boolean isDebitConsideringSectionAndTypePositiveOnly(AccountingDocument accountingDocument, AccountingLine accountingLine) {
163 LOG.debug("isDebitConsideringSectionAndTypePositiveOnly(AccountingDocumentRuleBase, AccountingDocument, AccountingLine) - start");
164
165 boolean isDebit = false;
166 KualiDecimal amount = accountingLine.getAmount();
167 boolean isPositiveAmount = amount.isPositive();
168 // non error correction - only allow amount >0
169 if (!isPositiveAmount && !isErrorCorrection(accountingDocument)) {
170 throw new IllegalStateException(isDebitCalculationIllegalStateExceptionMessage);
171 }
172 // source line
173 if (accountingLine.isSourceAccountingLine()) {
174 // could write below block in one line using == as XNOR operator, but that's confusing to read:
175 // isDebit = (rule.isIncomeOrLiability(accountingLine) == isPositiveAmount);
176 if (isPositiveAmount) {
177 isDebit = isIncomeOrLiability(accountingLine);
178 }
179 else {
180 isDebit = isExpenseOrAsset(accountingLine);
181 }
182 }
183 // target line
184 else {
185 if (accountingLine.isTargetAccountingLine()) {
186 if (isPositiveAmount) {
187 isDebit = isExpenseOrAsset(accountingLine);
188 }
189 else {
190 isDebit = isIncomeOrLiability(accountingLine);
191 }
192 }
193 else {
194 throw new IllegalArgumentException(isInvalidLineTypeIllegalArgumentExceptionMessage);
195 }
196 }
197
198 LOG.debug("isDebitConsideringSectionAndTypePositiveOnly(AccountingDocumentRuleBase, AccountingDocument, AccountingLine) - end");
199 return isDebit;
200 }
201
202 /**
203 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isDebitConsideringType(org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource, org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
204 */
205 public boolean isDebitConsideringType(GeneralLedgerPendingEntrySource poster, GeneralLedgerPendingEntrySourceDetail postable) {
206 LOG.debug("isDebitConsideringType(AccountingDocumentRuleBase, AccountingDocument, AccountingLine) - start");
207
208 KualiDecimal amount = postable.getAmount();
209 // zero amounts are not allowed
210 if (amount.isZero()) {
211 throw new IllegalStateException(isDebitCalculationIllegalStateExceptionMessage);
212 }
213 boolean isDebit = false;
214 boolean isPositiveAmount = postable.getAmount().isPositive();
215
216 // income/liability
217 if (isIncomeOrLiability(postable)) {
218 isDebit = !isPositiveAmount;
219 }
220 // expense/asset
221 else {
222 if (isExpenseOrAsset(postable)) {
223 isDebit = isPositiveAmount;
224 }
225 else {
226 throw new IllegalStateException(isDebitCalculationIllegalStateExceptionMessage);
227 }
228 }
229
230 LOG.debug("isDebitConsideringType(AccountingDocumentRuleBase, AccountingDocument, AccountingLine) - end");
231 return isDebit;
232 }
233
234 /**
235 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isErrorCorrection(org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource)
236 */
237 public boolean isErrorCorrection(GeneralLedgerPendingEntrySource poster) {
238 return StringUtils.isNotBlank(poster.getDocumentHeader().getFinancialDocumentInErrorNumber());
239 }
240
241 /**
242 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isExpense(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
243 */
244 public boolean isExpense(GeneralLedgerPendingEntrySourceDetail postable) {
245 LOG.debug("isExpense(AccountingLine) - start");
246
247 boolean returnboolean = accountingDocumentRuleUtil.isExpense(postable);
248 LOG.debug("isExpense(AccountingLine) - end");
249 return returnboolean;
250 }
251
252 /**
253 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isExpenseOrAsset(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
254 */
255 public boolean isExpenseOrAsset(GeneralLedgerPendingEntrySourceDetail postable) {
256 LOG.debug("isExpenseOrAsset(AccountingLine) - start");
257
258 boolean returnboolean = isAsset(postable) || isExpense(postable);
259 LOG.debug("isExpenseOrAsset(AccountingLine) - end");
260 return returnboolean;
261 }
262
263 /**
264 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isIncome(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
265 */
266 public boolean isIncome(GeneralLedgerPendingEntrySourceDetail postable) {
267 LOG.debug("isIncome(AccountingLine) - start");
268
269 boolean returnboolean = accountingDocumentRuleUtil.isIncome(postable);
270 LOG.debug("isIncome(AccountingLine) - end");
271 return returnboolean;
272 }
273
274 /**
275 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isIncomeOrLiability(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
276 */
277 public boolean isIncomeOrLiability(GeneralLedgerPendingEntrySourceDetail postable) {
278 LOG.debug("isIncomeOrLiability(AccountingLine) - start");
279
280 boolean returnboolean = isLiability(postable) || isIncome(postable);
281 LOG.debug("isIncomeOrLiability(AccountingLine) - end");
282 return returnboolean;
283 }
284
285 /**
286 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isLiability(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
287 */
288 public boolean isLiability(GeneralLedgerPendingEntrySourceDetail postable) {
289 LOG.debug("isLiability(AccountingLine) - start");
290
291 boolean returnboolean = isLiabilityTypeCode(accountingDocumentRuleUtil.getObjectCodeTypeCodeWithoutSideEffects(postable));
292 LOG.debug("isLiability(AccountingLine) - end");
293 return returnboolean;
294 }
295
296 /**
297 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isLiabilityTypeCode(java.lang.String)
298 */
299 public boolean isLiabilityTypeCode(String objectTypeCode) {
300 LOG.debug("isLiabilityTypeCode(String) - start");
301
302 boolean returnboolean = optionsService.getCurrentYearOptions().getFinObjectTypeLiabilitiesCode().equals(objectTypeCode);
303 LOG.debug("isLiabilityTypeCode(String) - end");
304 return returnboolean;
305 }
306
307 /**
308 * @see org.kuali.kfs.sys.document.service.DebitDeterminerService#isRevenue(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
309 */
310 public boolean isRevenue(GeneralLedgerPendingEntrySourceDetail postable) {
311 LOG.debug("isRevenue(AccountingLine) - start");
312
313 boolean returnboolean = !isExpense(postable);
314 LOG.debug("isRevenue(AccountingLine) - end");
315 return returnboolean;
316 }
317
318 /**
319 * Sets the accountingDocumentRuleUtils attribute value.
320 * @param accountingDocumentRuleUtils The accountingDocumentRuleUtils to set.
321 */
322 public void setAccountingDocumentRuleUtils(AccountingDocumentRuleHelperService accountingDocumentRuleUtil) {
323 this.accountingDocumentRuleUtil = accountingDocumentRuleUtil;
324 }
325
326 /**
327 * Sets the optionsService attribute value.
328 * @param optionsService The optionsService to set.
329 */
330 public void setOptionsService(OptionsService optionsService) {
331 this.optionsService = optionsService;
332 }
333
334 /**
335 * Gets the isDebitCalculationIllegalStateExceptionMessage attribute.
336 * @return Returns the isDebitCalculationIllegalStateExceptionMessage.
337 */
338 public String getDebitCalculationIllegalStateExceptionMessage() {
339 return isDebitCalculationIllegalStateExceptionMessage;
340 }
341
342 /**
343 * Gets the isErrorCorrectionIllegalStateExceptionMessage attribute.
344 * @return Returns the isErrorCorrectionIllegalStateExceptionMessage.
345 */
346 public String getErrorCorrectionIllegalStateExceptionMessage() {
347 return isErrorCorrectionIllegalStateExceptionMessage;
348 }
349
350 /**
351 * Gets the isInvalidLineTypeIllegalArgumentExceptionMessage attribute.
352 * @return Returns the isInvalidLineTypeIllegalArgumentExceptionMessage.
353 */
354 public String getInvalidLineTypeIllegalArgumentExceptionMessage() {
355 return isInvalidLineTypeIllegalArgumentExceptionMessage;
356 }
357
358
359 }