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.web.struts;
017    
018    import java.util.HashMap;
019    import java.util.List;
020    import java.util.Properties;
021    
022    import javax.servlet.http.HttpServletRequest;
023    import javax.servlet.http.HttpServletResponse;
024    
025    import org.apache.commons.lang.StringUtils;
026    import org.apache.struts.action.ActionForm;
027    import org.apache.struts.action.ActionForward;
028    import org.apache.struts.action.ActionMapping;
029    import org.kuali.kfs.module.purap.PurapConstants;
030    import org.kuali.kfs.module.purap.PurapKeyConstants;
031    import org.kuali.kfs.module.purap.PurapPropertyConstants;
032    import org.kuali.kfs.module.purap.PurapConstants.CorrectionReceivingDocumentStrings;
033    import org.kuali.kfs.module.purap.PurapConstants.PREQDocumentsStrings;
034    import org.kuali.kfs.module.purap.businessobject.LineItemReceivingItem;
035    import org.kuali.kfs.module.purap.document.LineItemReceivingDocument;
036    import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
037    import org.kuali.kfs.module.purap.document.ReceivingDocument;
038    import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
039    import org.kuali.kfs.module.purap.document.service.ReceivingService;
040    import org.kuali.kfs.module.purap.document.validation.event.AddReceivingItemEvent;
041    import org.kuali.kfs.module.purap.util.ReceivingQuestionCallback;
042    import org.kuali.kfs.sys.KFSConstants;
043    import org.kuali.kfs.sys.KFSKeyConstants;
044    import org.kuali.kfs.sys.KFSPropertyConstants;
045    import org.kuali.kfs.sys.context.SpringContext;
046    import org.kuali.rice.kew.exception.WorkflowException;
047    import org.kuali.rice.kim.util.KimConstants;
048    import org.kuali.rice.kns.question.ConfirmationQuestion;
049    import org.kuali.rice.kns.service.DocumentHelperService;
050    import org.kuali.rice.kns.service.KualiRuleService;
051    import org.kuali.rice.kns.util.GlobalVariables;
052    import org.kuali.rice.kns.util.KNSConstants;
053    import org.kuali.rice.kns.util.KualiDecimal;
054    import org.kuali.rice.kns.util.ObjectUtils;
055    import org.kuali.rice.kns.util.UrlFactory;
056    import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
057    
058    public class LineItemReceivingAction extends ReceivingBaseAction {
059    
060        protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {       
061            
062            super.createDocument(kualiDocumentFormBase);
063    
064            LineItemReceivingForm rlf = (LineItemReceivingForm)kualiDocumentFormBase;
065            LineItemReceivingDocument rlDoc = (LineItemReceivingDocument)rlf.getDocument();
066            
067            //set identifier from form value
068            rlDoc.setPurchaseOrderIdentifier( rlf.getPurchaseOrderId() );
069            
070            rlDoc.initiateDocument();
071            
072        }
073    
074        public ActionForward continueReceivingLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
075            LineItemReceivingForm rlf = (LineItemReceivingForm)form;
076            LineItemReceivingDocument rlDoc = (LineItemReceivingDocument)rlf.getDocument();
077            
078            GlobalVariables.getMessageMap().clearErrorPath();
079            GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.DOCUMENT);
080            boolean valid = true;
081            boolean poNotNull = true;
082            
083            //check for a po id
084            if (ObjectUtils.isNull(rlDoc.getPurchaseOrderIdentifier())) {
085                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, KFSKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.PURCHASE_ORDER_ID);
086                poNotNull = false;
087            }
088    
089            if (ObjectUtils.isNull(rlDoc.getShipmentReceivedDate())) {
090                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.SHIPMENT_RECEIVED_DATE, KFSKeyConstants.ERROR_REQUIRED, PurapConstants.LineItemReceivingDocumentStrings.VENDOR_DATE);            
091            }
092    
093            //exit early as the po is null, no need to proceed further until this is taken care of
094            if(poNotNull == false){
095                return mapping.findForward(KFSConstants.MAPPING_BASIC);
096            }
097            
098            PurchaseOrderDocument po = SpringContext.getBean(PurchaseOrderService.class).getCurrentPurchaseOrder(rlDoc.getPurchaseOrderIdentifier());
099            if (ObjectUtils.isNotNull(po)) {
100                // TODO figure out a more straightforward way to do this.  ailish put this in so the link id would be set and the perm check would work
101                rlDoc.setAccountsPayablePurchasingDocumentLinkIdentifier(po.getAccountsPayablePurchasingDocumentLinkIdentifier());
102    
103                //TODO hjs-check to see if user is allowed to initiate doc based on PO sensitive data (add this to all other docs except acm doc)
104                if (!SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(rlDoc).isAuthorizedByTemplate(rlDoc, KNSConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, GlobalVariables.getUserSession().getPrincipalId())) {
105                    throw buildAuthorizationException("initiate document", rlDoc);
106                }
107            }else{
108                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_PURCHASE_ORDER_NOT_EXIST);
109                return mapping.findForward(KFSConstants.MAPPING_BASIC);
110            }
111            
112            //perform duplicate check
113            ActionForward forward = performDuplicateReceivingLineCheck(mapping, form, request, response, rlDoc);
114            if( forward != null ){
115                return forward;
116            }
117                    
118            if (!SpringContext.getBean(ReceivingService.class).isPurchaseOrderActiveForLineItemReceivingDocumentCreation(rlDoc.getPurchaseOrderIdentifier())){
119                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_RECEIVING_LINE_DOCUMENT_PO_NOT_ACTIVE, rlDoc.getPurchaseOrderIdentifier().toString());
120                valid &= false;
121            }
122    
123            if( SpringContext.getBean(ReceivingService.class).canCreateLineItemReceivingDocument(rlDoc.getPurchaseOrderIdentifier(), rlDoc.getDocumentNumber()) == false){
124                String inProcessDocNum = "";
125                List<String> inProcessDocNumbers = SpringContext.getBean(ReceivingService.class).getLineItemReceivingDocumentNumbersInProcessForPurchaseOrder(rlDoc.getPurchaseOrderIdentifier(), rlDoc.getDocumentNumber());
126                if (!inProcessDocNumbers.isEmpty()) {    // should not be empty if we reach this point
127                    inProcessDocNum = inProcessDocNumbers.get(0);
128                }
129                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_RECEIVING_LINE_DOCUMENT_ACTIVE_FOR_PO, inProcessDocNum, rlDoc.getPurchaseOrderIdentifier().toString());
130                valid &= false;
131            }
132            
133            //populate and save Receiving Line Document from Purchase Order, only if we passed all the rules
134            if(valid){
135                SpringContext.getBean(ReceivingService.class).populateAndSaveLineItemReceivingDocument(rlDoc);
136            }
137            
138            return mapping.findForward(KFSConstants.MAPPING_BASIC);
139        }
140            
141        public ActionForward createReceivingCorrection(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
142            LineItemReceivingForm rlForm = (LineItemReceivingForm) form;
143            LineItemReceivingDocument document = (LineItemReceivingDocument) rlForm.getDocument();        
144            
145            String operation = "AddCorrectionNote ";
146    
147            ReceivingQuestionCallback callback = new ReceivingQuestionCallback() {
148                public boolean questionComplete = false;
149                protected String correctionDocumentnoteText;
150                
151                public ReceivingDocument doPostQuestion(ReceivingDocument document, String noteText) throws Exception {
152                    //mark question completed
153                    this.setQuestionComplete(true);
154                    this.setCorrectionDocumentCreationNoteText(noteText);
155                    return document;
156                }
157                
158                public boolean isQuestionComplete(){
159                    return this.questionComplete;
160                }
161                
162                public void setQuestionComplete(boolean questionComplete){
163                    this.questionComplete = questionComplete;
164                }
165    
166                public String getCorrectionDocumentCreationNoteText() {
167                    return correctionDocumentnoteText;
168                }
169    
170                public void setCorrectionDocumentCreationNoteText(String noteText) {
171                    correctionDocumentnoteText = noteText;
172                }
173            };
174    
175            //ask question
176            ActionForward forward = askQuestionWithInput(mapping, form, request, response, CorrectionReceivingDocumentStrings.NOTE_QUESTION, CorrectionReceivingDocumentStrings.NOTE_PREFIX, operation, PurapKeyConstants.MESSAGE_RECEIVING_CORRECTION_NOTE, callback);
177            
178            //if question asked is complete, then route
179            if(callback.isQuestionComplete()){
180                                
181                //set parameters
182                String basePath = getBasePath(request);
183                String methodToCallDocHandler = "docHandler";
184                String methodToCallReceivingCorrection = "initiate";
185                
186                Properties parameters = new Properties();
187                parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, methodToCallDocHandler);
188                parameters.put(KFSConstants.PARAMETER_COMMAND, methodToCallReceivingCorrection);
189                parameters.put(KFSConstants.DOCUMENT_TYPE_NAME, "RCVC");        
190                parameters.put("receivingLineDocId", document.getDocumentHeader().getDocumentNumber() );
191                parameters.put(PurapConstants.CorrectionReceivingDocumentStrings.CORRECTION_RECEIVING_CREATION_NOTE_PARAMETER, callback.getCorrectionDocumentCreationNoteText());
192                
193                //create url
194                String receivingCorrectionUrl = UrlFactory.parameterizeUrl(basePath + "/" + "purapCorrectionReceiving.do", parameters);
195                //create forward
196                forward = new ActionForward(receivingCorrectionUrl, true);
197            }
198            
199            return forward;
200            
201        }
202    
203        public ActionForward clearInitFields(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
204            LineItemReceivingForm rlForm = (LineItemReceivingForm) form;
205            LineItemReceivingDocument rlDocument = (LineItemReceivingDocument) rlForm.getDocument();
206            rlDocument.clearInitFields(rlForm.isFromPurchaseOrder());
207    
208            return mapping.findForward(KFSConstants.MAPPING_BASIC);
209        }
210    
211        protected ActionForward performDuplicateReceivingLineCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, LineItemReceivingDocument lineItemReceivingDocument) throws Exception {
212            ActionForward forward = null;
213            HashMap<String, String> duplicateMessages = SpringContext.getBean(ReceivingService.class).receivingLineDuplicateMessages(lineItemReceivingDocument);
214            if (duplicateMessages != null && !duplicateMessages.isEmpty()) {
215                Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
216                if (question == null) {
217    
218                    return this.performQuestionWithoutInput(mapping, form, request, response, PurapConstants.LineItemReceivingDocumentStrings.DUPLICATE_RECEIVING_LINE_QUESTION, duplicateMessages.get(PurapConstants.LineItemReceivingDocumentStrings.DUPLICATE_RECEIVING_LINE_QUESTION), KFSConstants.CONFIRMATION_QUESTION, KFSConstants.ROUTE_METHOD, "");
219                }
220    
221                Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
222                if ((PurapConstants.LineItemReceivingDocumentStrings.DUPLICATE_RECEIVING_LINE_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {                
223                    forward = mapping.findForward(KFSConstants.MAPPING_BASIC);
224                }
225            }
226    
227            return forward;
228        }
229        /**
230         * Add a new item to the document.
231         * 
232         * @param mapping An ActionMapping
233         * @param form An ActionForm
234         * @param request The HttpServletRequest
235         * @param response The HttpServletResponse
236         * @throws Exception
237         * @return An ActionForward
238         */
239        public ActionForward addItem(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
240            LineItemReceivingForm lineItemReceivingForm = (LineItemReceivingForm) form;
241            LineItemReceivingItem item = lineItemReceivingForm.getNewLineItemReceivingItemLine();
242            LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument) lineItemReceivingForm.getDocument();
243            boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddReceivingItemEvent(PurapPropertyConstants.NEW_LINE_ITEM_RECEIVING_ITEM_LINE, lineItemReceivingDocument, item));
244    
245            if (rulePassed) {
246                item = lineItemReceivingForm.getAndResetNewReceivingItemLine();                       
247                lineItemReceivingDocument.addItem(item);                       
248                //TODO: we need to set the line number correctly to match up to PO
249            }
250    
251            return mapping.findForward(KFSConstants.MAPPING_BASIC);
252        }
253    
254        /**
255         * For each item, it's quantity received value is set to zero. 
256         * 
257         * @param mapping
258         * @param form
259         * @param request
260         * @param response
261         * @return
262         * @throws Exception
263         */
264        public ActionForward clearQty(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
265            LineItemReceivingForm lineItemReceivingForm = (LineItemReceivingForm) form;
266    
267            LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument) lineItemReceivingForm.getDocument();
268            
269            for(LineItemReceivingItem item : (List <LineItemReceivingItem>)lineItemReceivingDocument.getItems()){
270                item.setItemReceivedTotalQuantity(KualiDecimal.ZERO);
271            }
272            
273            return mapping.findForward(KFSConstants.MAPPING_BASIC);
274        }
275        
276        /**
277         * For each item, loads total order quantity minus prior received quantity into total received quantity.
278         * 
279         * @param mapping
280         * @param form
281         * @param request
282         * @param response
283         * @return
284         * @throws Exception
285         */
286        public ActionForward loadQty(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
287            LineItemReceivingForm lineItemReceivingForm = (LineItemReceivingForm) form;
288    
289            LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument) lineItemReceivingForm.getDocument();
290    
291            for(LineItemReceivingItem item : (List <LineItemReceivingItem>)lineItemReceivingDocument.getItems()){
292                if (item.isOrderedItem()){
293                    if( item.getItemOrderedQuantity().subtract(item.getItemReceivedPriorQuantity()).isGreaterEqual(KualiDecimal.ZERO)  ){
294                        item.setItemReceivedTotalQuantity( item.getItemOrderedQuantity().subtract(item.getItemReceivedPriorQuantity()) );
295                    }else{
296                        item.setItemReceivedTotalQuantity(KualiDecimal.ZERO);
297                    }
298                }
299            }
300    
301            return mapping.findForward(KFSConstants.MAPPING_BASIC);
302        }
303    
304    }