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.fp.document.validation.impl; 017 018 import static org.kuali.kfs.sys.KFSConstants.AMOUNT_PROPERTY_NAME; 019 import static org.kuali.kfs.sys.KFSConstants.BALANCE_TYPE_BASE_BUDGET; 020 import static org.kuali.kfs.sys.KFSConstants.BALANCE_TYPE_CURRENT_BUDGET; 021 import static org.kuali.kfs.sys.KFSConstants.BALANCE_TYPE_MONTHLY_BUDGET; 022 import static org.kuali.kfs.sys.KFSConstants.CREDIT_AMOUNT_PROPERTY_NAME; 023 import static org.kuali.kfs.sys.KFSConstants.DEBIT_AMOUNT_PROPERTY_NAME; 024 import static org.kuali.kfs.sys.KFSConstants.GL_DEBIT_CODE; 025 import static org.kuali.kfs.sys.KFSConstants.JOURNAL_LINE_HELPER_PROPERTY_NAME; 026 import static org.kuali.kfs.sys.KFSConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME; 027 import static org.kuali.kfs.sys.KFSConstants.SQUARE_BRACKET_LEFT; 028 import static org.kuali.kfs.sys.KFSConstants.SQUARE_BRACKET_RIGHT; 029 import static org.kuali.kfs.sys.KFSConstants.VOUCHER_LINE_HELPER_CREDIT_PROPERTY_NAME; 030 import static org.kuali.kfs.sys.KFSConstants.VOUCHER_LINE_HELPER_DEBIT_PROPERTY_NAME; 031 import static org.kuali.kfs.sys.KFSKeyConstants.ERROR_ZERO_AMOUNT; 032 import static org.kuali.kfs.sys.KFSKeyConstants.ERROR_ZERO_OR_NEGATIVE_AMOUNT; 033 import static org.kuali.kfs.sys.KFSKeyConstants.JournalVoucher.ERROR_NEGATIVE_NON_BUDGET_AMOUNTS; 034 import static org.kuali.kfs.sys.KFSPropertyConstants.BALANCE_TYPE; 035 036 import org.apache.commons.lang.StringUtils; 037 import org.kuali.kfs.fp.document.JournalVoucherDocument; 038 import org.kuali.kfs.sys.businessobject.AccountingLine; 039 import org.kuali.kfs.sys.document.validation.GenericValidation; 040 import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent; 041 import org.kuali.rice.kns.util.GlobalVariables; 042 import org.kuali.rice.kns.util.KualiDecimal; 043 044 /** 045 * The Journal Voucher's version of the accounting line amount validation 046 */ 047 public class JournalVoucherAccountingLineAmountValidation extends GenericValidation { 048 private JournalVoucherDocument journalVoucherForValidation; 049 private AccountingLine accountingLineForValidation; 050 051 /** 052 * Accounting lines for Journal Vouchers can be positive or negative, just not "$0.00". 053 * 054 * Additionally, accounting lines cannot have negative dollar amounts if the balance type of the 055 * journal voucher allows for general ledger pending entry offset generation or the balance type 056 * is not a budget type code. 057 * @see org.kuali.kfs.sys.document.validation.Validation#validate(org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent) 058 */ 059 public boolean validate(AttributedDocumentEvent event) { 060 KualiDecimal amount = getAccountingLineForValidation().getAmount(); 061 062 getJournalVoucherForValidation().refreshReferenceObject(BALANCE_TYPE); 063 064 if (getJournalVoucherForValidation().getBalanceType().isFinancialOffsetGenerationIndicator()) { 065 // check for negative or zero amounts 066 if (amount.isZero()) { // if 0 067 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(buildErrorMapKeyPathForDebitCreditAmount(true), ERROR_ZERO_OR_NEGATIVE_AMOUNT, "an accounting line"); 068 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(buildErrorMapKeyPathForDebitCreditAmount(false), ERROR_ZERO_OR_NEGATIVE_AMOUNT, "an accounting line"); 069 070 return false; 071 } 072 else if (amount.isNegative()) { // entered a negative number 073 String debitCreditCode = getAccountingLineForValidation().getDebitCreditCode(); 074 if (StringUtils.isNotBlank(debitCreditCode) && GL_DEBIT_CODE.equals(debitCreditCode)) { 075 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(buildErrorMapKeyPathForDebitCreditAmount(true), ERROR_ZERO_OR_NEGATIVE_AMOUNT, "an accounting line"); 076 } 077 else { 078 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(buildErrorMapKeyPathForDebitCreditAmount(false), ERROR_ZERO_OR_NEGATIVE_AMOUNT, "an accounting line"); 079 } 080 081 return false; 082 } 083 } 084 else { 085 // Check for zero amounts 086 if (amount.isZero()) { // amount == 0 087 GlobalVariables.getMessageMap().putError(AMOUNT_PROPERTY_NAME, ERROR_ZERO_AMOUNT, "an accounting line"); 088 return false; 089 } 090 else if (amount.isNegative()) { 091 if (!getAccountingLineForValidation().getBalanceTypeCode().equals(BALANCE_TYPE_BASE_BUDGET) && !getAccountingLineForValidation().getBalanceTypeCode().equals(BALANCE_TYPE_CURRENT_BUDGET) && !getAccountingLineForValidation().getBalanceTypeCode().equals(BALANCE_TYPE_MONTHLY_BUDGET)) { 092 GlobalVariables.getMessageMap().putError(AMOUNT_PROPERTY_NAME, ERROR_NEGATIVE_NON_BUDGET_AMOUNTS); 093 } 094 } 095 } 096 097 return true; 098 } 099 100 /** 101 * This method looks at the current full key path that exists in the ErrorMap structure to determine how to build 102 * the error map for the special journal voucher credit and debit fields since they don't conform to the standard 103 * pattern of accounting lines. 104 * 105 * The error map key path is also dependent on whether or not the accounting line containing an error is a new 106 * accounting line or an existing line that is being updated. This determination is made by searching for 107 * NEW_SOURCE_ACCT_LINE_PROPERTY_NAME in the error path of the global error map. 108 * 109 * @param isDebit Identifies whether or not the line we are returning an error path for is a debit accounting line or not. 110 * @return The full error map key path for the appropriate amount type. 111 */ 112 protected String buildErrorMapKeyPathForDebitCreditAmount(boolean isDebit) { 113 // determine if we are looking at a new line add or an update 114 boolean isNewLineAdd = GlobalVariables.getMessageMap().getErrorPath().contains(NEW_SOURCE_ACCT_LINE_PROPERTY_NAME); 115 isNewLineAdd |= GlobalVariables.getMessageMap().getErrorPath().contains(NEW_SOURCE_ACCT_LINE_PROPERTY_NAME); 116 117 if (isNewLineAdd) { 118 return isDebit ? DEBIT_AMOUNT_PROPERTY_NAME : CREDIT_AMOUNT_PROPERTY_NAME; 119 } 120 else { 121 String index = StringUtils.substringBetween(GlobalVariables.getMessageMap().getKeyPath("", true), SQUARE_BRACKET_LEFT, SQUARE_BRACKET_RIGHT); 122 String indexWithParams = SQUARE_BRACKET_LEFT + index + SQUARE_BRACKET_RIGHT; 123 return isDebit ? (JOURNAL_LINE_HELPER_PROPERTY_NAME + indexWithParams + VOUCHER_LINE_HELPER_DEBIT_PROPERTY_NAME) : (JOURNAL_LINE_HELPER_PROPERTY_NAME + indexWithParams + VOUCHER_LINE_HELPER_CREDIT_PROPERTY_NAME); 124 } 125 } 126 127 /** 128 * Gets the accountingLineForValidation attribute. 129 * @return Returns the accountingLineForValidation. 130 */ 131 public AccountingLine getAccountingLineForValidation() { 132 return accountingLineForValidation; 133 } 134 135 /** 136 * Sets the accountingLineForValidation attribute value. 137 * @param accountingLineForValidation The accountingLineForValidation to set. 138 */ 139 public void setAccountingLineForValidation(AccountingLine accountingLineForValidation) { 140 this.accountingLineForValidation = accountingLineForValidation; 141 } 142 143 /** 144 * Gets the journalVoucherForValidation attribute. 145 * @return Returns the journalVoucherForValidation. 146 */ 147 public JournalVoucherDocument getJournalVoucherForValidation() { 148 return journalVoucherForValidation; 149 } 150 151 /** 152 * Sets the journalVoucherForValidation attribute value. 153 * @param journalVoucherForValidation The journalVoucherForValidation to set. 154 */ 155 public void setJournalVoucherForValidation(JournalVoucherDocument journalVoucherForValidation) { 156 this.journalVoucherForValidation = journalVoucherForValidation; 157 } 158 }