/*
* 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.document.authorization;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.module.tem.TemConstants;
import org.kuali.kfs.module.tem.TemPropertyConstants.TemProfileProperties;
import org.kuali.kfs.module.tem.businessobject.TemProfile;
import org.kuali.kfs.module.tem.businessobject.TravelerDetail;
import org.kuali.kfs.module.tem.document.TravelDocument;
import org.kuali.kfs.module.tem.document.service.TravelDocumentService;
import org.kuali.kfs.module.tem.service.TemRoleService;
import org.kuali.kfs.module.tem.service.TravelService;
import org.kuali.kfs.module.tem.service.TravelerService;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.document.authorization.AccountingDocumentAuthorizerBase;
import org.kuali.kfs.sys.identity.KfsKimAttributes;
import org.kuali.rice.kew.api.WorkflowDocument;
import org.kuali.rice.kim.api.KimConstants;
import org.kuali.rice.kim.api.identity.Person;
import org.kuali.rice.kim.api.role.RoleService;
import org.kuali.rice.krad.document.Document;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.util.KRADConstants;
import org.kuali.rice.krad.util.ObjectUtils;
/**
* Check for travel arranger access
* Checking for ReturnToFiscalOfficerAuthorization
*
*/
abstract public class TravelArrangeableAuthorizer extends AccountingDocumentAuthorizerBase implements ReturnToFiscalOfficerAuthorizer {
private volatile RoleService roleService;
private volatile BusinessObjectService businessObjectService;
/**
* @see org.kuali.kfs.sys.document.authorization.AccountingDocumentAuthorizerBase#addRoleQualification(org.kuali.rice.kns.bo.BusinessObject,java.util.Map)
*/
@Override
protected void addRoleQualification(Object dataObject, Map<String, String> qualification) {
super.addRoleQualification(dataObject, qualification);
if (dataObject instanceof TravelDocument) {
TravelDocument document = (TravelDocument) dataObject;
// add the qualifications - profile and document type
if (ObjectUtils.isNotNull(document.getProfileId())) {
qualification.put(TemProfileProperties.PROFILE_ID, document.getProfileId().toString());
qualification.put(KFSPropertyConstants.DOCUMENT_TYPE_NAME, document.getDocumentTypeName());
final TemProfile profile = getBusinessObjectService().findBySinglePrimaryKey(TemProfile.class, document.getProfileId());
if (profile != null) {
if (!qualification.containsKey(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE)) {
qualification.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, profile.getHomeDeptChartOfAccountsCode());
}
if (!qualification.containsKey(KFSPropertyConstants.ORGANIZATION_CODE)) {
qualification.put(KFSPropertyConstants.ORGANIZATION_CODE, profile.getHomeDeptOrgCode());
}
}
}
if (ObjectUtils.isNotNull(document.getTraveler()) && !StringUtils.isBlank(document.getTraveler().getPrincipalId())) {
qualification.put(KfsKimAttributes.PROFILE_PRINCIPAL_ID, document.getTraveler().getPrincipalId());
}
}
}
/**
* Overridden to pass in profile principal id as the current user's principal id
* @see org.kuali.rice.kns.document.authorization.DocumentAuthorizerBase#canInitiate(java.lang.String, org.kuali.rice.kim.api.identity.Person)
*/
@Override
public boolean canInitiate(String documentTypeName, Person user) {
String nameSpaceCode = KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE;
Map<String, String> permissionDetails = new HashMap<String, String>();
Map<String, String> qualificationDetails = new HashMap<String, String>();
qualificationDetails.put(KfsKimAttributes.PROFILE_PRINCIPAL_ID, user.getPrincipalId());
permissionDetails.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, documentTypeName);
return getPermissionService().isAuthorizedByTemplate(user.getPrincipalId(), nameSpaceCode,
KimConstants.PermissionTemplateNames.INITIATE_DOCUMENT, permissionDetails, qualificationDetails);
}
/**
* @see org.kuali.rice.kns.document.authorization.DocumentAuthorizerBase#canEditDocumentOverview(org.kuali.rice.kns.document.Document,org.kuali.rice.kim.bo.Person)
*/
@Override
public boolean canEditDocumentOverview(Document document, Person user) {
return canEditDocument(document, user);
}
/**
* Check edit permission on document
*
* @param document
* @param user
* @return
*/
public boolean canEditDocument(Document document, Person user) {
// override base implementation to only allow initiator to edit doc overview
return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId());
}
public boolean canTaxSelectable(final Person user){
return getPermissionService().hasPermission(user.getPrincipalId(), TemConstants.PARAM_NAMESPACE, TemConstants.Permission.EDIT_TAXABLE_IND);
}
/**
* @see org.kuali.kfs.module.tem.document.authorization.ReturnToFiscalOfficerAuthorizer#canReturnToFisicalOfficer(org.kuali.kfs.module.tem.document.TravelDocument, org.kuali.rice.kim.bo.Person)
*/
@Override
public boolean canReturnToFisicalOfficer(final TravelDocument travelDocument, final Person user) {
if(ObjectUtils.isNull(user)) {
return false;
}
WorkflowDocument workflowDocument = travelDocument.getDocumentHeader().getWorkflowDocument();
// initiator cannot Hold their own document
String initiator = workflowDocument.getInitiatorPrincipalId();
if (initiator.equals(user.getPrincipalId())){
return false;
}
if (!workflowDocument.isEnroute()) {
return false;
}
//now check to see if they are a Fiscal Officer
final Set<String> appDocStatuses = getNonReturnToFiscalOfficerDocumentStatuses();
if (appDocStatuses.contains(travelDocument.getDocumentHeader().getWorkflowDocument().getApplicationDocumentStatus())) {
return false;
}
String nameSpaceCode = org.kuali.kfs.module.tem.TemConstants.PARAM_NAMESPACE;
Map<String,String> roleQualifications = new HashMap<String,String>();
addRoleQualification(travelDocument, roleQualifications);
return getPermissionService().isAuthorized(user.getPrincipalId(), nameSpaceCode, TemConstants.Permission.RETURN_TO_FO, roleQualifications);
}
/**
* @return the generic Set of names of application document statuses where returning to Fiscal Officer is impossible (either because we're at fiscal officer or because we're before it)
*/
protected Set<String> getNonReturnToFiscalOfficerDocumentStatuses() {
Set<String> appDocStatuses = new HashSet<String>();
appDocStatuses.add(TemConstants.TravelStatusCodeKeys.IN_PROCESS);
appDocStatuses.add(TemConstants.TravelStatusCodeKeys.AWAIT_TRVLR);
appDocStatuses.add(TemConstants.TravelStatusCodeKeys.AWAIT_FISCAL);
return appDocStatuses;
}
/**
* Determine if the Fiscal Officer Role has permission named by permission name
*
* @param name of the permission to check for Fiscal Officer authorization on. This is usually, "Amend TA", "Close TA", "Cancel TA", "Hold TA", or "Unhold TA"
* @boolean true if fiscal officer has rights or false otherwise
*/
protected boolean isFiscalOfficerAuthorizedTo(final String permission, String documentTypeName) {
final String fiscalOfficerRoleId = getRoleService().getRoleIdByNamespaceCodeAndName(KFSConstants.CoreModuleNamespaces.KFS, KFSConstants.SysKimApiConstants.FISCAL_OFFICER_KIM_ROLE_NAME);
//**TODO remove the checking because new permission service does not allow for permission detail - and each permission is tied specifically to the travel document type,
// No need to further qualified by document type name
//final List<String> roles = getPermissionService().getRoleIdsForPermission(TemConstants.PARAM_NAMESPACE, action, permissionDetails);
final List<String> roles = getPermissionService().getRoleIdsForPermission(TemConstants.PARAM_NAMESPACE, permission);
return (roles != null && roles.size() > 0 && roles.contains(fiscalOfficerRoleId));
}
/**
* calculate and save falls in the exact same logic
*
* @param travelDocument
* @param user
* @return
*/
public boolean canCalculate(TravelDocument travelDocument, Person user) {
return canSave(travelDocument, user);
}
/**
*
* @return
*/
protected TravelDocumentService getTravelDocumentService() {
return SpringContext.getBean(TravelDocumentService.class);
}
/**
* Check for employee
*
* @param traveler
* @return
*/
protected boolean isEmployee(final TravelerDetail traveler) {
return traveler == null? false : getTravelerService().isEmployee(traveler);
}
protected TravelerService getTravelerService() {
return SpringContext.getBean(TravelerService.class);
}
public TravelService getTravelService() {
return SpringContext.getBean(TravelService.class);
}
protected TemRoleService getTemRoleService() {
return SpringContext.getBean(TemRoleService.class);
}
protected RoleService getRoleService() {
if ( roleService == null ) {
roleService = SpringContext.getBean(RoleService.class);
}
return roleService;
}
/**
* @return the default implementation of the BusinessObjectService
*/
protected BusinessObjectService getBusinessObjectService() {
if (businessObjectService == null) {
businessObjectService = SpringContext.getBean(BusinessObjectService.class);
}
return businessObjectService;
}
}