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 java.util.Collection;
019    import java.util.HashMap;
020    import java.util.Map;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.kuali.kfs.coa.businessobject.Chart;
024    import org.kuali.kfs.coa.businessobject.ObjectCode;
025    import org.kuali.kfs.coa.businessobject.Organization;
026    import org.kuali.kfs.coa.businessobject.SubFundGroup;
027    import org.kuali.kfs.coa.service.AccountService;
028    import org.kuali.kfs.coa.service.ChartService;
029    import org.kuali.kfs.module.purap.PurapKeyConstants;
030    import org.kuali.kfs.module.purap.businessobject.ReceivingThreshold;
031    import org.kuali.kfs.module.purap.util.ThresholdField;
032    import org.kuali.kfs.sys.context.SpringContext;
033    import org.kuali.kfs.vnd.businessobject.CommodityCode;
034    import org.kuali.kfs.vnd.businessobject.VendorDetail;
035    import org.kuali.rice.kns.document.MaintenanceDocument;
036    import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
037    
038    public class ThresholdRule extends MaintenanceDocumentRuleBase {
039    
040        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ThresholdRule.class);
041        protected ChartService chartService;
042        protected AccountService accountService;
043        protected ReceivingThreshold newThreshold;
044        protected ReceivingThreshold oldThreshold;
045        
046        public ThresholdRule(){
047            chartService = SpringContext.getBean(ChartService.class);
048            accountService = SpringContext.getBean(AccountService.class);
049        }
050        
051        @Override
052        protected boolean isDocumentValidForSave(MaintenanceDocument document) {
053            if (document.isNew() || document.isEdit() || document.isNewWithExisting()) {
054                newThreshold = (ReceivingThreshold) document.getNewMaintainableObject().getBusinessObject();            
055                oldThreshold = document.getOldMaintainableObject() != null ? (ReceivingThreshold)document.getOldMaintainableObject().getBusinessObject() : null;
056    
057                //boolean checkDuplicate = newThreshold.isActive(); // we only need to check duplicate if newThreshold is active
058                // compare oldThreshold and newThreshold, check if there's any update on the various code fields
059                // if yes, then we need to check duplicate of the new threshold among other thresholds; otherwise no need to check            
060                boolean checkDuplicate = oldThreshold == null;
061                checkDuplicate |= !StringUtils.equals(newThreshold.getChartOfAccountsCode(), oldThreshold.getChartOfAccountsCode());
062                checkDuplicate |= !StringUtils.equals(newThreshold.getAccountTypeCode(), oldThreshold.getAccountTypeCode());
063                checkDuplicate |= !StringUtils.equals(newThreshold.getSubFundGroupCode(), oldThreshold.getSubFundGroupCode());
064                checkDuplicate |= !StringUtils.equals(newThreshold.getPurchasingCommodityCode(), oldThreshold.getPurchasingCommodityCode());
065                checkDuplicate |= !StringUtils.equals(newThreshold.getFinancialObjectCode(), oldThreshold.getFinancialObjectCode());
066                checkDuplicate |= !StringUtils.equals(newThreshold.getOrganizationCode(), oldThreshold.getOrganizationCode()); 
067                checkDuplicate |= !StringUtils.equals(newThreshold.getVendorNumber(), oldThreshold.getVendorNumber());
068                return isValidDocument(newThreshold, checkDuplicate);
069            }
070            return  true;
071        }
072        
073        protected boolean isValidDocument(ReceivingThreshold newThreshold, boolean checkDuplicate){
074            
075            boolean valid = isValidThresholdCriteria(newThreshold);
076            if (!valid){
077                constructFieldError(newThreshold);
078                return false;
079            }
080            
081            valid = isValidChartCode(newThreshold);
082            if (valid){
083                valid = isValidSubFund(newThreshold) &&
084                        isValidCommodityCode(newThreshold) &&
085                        isValidObjectCode(newThreshold) &&
086                        isValidOrgCode(newThreshold) &&
087                        isValidVendorNumber(newThreshold);
088            }
089            
090            // check duplication if needed
091            if (valid && checkDuplicate){
092                valid = !isDuplicateEntry(newThreshold);
093            }
094            return valid;
095        }
096        
097        protected void constructFieldError(ReceivingThreshold threshold){
098            
099            if (StringUtils.isNotBlank(threshold.getAccountTypeCode())){
100                putFieldError(ThresholdField.ACCOUNT_TYPE_CODE.getName(), PurapKeyConstants.INVALID_THRESHOLD_CRITERIA);
101            }
102            if (StringUtils.isNotBlank(threshold.getSubFundGroupCode())){
103                putFieldError(ThresholdField.SUBFUND_GROUP_CODE.getName(), PurapKeyConstants.INVALID_THRESHOLD_CRITERIA);
104            }
105            if (StringUtils.isNotBlank(threshold.getPurchasingCommodityCode())){
106                putFieldError(ThresholdField.COMMODITY_CODE.getName(), PurapKeyConstants.INVALID_THRESHOLD_CRITERIA);
107            }
108            if (StringUtils.isNotBlank(threshold.getFinancialObjectCode())){
109                putFieldError(ThresholdField.FINANCIAL_OBJECT_CODE.getName(), PurapKeyConstants.INVALID_THRESHOLD_CRITERIA);
110            }
111            if (StringUtils.isNotBlank(threshold.getOrganizationCode())){
112                putFieldError(ThresholdField.ORGANIZATION_CODE.getName(), PurapKeyConstants.INVALID_THRESHOLD_CRITERIA);
113            }
114            if (StringUtils.isNotBlank(threshold.getVendorNumber())){
115                putFieldError(ThresholdField.VENDOR_NUMBER.getName(), PurapKeyConstants.INVALID_THRESHOLD_CRITERIA);
116            }
117            
118        }
119        
120        protected boolean isValidChartCode(ReceivingThreshold threshold){
121            if (StringUtils.isNotBlank(threshold.getChartOfAccountsCode())){
122                Map pkMap = new HashMap();
123                pkMap.put(ThresholdField.CHART_OF_ACCOUNTS_CODE.getName(), newThreshold.getChartOfAccountsCode());
124        
125                Chart chart = (Chart) getBoService().findByPrimaryKey(Chart.class, pkMap);
126                if (chart == null) {
127                   putFieldError(ThresholdField.CHART_OF_ACCOUNTS_CODE.getName(), PurapKeyConstants.THRESHOLD_FIELD_INVALID, newThreshold.getChartOfAccountsCode());
128                   return false;
129                }else{
130                   return true;
131                }
132            }
133            return false;
134        }
135        
136        protected boolean isValidSubFund(ReceivingThreshold threshold){
137        
138            if (StringUtils.isNotBlank(threshold.getSubFundGroupCode())){
139                Map pkMap = new HashMap();
140                pkMap.put(ThresholdField.SUBFUND_GROUP_CODE.getName(), newThreshold.getSubFundGroupCode());
141                SubFundGroup subFundGroup = (SubFundGroup) getBoService().findByPrimaryKey(SubFundGroup.class, pkMap);
142                if (subFundGroup == null) {
143                   putFieldError(ThresholdField.SUBFUND_GROUP_CODE.getName(), PurapKeyConstants.THRESHOLD_FIELD_INVALID, newThreshold.getSubFundGroupCode());
144                   return false;
145                }
146            }
147            return true;
148        }
149        
150        protected boolean isValidCommodityCode(ReceivingThreshold threshold){
151            
152            if (StringUtils.isNotBlank(threshold.getPurchasingCommodityCode())){
153                Map pkMap = new HashMap();
154                pkMap.put(ThresholdField.COMMODITY_CODE.getName(), newThreshold.getPurchasingCommodityCode());
155            
156                CommodityCode commodityCode = (CommodityCode) getBoService().findByPrimaryKey(CommodityCode.class, pkMap);
157                if (commodityCode == null) {
158                   putFieldError(ThresholdField.COMMODITY_CODE.getName(), PurapKeyConstants.THRESHOLD_FIELD_INVALID, newThreshold.getPurchasingCommodityCode());
159                   return false;
160                }
161            }
162            return true;
163        }
164    
165        protected boolean isValidObjectCode(ReceivingThreshold threshold){
166            
167            if (StringUtils.isNotBlank(threshold.getFinancialObjectCode())){
168                Map pkMap = new HashMap();
169                pkMap.put(ThresholdField.FINANCIAL_OBJECT_CODE.getName(), newThreshold.getFinancialObjectCode());
170            
171                ObjectCode objectCode = (ObjectCode) getBoService().findByPrimaryKey(ObjectCode.class, pkMap);
172                if (objectCode == null) {
173                   putFieldError(ThresholdField.FINANCIAL_OBJECT_CODE.getName(), PurapKeyConstants.THRESHOLD_FIELD_INVALID, newThreshold.getFinancialObjectCode());
174                   return false;
175                }
176            }
177            return true;
178        }
179        
180        protected boolean isValidOrgCode(ReceivingThreshold threshold){
181            
182            if (StringUtils.isNotBlank(threshold.getOrganizationCode())){
183                Map pkMap = new HashMap();
184                pkMap.put(ThresholdField.ORGANIZATION_CODE.getName(), newThreshold.getOrganizationCode());
185            
186                Organization org = (Organization) getBoService().findByPrimaryKey(Organization.class, pkMap);
187                if (org == null) {
188                   putFieldError(ThresholdField.ORGANIZATION_CODE.getName(), PurapKeyConstants.THRESHOLD_FIELD_INVALID, newThreshold.getOrganizationCode());
189                   return false;
190                }
191            }
192            return true;
193        }
194        
195        protected boolean isValidVendorNumber(ReceivingThreshold threshold){
196            
197            if (StringUtils.isNotBlank(threshold.getVendorNumber())){
198                Map keys = new HashMap();
199                keys.put(ThresholdField.VENDOR_HEADER_GENERATED_ID.getName(), threshold.getVendorHeaderGeneratedIdentifier());
200                keys.put(ThresholdField.VENDOR_DETAIL_ASSIGNED_ID.getName(), threshold.getVendorDetailAssignedIdentifier());
201                
202                VendorDetail vendorDetail = (VendorDetail) getBoService().findByPrimaryKey(VendorDetail.class, keys);
203                if (vendorDetail == null) {
204                    putFieldError(ThresholdField.VENDOR_NUMBER.getName(), PurapKeyConstants.THRESHOLD_FIELD_INVALID, newThreshold.getVendorNumber());
205                    return false;
206                }
207            }
208            return true;
209        }
210        
211        protected boolean isValidThresholdCriteria(ReceivingThreshold threshold){
212            
213            if (StringUtils.isBlank(threshold.getAccountTypeCode()) &&
214                StringUtils.isBlank(threshold.getSubFundGroupCode()) &&
215                StringUtils.isBlank(threshold.getPurchasingCommodityCode()) &&
216                StringUtils.isBlank(threshold.getFinancialObjectCode()) &&
217                StringUtils.isBlank(threshold.getOrganizationCode()) && 
218                StringUtils.isBlank(threshold.getVendorNumber())){
219                return true;
220            }else if (StringUtils.isNotBlank(threshold.getAccountTypeCode()) &&
221                      StringUtils.isBlank(threshold.getSubFundGroupCode()) &&
222                      StringUtils.isBlank(threshold.getPurchasingCommodityCode()) &&
223                      StringUtils.isBlank(threshold.getFinancialObjectCode()) &&
224                      StringUtils.isBlank(threshold.getOrganizationCode()) && 
225                      StringUtils.isBlank(threshold.getVendorNumber())){
226                      return true;
227            }else if (StringUtils.isBlank(threshold.getAccountTypeCode()) &&
228                      StringUtils.isNotBlank(threshold.getSubFundGroupCode()) &&
229                      StringUtils.isBlank(threshold.getPurchasingCommodityCode()) &&
230                      StringUtils.isBlank(threshold.getFinancialObjectCode()) &&
231                      StringUtils.isBlank(threshold.getOrganizationCode()) && 
232                      StringUtils.isBlank(threshold.getVendorNumber())){
233                      return true;
234            }else if (StringUtils.isBlank(threshold.getAccountTypeCode()) &&
235                      StringUtils.isBlank(threshold.getSubFundGroupCode()) &&
236                      StringUtils.isNotBlank(threshold.getPurchasingCommodityCode()) &&
237                      StringUtils.isBlank(threshold.getFinancialObjectCode()) &&
238                      StringUtils.isBlank(threshold.getOrganizationCode()) && 
239                      StringUtils.isBlank(threshold.getVendorNumber())){
240                      return true;
241            }else if (StringUtils.isBlank(threshold.getAccountTypeCode()) &&
242                      StringUtils.isBlank(threshold.getSubFundGroupCode()) &&
243                      StringUtils.isBlank(threshold.getPurchasingCommodityCode()) &&
244                      StringUtils.isNotBlank(threshold.getFinancialObjectCode()) &&
245                      StringUtils.isBlank(threshold.getOrganizationCode()) && 
246                      StringUtils.isBlank(threshold.getVendorNumber())){
247                      return true;
248            }else if (StringUtils.isBlank(threshold.getAccountTypeCode()) &&
249                      StringUtils.isBlank(threshold.getSubFundGroupCode()) &&
250                      StringUtils.isBlank(threshold.getPurchasingCommodityCode()) &&
251                      StringUtils.isBlank(threshold.getFinancialObjectCode()) &&
252                      StringUtils.isNotBlank(threshold.getOrganizationCode()) && 
253                      StringUtils.isBlank(threshold.getVendorNumber())){
254                      return true;
255            }else if (StringUtils.isBlank(threshold.getAccountTypeCode()) &&
256                      StringUtils.isBlank(threshold.getSubFundGroupCode()) &&
257                      StringUtils.isBlank(threshold.getPurchasingCommodityCode()) &&
258                      StringUtils.isBlank(threshold.getFinancialObjectCode()) &&
259                      StringUtils.isBlank(threshold.getOrganizationCode()) && 
260                      StringUtils.isNotBlank(threshold.getVendorNumber())){
261                      return true;
262            }
263            return false;
264        }
265        
266        protected boolean isDuplicateEntry(ReceivingThreshold newThreshold){
267            
268            Map fieldValues = new HashMap();
269            fieldValues.put(ThresholdField.CHART_OF_ACCOUNTS_CODE.getName(), newThreshold.getChartOfAccountsCode());
270            //fieldValues.put("active", "Y"); // check duplicates only among active thresholds
271            
272            if (StringUtils.isNotBlank(newThreshold.getAccountTypeCode())){
273                fieldValues.put(ThresholdField.ACCOUNT_TYPE_CODE.getName(), newThreshold.getAccountTypeCode());
274            }else if (StringUtils.isNotBlank(newThreshold.getSubFundGroupCode())){
275                    fieldValues.put(ThresholdField.SUBFUND_GROUP_CODE.getName(), newThreshold.getSubFundGroupCode());    
276            }else if (StringUtils.isNotBlank(newThreshold.getPurchasingCommodityCode())){
277                fieldValues.put(ThresholdField.COMMODITY_CODE.getName(), newThreshold.getPurchasingCommodityCode());
278            }else if (StringUtils.isNotBlank(newThreshold.getFinancialObjectCode())){
279                fieldValues.put(ThresholdField.FINANCIAL_OBJECT_CODE.getName(), newThreshold.getFinancialObjectCode());
280            }else if (StringUtils.isNotBlank(newThreshold.getOrganizationCode())){
281                fieldValues.put(ThresholdField.ORGANIZATION_CODE.getName(), newThreshold.getOrganizationCode());
282            }else if (StringUtils.isNotBlank(newThreshold.getVendorNumber())){
283                fieldValues.put(ThresholdField.VENDOR_HEADER_GENERATED_ID.getName(), newThreshold.getVendorHeaderGeneratedIdentifier());
284                fieldValues.put(ThresholdField.VENDOR_DETAIL_ASSIGNED_ID.getName(), newThreshold.getVendorDetailAssignedIdentifier());
285            }
286            
287            Collection<ReceivingThreshold> result = (Collection<ReceivingThreshold>)getBoService().findMatching(ReceivingThreshold.class, fieldValues);
288            if (result != null && result.size() > 0) {
289                putGlobalError(PurapKeyConstants.PURAP_GENERAL_POTENTIAL_DUPLICATE);
290                return true;
291            }
292            return false;
293        }
294    }