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 */
016package org.kuali.ole.select.document.validation.impl;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.ole.module.purap.PurapConstants;
020import org.kuali.ole.module.purap.businessobject.LineItemReceivingItem;
021import org.kuali.ole.module.purap.businessobject.PurapEnterableItem;
022import org.kuali.ole.module.purap.businessobject.ReceivingItem;
023import org.kuali.ole.module.purap.document.LineItemReceivingDocument;
024import org.kuali.ole.module.purap.document.ReceivingDocument;
025import org.kuali.ole.module.purap.document.validation.impl.LineItemReceivingDocumentRule;
026import org.kuali.ole.select.OleSelectConstant;
027import org.kuali.ole.select.businessobject.OleCopies;
028import org.kuali.ole.select.businessobject.OleLineItemReceivingItem;
029import org.kuali.ole.select.businessobject.OleLineItemReceivingReceiptNotes;
030import org.kuali.ole.select.businessobject.OleReceivingItem;
031import org.kuali.ole.select.document.OleLineItemReceivingDocument;
032import org.kuali.ole.sys.OLEKeyConstants;
033import org.kuali.rice.core.api.util.type.KualiDecimal;
034import org.kuali.rice.krad.document.Document;
035import org.kuali.rice.krad.util.GlobalVariables;
036import org.kuali.rice.krad.util.ObjectUtils;
037
038import java.util.List;
039
040/**
041 * This class handles validation rules for OLE Line Item Receiving Document.
042 */
043
044public class OleLineItemReceivingDocumentRule extends LineItemReceivingDocumentRule {
045
046    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(OleLineItemReceivingDocumentRule.class);
047
048    /**
049     * Overridden method to include validation for parts along with the existing validation
050     * for OLE Line Item Receiving Document.
051     *
052     * @param document
053     * @return If the document passed all validations
054     */
055    @Override
056    protected boolean processCustomRouteDocumentBusinessRules(Document document) {
057        LOG.debug("Inside processCustomRouteDocumentBusinessRules of OleLineItemReceivingDocumentRule");
058        boolean valid = true;
059
060        LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument) document;
061        valid &= canCreateLineItemReceivingDocument(lineItemReceivingDocument);
062        valid &= isAtLeastOneItemEntered(lineItemReceivingDocument);
063        valid &= validateItemUnitOfMeasure(lineItemReceivingDocument);
064        //  makes sure all of the lines adhere to the rule that quantityDamaged and
065        // quantityReturned cannot (each) equal more than the quantityReceived
066        valid &= validateAllReceivingLinesHaveSaneQuantities(lineItemReceivingDocument);
067
068        valid &= validateAllReceivingLinesHaveSaneParts(lineItemReceivingDocument);
069        //valid &= validateReceivedQuantityAndParts(lineItemReceivingDocument);
070        valid &= isExceptionNotesMandatory(lineItemReceivingDocument);
071        valid &= isAcknowledged(lineItemReceivingDocument);
072        valid &= validateItemDescriptionRequired(lineItemReceivingDocument);
073        /*
074         * valid &= checkForValidCopiesAndPartsForSubmit((OleLineItemReceivingDocument) lineItemReceivingDocument); valid &=
075         * validateCopies((OleLineItemReceivingDocument) lineItemReceivingDocument);
076         */
077        LOG.debug("Leaving processCustomRouteDocumentBusinessRules of OleLineItemReceivingDocumentRule");
078        return valid;
079    }
080
081    /**
082     * Overridden method to include validation for parts along with the existing validation
083     * when adding a new line item in OLE Line Item Receiving Document.
084     *
085     * @param document
086     * @param item
087     * @param errorPathPrefix
088     * @return If the newly added item passed all validations
089     */
090    @Override
091    public boolean processAddReceivingItemRules(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix) {
092        LOG.debug("Inside processAddReceivingItemRules of OleLineItemReceivingDocumentRule");
093        boolean valid = super.processAddReceivingItemRules(document, item, errorPathPrefix);
094
095        valid &= validatePartsReturnedNotMoreThanReceived(document, item, errorPathPrefix, new Integer(0));
096        valid &= validatePartsDamagedNotMoreThanReceived(document, item, errorPathPrefix, new Integer(0));
097        LOG.debug("Leaving processAddReceivingItemRules of OleLineItemReceivingDocumentRule");
098        return valid;
099    }
100
101    /**
102     * This method validates if parts returned is greater than parts received for a line item
103     * in OLE Line Item Receiving document and sets error accordingly.
104     *
105     * @param document
106     * @param item
107     * @param errorPathPrefix
108     * @param lineNumber
109     * @return boolean value (If the line item is valid or not)
110     */
111    protected boolean validatePartsReturnedNotMoreThanReceived(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix, Integer lineNumber) {
112        LOG.debug("Inside validatePartsReturnedNotMoreThanReceived of OleLineItemReceivingDocumentRule");
113        OleLineItemReceivingItem oleItem = (OleLineItemReceivingItem) item;
114        if (oleItem.getItemReturnedTotalParts() != null && oleItem.getItemReceivedTotalParts() != null) {
115            if (oleItem.getItemReturnedTotalParts().isGreaterThan(oleItem.getItemReceivedTotalParts())) {
116                GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_PRTRETURNED_GT_PRTRECEIVED, (lineNumber.intValue() == 0 ? "Add Line" : lineNumber.toString()));
117                return false;
118            }
119        }
120        LOG.debug("Leaving validatePartsReturnedNotMoreThanReceived of OleLineItemReceivingDocumentRule");
121        return true;
122    }
123
124    /**
125     * This method validates if parts damaged is greater than parts received for a line item
126     * in OLE Line Item Receiving document and sets error accordingly.
127     *
128     * @param document
129     * @param item
130     * @param errorPathPrefix
131     * @param lineNumber
132     * @return boolean value (If the line item is valid or not)
133     */
134    protected boolean validatePartsDamagedNotMoreThanReceived(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix, Integer lineNumber) {
135        LOG.debug("Inside validatePartsDamagedNotMoreThanReceived of OleLineItemReceivingDocumentRule");
136        OleLineItemReceivingItem oleItem = (OleLineItemReceivingItem) item;
137        if (oleItem.getItemDamagedTotalParts() != null && oleItem.getItemReceivedTotalParts() != null) {
138            if (oleItem.getItemDamagedTotalParts().isGreaterThan(oleItem.getItemReceivedTotalParts())) {
139                GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_PRTDAMAGED_GT_PRTRECEIVED, (lineNumber.intValue() == 0 ? "Add Line" : lineNumber.toString()));
140                return false;
141            }
142        }
143        LOG.debug("Leaving validatePartsDamagedNotMoreThanReceived of OleLineItemReceivingDocumentRule");
144        return true;
145    }
146
147    /**
148     * This method validates if parts returned/damaged is greater than parts received for a line item
149     * in OLE Line Item Receiving document
150     *
151     * @param document
152     * @return boolean value (If the line item is valid or not)
153     */
154    protected boolean validateAllReceivingLinesHaveSaneParts(ReceivingDocument document) {
155        LOG.debug("Inside validateAllReceivingLinesHaveSaneParts of OleLineItemReceivingDocumentRule");
156        GlobalVariables.getMessageMap().clearErrorPath();
157        boolean valid = true;
158        for (int i = 0; i < document.getItems().size(); i++) {
159            LineItemReceivingItem item = (LineItemReceivingItem) document.getItems().get(i);
160
161            valid &= validatePartsReturnedNotMoreThanReceived(document, item, "", new Integer(i + 1));
162            valid &= validatePartsDamagedNotMoreThanReceived(document, item, "", new Integer(i + 1));
163        }
164        LOG.debug("Leaving validateAllReceivingLinesHaveSaneParts of OleLineItemReceivingDocumentRule");
165        return valid;
166    }
167
168    /**
169     * This method validates if exception note is mandatory for the line item entered.
170     * Sets an error message accordingly.
171     *
172     * @param receivingDocument
173     * @return boolean
174     */
175    private boolean isExceptionNotesMandatory(LineItemReceivingDocument receivingDocument) {
176        LOG.debug("Inside isExceptionNotesMandatory of OleLineItemReceivingDocumentRule");
177        boolean isMandatory = false;
178        boolean isMandatoryAll = true;
179        for (OleLineItemReceivingItem item : (List<OleLineItemReceivingItem>) receivingDocument.getItems()) {
180            if (ObjectUtils.isNotNull(item.getItemDamagedTotalParts()) && ObjectUtils.isNotNull(item.getItemDamagedTotalQuantity()) && ObjectUtils.isNotNull(item.getItemReturnedTotalParts()) && ObjectUtils.isNotNull(item.getItemReturnedTotalQuantity())) {
181                if ((item.getItemDamagedTotalParts().isNonZero() || item.getItemDamagedTotalQuantity().isNonZero() || item.getItemReturnedTotalParts().isNonZero() || item.getItemReturnedTotalQuantity().isNonZero()) && !item.getExceptionNoteList().isEmpty()) {
182                    isMandatory = true;
183                } else if (item.getItemDamagedTotalParts().isZero() && item.getItemDamagedTotalQuantity().isZero() && item.getItemReturnedTotalParts().isZero() && item.getItemReturnedTotalQuantity().isZero()) {
184                    isMandatory = true;
185                } else {
186                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_EXCEPTION_NOTE_MANDATORY);
187                    isMandatory = false;
188                }
189                isMandatoryAll &= isMandatory;
190            }
191        }
192
193        return isMandatoryAll;
194    }
195
196    /**
197     * This method validates if all Special Handling notes are acknowledged
198     * for the line item entered.
199     *
200     * @param receivingDocument
201     * @return boolean
202     */
203    protected boolean isAcknowledged(LineItemReceivingDocument receivingDocument) {
204        LOG.debug("Inside isAcknowledged of OleLineItemReceivingDocumentRule");
205        boolean isNotesAck = true;
206        for (OleLineItemReceivingItem item : (List<OleLineItemReceivingItem>) receivingDocument.getItems()) {
207            boolean ack = item.isConsideredEntered();
208            boolean isAck = false;
209            for (OleLineItemReceivingReceiptNotes notes : item.getSpecialHandlingNoteList()) {
210                isAck = notes.isNotesAck();
211                isNotesAck &= isAck;
212            }
213            if (ack & isNotesAck) {
214                return true;
215            } else if (!ack) {
216                return true;
217            }
218        }
219        GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_NOTACKNOWLEDGED);
220        return false;
221    }
222
223    /**
224     * This method validates if exception note is mandatory for the line item entered.
225     * Sets an error message accordingly.
226     *
227     * @param receivingDocument
228     * @return boolean
229     */
230    private boolean validateReceivedQuantityAndParts(LineItemReceivingDocument receivingDocument) {
231        LOG.debug("Inside isExceptionNotesMandatory of OleLineItemReceivingDocumentRule");
232        boolean isNonZero = false;
233        boolean isNonZeroAll = true;
234        int index = 0;
235        for (OleLineItemReceivingItem item : (List<OleLineItemReceivingItem>) receivingDocument.getItems()) {
236            index += 1;
237            if (StringUtils.equalsIgnoreCase(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE)) {
238                if ((ObjectUtils.isNull(item.getItemReceivedTotalQuantity()) || item.getItemReceivedTotalQuantity().isZero()) && (ObjectUtils.isNull(item.getItemReceivedTotalParts()) || item.getItemReceivedTotalParts().isZero())) {
239                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_RECEIVED_TOTAL_QUANTITY_NON_ZERO_UNORDERED, String.valueOf(index));
240                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_RECEIVED_TOTAL_PARTS_NON_ZERO_UNORDERED, String.valueOf(index));
241                    isNonZero = false;
242                } else if ((ObjectUtils.isNull(item.getItemReceivedTotalParts()) || item.getItemReceivedTotalParts().isZero()) && (ObjectUtils.isNotNull(item.getItemReceivedTotalQuantity()) && item.getItemReceivedTotalQuantity().isGreaterThan(KualiDecimal.ZERO))) {
243                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_RECEIVED_TOTAL_PARTS_NON_ZERO_UNORDERED, String.valueOf(index));
244                    isNonZero = false;
245                } else if ((ObjectUtils.isNull(item.getItemReceivedTotalQuantity()) || item.getItemReceivedTotalQuantity().isZero()) && (ObjectUtils.isNotNull(item.getItemReceivedTotalParts()) && item.getItemReceivedTotalParts().isGreaterThan(KualiDecimal.ZERO))) {
246                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_RECEIVED_TOTAL_QUANTITY_NON_ZERO_UNORDERED, String.valueOf(index));
247                    isNonZero = false;
248                } else {
249                    isNonZero = true;
250                }
251                isNonZeroAll &= isNonZero;
252            }
253        }
254        return isNonZeroAll;
255    }
256
257    /**
258     * This method overrided to Add the Error Message separatly for Total Quantity Received and Total Parts Received
259     *
260     * @param receivingDocument
261     * @return
262     */
263    @Override
264    protected boolean isAtLeastOneItemEntered(ReceivingDocument receivingDocument) {
265
266        if (LOG.isDebugEnabled()) {
267            LOG.debug("Inside isAtLeastOneItemEntered of LineItemReceivingDocumentRule");
268            LOG.debug("Number of Items :" + receivingDocument.getItems().size());
269        }
270
271        LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument) receivingDocument;
272        boolean valid = false;
273        for (ReceivingItem items : (List<ReceivingItem>) receivingDocument.getItems()) {
274            if (StringUtils.equalsIgnoreCase(items.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE)) {
275                valid = true;
276                break;
277            }
278        }
279        if (valid) {
280            validateReceivedQuantityAndParts(lineItemReceivingDocument);
281        } else {
282            for (ReceivingItem item : (List<ReceivingItem>) receivingDocument.getItems()) {
283                if (((PurapEnterableItem) item).isConsideredEntered()) {
284                    // if any item is entered return true
285                    return true;
286                }
287            }
288            boolean quantity = true;
289            boolean parts = true;
290            boolean noOfQuantity=true;
291            if (!valid) {
292                valid = true;
293                for (OleReceivingItem oleItem : (List<OleReceivingItem>) receivingDocument.getItems()) {
294
295                    if ((ObjectUtils.isNull(oleItem.getItemReceivedTotalQuantity()) || oleItem.getItemReceivedTotalQuantity().isZero()) && (ObjectUtils.isNotNull(oleItem.getItemReceivedTotalParts()) && oleItem.getItemReceivedTotalParts().isGreaterThan(KualiDecimal.ZERO))) {
296                        quantity = false;
297                    } else if ((ObjectUtils.isNull(oleItem.getItemReceivedTotalParts()) || oleItem.getItemReceivedTotalParts().isZero()) && (ObjectUtils.isNotNull(oleItem.getItemReceivedTotalQuantity()) && oleItem.getItemReceivedTotalQuantity().isGreaterThan(KualiDecimal.ZERO))) {
298                        parts = false;
299                    }
300                    if((ObjectUtils.isNull(oleItem.getItemReceivedTotalQuantity()) || oleItem.getItemReceivedTotalQuantity().isZero())&&(ObjectUtils.isNull(oleItem.getItemReceivedTotalParts()) || oleItem.getItemReceivedTotalParts().isZero()))  {
301                        noOfQuantity=false;
302                    }
303                }
304                // if no items are entered return false
305                if (!quantity) {
306                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_RECEIVED_TOTAL_QUANTITY_NON_ZERO_ORDERED);
307                    quantity = true;
308                } else if (!parts) {
309                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_RECEIVED_TOTAL_PARTS_NON_ZERO_ORDERED);
310                    parts = true;
311                }
312                else if(!noOfQuantity){
313                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_ITEM_RECEIVED_TOTAL_QUANTITY);
314                }
315                /* else {
316                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_RECEIVED_TOTAL_QUANTITY_NON_ZERO_ORDERED);
317                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_RECEIVING_LINE_RECEIVED_TOTAL_PARTS_NON_ZERO_ORDERED)
318                }*/
319
320            }
321        }
322        return valid;
323    }
324
325    private boolean validateItemDescriptionRequired(LineItemReceivingDocument receivingDocument) {
326        LOG.debug("Inside isExceptionNotesMandatory of OleLineItemReceivingDocumentRule");
327        boolean isNotNull = true;
328        int index = 0;
329        for (LineItemReceivingItem item : (List<LineItemReceivingItem>) receivingDocument.getItems()) {
330            index += 1;
331            if (StringUtils.equalsIgnoreCase(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE) || StringUtils.equalsIgnoreCase(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_ITEM_CODE)) {
332                if (item.getItemDescription() == null || item.getItemDescription().trim().length() <= 0) {
333                    GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OleSelectConstant.ERROR_REQUIRED, new String("Item Line " + index));
334                    isNotNull = false;
335                }
336            }
337        }
338        return isNotNull;
339    }
340
341    public boolean processCustomLineItemReceivingDescriptionBusinessRules(Document document, OleLineItemReceivingItem lineItem) {
342        boolean validate = true;
343        if (lineItem.getItemDescription() == null || lineItem.getItemDescription().isEmpty()) {
344            GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OleSelectConstant.ERROR_REQUIRED, new String[]{"Line Item"});
345            validate = false;
346        }
347        return validate;
348    }
349
350    /**
351     * This method validates the copies entered for the line item
352     */
353    private boolean validateCopies(OleLineItemReceivingDocument receivingDocument) {
354        LOG.debug("Inside validateCopies of OleLineItemReceivingDocumentRule");
355        boolean isValid = true;
356        for (OleLineItemReceivingItem item : (List<OleLineItemReceivingItem>) receivingDocument.getItems()) {
357            KualiDecimal itemQuantity = item.getItemReceivedTotalQuantity();
358            KualiDecimal itemCopies = KualiDecimal.ZERO;
359            if (item.getCopies().size() > 0) {
360                for (OleCopies copies : item.getCopies()) {
361                    itemCopies = itemCopies.add(copies.getItemCopies());
362                }
363                if (item.getItemReceivedTotalQuantity().isGreaterThan(new KualiDecimal(1))
364                        || item.getItemReceivedTotalParts().isGreaterThan(new KualiDecimal(1))) {
365                    if (!itemQuantity.equals(itemCopies)) {
366                        GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY,
367                                OLEKeyConstants.ERROR_RECEIVING_LINE_TOTAL_COPIES_NOT_EQUAL_QUANITY);
368                        return false;
369                    }
370                }
371            } else {
372                GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY,
373                        OLEKeyConstants.ERROR_ATLEAST_ONE_COPY_SHOULD_ADD_WHEN_TOTAL_RECEIVED_COPY_IS_GREATERTHAN_ZERO);
374                return false;
375            }
376        }
377        return isValid;
378    }
379
380    /**
381     * This method validates whether total copies and total parts are lessThan or equal to quantity to be received and parts to be
382     * received
383     *
384     * @param receivingDocument
385     * @return boolean
386     */
387    private boolean checkForValidCopiesAndPartsForSubmit(OleLineItemReceivingDocument receivingDocument) {
388        LOG.debug("Inside checkForValidCopiesAndPartsForSubmit of OleLineItemReceivingDocumentRule");
389        boolean isValid = true;
390        for (OleLineItemReceivingItem item : (List<OleLineItemReceivingItem>) receivingDocument.getItems()) {
391            if (null != item.getPurchaseOrderIdentifier()) {
392                KualiDecimal itemTotalQuantity = item.getItemReceivedTotalQuantity();
393                KualiDecimal itemTotalParts = item.getItemReceivedTotalParts();
394                KualiDecimal itemQuantityToBeReceived = item.getItemReceivedToBeQuantity();
395                KualiDecimal itemPartsToBeReceived = item.getItemReceivedToBeParts();
396                if (!(itemTotalQuantity.isLessEqual(itemQuantityToBeReceived))
397                        && !(itemTotalParts.isLessEqual(itemPartsToBeReceived))) {
398                    GlobalVariables
399                            .getMessageMap()
400                            .putError(
401                                    PurapConstants.ITEM_TAB_ERROR_PROPERTY,
402                                    OLEKeyConstants.ERROR_TOTAL_COPIES_TOTAL_PARTS_SHOULDBE_LESSTHAN_OR_EQUALTO_QUANTITY_TOBE_RECEIVED_AND_PARTS_TOBE_RECEIVED);
403                    return false;
404                }
405            }
406        }
407        return isValid;
408    }
409}