/* * 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.ar.identity; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.identity.OrganizationHierarchyAwareRoleTypeServiceBase; import org.kuali.kfs.module.ar.ArKeyConstants; import org.kuali.rice.core.api.uif.RemotableAttributeError; import org.kuali.rice.core.api.uif.RemotableAttributeError.Builder; /** * Role Type Service for the CGB Collector role, used to perform validation and matching of role qualifiers. */ public class CollectorRoleTypeServiceImpl extends OrganizationHierarchyAwareRoleTypeServiceBase { /** * qualification matches roleQualifiers if customer name matches, * and if chart/org match (only if they are included - they're optional) * * @see org.kuali.rice.kns.kim.type.DataDictionaryTypeServiceBase#performMatch(java.util.Map, java.util.Map) */ @Override public boolean performMatch(Map<String,String> qualification, Map<String,String> roleQualifier) { boolean matches = false; matches = doesCustomerMatch(qualification, roleQualifier); String billingChartOfAccountsCode = qualification.get(ArKimAttributes.BILLING_CHART_OF_ACCOUNTS_CODE); String billingOrganizationCode = qualification.get(ArKimAttributes.BILLING_ORGANIZATION_CODE); String processingChartOfAccountsCode = qualification.get(ArKimAttributes.PROCESSING_CHART_OF_ACCOUNTS_CODE); String processingOrganizationCode = qualification.get(ArKimAttributes.PROCESSING_ORGANIZATION_CODE); // only test chart/org if either billing chart/org or processing chart/org are populated // otherwise we only care if customer matches if ((StringUtils.isNotBlank(billingChartOfAccountsCode) && StringUtils.isNotBlank(billingOrganizationCode) || (StringUtils.isNotBlank(processingChartOfAccountsCode) && StringUtils.isNotBlank(processingOrganizationCode)))) { matches &= (doesOrgMatch(billingChartOfAccountsCode, billingOrganizationCode, ArKimAttributes.BILLING_CHART_OF_ACCOUNTS_CODE, ArKimAttributes.BILLING_ORGANIZATION_CODE, roleQualifier) || doesOrgMatch(processingChartOfAccountsCode, processingOrganizationCode, ArKimAttributes.PROCESSING_CHART_OF_ACCOUNTS_CODE, ArKimAttributes.PROCESSING_ORGANIZATION_CODE, roleQualifier)); } return matches; } /** * Does a check to see if the chart/org passed in match either the billing chart/org or processing chart/org * on the role qualifier. Is org hierarchy aware and descends the org hierarchy to do this check. * * @param chartOfAccountsCode chart code to check against billing or processing chart in role qualifiers * @param organizationCode org code to check against billing or processing org in role qualifiers * @param roleQualifier role qualifier containing either billing chart/org or processing chart/org * @return true if the passed in chart/org match, false otherwise */ protected boolean doesOrgMatch(String chartOfAccountsCode, String organizationCode, String chartOfAccountsCodeKey, String organizationCodeKey, Map<String, String> roleQualifier) { boolean orgMatches = false; String chart = roleQualifier.get(chartOfAccountsCodeKey); String org = roleQualifier.get(organizationCodeKey); // only billing chart/org or processing chart/org will be populated, and we don't want to call isParentOrg // with null values, so we need to check for empty values first before calling isParentOrg if (StringUtils.isNotEmpty(chart) && StringUtils.isNotEmpty(org) && StringUtils.isNotEmpty(chartOfAccountsCode) && StringUtils.isNotEmpty(organizationCode) && isParentOrg(chartOfAccountsCode, organizationCode, chart, org, true)) { orgMatches = true; } return orgMatches; } /** * Check if customer name matches customer name starting letter and ending letter * * If customer name isn't passed in the role qualification or customer name starting letter and * customer name ending letter qualifiers aren't in the roleQualifier, return true because we want * to match all customers in that case. * * If the customer name and starting/ending letter qualifiers are passed in, check to see if the first letter * of the customer name falls between the starting and ending letter qualifiers - if not, return false as the * name doesn't match the qualifiers, otherwise return true for a match. * * @param qualification * @param roleQualifier * @return */ protected boolean doesCustomerMatch(Map<String, String> qualification, Map<String, String> roleQualifier) { boolean customerMatches = true; if (qualification != null && !qualification.isEmpty() && roleQualifier != null && !roleQualifier.isEmpty()) { String customerName = qualification.get(ArKimAttributes.CUSTOMER_NAME); if (StringUtils.isNotEmpty(customerName)) { char startingQualificationLetter = customerName.charAt(0); char endingQualificationLetter = customerName.charAt(0); String startingQualifierLetter = roleQualifier.get(ArKimAttributes.CUSTOMER_NAME_STARTING_LETTER); String endingQualifierLetter = roleQualifier.get(ArKimAttributes.CUSTOMER_NAME_ENDING_LETTER); if (StringUtils.isNotEmpty(startingQualifierLetter) && StringUtils.isNotEmpty(endingQualifierLetter)) { if (startingQualificationLetter < startingQualifierLetter.charAt(0) || endingQualificationLetter > endingQualifierLetter.charAt(0)) { customerMatches = false; } } } } return customerMatches; } /** * note: for validating Collector role - either billing chart/org OR processing chart/org are required * and starting and ending letters are all or nothing: they aren't required, but if either one is entered, both need to be entered * * @see org.kuali.rice.kns.kim.type.DataDictionaryTypeServiceBase#validateAttributes(java.lang.String, java.util.Map) */ @Override public List<RemotableAttributeError> validateAttributes(String kimTypeId, Map<String,String> attributes) { List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>(); errors.addAll(super.validateAttributes(kimTypeId, attributes)); Builder errorBuilder = null; String billingChartCode = attributes.get(ArKimAttributes.BILLING_CHART_OF_ACCOUNTS_CODE); String billingOrganizationCode = attributes.get(ArKimAttributes.BILLING_ORGANIZATION_CODE); String processingChartCode = attributes.get(ArKimAttributes.PROCESSING_CHART_OF_ACCOUNTS_CODE); String processingOrganizationCode = attributes.get(ArKimAttributes.PROCESSING_ORGANIZATION_CODE); // either billing chart/org OR processing chart/org are required if (StringUtils.isNotEmpty(billingChartCode)) { if (StringUtils.isEmpty(billingOrganizationCode)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.BILLING_ORGANIZATION_CODE, ArKeyConstants.ERROR_BILLINGCHART_OR_BILLINGORG_NOTEMPTY_ALL_REQUIRED); errors.add(errorBuilder.build()); } if (StringUtils.isNotEmpty(processingChartCode)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.PROCESSING_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.ERROR_EITHER_BILLINGCHART_OR_PROCESSCHART_REQUIRED_NOT_BOTH); errors.add(errorBuilder.build()); } if (StringUtils.isNotEmpty(processingOrganizationCode)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.PROCESSING_ORGANIZATION_CODE, ArKeyConstants.ERROR_EITHER_BILLINGCHART_OR_PROCESSCHART_REQUIRED_NOT_BOTH); errors.add(errorBuilder.build()); } } else { if (StringUtils.isNotEmpty(billingOrganizationCode)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.BILLING_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.ERROR_BILLINGCHART_OR_BILLINGORG_NOTEMPTY_ALL_REQUIRED); errors.add(errorBuilder.build()); if (StringUtils.isNotEmpty(processingChartCode)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.PROCESSING_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.ERROR_EITHER_BILLINGCHART_OR_PROCESSCHART_REQUIRED_NOT_BOTH); errors.add(errorBuilder.build()); } if (StringUtils.isNotEmpty(processingOrganizationCode)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.PROCESSING_ORGANIZATION_CODE, ArKeyConstants.ERROR_EITHER_BILLINGCHART_OR_PROCESSCHART_REQUIRED_NOT_BOTH); errors.add(errorBuilder.build()); } } else { if (StringUtils.isEmpty(processingChartCode)) { if (StringUtils.isNotEmpty(processingOrganizationCode)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.PROCESSING_ORGANIZATION_CODE, ArKeyConstants.ERROR_PROCESSCHART_OR_PROCESSORG_NOTEMPTY_ALL_REQUIRED); errors.add(errorBuilder.build()); } else { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.BILLING_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.ERROR_EITHER_BILLINGCHART_OR_PROCESSCHART_REQUIRED_NOT_BOTH); errors.add(errorBuilder.build()); } } else { if (StringUtils.isEmpty(processingOrganizationCode)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.BILLING_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.ERROR_EITHER_BILLINGCHART_OR_PROCESSCHART_REQUIRED_NOT_BOTH); errors.add(errorBuilder.build()); } } } } String startingLetter = attributes.get(ArKimAttributes.CUSTOMER_NAME_STARTING_LETTER); String endingLetter = attributes.get(ArKimAttributes.CUSTOMER_NAME_ENDING_LETTER); // starting and ending letters are all or nothing: // they aren't required, but if either one is entered, both need to be entered if (StringUtils.isNotEmpty(startingLetter)) { if (StringUtils.isNotEmpty(endingLetter)) { char customerNameStartingLetter = attributes.get(ArKimAttributes.CUSTOMER_NAME_STARTING_LETTER).charAt(0); char customerNameEndingLetter = attributes.get(ArKimAttributes.CUSTOMER_NAME_ENDING_LETTER).charAt(0); if (customerNameStartingLetter > customerNameEndingLetter) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.CUSTOMER_NAME_STARTING_LETTER, ArKeyConstants.ERROR_STARTLETTER_AFTER_ENDLETTER); errors.add(errorBuilder.build()); } } else { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.CUSTOMER_NAME_STARTING_LETTER, ArKeyConstants.ERROR_STARTLETTER_OR_ENDLETTER_NOTEMPTY_ALL_REQUIRED); errors.add(errorBuilder.build()); } } else if (StringUtils.isNotEmpty(endingLetter)) { errorBuilder = RemotableAttributeError.Builder.create(ArKimAttributes.CUSTOMER_NAME_STARTING_LETTER, ArKeyConstants.ERROR_STARTLETTER_OR_ENDLETTER_NOTEMPTY_ALL_REQUIRED); errors.add(errorBuilder.build()); } return errors; } }