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 }