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.businessobject.lookup; 017 018 import java.util.ArrayList; 019 import java.util.Collection; 020 import java.util.Collections; 021 import java.util.HashMap; 022 import java.util.List; 023 import java.util.Map; 024 025 import org.apache.commons.lang.StringUtils; 026 import org.kuali.kfs.fp.businessobject.DisbursementPayee; 027 import org.kuali.kfs.fp.document.service.DisbursementVoucherPaymentReasonService; 028 import org.kuali.kfs.sys.KFSConstants; 029 import org.kuali.kfs.sys.KFSKeyConstants; 030 import org.kuali.kfs.sys.KFSPropertyConstants; 031 import org.kuali.kfs.sys.context.SpringContext; 032 import org.kuali.kfs.vnd.VendorConstants; 033 import org.kuali.kfs.vnd.VendorPropertyConstants; 034 import org.kuali.kfs.vnd.businessobject.VendorDetail; 035 import org.kuali.rice.kim.bo.Person; 036 import org.kuali.rice.kim.service.KIMServiceLocator; 037 import org.kuali.rice.kim.util.KIMPropertyConstants; 038 import org.kuali.rice.kns.bo.BusinessObject; 039 import org.kuali.rice.kns.exception.ValidationException; 040 import org.kuali.rice.kns.lookup.CollectionIncomplete; 041 import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl; 042 import org.kuali.rice.kns.lookup.Lookupable; 043 import org.kuali.rice.kns.service.DataDictionaryService; 044 import org.kuali.rice.kns.util.BeanPropertyComparator; 045 import org.kuali.rice.kns.util.GlobalVariables; 046 import org.kuali.rice.kns.util.MessageList; 047 import org.kuali.rice.kns.web.struts.form.LookupForm; 048 import org.kuali.rice.kns.web.ui.ResultRow; 049 import org.kuali.rice.kns.datadictionary.AttributeDefinition; 050 import org.kuali.rice.kns.datadictionary.AttributeSecurity; 051 052 public class DisbursementPayeeLookupableHelperServiceImpl extends KualiLookupableHelperServiceImpl { 053 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementPayeeLookupableHelperServiceImpl.class); 054 055 private Lookupable vendorLookupable; 056 private DisbursementVoucherPaymentReasonService disbursementVoucherPaymentReasonService; 057 058 private static final int NAME_REQUIRED_FILLED_WITH_WILDCARD = 4; 059 060 /** 061 * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#performLookup(org.kuali.rice.kns.web.struts.form.LookupForm, 062 * java.util.Collection, boolean) 063 */ 064 @Override 065 public Collection performLookup(LookupForm lookupForm, Collection resultTable, boolean bounded) { 066 Map<String, String> fieldValues = lookupForm.getFieldsForLookup(); 067 String paymentReasonCode = fieldValues.get(KFSPropertyConstants.PAYMENT_REASON_CODE); 068 069 List<DisbursementPayee> displayList = (List<DisbursementPayee>) super.performLookup(lookupForm, resultTable, bounded); 070 071 this.filterReturnUrl((List<ResultRow>) resultTable, displayList, paymentReasonCode); 072 073 MessageList messageList = GlobalVariables.getMessageList(); 074 disbursementVoucherPaymentReasonService.postPaymentReasonCodeUsage(paymentReasonCode, messageList); 075 076 return displayList; 077 } 078 079 /** 080 * @see org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl#getSearchResults(java.util.Map) 081 */ 082 @Override 083 public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues) { 084 List<DisbursementPayee> searchResults = new ArrayList<DisbursementPayee>(); 085 086 if (StringUtils.isNotBlank(fieldValues.get(KFSPropertyConstants.VENDOR_NUMBER)) || StringUtils.isNotBlank(fieldValues.get(KFSPropertyConstants.VENDOR_NAME))) { 087 searchResults.addAll(this.getVendorsAsPayees(fieldValues)); 088 } 089 else if (StringUtils.isNotBlank(fieldValues.get(KIMPropertyConstants.Person.EMPLOYEE_ID))) { 090 searchResults.addAll(this.getPersonAsPayees(fieldValues)); 091 } 092 else { 093 searchResults.addAll(this.getVendorsAsPayees(fieldValues)); 094 searchResults.addAll(this.getPersonAsPayees(fieldValues)); 095 } 096 097 CollectionIncomplete results = new CollectionIncomplete(searchResults, Long.valueOf(searchResults.size())); 098 099 // sort list if default sort column given 100 List<String> defaultSortColumns = getDefaultSortColumns(); 101 if (defaultSortColumns.size() > 0) { 102 Collections.sort(results, new BeanPropertyComparator(getDefaultSortColumns(), true)); 103 } 104 105 return results; 106 } 107 108 /** 109 * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#validateSearchParameters(java.util.Map) 110 */ 111 @Override 112 public void validateSearchParameters(Map fieldValues) { 113 super.validateSearchParameters(fieldValues); 114 115 final String vendorName = (String) fieldValues.get(KFSPropertyConstants.VENDOR_NAME); 116 final String vendorNumber = (String) fieldValues.get(KFSPropertyConstants.VENDOR_NUMBER); 117 final String employeeId = (String) fieldValues.get(KIMPropertyConstants.Person.EMPLOYEE_ID); 118 final String firstName = (String)fieldValues.get(KIMPropertyConstants.Person.FIRST_NAME); 119 final String lastName = (String)fieldValues.get(KIMPropertyConstants.Person.LAST_NAME); 120 final String vendorTaxNumber = (String)fieldValues.get(KFSPropertyConstants.TAX_NUMBER); 121 final String vendorTaxNumberLabel = this.getAttributeLabel(KFSPropertyConstants.TAX_NUMBER); 122 123 final String employeeIdLabel = this.getAttributeLabel(KIMPropertyConstants.Person.EMPLOYEE_ID); 124 125 if (StringUtils.isBlank(vendorNumber) && StringUtils.isBlank(employeeId) && StringUtils.isBlank(firstName) && StringUtils.isBlank(lastName) && StringUtils.isBlank(vendorName)) { 126 final String vendorNumberLabel = this.getAttributeLabel(KFSPropertyConstants.VENDOR_NUMBER); 127 final String vendorNameLabel = this.getAttributeLabel(KFSPropertyConstants.VENDOR_NAME); 128 final String firstNameLabel = this.getAttributeLabel(KIMPropertyConstants.Person.FIRST_NAME); 129 final String lastNameLabel = this.getAttributeLabel(KIMPropertyConstants.Person.LAST_NAME); 130 GlobalVariables.getMessageMap().putError(KFSPropertyConstants.VENDOR_NUMBER, KFSKeyConstants.ERROR_DV_LOOKUP_NEEDS_SOME_FIELD, new String[] {vendorNumberLabel, employeeIdLabel, vendorNameLabel, firstNameLabel, lastNameLabel}); 131 } else { 132 final boolean isVendorInfoEntered = StringUtils.isNotBlank(vendorName) || StringUtils.isNotBlank(vendorNumber); 133 if (isVendorInfoEntered && StringUtils.isNotBlank(employeeId)) { 134 // only can use the vendor name and vendor number fields or the employee id field, but not both. 135 String messageKey = KFSKeyConstants.ERROR_DV_VENDOR_EMPLOYEE_CONFUSION; 136 String vendorNameLabel = this.getAttributeLabel(KFSPropertyConstants.VENDOR_NAME); 137 String vendorNumberLabel = this.getAttributeLabel(KFSPropertyConstants.VENDOR_NUMBER); 138 GlobalVariables.getMessageMap().putError(KIMPropertyConstants.Person.EMPLOYEE_ID, messageKey, employeeIdLabel, vendorNameLabel, vendorNumberLabel); 139 } 140 if (StringUtils.isBlank(vendorNumber) && !StringUtils.isBlank(vendorName) && !filledEnough(vendorName)) { 141 final String vendorNameLabel = this.getAttributeLabel(KFSPropertyConstants.VENDOR_NAME); 142 GlobalVariables.getMessageMap().putError(KFSPropertyConstants.VENDOR_NAME, KFSKeyConstants.ERROR_DV_NAME_NOT_FILLED_ENOUGH, new String[] {vendorNameLabel, Integer.toString(getNameLengthWithWildcardRequirement())}); 143 } 144 145 final boolean isPersonNameEntered = StringUtils.isNotBlank(firstName) || StringUtils.isNotBlank(lastName); 146 final String employeeFirstNameLabel = this.getAttributeLabel(KIMPropertyConstants.Person.FIRST_NAME); 147 final String employeeLastNameLabel = this.getAttributeLabel(KIMPropertyConstants.Person.LAST_NAME); 148 149 // we do not use to use Tax Number field for the lookup on the person... 150 if(StringUtils.isNotBlank(vendorTaxNumber) && StringUtils.isNotBlank(firstName)) { 151 fieldValues.remove(KFSPropertyConstants.TAX_NUMBER); 152 String messageKey = KFSKeyConstants.ERROR_DV_LOOKUP_TAX_NUMBER_EMPLOYEE_DETAILS_CONFUSION; 153 GlobalVariables.getMessageMap().putError(KIMPropertyConstants.Person.FIRST_NAME, messageKey, vendorTaxNumberLabel, employeeFirstNameLabel); 154 } 155 // if tax number and employee last name entered then send an error message... 156 if(StringUtils.isNotBlank(vendorTaxNumber) && StringUtils.isNotBlank(lastName)) { 157 fieldValues.remove(KFSPropertyConstants.TAX_NUMBER); 158 String messageKey = KFSKeyConstants.ERROR_DV_LOOKUP_TAX_NUMBER_EMPLOYEE_DETAILS_CONFUSION; 159 GlobalVariables.getMessageMap().putError(KIMPropertyConstants.Person.LAST_NAME, messageKey, vendorTaxNumberLabel, employeeLastNameLabel); 160 } 161 // if tax number and employee id entered then send an error message... 162 if(StringUtils.isNotBlank(vendorTaxNumber) && StringUtils.isNotBlank(employeeId)) { 163 fieldValues.remove(KFSPropertyConstants.TAX_NUMBER); 164 String messageKey = KFSKeyConstants.ERROR_DV_LOOKUP_TAX_NUMBER_EMPLOYEE_DETAILS_CONFUSION; 165 GlobalVariables.getMessageMap().putError(KIMPropertyConstants.Person.EMPLOYEE_ID, messageKey, employeeIdLabel, vendorTaxNumberLabel); 166 } 167 168 if (isPersonNameEntered && StringUtils.isNotBlank(vendorName)) { 169 // only can use the person first and last name fields or the vendor name field, but not both. 170 String messageKey = KFSKeyConstants.ERROR_DV_VENDOR_NAME_PERSON_NAME_CONFUSION; 171 172 String vendorNameLabel = this.getAttributeLabel(KFSPropertyConstants.VENDOR_NAME); 173 String firstNameLabel = this.getAttributeLabel(KIMPropertyConstants.Person.FIRST_NAME); 174 String lastNameLabel = this.getAttributeLabel(KIMPropertyConstants.Person.LAST_NAME); 175 176 GlobalVariables.getMessageMap().putError(KFSPropertyConstants.VENDOR_NAME, messageKey, vendorNameLabel, firstNameLabel, lastNameLabel); 177 } 178 if (StringUtils.isBlank(employeeId)) { 179 if (StringUtils.isBlank(firstName) && !StringUtils.isBlank(lastName) && !filledEnough(lastName)) { 180 final String label = getAttributeLabel(KIMPropertyConstants.Person.LAST_NAME); 181 GlobalVariables.getMessageMap().putError(KIMPropertyConstants.Person.LAST_NAME, KFSKeyConstants.ERROR_DV_NAME_NOT_FILLED_ENOUGH, new String[] { label, Integer.toString(getNameLengthWithWildcardRequirement() ) } ); 182 } else if (StringUtils.isBlank(lastName) && !StringUtils.isBlank(firstName) && !filledEnough(firstName)) { 183 final String label = getAttributeLabel(KIMPropertyConstants.Person.FIRST_NAME); 184 GlobalVariables.getMessageMap().putError(KIMPropertyConstants.Person.FIRST_NAME, KFSKeyConstants.ERROR_DV_NAME_NOT_FILLED_ENOUGH, new String[] { label, Integer.toString(getNameLengthWithWildcardRequirement() ) } ); 185 } 186 } 187 } 188 189 if (GlobalVariables.getMessageMap().hasErrors()) { 190 throw new ValidationException("errors in search criteria"); 191 } 192 } 193 194 /** 195 * Determines if a String is "filled enough" - ie, is not null, has a length greater than zero and if a wildcard is present, has a length greater than 4 (3 characters, plus a wildcard) 196 * @param s the String to test 197 * @return true if the given String is "filled" by the definition above, false otherwise 198 */ 199 protected boolean filledEnough(String s) { 200 final boolean containsWildcard = containsLookupWildcard(s); 201 return s != null && s.length() > 0 && ((containsWildcard && s.length() >= getNameLengthWithWildcardRequirement()) || !containsWildcard); 202 } 203 204 /** 205 * @return the number of characters a name field must be filled in for the search to be valid 206 */ 207 protected int getNameLengthWithWildcardRequirement() { 208 return DisbursementPayeeLookupableHelperServiceImpl.NAME_REQUIRED_FILLED_WITH_WILDCARD; 209 } 210 211 /** 212 * Determines if the given String contains a lookup wildcard 213 * @param s the String to test 214 * @return true if a lookup wildcard is in the String, false otherwise 215 */ 216 protected boolean containsLookupWildcard(String s) { 217 return s != null && (s.indexOf('*') > -1 || s.indexOf('%') > -1); 218 } 219 220 // get the label for the given attribute of the current business object 221 protected String getAttributeLabel(String attributeName) { 222 return this.getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), attributeName); 223 } 224 225 // perform vendor search 226 protected List<DisbursementPayee> getVendorsAsPayees(Map<String, String> fieldValues) { 227 List<DisbursementPayee> payeeList = new ArrayList<DisbursementPayee>(); 228 229 Map<String, String> fieldsForLookup = this.getVendorFieldValues(fieldValues); 230 vendorLookupable.setBusinessObjectClass(VendorDetail.class); 231 vendorLookupable.validateSearchParameters(fieldsForLookup); 232 233 List<BusinessObject> vendorList = vendorLookupable.getSearchResults(fieldsForLookup); 234 for (BusinessObject vendor : vendorList) { 235 VendorDetail vendorDetail = (VendorDetail) vendor; 236 DisbursementPayee payee = getPayeeFromVendor(vendorDetail, fieldValues); 237 payeeList.add(payee); 238 } 239 240 return payeeList; 241 } 242 243 protected DisbursementPayee getPayeeFromVendor(VendorDetail vendorDetail, Map<String, String> fieldValues) { 244 DisbursementPayee payee = DisbursementPayee.getPayeeFromVendor(vendorDetail); 245 payee.setPaymentReasonCode(fieldValues.get(KFSPropertyConstants.PAYMENT_REASON_CODE)); 246 247 //KFSMI-5497 248 //get the attributeSecurity property and mask the field so that on results screen will be shown masked. 249 DataDictionaryService dataDictionaryService = SpringContext.getBean(DataDictionaryService.class); 250 AttributeSecurity attributeSecurity = dataDictionaryService.getAttributeSecurity(DisbursementPayee.class.getName(), "taxNumber"); 251 attributeSecurity.setMask(true); 252 253 return payee; 254 } 255 256 // get the search criteria valid for vendor lookup 257 private Map<String, String> getVendorFieldValues(Map<String, String> fieldValues) { 258 Map<String, String> vendorFieldValues = new HashMap<String, String>(); 259 vendorFieldValues.putAll(fieldValues); 260 261 Map<String, String> fieldConversionMap = DisbursementPayee.getFieldConversionBetweenPayeeAndVendor(); 262 this.replaceFieldKeys(vendorFieldValues, fieldConversionMap); 263 264 String vendorName = this.getVendorName(vendorFieldValues); 265 if (StringUtils.isNotBlank(vendorName)) { 266 vendorFieldValues.put(KFSPropertyConstants.VENDOR_NAME, vendorName); 267 } 268 269 vendorFieldValues.remove(VendorPropertyConstants.VENDOR_FIRST_NAME); 270 vendorFieldValues.remove(VendorPropertyConstants.VENDOR_LAST_NAME); 271 272 return vendorFieldValues; 273 } 274 275 // get the vendor name from the given field value map 276 private String getVendorName(Map<String, String> vendorFieldValues) { 277 String firstName = vendorFieldValues.get(VendorPropertyConstants.VENDOR_FIRST_NAME); 278 String lastName = vendorFieldValues.get(VendorPropertyConstants.VENDOR_LAST_NAME); 279 280 if (StringUtils.isNotBlank(lastName)) { 281 return lastName + VendorConstants.NAME_DELIM + firstName; 282 } 283 else if (StringUtils.isNotBlank(firstName)) { 284 return KFSConstants.WILDCARD_CHARACTER + VendorConstants.NAME_DELIM + firstName; 285 } 286 287 return StringUtils.EMPTY; 288 } 289 290 // perform person search 291 protected List<DisbursementPayee> getPersonAsPayees(Map<String, String> fieldValues) { 292 List<DisbursementPayee> payeeList = new ArrayList<DisbursementPayee>(); 293 294 Map<String, String> fieldsForLookup = this.getPersonFieldValues(fieldValues); 295 List<? extends Person> persons = KIMServiceLocator.getPersonService().findPeople(fieldsForLookup); 296 297 for (Person personDetail : persons) { 298 DisbursementPayee payee = getPayeeFromPerson(personDetail, fieldValues); 299 payeeList.add(payee); 300 } 301 302 return payeeList; 303 } 304 305 protected DisbursementPayee getPayeeFromPerson(Person personDetail, Map<String, String> fieldValues) { 306 DisbursementPayee payee = DisbursementPayee.getPayeeFromPerson(personDetail); 307 payee.setPaymentReasonCode(fieldValues.get(KFSPropertyConstants.PAYMENT_REASON_CODE)); 308 309 //KFSMI-5497 310 //get the attributeSecurity property and unmask the field so that on results screen, it will set as blank. 311 DataDictionaryService dataDictionaryService = SpringContext.getBean(DataDictionaryService.class); 312 AttributeSecurity attributeSecurity = dataDictionaryService.getAttributeSecurity(DisbursementPayee.class.getName(), "taxNumber"); 313 attributeSecurity.setMask(false); 314 315 return payee; 316 } 317 318 // get the search criteria valid for person lookup 319 private Map<String, String> getPersonFieldValues(Map<String, String> fieldValues) { 320 Map<String, String> personFieldValues = new HashMap<String, String>(); 321 personFieldValues.putAll(fieldValues); 322 323 Map<String, String> fieldConversionMap = DisbursementPayee.getFieldConversionBetweenPayeeAndPerson(); 324 this.replaceFieldKeys(personFieldValues, fieldConversionMap); 325 326 personFieldValues.put(KIMPropertyConstants.Person.EMPLOYEE_STATUS_CODE, KFSConstants.EMPLOYEE_ACTIVE_STATUS); 327 328 return personFieldValues; 329 } 330 331 // replace the keys in fieldValues with the corresponding values defined in fieldConversionMap 332 private void replaceFieldKeys(Map<String, String> fieldValues, Map<String, String> fieldConversionMap) { 333 for (String key : fieldConversionMap.keySet()) { 334 if (fieldValues.containsKey(key)) { 335 String value = fieldValues.get(key); 336 String newKey = fieldConversionMap.get(key); 337 338 fieldValues.remove(key); 339 fieldValues.put(newKey, value); 340 } 341 } 342 } 343 344 // remove its return URLs if a row is not qualified for returning 345 protected void filterReturnUrl(List<ResultRow> resultRowList, List<DisbursementPayee> payeeList, String paymentReasonCode) { 346 List<String> payeeTypeCodes = disbursementVoucherPaymentReasonService.getPayeeTypesByPaymentReason(paymentReasonCode); 347 if (payeeTypeCodes == null || payeeTypeCodes.isEmpty()) { 348 return; 349 } 350 351 for (int index = 0; index < payeeList.size(); index++) { 352 DisbursementPayee payee = payeeList.get(index); 353 354 boolean isQualified = disbursementVoucherPaymentReasonService.isPayeeQualifiedForPayment(payee, paymentReasonCode, payeeTypeCodes); 355 if (!isQualified) { 356 resultRowList.get(index).setReturnUrl(StringUtils.EMPTY); 357 } 358 } 359 } 360 361 /** 362 * Sets the vendorLookupable attribute value. 363 * 364 * @param vendorLookupable The vendorLookupable to set. 365 */ 366 public void setVendorLookupable(Lookupable vendorLookupable) { 367 this.vendorLookupable = vendorLookupable; 368 } 369 370 /** 371 * Sets the disbursementVoucherPaymentReasonService attribute value. 372 * 373 * @param disbursementVoucherPaymentReasonService The disbursementVoucherPaymentReasonService to set. 374 */ 375 public void setDisbursementVoucherPaymentReasonService(DisbursementVoucherPaymentReasonService disbursementVoucherPaymentReasonService) { 376 this.disbursementVoucherPaymentReasonService = disbursementVoucherPaymentReasonService; 377 } 378 }