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