/* * 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.purap.document.validation.impl; import org.kuali.kfs.coa.document.validation.impl.MaintenancePreRulesBase; import org.kuali.kfs.module.purap.PurapConstants; import org.kuali.kfs.module.purap.PurapKeyConstants; import org.kuali.kfs.module.purap.PurapPropertyConstants; import org.kuali.kfs.module.purap.businessobject.ReceivingAddress; import org.kuali.kfs.module.purap.document.service.ReceivingAddressService; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.rice.kns.document.MaintenanceDocument; import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; import org.kuali.rice.krad.util.GlobalVariables; /** * Business Prerules applicable to ReceivingAddressMaintenanceDocument. * These prerules check whether the maintenance action to a Receiving Address business objects abide certain constraint rules. */ public class ReceivingAddressPreRules extends MaintenancePreRulesBase { /** * Checks whether the maintenance action to a Receiving Address business objects abide to the contraint that, * there is one and only one active default receiving address for each chart or chart/org at any given time, * if there exists at least one active receiving address for this chart or chart/org. * If the contraint would be broken as a result of the update, the method will present an error or warning * to the user; and if proceed, enforce the rule by updating the related receiving address as well. * Note: this method relies on the condition that the current status of the DB satisfies the constraints. * * @see org.kuali.kfs.coa.document.validation.impl.MaintenancePreRulesBase#doCustomPreRules(org.kuali.rice.kns.document.MaintenanceDocument) */ @Override protected boolean doCustomPreRules( MaintenanceDocument document ) { ReceivingAddress raOld = ( ReceivingAddress )document.getOldMaintainableObject().getBusinessObject(); ReceivingAddress raNew = ( ReceivingAddress )document.getNewMaintainableObject().getBusinessObject(); /* The fields that affect the rule are the default and active indicators. * According to the create/copy/edit action, and various combinations of updates to these two fields, * including unchanged (No->NO or Yes->Yes), set (No->Yes), unset (Yes->No), the rule checking will * proceed respectively. The following boolean variables indicates the various updates and combinations. */ boolean isNew = document.isNew(); boolean isEdit = document.isEdit(); boolean wasActive = isEdit && raOld.isActive(); boolean wasDefault = isEdit && raOld.isDefaultIndicator(); boolean isActive = raNew.isActive(); boolean isDefault = raNew.isDefaultIndicator(); boolean stayActive = wasActive && isActive; boolean stayDefault = wasDefault && isDefault; boolean setActive = (isNew || !wasActive) && isActive; boolean unsetActive = wasActive && !isActive; boolean setDefault = (isNew || !wasDefault) && isDefault; boolean unsetDefault = wasDefault && !isDefault; /* Check whether there're other active RA exist. * We only need to search within the same chart/org group, since we don't allow editting on chart/org. * However, we need to exclude the current address being edited if it is not a new one and was active. */ /* Map criteria = new HashMap(); criteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, raNew.getChartOfAccountsCode()); criteria.put(KFSPropertyConstants.ORGANIZATION_CODE, raNew.getOrganizationCode()); //criteria.put(PurapPropertyConstants.RCVNG_ADDR_DFLT_IND, true); criteria.put(PurapPropertyConstants.RCVNG_ADDR_ACTIVE, true); int count = SpringContext.getBean(BusinessObjectService.class).countMatching(ReceivingAddress.class, criteria); */ int count = SpringContext.getBean(ReceivingAddressService.class).countActiveByChartOrg(raNew.getChartOfAccountsCode(),raNew.getOrganizationCode()); boolean existOther = wasActive ? (count>1) : (count>0); /* Case 1 - adding the first active address: * Force it to be the default one. */ if ( setActive && !isDefault && !existOther ) { raNew.setDefaultIndicator( true ); } /* Case 2 - switching the default address from another one to this one: * Give warning; if proceed, will unset the other default address in post-processing. */ else if ( (stayActive && setDefault) || (setActive && isDefault && existOther) ) { if (!super.askOrAnalyzeYesNoQuestion(PurapConstants.CONFIRM_CHANGE_DFLT_RVNG_ADDR, PurapConstants.CONFIRM_CHANGE_DFLT_RVNG_ADDR_TXT) ) { abortRulesCheck(); } } /* Case 3 - unsetting the default address that's still active: * Give error: Can't unset the default address; you must set another default address to replace this one. */ else if ( stayActive && unsetDefault ) { putFieldError(PurapPropertyConstants.RECEIVING_ADDRESS_DEFAULT_INDICATOR, PurapKeyConstants.ERROR_RCVNG_ADDR_UNSET_DFLT); abortRulesCheck(); return false; } /* Case 4 - deactivating the default address while there're still other active ones: * Give error: Can't deactivate the default address when there're still other active ones; * you must set another default address first. */ else if ( unsetActive && wasDefault && existOther ) { putFieldError(PurapPropertyConstants.BO_ACTIVE, PurapKeyConstants.ERROR_RCVNG_ADDR_DEACTIVATE_DFLT); abortRulesCheck(); return false; } /* Other cases are harmless, i.e. won't break the constraint, so we can proceed without doing anything extra. */ return true; } /** * Convenience method to add a property-specific error to the global errors list, with the correct prefix * added to the property name so that it will display correctly on maintenance documents. * * @param propertyName Property name of the element that is associated with the error, to mark the field as errored in the UI. * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message. * */ protected void putFieldError(String propertyName, String errorConstant) { GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(MaintenanceDocumentRuleBase.MAINTAINABLE_ERROR_PREFIX+propertyName, errorConstant); } }