View Javadoc
1   /*
2    * Copyright 2008-2009 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.module.purap.document.validation.impl;
17  
18  import org.apache.commons.beanutils.PropertyUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.ole.module.purap.PurapConstants.PaymentRequestStatuses;
21  import org.kuali.ole.module.purap.businessobject.PurApAccountingLine;
22  import org.kuali.ole.module.purap.businessobject.PurApItem;
23  import org.kuali.ole.module.purap.document.PaymentRequestDocument;
24  import org.kuali.ole.sys.businessobject.AccountingLine;
25  import org.kuali.ole.sys.context.SpringContext;
26  import org.kuali.ole.sys.document.AccountingDocument;
27  import org.kuali.ole.sys.document.OLEAccountingDocument;
28  import org.kuali.ole.sys.document.validation.BranchingValidation;
29  import org.kuali.ole.sys.document.validation.event.AttributedDocumentEvent;
30  import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
31  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
32  import org.kuali.rice.krad.bo.PersistableBusinessObject;
33  import org.kuali.rice.krad.util.ObjectUtils;
34  
35  import java.lang.reflect.InvocationTargetException;
36  import java.util.LinkedList;
37  import java.util.Queue;
38  
39  /**
40   * A validation which uses parameters to determine if a value on an accounting line is valid.
41   */
42  public class PurchasingAccountsPayableObjectCodeOverrideBranchingValidation extends BranchingValidation {
43      protected String propertyPath;
44      protected String parameterToCheckAgainst;
45      protected ParameterService parameterService;
46      protected String responsibleProperty;
47      protected OLEAccountingDocument accountingDocumentForValidation;
48      protected AccountingLine accountingLineForValidation;
49  
50      protected final static String OBJECT_CODE_OVERRIDEN = "ObjectCodeOverriden";
51      protected final static String OBJECT_CODE_NOT_OVERRIDEN = "ObjectCodeNotOverriden";
52  
53      @Override
54      protected String determineBranch(AttributedDocumentEvent event) {
55          if (!StringUtils.isBlank(propertyPath)) {
56              refreshByPath(accountingLineForValidation);
57          }
58  
59          boolean isTaxApproval = false;
60          //if payment request, skip object code check when this is a tax approval, 
61          // or if this accounting line is from a Tax Charge line.
62          if (accountingDocumentForValidation instanceof PaymentRequestDocument) {
63              PaymentRequestDocument preq = (PaymentRequestDocument) accountingDocumentForValidation;
64              PurApAccountingLine purapAccountingLine = (PurApAccountingLine) accountingLineForValidation;
65              PurApItem item = purapAccountingLine.getPurapItem();
66  
67              if (StringUtils.equals(PaymentRequestStatuses.APPDOC_AWAITING_TAX_REVIEW, preq.getApplicationDocumentStatus())) {
68                  isTaxApproval = true;
69              } else if (StringUtils.equals(PaymentRequestStatuses.APPDOC_DEPARTMENT_APPROVED, preq.getApplicationDocumentStatus()) &&
70                      (ObjectUtils.isNotNull(item) && item.getItemType().getIsTaxCharge())) {
71                  isTaxApproval = true;
72              }
73          }
74  
75          if (isTaxApproval) {
76              return null;
77          } else if (isAccountingLineValueAllowed(accountingDocumentForValidation.getClass(), accountingLineForValidation, parameterToCheckAgainst, propertyPath, (responsibleProperty != null ? responsibleProperty : propertyPath))) {
78              return OBJECT_CODE_OVERRIDEN;
79          } else {
80              return OBJECT_CODE_NOT_OVERRIDEN;
81          }
82      }
83  
84      /**
85       * Checks that a value on an accounting line is valid, based on parameters, for a document of the given class
86       *
87       * @param documentClass           the class of the document to check
88       * @param accountingLine          the accounting line to check
89       * @param parameterName           the name of the parameter to check
90       * @param propertyName            the name of the property to check
91       * @param userEnteredPropertyName the value the user entered on the line
92       * @return true if this passes validation, false otherwise
93       */
94      protected boolean isAccountingLineValueAllowed(Class documentClass, AccountingLine accountingLine, String parameterName, String propertyName, String userEnteredPropertyName) {
95          boolean isAllowed = false;
96          String exceptionMessage = "Invalid property name provided to PurchasingAccountsPayableObjectCodeOverrideBranchingValidation isAccountingLineValueAllowed method: " + propertyName;
97          try {
98              String propertyValue = (String) PropertyUtils.getProperty(accountingLine, propertyName);
99              if (getParameterService().parameterExists(documentClass, parameterName)) {
100                 isAllowed = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(documentClass, parameterName, propertyValue).evaluationSucceeds();
101             }
102         } catch (IllegalAccessException e) {
103             throw new RuntimeException(exceptionMessage, e);
104         } catch (InvocationTargetException e) {
105             throw new RuntimeException(exceptionMessage, e);
106         } catch (NoSuchMethodException e) {
107             throw new RuntimeException(exceptionMessage, e);
108         }
109         return isAllowed;
110     }
111 
112     /**
113      * Refreshes a value on the accounting line, using the propertyPath to decided what to refresh
114      *
115      * @param line the accounting line to refresh a property on
116      */
117     public void refreshByPath(AccountingLine line) {
118         refreshByQueue(line, convertPathToQueue(propertyPath));
119     }
120 
121     /**
122      * Creates a Queue which represents a FIFO path of what properties to visit, based on the given property path
123      *
124      * @param path the path to convert to a Queue
125      * @return a Queue representing the path
126      */
127     protected Queue<String> convertPathToQueue(String path) {
128         Queue<String> pathQueue = new LinkedList<String>();
129         for (String property : path.split("\\.")) {
130             pathQueue.add(property);
131         }
132         return pathQueue;
133     }
134 
135     /**
136      * Recursively refreshes a property given by the queue path
137      *
138      * @param bo   the business object to refresh
139      * @param path the path, in Queue form, of properties to refresh
140      */
141     protected void refreshByQueue(PersistableBusinessObject bo, Queue<String> path) {
142         if (path.size() > 1) { // we know that the last thing on our list is a code. why refresh that?
143             String currentProperty = path.remove();
144             bo.refreshReferenceObject(currentProperty);
145             PersistableBusinessObject childBO = (PersistableBusinessObject) ObjectUtils.getPropertyValue(bo, currentProperty);
146             if (!ObjectUtils.isNull(childBO)) {
147                 refreshByQueue(childBO, path);
148             }
149         }
150     }
151 
152     /**
153      * Gets the propertyPath attribute. This is the path to the value to check, e. g. "accountNumber.subFundGroup.fundGroupCode"
154      *
155      * @return Returns the propertyPath.
156      */
157     public String getPropertyPath() {
158         return propertyPath;
159     }
160 
161     /**
162      * Sets the propertyPath attribute value. This is the path to the value to check, e. g. "accountNumber.subFundGroup.fundGroupCode"
163      *
164      * @param propertyPath The propertyPath to set.
165      */
166     public void setPropertyPath(String refreshPath) {
167         this.propertyPath = refreshPath;
168     }
169 
170     /**
171      * Gets the parameterService attribute.
172      *
173      * @return Returns the parameterService.
174      */
175     public ParameterService getParameterService() {
176         return parameterService;
177     }
178 
179     /**
180      * Sets the parameterService attribute value.
181      *
182      * @param parameterService The parameterService to set.
183      */
184     public void setParameterService(ParameterService parameterService) {
185         this.parameterService = parameterService;
186     }
187 
188     /**
189      * Gets the parameterToCheckAgainst attribute. This is the name of the parameter which has the values to validate against.
190      *
191      * @return Returns the parameterToCheckAgainst.
192      */
193     public String getParameterToCheckAgainst() {
194         return parameterToCheckAgainst;
195     }
196 
197     /**
198      * Sets the parameterToCheckAgainst attribute value.  This is the name of the parameter which has the values to validate against.
199      *
200      * @param parameterToCheckAgainst The parameterToCheckAgainst to set.
201      */
202     public void setParameterToCheckAgainst(String parameterToCheckAgainst) {
203         this.parameterToCheckAgainst = parameterToCheckAgainst;
204     }
205 
206     /**
207      * Gets the responsibleProperty attribute. This is the property on the accounting line to show the error on.
208      *
209      * @return Returns the responsibleProperty.
210      */
211     public String getResponsibleProperty() {
212         return responsibleProperty;
213     }
214 
215     /**
216      * Sets the responsibleProperty attribute value. This is the property on the accounting line to show the error on.
217      *
218      * @param responsibleProperty The responsibleProperty to set.
219      */
220     public void setResponsibleProperty(String responsibleProperty) {
221         this.responsibleProperty = responsibleProperty;
222     }
223 
224     /**
225      * Gets the accountingDocumentForValidation attribute.
226      *
227      * @return Returns the accountingDocumentForValidation.
228      */
229     public OLEAccountingDocument getAccountingDocumentForValidation() {
230         return accountingDocumentForValidation;
231     }
232 
233     /**
234      * Sets the accountingDocumentForValidation attribute value.
235      *
236      * @param accountingDocumentForValidation
237      *         The accountingDocumentForValidation to set.
238      */
239     public void setAccountingDocumentForValidation(OLEAccountingDocument accountingDocumentForValidation) {
240         this.accountingDocumentForValidation = accountingDocumentForValidation;
241     }
242 
243     /**
244      * Gets the accountingLineForValidation attribute.
245      *
246      * @return Returns the accountingLineForValidation.
247      */
248     public AccountingLine getAccountingLineForValidation() {
249         return accountingLineForValidation;
250     }
251 
252     /**
253      * Sets the accountingLineForValidation attribute value.
254      *
255      * @param accountingLineForValidation The accountingLineForValidation to set.
256      */
257     public void setAccountingLineForValidation(AccountingLine accountingLineForValidation) {
258         this.accountingLineForValidation = accountingLineForValidation;
259     }
260 
261 }