001/*
002 * Copyright 2008 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 */
016package org.kuali.ole.module.purap.document.validation.impl;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.ole.coa.businessobject.Chart;
020import org.kuali.ole.coa.businessobject.ObjectCode;
021import org.kuali.ole.coa.businessobject.Organization;
022import org.kuali.ole.coa.businessobject.SubFundGroup;
023import org.kuali.ole.coa.service.AccountService;
024import org.kuali.ole.coa.service.ChartService;
025import org.kuali.ole.module.purap.PurapKeyConstants;
026import org.kuali.ole.module.purap.businessobject.ReceivingThreshold;
027import org.kuali.ole.module.purap.util.ThresholdField;
028import org.kuali.ole.sys.context.SpringContext;
029import org.kuali.ole.vnd.businessobject.CommodityCode;
030import org.kuali.ole.vnd.businessobject.VendorDetail;
031import org.kuali.rice.kns.document.MaintenanceDocument;
032import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
033
034import java.util.Collection;
035import java.util.HashMap;
036import java.util.Map;
037
038public 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}