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 }