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.Map;
020    
021    import javax.servlet.http.HttpServletRequest;
022    import javax.servlet.http.HttpServletResponse;
023    
024    import org.apache.commons.lang.StringUtils;
025    import org.apache.struts.action.ActionForm;
026    import org.apache.struts.action.ActionForward;
027    import org.apache.struts.action.ActionMapping;
028    import org.kuali.kfs.module.purap.PurapConstants;
029    import org.kuali.kfs.module.purap.PurapKeyConstants;
030    import org.kuali.kfs.module.purap.PurapConstants.CMDocumentsStrings;
031    import org.kuali.kfs.module.purap.document.AccountsPayableDocument;
032    import org.kuali.kfs.module.purap.document.PaymentRequestDocument;
033    import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
034    import org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument;
035    import org.kuali.kfs.module.purap.document.VendorCreditMemoDocument;
036    import org.kuali.kfs.module.purap.document.service.CreditMemoService;
037    import org.kuali.kfs.module.purap.document.service.PaymentRequestService;
038    import org.kuali.kfs.module.purap.document.service.PurapService;
039    import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
040    import org.kuali.kfs.module.purap.document.validation.event.AttributedCalculateAccountsPayableEvent;
041    import org.kuali.kfs.module.purap.document.validation.event.AttributedContinuePurapEvent;
042    import org.kuali.kfs.module.purap.util.PurQuestionCallback;
043    import org.kuali.kfs.sys.KFSConstants;
044    import org.kuali.kfs.sys.context.SpringContext;
045    import org.kuali.rice.kew.exception.WorkflowException;
046    import org.kuali.rice.kew.util.KEWConstants;
047    import org.kuali.rice.kim.util.KimConstants;
048    import org.kuali.rice.kns.document.Document;
049    import org.kuali.rice.kns.document.authorization.DocumentAuthorizer;
050    import org.kuali.rice.kns.question.ConfirmationQuestion;
051    import org.kuali.rice.kns.service.DocumentHelperService;
052    import org.kuali.rice.kns.service.KualiRuleService;
053    import org.kuali.rice.kns.util.GlobalVariables;
054    import org.kuali.rice.kns.util.KNSConstants;
055    import org.kuali.rice.kns.util.ObjectUtils;
056    import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
057    
058    /**
059     * Struts Action for Credit Memo document.
060     */
061    public class VendorCreditMemoAction extends AccountsPayableActionBase {
062        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(VendorCreditMemoAction.class);
063    
064        /**
065         * Do initialization for a new credit memo.
066         * 
067         * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
068         */
069        @Override
070        protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
071            super.createDocument(kualiDocumentFormBase);
072            ((VendorCreditMemoDocument) kualiDocumentFormBase.getDocument()).initiateDocument();
073        }
074    
075        /**
076         * Handles continue request. This request comes from the initial screen which gives indicates whether the type is payment
077         * request, purchase order, or vendor. Based on that, the credit memo is initially populated and the remaining tabs shown.
078         * 
079         * @param mapping An ActionMapping
080         * @param form An ActionForm
081         * @param request The HttpServletRequest
082         * @param response The HttpServletResponse
083         * @throws Exception
084         * @return An ActionForward
085         */
086        public ActionForward continueCreditMemo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
087            VendorCreditMemoForm cmForm = (VendorCreditMemoForm) form;
088            VendorCreditMemoDocument creditMemoDocument = (VendorCreditMemoDocument) cmForm.getDocument();
089            
090            boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedContinuePurapEvent(creditMemoDocument));
091            if (!rulePassed){
092                return mapping.findForward(KFSConstants.MAPPING_BASIC);
093            }
094            
095            if (creditMemoDocument.isSourceDocumentPaymentRequest()) {
096                PaymentRequestDocument preq = SpringContext.getBean(PaymentRequestService.class).getPaymentRequestById(creditMemoDocument.getPaymentRequestIdentifier());
097                if (ObjectUtils.isNotNull(preq)) {
098                    // 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
099                    creditMemoDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(preq.getAccountsPayablePurchasingDocumentLinkIdentifier());
100                    
101                    if (!SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(creditMemoDocument).isAuthorizedByTemplate(creditMemoDocument, KNSConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, GlobalVariables.getUserSession().getPrincipalId())) {
102                        throw buildAuthorizationException("initiate document", creditMemoDocument);
103                    }
104                }
105            }
106            else if (creditMemoDocument.isSourceDocumentPurchaseOrder()) {
107                PurchaseOrderDocument po = SpringContext.getBean(PurchaseOrderService.class).getCurrentPurchaseOrder(creditMemoDocument.getPurchaseOrderIdentifier());
108                if (ObjectUtils.isNotNull(po)) {
109                    // 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
110                    creditMemoDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(po.getAccountsPayablePurchasingDocumentLinkIdentifier());
111                    
112                    if (!SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(creditMemoDocument).isAuthorizedByTemplate(creditMemoDocument, KNSConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, GlobalVariables.getUserSession().getPrincipalId())) {
113                        throw buildAuthorizationException("initiate document", creditMemoDocument);
114                    }
115                }
116            }
117            else {
118                //do nothing for credit memos against a vendor; no link to PO means no need to hide doc based on sensitive data
119            }
120    
121    
122            // preform duplicate check which will forward to a question prompt if one is found
123            ActionForward forward = performDuplicateCreditMemoCheck(mapping, form, request, response, creditMemoDocument);
124            if (forward != null) {
125                return forward;
126            }
127    
128            // perform validation of init tab
129            SpringContext.getBean(CreditMemoService.class).populateAndSaveCreditMemo(creditMemoDocument);
130    
131            // sort below the line (doesn't really need to be done on CM, but will help if we ever bring btl from other docs)
132            SpringContext.getBean(PurapService.class).sortBelowTheLine(creditMemoDocument);
133    
134            // update the counts on the form
135            cmForm.updateItemCounts();
136    
137            //if source is (PREQ or PO) and the PO status is CLOSED, automatically reopen the PO
138            PurchaseOrderDocument po = creditMemoDocument.getPurchaseOrderDocument();
139            if ((creditMemoDocument.isSourceDocumentPaymentRequest() || creditMemoDocument.isSourceDocumentPurchaseOrder()) && PurapConstants.PurchaseOrderStatuses.CLOSED.equals(po.getStatusCode())) {
140                initiateReopenPurchaseOrder(po, cmForm.getAnnotation());
141            }
142            
143            return mapping.findForward(KFSConstants.MAPPING_BASIC);
144        }
145    
146        /**
147         * Clears out fields of the init tab.
148         * 
149         * @param mapping An ActionMapping
150         * @param form An ActionForm
151         * @param request The HttpServletRequest
152         * @param response The HttpServletResponse
153         * @throws Exception
154         * @return An ActionForward
155         */
156        public ActionForward clearInitFields(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
157            VendorCreditMemoForm cmForm = (VendorCreditMemoForm) form;
158            VendorCreditMemoDocument creditMemoDocument = (VendorCreditMemoDocument) cmForm.getDocument();
159            creditMemoDocument.clearInitFields();
160    
161            return super.refresh(mapping, form, request, response);
162        }
163    
164        /**
165         * Calls <code>CreditMemoService</code> to perform the duplicate credit memo check. If one is found, a question is setup and
166         * control is forwarded to the question action method. Coming back from the question prompt, the button that was clicked is
167         * checked, and if 'no' was selected, they are forward back to the page still in init mode.
168         * 
169         * @param mapping An ActionMapping
170         * @param form An ActionForm
171         * @param request The HttpServletRequest
172         * @param response The HttpServletResponse
173         * @param creditMemoDocument The CreditMemoDocument
174         * @throws Exception
175         * @return An ActionForward
176         * @see org.kuali.kfs.module.purap.document.service.CreditMemoService
177         */
178        protected ActionForward performDuplicateCreditMemoCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, VendorCreditMemoDocument creditMemoDocument) throws Exception {
179            ActionForward forward = null;
180            String duplicateMessage = SpringContext.getBean(CreditMemoService.class).creditMemoDuplicateMessages(creditMemoDocument);
181            if (StringUtils.isNotBlank(duplicateMessage)) {
182                Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
183                if (question == null) {
184    
185                    return this.performQuestionWithoutInput(mapping, form, request, response, PurapConstants.PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessage, KFSConstants.CONFIRMATION_QUESTION, "continueCreditMemo", "");
186                }
187    
188                Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
189                if ((PurapConstants.PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
190                    forward = mapping.findForward(KFSConstants.MAPPING_BASIC);
191                }
192            }
193    
194            return forward;
195        }
196    
197        /**
198         * Calls methods to perform credit allowed calculation and total credit memo amount.
199         * 
200         * @param apDoc An AccountsPayableDocument
201         */
202        @Override
203        protected void customCalculate(PurchasingAccountsPayableDocument apDoc) {
204            VendorCreditMemoDocument cmDocument = (VendorCreditMemoDocument) apDoc;
205    
206            // call service method to finish up calculation
207            SpringContext.getBean(CreditMemoService.class).calculateCreditMemo(cmDocument);
208            
209            // notice we're ignoring the boolean because these are just warnings they shouldn't halt anything
210            SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedCalculateAccountsPayableEvent(cmDocument));
211            // }
212        }
213    
214        /**
215         * Puts a credit memo on hold, prompting for a reason before hand. This stops further approvals or routing.
216         * 
217         * @param mapping An ActionMapping
218         * @param form An ActionForm
219         * @param request The HttpServletRequest
220         * @param response The HttpServletResponse
221         * @throws Exception
222         * @return An ActionForward
223         */
224        public ActionForward addHoldOnCreditMemo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
225            String operation = "Hold ";
226    
227            PurQuestionCallback callback = new PurQuestionCallback() {
228                public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
229                    VendorCreditMemoDocument cmDocument = SpringContext.getBean(CreditMemoService.class).addHoldOnCreditMemo((VendorCreditMemoDocument) document, noteText);
230                    return cmDocument;
231                }
232            };
233    
234            return askQuestionWithInput(mapping, form, request, response, CMDocumentsStrings.HOLD_CM_QUESTION, operation, CMDocumentsStrings.HOLD_NOTE_PREFIX, PurapKeyConstants.CREDIT_MEMO_QUESTION_HOLD_DOCUMENT, callback);
235        }
236    
237        /**
238         * Removes a hold on the credit memo.
239         * 
240         * @param mapping An ActionMapping
241         * @param form An ActionForm
242         * @param request The HttpServletRequest
243         * @param response The HttpServletResponse
244         * @throws Exception
245         * @return An ActionForward
246         */
247        public ActionForward removeHoldFromCreditMemo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
248            String operation = "Remove Hold ";
249    
250            PurQuestionCallback callback = new PurQuestionCallback() {
251                public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
252                    VendorCreditMemoDocument cmDocument = SpringContext.getBean(CreditMemoService.class).removeHoldOnCreditMemo((VendorCreditMemoDocument) document, noteText);
253                    return cmDocument;
254                }
255            };
256    
257            return askQuestionWithInput(mapping, form, request, response, CMDocumentsStrings.REMOVE_HOLD_CM_QUESTION, operation, CMDocumentsStrings.REMOVE_HOLD_NOTE_PREFIX, PurapKeyConstants.CREDIT_MEMO_QUESTION_REMOVE_HOLD_DOCUMENT, callback);
258        }
259    
260        /**
261         * @see org.kuali.kfs.module.purap.document.web.struts.AccountsPayableActionBase#cancelPOActionCallbackMethod()
262         */
263    //    @Override
264    //    protected PurQuestionCallback cancelPOActionCallbackMethod() {
265    //        return new PurQuestionCallback() {
266    //            public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
267    //                VendorCreditMemoDocument cmDocument = (VendorCreditMemoDocument) document;
268    //                cmDocument.setClosePurchaseOrderIndicator(true);
269    //                return cmDocument;
270    //            }
271    //        };
272    //    }
273    
274        /**
275         * @see org.kuali.kfs.module.purap.document.web.struts.AccountsPayableActionBase#getActionName()
276         */
277        @Override
278        public String getActionName() {
279            return PurapConstants.CREDIT_MEMO_ACTION_NAME;
280        }
281        
282        @Override
283        protected void populateAdHocActionRequestCodes(KualiDocumentFormBase formBase){
284            Document document = formBase.getDocument();
285            DocumentAuthorizer documentAuthorizer = getDocumentHelperService().getDocumentAuthorizer(document);
286            Map<String,String> adHocActionRequestCodes = new HashMap<String,String>();
287    
288            if (documentAuthorizer.canSendAdHocRequests(document, KEWConstants.ACTION_REQUEST_FYI_REQ, GlobalVariables.getUserSession().getPerson())) {
289                    adHocActionRequestCodes.put(KEWConstants.ACTION_REQUEST_FYI_REQ, KEWConstants.ACTION_REQUEST_FYI_REQ_LABEL);
290            }
291            if ( (document.getDocumentHeader().getWorkflowDocument().stateIsInitiated()
292                  || document.getDocumentHeader().getWorkflowDocument().stateIsSaved()
293                  || document.getDocumentHeader().getWorkflowDocument().stateIsEnroute()
294                  )&& documentAuthorizer.canSendAdHocRequests(document, KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, GlobalVariables.getUserSession().getPerson())) {
295                    adHocActionRequestCodes.put(KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ_LABEL);
296            } 
297            formBase.setAdHocActionRequestCodes(adHocActionRequestCodes);
298    
299        }
300    }