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.module.purap.document.validation.impl; 017 018 import java.lang.reflect.InvocationTargetException; 019 import java.util.LinkedList; 020 import java.util.Queue; 021 022 import org.apache.commons.beanutils.PropertyUtils; 023 import org.apache.commons.lang.StringUtils; 024 import org.kuali.kfs.module.purap.PurapConstants.PaymentRequestStatuses; 025 import org.kuali.kfs.module.purap.businessobject.PurApAccountingLine; 026 import org.kuali.kfs.module.purap.businessobject.PurApItem; 027 import org.kuali.kfs.module.purap.document.PaymentRequestDocument; 028 import org.kuali.kfs.sys.businessobject.AccountingLine; 029 import org.kuali.kfs.sys.document.AccountingDocument; 030 import org.kuali.kfs.sys.document.validation.BranchingValidation; 031 import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent; 032 import org.kuali.rice.kns.bo.PersistableBusinessObject; 033 import org.kuali.rice.kns.service.ParameterService; 034 import org.kuali.rice.kns.util.ObjectUtils; 035 036 /** 037 * A validation which uses parameters to determine if a value on an accounting line is valid. 038 */ 039 public class PurchasingAccountsPayableObjectCodeOverrideBranchingValidation extends BranchingValidation { 040 protected String propertyPath; 041 protected String parameterToCheckAgainst; 042 protected ParameterService parameterService; 043 protected String responsibleProperty; 044 protected AccountingDocument accountingDocumentForValidation; 045 protected AccountingLine accountingLineForValidation; 046 047 protected final static String OBJECT_CODE_OVERRIDEN = "ObjectCodeOverriden"; 048 protected final static String OBJECT_CODE_NOT_OVERRIDEN = "ObjectCodeNotOverriden"; 049 050 @Override 051 protected String determineBranch(AttributedDocumentEvent event) { 052 if (!StringUtils.isBlank(propertyPath)) { 053 refreshByPath(accountingLineForValidation); 054 } 055 056 boolean isTaxApproval = false; 057 //if payment request, skip object code check when this is a tax approval, 058 // or if this accounting line is from a Tax Charge line. 059 if (accountingDocumentForValidation instanceof PaymentRequestDocument) { 060 PaymentRequestDocument preq = (PaymentRequestDocument)accountingDocumentForValidation; 061 PurApAccountingLine purapAccountingLine = (PurApAccountingLine)accountingLineForValidation; 062 PurApItem item = purapAccountingLine.getPurapItem(); 063 064 if (StringUtils.equals(PaymentRequestStatuses.AWAITING_TAX_REVIEW, preq.getStatusCode())){ 065 isTaxApproval = true; 066 }else if(StringUtils.equals(PaymentRequestStatuses.DEPARTMENT_APPROVED, preq.getStatusCode()) && 067 (ObjectUtils.isNotNull(item) && item.getItemType().getIsTaxCharge()) ){ 068 isTaxApproval = true; 069 } 070 } 071 072 if (isTaxApproval) { 073 return null; 074 } else if (isAccountingLineValueAllowed(accountingDocumentForValidation.getClass(), accountingLineForValidation, parameterToCheckAgainst, propertyPath, (responsibleProperty != null ? responsibleProperty : propertyPath))){ 075 return OBJECT_CODE_OVERRIDEN; 076 } else { 077 return OBJECT_CODE_NOT_OVERRIDEN; 078 } 079 } 080 081 /** 082 * Checks that a value on an accounting line is valid, based on parameters, for a document of the given class 083 * @param documentClass the class of the document to check 084 * @param accountingLine the accounting line to check 085 * @param parameterName the name of the parameter to check 086 * @param propertyName the name of the property to check 087 * @param userEnteredPropertyName the value the user entered on the line 088 * @return true if this passes validation, false otherwise 089 */ 090 protected boolean isAccountingLineValueAllowed(Class documentClass, AccountingLine accountingLine, String parameterName, String propertyName, String userEnteredPropertyName) { 091 boolean isAllowed = false; 092 String exceptionMessage = "Invalid property name provided to PurchasingAccountsPayableObjectCodeOverrideBranchingValidation isAccountingLineValueAllowed method: " + propertyName; 093 try { 094 String propertyValue = (String) PropertyUtils.getProperty(accountingLine, propertyName); 095 if (getParameterService().parameterExists(documentClass, parameterName)) { 096 isAllowed = getParameterService().getParameterEvaluator(documentClass, parameterName, propertyValue).evaluationSucceeds(); 097 } 098 } 099 catch (IllegalAccessException e) { 100 throw new RuntimeException(exceptionMessage, e); 101 } 102 catch (InvocationTargetException e) { 103 throw new RuntimeException(exceptionMessage, e); 104 } 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 * @param line the accounting line to refresh a property on 114 */ 115 public void refreshByPath(AccountingLine line) { 116 refreshByQueue(line, convertPathToQueue(propertyPath)); 117 } 118 119 /** 120 * Creates a Queue which represents a FIFO path of what properties to visit, based on the given property path 121 * @param path the path to convert to a Queue 122 * @return a Queue representing the path 123 */ 124 protected Queue<String> convertPathToQueue(String path) { 125 Queue<String> pathQueue = new LinkedList<String>(); 126 for (String property: path.split("\\.")) { 127 pathQueue.add(property); 128 } 129 return pathQueue; 130 } 131 132 /** 133 * Recursively refreshes a property given by the queue path 134 * @param bo the business object to refresh 135 * @param path the path, in Queue form, of properties to refresh 136 */ 137 protected void refreshByQueue(PersistableBusinessObject bo, Queue<String> path) { 138 if (path.size() > 1) { // we know that the last thing on our list is a code. why refresh that? 139 String currentProperty = path.remove(); 140 bo.refreshReferenceObject(currentProperty); 141 PersistableBusinessObject childBO = (PersistableBusinessObject)ObjectUtils.getPropertyValue(bo, currentProperty); 142 if (!ObjectUtils.isNull(childBO)) { 143 refreshByQueue(childBO, path); 144 } 145 } 146 } 147 148 /** 149 * Gets the propertyPath attribute. This is the path to the value to check, e. g. "accountNumber.subFundGroup.fundGroupCode" 150 * @return Returns the propertyPath. 151 */ 152 public String getPropertyPath() { 153 return propertyPath; 154 } 155 156 /** 157 * Sets the propertyPath attribute value. This is the path to the value to check, e. g. "accountNumber.subFundGroup.fundGroupCode" 158 * @param propertyPath The propertyPath to set. 159 */ 160 public void setPropertyPath(String refreshPath) { 161 this.propertyPath = refreshPath; 162 } 163 164 /** 165 * Gets the parameterService attribute. 166 * @return Returns the parameterService. 167 */ 168 public ParameterService getParameterService() { 169 return parameterService; 170 } 171 172 /** 173 * Sets the parameterService attribute value. 174 * @param parameterService The parameterService to set. 175 */ 176 public void setParameterService(ParameterService parameterService) { 177 this.parameterService = parameterService; 178 } 179 180 /** 181 * Gets the parameterToCheckAgainst attribute. This is the name of the parameter which has the values to validate against. 182 * @return Returns the parameterToCheckAgainst. 183 */ 184 public String getParameterToCheckAgainst() { 185 return parameterToCheckAgainst; 186 } 187 188 /** 189 * Sets the parameterToCheckAgainst attribute value. This is the name of the parameter which has the values to validate against. 190 * @param parameterToCheckAgainst The parameterToCheckAgainst to set. 191 */ 192 public void setParameterToCheckAgainst(String parameterToCheckAgainst) { 193 this.parameterToCheckAgainst = parameterToCheckAgainst; 194 } 195 196 /** 197 * Gets the responsibleProperty attribute. This is the property on the accounting line to show the error on. 198 * @return Returns the responsibleProperty. 199 */ 200 public String getResponsibleProperty() { 201 return responsibleProperty; 202 } 203 204 /** 205 * Sets the responsibleProperty attribute value. This is the property on the accounting line to show the error on. 206 * @param responsibleProperty The responsibleProperty to set. 207 */ 208 public void setResponsibleProperty(String responsibleProperty) { 209 this.responsibleProperty = responsibleProperty; 210 } 211 212 /** 213 * Gets the accountingDocumentForValidation attribute. 214 * @return Returns the accountingDocumentForValidation. 215 */ 216 public AccountingDocument getAccountingDocumentForValidation() { 217 return accountingDocumentForValidation; 218 } 219 220 /** 221 * Sets the accountingDocumentForValidation attribute value. 222 * @param accountingDocumentForValidation The accountingDocumentForValidation to set. 223 */ 224 public void setAccountingDocumentForValidation(AccountingDocument accountingDocumentForValidation) { 225 this.accountingDocumentForValidation = accountingDocumentForValidation; 226 } 227 228 /** 229 * Gets the accountingLineForValidation attribute. 230 * @return Returns the accountingLineForValidation. 231 */ 232 public AccountingLine getAccountingLineForValidation() { 233 return accountingLineForValidation; 234 } 235 236 /** 237 * Sets the accountingLineForValidation attribute value. 238 * @param accountingLineForValidation The accountingLineForValidation to set. 239 */ 240 public void setAccountingLineForValidation(AccountingLine accountingLineForValidation) { 241 this.accountingLineForValidation = accountingLineForValidation; 242 } 243 244 }