View Javadoc
1   /*
2    * Copyright 2008 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.fp.document.validation.impl;
17  
18  import static org.kuali.ole.sys.OLEConstants.AMOUNT_PROPERTY_NAME;
19  import static org.kuali.ole.sys.OLEConstants.BALANCE_TYPE_BASE_BUDGET;
20  import static org.kuali.ole.sys.OLEConstants.BALANCE_TYPE_CURRENT_BUDGET;
21  import static org.kuali.ole.sys.OLEConstants.BALANCE_TYPE_MONTHLY_BUDGET;
22  import static org.kuali.ole.sys.OLEConstants.CREDIT_AMOUNT_PROPERTY_NAME;
23  import static org.kuali.ole.sys.OLEConstants.DEBIT_AMOUNT_PROPERTY_NAME;
24  import static org.kuali.ole.sys.OLEConstants.GL_DEBIT_CODE;
25  import static org.kuali.ole.sys.OLEConstants.JOURNAL_LINE_HELPER_PROPERTY_NAME;
26  import static org.kuali.ole.sys.OLEConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME;
27  import static org.kuali.ole.sys.OLEConstants.SQUARE_BRACKET_LEFT;
28  import static org.kuali.ole.sys.OLEConstants.SQUARE_BRACKET_RIGHT;
29  import static org.kuali.ole.sys.OLEConstants.VOUCHER_LINE_HELPER_CREDIT_PROPERTY_NAME;
30  import static org.kuali.ole.sys.OLEConstants.VOUCHER_LINE_HELPER_DEBIT_PROPERTY_NAME;
31  import static org.kuali.ole.sys.OLEKeyConstants.ERROR_ZERO_AMOUNT;
32  import static org.kuali.ole.sys.OLEKeyConstants.ERROR_ZERO_OR_NEGATIVE_AMOUNT;
33  import static org.kuali.ole.sys.OLEKeyConstants.JournalVoucher.ERROR_NEGATIVE_NON_BUDGET_AMOUNTS;
34  import static org.kuali.ole.sys.OLEPropertyConstants.BALANCE_TYPE;
35  
36  import org.apache.commons.lang.StringUtils;
37  import org.kuali.ole.fp.document.JournalVoucherDocument;
38  import org.kuali.ole.sys.businessobject.AccountingLine;
39  import org.kuali.ole.sys.document.validation.GenericValidation;
40  import org.kuali.ole.sys.document.validation.event.AttributedDocumentEvent;
41  import org.kuali.rice.core.api.util.type.KualiDecimal;
42  import org.kuali.rice.krad.util.GlobalVariables;
43  
44  /**
45   * The Journal Voucher's version of the accounting line amount validation
46   */
47  public class JournalVoucherAccountingLineAmountValidation extends GenericValidation {
48      private JournalVoucherDocument journalVoucherForValidation;
49      private AccountingLine accountingLineForValidation;
50  
51      /**
52       * Accounting lines for Journal Vouchers can be positive or negative, just not "$0.00".  
53       * 
54       * Additionally, accounting lines cannot have negative dollar amounts if the balance type of the 
55       * journal voucher allows for general ledger pending entry offset generation or the balance type 
56       * is not a budget type code.
57       * @see org.kuali.ole.sys.document.validation.Validation#validate(org.kuali.ole.sys.document.validation.event.AttributedDocumentEvent)
58       */
59      public boolean validate(AttributedDocumentEvent event) {
60          KualiDecimal amount = getAccountingLineForValidation().getAmount();
61  
62          getJournalVoucherForValidation().refreshReferenceObject(BALANCE_TYPE);
63  
64          if (getJournalVoucherForValidation().getBalanceType().isFinancialOffsetGenerationIndicator()) {
65              // check for negative or zero amounts
66              if (amount.isZero()) { // if 0
67                  GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(buildMessageMapKeyPathForDebitCreditAmount(true), ERROR_ZERO_OR_NEGATIVE_AMOUNT, "an accounting line");
68                  GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(buildMessageMapKeyPathForDebitCreditAmount(false), ERROR_ZERO_OR_NEGATIVE_AMOUNT, "an accounting line");
69  
70                  return false;
71              }
72              else if (amount.isNegative()) { // entered a negative number
73                  String debitCreditCode = getAccountingLineForValidation().getDebitCreditCode();
74                  if (StringUtils.isNotBlank(debitCreditCode) && GL_DEBIT_CODE.equals(debitCreditCode)) {
75                      GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(buildMessageMapKeyPathForDebitCreditAmount(true), ERROR_ZERO_OR_NEGATIVE_AMOUNT, "an accounting line");
76                  }
77                  else {
78                      GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(buildMessageMapKeyPathForDebitCreditAmount(false), ERROR_ZERO_OR_NEGATIVE_AMOUNT, "an accounting line");
79                  }
80  
81                  return false;
82              }
83          }
84          else {
85              // Check for zero amounts
86              if (amount.isZero()) { // amount == 0
87                  GlobalVariables.getMessageMap().putError(AMOUNT_PROPERTY_NAME, ERROR_ZERO_AMOUNT, "an accounting line");
88                  return false;
89              }
90              else if (amount.isNegative()) {
91                  if (!getAccountingLineForValidation().getBalanceTypeCode().equals(BALANCE_TYPE_BASE_BUDGET) && !getAccountingLineForValidation().getBalanceTypeCode().equals(BALANCE_TYPE_CURRENT_BUDGET) && !getAccountingLineForValidation().getBalanceTypeCode().equals(BALANCE_TYPE_MONTHLY_BUDGET)) {
92                      GlobalVariables.getMessageMap().putError(AMOUNT_PROPERTY_NAME, ERROR_NEGATIVE_NON_BUDGET_AMOUNTS);
93                  }
94              }
95          }
96  
97          return true;
98      }
99      
100     /**
101      * This method looks at the current full key path that exists in the MessageMap 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 buildMessageMapKeyPathForDebitCreditAmount(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 }