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.module.purap.document.validation.impl;
017
018 import org.kuali.kfs.coa.document.validation.impl.MaintenancePreRulesBase;
019 import org.kuali.kfs.module.purap.PurapConstants;
020 import org.kuali.kfs.module.purap.PurapKeyConstants;
021 import org.kuali.kfs.module.purap.PurapPropertyConstants;
022 import org.kuali.kfs.module.purap.businessobject.ReceivingAddress;
023 import org.kuali.kfs.module.purap.document.service.ReceivingAddressService;
024 import org.kuali.kfs.sys.context.SpringContext;
025 import org.kuali.rice.kns.document.MaintenanceDocument;
026 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
027 import org.kuali.rice.kns.util.GlobalVariables;
028
029 /**
030 * Business Prerules applicable to ReceivingAddressMaintenanceDocument.
031 * These prerules check whether the maintenance action to a Receiving Address business objects abide certain constraint rules.
032 */
033 public class ReceivingAddressPreRules extends MaintenancePreRulesBase {
034
035 /**
036 * Checks whether the maintenance action to a Receiving Address business objects abide to the contraint that,
037 * there is one and only one active default receiving address for each chart or chart/org at any given time,
038 * if there exists at least one active receiving address for this chart or chart/org.
039 * If the contraint would be broken as a result of the update, the method will present an error or warning
040 * to the user; and if proceed, enforce the rule by updating the related receiving address as well.
041 * Note: this method relies on the condition that the current status of the DB satisfies the constraints.
042 *
043 * @see org.kuali.kfs.coa.document.validation.impl.MaintenancePreRulesBase#doCustomPreRules(org.kuali.rice.kns.document.MaintenanceDocument)
044 */
045 @Override
046 protected boolean doCustomPreRules( MaintenanceDocument document ) {
047 ReceivingAddress raOld = ( ReceivingAddress )document.getOldMaintainableObject().getBusinessObject();
048 ReceivingAddress raNew = ( ReceivingAddress )document.getNewMaintainableObject().getBusinessObject();
049
050 /* The fields that affect the rule are the default and active indicators.
051 * According to the create/copy/edit action, and various combinations of updates to these two fields,
052 * including unchanged (No->NO or Yes->Yes), set (No->Yes), unset (Yes->No), the rule checking will
053 * proceed respectively. The following boolean variables indicates the various updates and combinations.
054 */
055 boolean isNew = document.isNew();
056 boolean isEdit = document.isEdit();
057 boolean wasActive = isEdit && raOld.isActive();
058 boolean wasDefault = isEdit && raOld.isDefaultIndicator();
059 boolean isActive = raNew.isActive();
060 boolean isDefault = raNew.isDefaultIndicator();
061 boolean stayActive = wasActive && isActive;
062 boolean stayDefault = wasDefault && isDefault;
063 boolean setActive = (isNew || !wasActive) && isActive;
064 boolean unsetActive = wasActive && !isActive;
065 boolean setDefault = (isNew || !wasDefault) && isDefault;
066 boolean unsetDefault = wasDefault && !isDefault;
067
068 /* Check whether there're other active RA exist.
069 * We only need to search within the same chart/org group, since we don't allow editting on chart/org.
070 * However, we need to exclude the current address being edited if it is not a new one and was active.
071 */
072 /*
073 Map criteria = new HashMap();
074 criteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, raNew.getChartOfAccountsCode());
075 criteria.put(KFSPropertyConstants.ORGANIZATION_CODE, raNew.getOrganizationCode());
076 //criteria.put(PurapPropertyConstants.RCVNG_ADDR_DFLT_IND, true);
077 criteria.put(PurapPropertyConstants.RCVNG_ADDR_ACTIVE, true);
078 int count = SpringContext.getBean(BusinessObjectService.class).countMatching(ReceivingAddress.class, criteria);
079 */
080 int count = SpringContext.getBean(ReceivingAddressService.class).countActiveByChartOrg(raNew.getChartOfAccountsCode(),raNew.getOrganizationCode());
081 boolean existOther = wasActive ? (count>1) : (count>0);
082
083 /* Case 1 - adding the first active address:
084 * Force it to be the default one.
085 */
086 if ( setActive && !isDefault && !existOther ) {
087 raNew.setDefaultIndicator( true );
088 }
089 /* Case 2 - switching the default address from another one to this one:
090 * Give warning; if proceed, will unset the other default address in post-processing.
091 */
092 else if ( (stayActive && setDefault) || (setActive && isDefault && existOther) ) {
093 if (!super.askOrAnalyzeYesNoQuestion(PurapConstants.CONFIRM_CHANGE_DFLT_RVNG_ADDR, PurapConstants.CONFIRM_CHANGE_DFLT_RVNG_ADDR_TXT) ) {
094 abortRulesCheck();
095 }
096 }
097 /* Case 3 - unsetting the default address that's still active:
098 * Give error: Can't unset the default address; you must set another default address to replace this one.
099 */
100 else if ( stayActive && unsetDefault ) {
101 putFieldError(PurapPropertyConstants.RECEIVING_ADDRESS_DEFAULT_INDICATOR, PurapKeyConstants.ERROR_RCVNG_ADDR_UNSET_DFLT);
102 abortRulesCheck();
103 return false;
104 }
105 /* Case 4 - deactivating the default address while there're still other active ones:
106 * Give error: Can't deactivate the default address when there're still other active ones;
107 * you must set another default address first.
108 */
109 else if ( unsetActive && wasDefault && existOther ) {
110 putFieldError(PurapPropertyConstants.BO_ACTIVE, PurapKeyConstants.ERROR_RCVNG_ADDR_DEACTIVATE_DFLT);
111 abortRulesCheck();
112 return false;
113 }
114 /* Other cases are harmless, i.e. won't break the constraint, so we can proceed without doing anything extra.
115 */
116
117 return true;
118 }
119
120 /**
121 * Convenience method to add a property-specific error to the global errors list, with the correct prefix
122 * added to the property name so that it will display correctly on maintenance documents.
123 *
124 * @param propertyName Property name of the element that is associated with the error, to mark the field as errored in the UI.
125 * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
126 *
127 */
128 protected void putFieldError(String propertyName, String errorConstant) {
129 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(MaintenanceDocumentRuleBase.MAINTAINABLE_ERROR_PREFIX+propertyName, errorConstant);
130 }
131
132 }