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.apache.commons.lang.StringUtils;
019    import org.kuali.kfs.module.purap.PurapConstants;
020    import org.kuali.kfs.module.purap.PurapKeyConstants;
021    import org.kuali.kfs.module.purap.businessobject.PurApItem;
022    import org.kuali.kfs.module.purap.businessobject.PurchasingItemBase;
023    import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
024    import org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument;
025    import org.kuali.kfs.module.purap.document.PurchasingDocument;
026    import org.kuali.kfs.module.purap.document.RequisitionDocument;
027    import org.kuali.kfs.module.purap.document.service.PurapService;
028    import org.kuali.kfs.module.purap.document.web.struts.PurchasingFormBase;
029    import org.kuali.kfs.sys.KFSConstants;
030    import org.kuali.kfs.sys.context.SpringContext;
031    import org.kuali.kfs.sys.document.AmountTotaling;
032    import org.kuali.rice.kns.document.Document;
033    import org.kuali.rice.kns.rules.PromptBeforeValidationBase;
034    import org.kuali.rice.kns.service.KualiConfigurationService;
035    import org.kuali.rice.kns.util.GlobalVariables;
036    import org.kuali.rice.kns.util.KualiDecimal;
037    import org.kuali.rice.kns.util.ObjectUtils;
038    
039    /**
040     * Business Prerules applicable to purchase order document.
041     */
042    public class PurchaseOrderDocumentPreRules extends PurchasingDocumentPreRulesBase {
043    
044        /**
045         * Overrides the method in PromptBeforeValidationBase to also invoke the confirmNotToExceedOverride if the PromptBeforeValidationEvent is
046         * blank and the question matches with the OverrideNotToExceed
047         * 
048         * @param document The purchase order document upon which we're performing the prerules logic.
049         * @return boolean true if it passes the pre rules conditions.
050         * @see org.kuali.rice.kns.rules.PromptBeforeValidationBase#doRules(org.kuali.rice.kns.document.Document)
051         */
052        @Override
053        public boolean doPrompts(Document document) {
054    
055            boolean preRulesOK = true;
056    
057            PurchaseOrderDocument purchaseOrderDocument = (PurchaseOrderDocument) document;
058    
059            if (StringUtils.isBlank(event.getQuestionContext()) || StringUtils.equals(question, PurapConstants.PO_OVERRIDE_NOT_TO_EXCEED_QUESTION)) {
060                preRulesOK &= confirmNotToExceedOverride(purchaseOrderDocument);
061            }
062            
063            if (isDocumentInStateToReceiveNextFyWarning(purchaseOrderDocument) && 
064                    (StringUtils.isBlank(event.getQuestionContext()) || StringUtils.equals(question, PurapConstants.PO_NEXT_FY_WARNING))) {
065                preRulesOK &= confirmNextFYPriorToApoAllowedDate(purchaseOrderDocument);
066            }
067            
068            if (!purchaseOrderDocument.isUseTaxIndicator()){
069                preRulesOK &= checkForTaxRecalculation(purchaseOrderDocument);
070            }
071            
072            return preRulesOK;
073        }
074        
075        /**
076         * Give next FY warning if the PO status is "In Process" or "Awaiting Purchasing Review"
077         * 
078         * @param poDocument
079         * @return boolean
080         */
081        protected boolean isDocumentInStateToReceiveNextFyWarning(PurchaseOrderDocument poDocument){
082            return (PurapConstants.PurchaseOrderStatuses.IN_PROCESS.equals(poDocument.getStatusCode()) ||
083                    PurapConstants.PurchaseOrderStatuses.AWAIT_PURCHASING_REVIEW.equals(poDocument.getStatusCode()));
084        }
085    
086        /**
087         * Checks whether the 'Not-to-exceed' amount has been exceeded by the purchase order total dollar limit. If so, it
088         * prompts the user for confirmation.
089         * 
090         * @param purchaseOrderDocument The current PurchaseOrderDocument
091         * @return True if the 'Not-to-exceed' amount is to be overridden or if the total dollar amount is less than the purchase order
092         *         total dollar limit.
093         */
094        protected boolean confirmNotToExceedOverride(PurchaseOrderDocument purchaseOrderDocument) {
095    
096            // If the total exceeds the limit, ask for confirmation.
097            if (!validateTotalDollarAmountIsLessThanPurchaseOrderTotalLimit(purchaseOrderDocument)) {
098                String questionText = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_OVERRIDE_NOT_TO_EXCEED);
099    
100                boolean confirmOverride = super.askOrAnalyzeYesNoQuestion(PurapConstants.PO_OVERRIDE_NOT_TO_EXCEED_QUESTION, questionText);
101    
102                // Set a marker to record that this method has been used.
103                if (confirmOverride && StringUtils.isBlank(event.getQuestionContext())) {
104                    event.setQuestionContext(PurapConstants.PO_OVERRIDE_NOT_TO_EXCEED_QUESTION);
105                }
106    
107                if (!confirmOverride) {
108                    event.setActionForwardName(KFSConstants.MAPPING_BASIC);
109    
110                    return false;
111                }
112            }
113    
114            return true;
115        }
116    
117        /**
118         * Validate that if the PurchaseOrderTotalLimit is not null then the TotalDollarAmount cannot be greater than the
119         * PurchaseOrderTotalLimit.
120         * 
121         * @param purDocument The purchase order document to be validated.
122         * @return True if the TotalDollarAmount is less than the PurchaseOrderTotalLimit. False otherwise.
123         */
124        public boolean validateTotalDollarAmountIsLessThanPurchaseOrderTotalLimit(PurchasingDocument purDocument) {
125            boolean valid = true;
126            if (ObjectUtils.isNotNull(purDocument.getPurchaseOrderTotalLimit()) && ObjectUtils.isNotNull(((AmountTotaling) purDocument).getTotalDollarAmount())) {
127                KualiDecimal totalAmount = ((AmountTotaling) purDocument).getTotalDollarAmount();
128                if (((AmountTotaling) purDocument).getTotalDollarAmount().isGreaterThan(purDocument.getPurchaseOrderTotalLimit())) {
129                    valid &= false;
130                    GlobalVariables.getMessageList().add(PurapKeyConstants.PO_TOTAL_GREATER_THAN_PO_TOTAL_LIMIT);
131                }
132            }
133    
134            return valid;
135        }
136    
137        /**
138         * If the PO is set to encumber in the next fiscal year and the PO is created before the APO allowed date, then give the user a
139         * warning that this might be a mistake. Prompt the user for confirmation that the year is set correctly both at submit and upon
140         * approval at the Purchasing Internal Review route level.
141         * 
142         * @param purchaseOrderDocument The current PurchaseOrderDocument
143         * @return True if the user wants to continue with PO routing; False to send the user back to the PO for editing.
144         */
145        protected boolean confirmNextFYPriorToApoAllowedDate(PurchaseOrderDocument poDocument) {
146    
147            // If the FY is set to NEXT and today is not within APO allowed range, ask for confirmation to continue
148            if (poDocument.isPostingYearNext() && !SpringContext.getBean(PurapService.class).isTodayWithinApoAllowedRange()) {
149                String questionText = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(PurapKeyConstants.WARNING_PURCHASE_ORDER_ENCUMBER_NEXT_FY);
150                boolean confirmOverride = super.askOrAnalyzeYesNoQuestion(PurapConstants.PO_NEXT_FY_WARNING, questionText);
151    
152                // Set a marker to record that this method has been used.
153                if (confirmOverride && StringUtils.isBlank(event.getQuestionContext())) {
154                    event.setQuestionContext(PurapConstants.PO_NEXT_FY_WARNING);
155    }
156                if (!confirmOverride) {
157                    event.setActionForwardName(KFSConstants.MAPPING_BASIC);
158                    return false;
159                }
160            }
161    
162            return true;
163        }
164    
165        @Override
166        protected boolean checkCAMSWarningStatus(PurchasingAccountsPayableDocument purapDocument) {
167            return PurapConstants.CAMSWarningStatuses.PURCHASEORDER_STATUS_WARNING_NO_CAMS_DATA.contains(purapDocument.getStatusCode());
168        }
169        
170    }