/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.tem.businessobject.lookup; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.kuali.kfs.module.tem.TemConstants; import org.kuali.kfs.module.tem.TemPropertyConstants; import org.kuali.kfs.module.tem.TemPropertyConstants.TemProfileProperties; import org.kuali.kfs.module.tem.businessobject.TemProfile; import org.kuali.kfs.module.tem.businessobject.TemProfileArranger; import org.kuali.kfs.module.tem.businessobject.TemProfileFromCustomer; import org.kuali.kfs.module.tem.businessobject.TemProfileFromKimPerson; import org.kuali.kfs.module.tem.businessobject.datadictionary.TravelDetailLookupMappedFieldProxy; import org.kuali.kfs.module.tem.document.authorization.TemProfileAuthorizer; import org.kuali.kfs.module.tem.document.service.TravelArrangerDocumentService; import org.kuali.kfs.module.tem.service.TemProfileService; import org.kuali.kfs.module.tem.service.TemRoleService; import org.kuali.kfs.module.tem.service.TravelerService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.businessobject.ChartOrgHolder; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.service.FinancialSystemUserService; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.core.framework.persistence.ojb.conversion.OjbCharBooleanConversion; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.kim.api.identity.PersonService; import org.kuali.rice.kim.api.services.IdentityManagementService; import org.kuali.rice.kns.datadictionary.BusinessObjectEntry; import org.kuali.rice.kns.datadictionary.FieldDefinition; import org.kuali.rice.kns.lookup.HtmlData; import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl; import org.kuali.rice.kns.service.DocumentHelperService; import org.kuali.rice.kns.web.struts.form.LookupForm; import org.kuali.rice.krad.UserSession; import org.kuali.rice.krad.bo.BusinessObject; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krad.util.ObjectUtils; import org.kuali.rice.krad.util.UrlFactory; public class TemProfileLookupableHelperServiceImpl extends KualiLookupableHelperServiceImpl { public static Logger LOG = Logger.getLogger(TemProfileLookupableHelperServiceImpl.class); private TemRoleService temRoleService; private TravelerService travelerService; private PersonService personService; private TemProfileService temProfileService; private IdentityManagementService identityManagementService; private TravelArrangerDocumentService travelArrangerDocumentService; private static final String[] addressLookupFields = { TemProfileProperties.ADDRESS_1, TemProfileProperties.ADDRESS_2, TemProfileProperties.CITY_NAME, TemProfileProperties.STATE_CODE, TemProfileProperties.ZIP_CODE, TemProfileProperties.COUNTRY_CODE }; /** * @see org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl#getSearchResults(java.util.Map) */ @Override public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues) { boolean arrangeesOnly = false; Person currentUser = GlobalVariables.getUserSession().getPerson(); // split homeDepartment field value into org code and coa code for TemProfile lookup if (fieldValues != null) { String homeDepartment = fieldValues.get(TemConstants.TEM_PROFILE_HOME_DEPARTMENT); if (homeDepartment != null) { String[] primaryDepartmentCode = homeDepartment.split("-"); if (primaryDepartmentCode != null) { if (primaryDepartmentCode.length == 2) { fieldValues.put(TemConstants.TEM_PROFILE_HOME_DEPT_ORG_CODE, primaryDepartmentCode[1]); } fieldValues.put(TemConstants.TEM_PROFILE_HOME_DEPT_COA_CODE, primaryDepartmentCode[0]); fieldValues.remove(TemConstants.TEM_PROFILE_HOME_DEPARTMENT); } } if (fieldValues.containsKey(TemPropertyConstants.TemProfileProperties.ONLY_ARRANGEES_IN_LOOKUP)) { final String arrangeesOnlyValue = fieldValues.remove(TemPropertyConstants.TemProfileProperties.ONLY_ARRANGEES_IN_LOOKUP); if (!StringUtils.isBlank(arrangeesOnlyValue)) { OjbCharBooleanConversion booleanConverter = new OjbCharBooleanConversion(); final Boolean arrangeesOnlyBool = (Boolean)booleanConverter.sqlToJava(arrangeesOnlyValue); arrangeesOnly = arrangeesOnlyBool.booleanValue(); } } } List<TemProfile> searchResults = (List<TemProfile>) super.getSearchResults(fieldValues); List<TemProfile> profiles = new ArrayList<TemProfile>(); for (TemProfile profile : searchResults){ //only repopulate kim based tem profiles if (!StringUtils.isBlank(profile.getPrincipalId())) { getTravelerService().populateTemProfile(profile); } if (!arrangeesOnly || isArranger(currentUser, profile)) { profiles.add(profile); } } // Need to also search kim. This is necessary because data could be different between kim and the tem profile, // and the kim data is the data that should be used. // First get a list of kim fields to search on. Map<String, String> kimLookupFields = convertFieldValues(Person.class, fieldValues, "", TemProfile.class.getName()); // Get a list of people matching the fields kim fields. if (kimLookupNeeded(fieldValues)) { List<? extends Person> people = getPersonService().findPeople(kimLookupFields); for (Person person : people) { // See if the person has a tem profile. TemProfile profileFromKim = getTemProfileService().findTemProfileByPrincipalId(person.getPrincipalId()); if (ObjectUtils.isNotNull(profileFromKim)) { // Found the tem profile for this person, see if the tem profile search returned their profile. getTravelerService().populateTemProfile(profileFromKim); Boolean isFound = false; for (TemProfile profile : profiles) { if (profile.getProfileId() == profileFromKim.getProfileId()) { isFound = true; break; } } } } } return profiles; } /** * Determines if the given possibleArranger is an arranger for the given possibleArrangee * @param possibleArranger the Person who could be the arranger of the given profile * @param possibleArrangee the profile, who could have trips arranged by the possibleArranger * @return true if possibleArranger is an arranger for possibleArrangee, false otherwise */ protected boolean isArranger(Person possibleArranger, TemProfile possibleArrangee) { if (possibleArranger == null) { // there's no current user running this lookup? Weird. return false; } if (possibleArrangee == null) { // there's no profile but we're adding it to a list? even weirder return false; } final TemProfileArranger temProfileArranger = getTravelArrangerDocumentService().findTemProfileArranger(possibleArranger.getPrincipalId(), possibleArrangee.getProfileId()); final boolean isOrganizationalApprover = getTravelerService().isArrangeeByOrganization(possibleArranger.getPrincipalId(), possibleArrangee); return temProfileArranger != null || isOrganizationalApprover; } @Override public List<HtmlData> getCustomActionUrls(BusinessObject businessObject, List pkNames) { List<HtmlData> htmlDataList = new ArrayList<HtmlData>(); if (allowsMaintenanceEditAction(businessObject)) { htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_EDIT_METHOD_TO_CALL, pkNames)); } if (allowsMaintenanceDeleteAction(businessObject)) { htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_DELETE_METHOD_TO_CALL, pkNames)); } return htmlDataList; } /** * This method searches through fieldValues for a not null value. Returns true if a not null value is found. Use this to * determine if a kim lookup is necessary or not. * * @param fieldValues * @return */ private boolean kimLookupNeeded(Map<String, String> fieldValues) { for (String key : addressLookupFields) { if (fieldValues.get(key) != null) { return true; } } return false; } /** * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#getReturnHref(java.util.Properties, * org.kuali.rice.kns.web.struts.form.LookupForm, java.util.List) */ @SuppressWarnings("rawtypes") @Override protected String getReturnHref(Properties parameters, LookupForm lookupForm, List returnKeys) { String url = super.getReturnHref(parameters, lookupForm, returnKeys); url = url.replaceAll(TemPropertyConstants.TemProfileProperties.PROFILE_ID, "document." + TemPropertyConstants.TemProfileProperties.PROFILE_ID); return url; } /** * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#getSupplementalMenuBar() */ @Override public String getSupplementalMenuBar() { // we are coming from a document; bail. if (parameters.containsKey("docNum")) { return ""; } // next we need to get the current user's info UserSession user = GlobalVariables.getUserSession(); final TemProfileAuthorizer authorizer = (TemProfileAuthorizer)SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(TemConstants.TravelDocTypes.TRAVEL_PROFILE_DOCUMENT); final TemProfile dummyProfile = new TemProfile(); // fill the dummy profile with the user's org, so that org qualified roles will have qualifiers final ChartOrgHolder chartOrg = SpringContext.getBean(FinancialSystemUserService.class).getPrimaryOrganization(user.getPerson(), TemConstants.NAMESPACE); dummyProfile.setHomeDeptChartOfAccountsCode(chartOrg.getChartOfAccountsCode()); dummyProfile.setHomeDeptOrgCode(chartOrg.getOrganizationCode()); boolean canCreateNewProfile = authorizer.canCreateAnyProfile(dummyProfile, user.getPerson()); boolean canCreateMyProfile = false; Map<String, String> criteria = new HashMap<String, String>(2); criteria.put("principalId", user.getPrincipalId()); // If a TEM Profile doesn't exist and user is granted KFS-TEM Edit My TEM Profile permission, allow the user to create their profile if (getTemProfileService().findTemProfile(criteria) == null ) { canCreateMyProfile = authorizer.canEditOwnProfile(dummyProfile, user.getPerson()); } String url = "<div class=\"createnew\" title=\"Create TEM Profile\">"; String imageBaseUrl = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY); Properties myProfileParameters = new Properties(); myProfileParameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.MAINTENANCE_NEW_METHOD_TO_CALL); myProfileParameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, TemProfile.class.getName()); myProfileParameters.put(KFSConstants.OVERRIDE_KEYS, "principalId"); myProfileParameters.put(KFSConstants.REFRESH_CALLER, "principalId" + "::" + user.getPrincipalId()); myProfileParameters.put("principalId", user.getPrincipalId()); String createMineUrl = UrlFactory.parameterizeUrl(KFSConstants.MAINTENANCE_ACTION, myProfileParameters); if (canCreateMyProfile) { // add in the create mine button url += "<a href=\"" + createMineUrl + "\"><img src=\"" + imageBaseUrl + "tinybutton-createmine.gif\" alt=\"refresh\"></a> "; } if (canCreateNewProfile) { Properties parameters = new Properties(); parameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, TemProfileFromKimPerson.class.getName()); parameters.put(KFSConstants.DOC_FORM_KEY, "88888888"); parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD); String personUrl = UrlFactory.parameterizeUrl(KRADConstants.LOOKUP_ACTION, parameters); url += "<a href=\"" + personUrl + "\"><img src=\"" + imageBaseUrl + "tinybutton-createnewfromkim.gif\" alt=\"refresh\"></a>"; // create new from customer Properties custParameters = new Properties(); custParameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, TemProfileFromCustomer.class.getName()); custParameters.put(KFSConstants.DOC_FORM_KEY, "88888888"); custParameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD); String custUrl = UrlFactory.parameterizeUrl(KRADConstants.LOOKUP_ACTION, custParameters); url = url + " <a href=\"" + custUrl + "\"><img src=\"" + imageBaseUrl + "tinybutton-createnewfromcustomer.gif\" alt=\"refresh\"></a>"; } url += "</div>"; return url; } /** * * @param boClass * @param fieldValues * @param prefix * @param lookupClassName * @return */ private Map<String, String> convertFieldValues(Class<? extends BusinessObject> boClass, Map<String, String> fieldValues, String prefix, String lookupClassName) { Map<String, String> retval = new HashMap<String, String>(); LOG.debug("Converting field values " + fieldValues); for (final FieldDefinition lookupField : getLookupFieldsFor(lookupClassName)) { String attrName = lookupField.getAttributeName(); if (lookupField instanceof TravelDetailLookupMappedFieldProxy) { final TravelDetailLookupMappedFieldProxy mappedField = (TravelDetailLookupMappedFieldProxy) lookupField; final String key = mappedField.getAttributeMap().get(boClass.getSimpleName()); String value = fieldValues.get(attrName); if (retval.containsKey(key)) { value = retval.get(key) + value; } if (key != null) { retval.put(prefix + key, value); } else { LOG.warn("Got a null key for attribute name " + attrName); } } else if (containsAttribute(boClass, attrName)) { retval.put(prefix + attrName, fieldValues.get(attrName)); } } return retval; } /** * * @param boClass * @param attributeName * @return */ @SuppressWarnings("rawtypes") protected boolean containsAttribute(final Class boClass, final String attributeName) { return getDataDictionaryService().isAttributeDefined(boClass, attributeName); } /** * * @param className * @return */ private Collection<FieldDefinition> getLookupFieldsFor(String className) { BusinessObjectEntry businessObjectEntry = (BusinessObjectEntry)getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(className); return businessObjectEntry.getLookupDefinition().getLookupFields(); } public TemRoleService getTemRoleService() { return temRoleService; } public void setTemRoleService(TemRoleService temRoleService) { this.temRoleService = temRoleService; } /** * Gets the travelerService attribute. * * @return Returns the travelerService. */ public TravelerService getTravelerService() { return travelerService; } /** * Sets the travelerService attribute value. * * @param travelerService The travelerService to set. */ public void setTravelerService(TravelerService travelerService) { this.travelerService = travelerService; } /** * Sets the personService attribute value. * * @param personService The personService to set. */ public void setPersonService(PersonService personService) { this.personService = personService; } /** * Gets the personService attribute. * * @return Returns the personService. */ public PersonService getPersonService() { return personService; } /** * Gets the temProfileService attribute. * * @return Returns the temProfileService. */ public TemProfileService getTemProfileService() { return temProfileService; } /** * Sets the temProfileService attribute value. * * @param temProfileService The temProfileService to set. */ public void setTemProfileService(TemProfileService temProfileService) { this.temProfileService = temProfileService; } public IdentityManagementService getIdentityManagementService() { return identityManagementService; } public void setIdentityManagementService(IdentityManagementService identityManagementService) { this.identityManagementService = identityManagementService; } public TravelArrangerDocumentService getTravelArrangerDocumentService() { return travelArrangerDocumentService; } public void setTravelArrangerDocumentService(TravelArrangerDocumentService travelArrangerDocumentService) { this.travelArrangerDocumentService = travelArrangerDocumentService; } }