View Javadoc
1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.module.purap.document.web.struts;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.struts.action.ActionForm;
20  import org.apache.struts.action.ActionForward;
21  import org.apache.struts.action.ActionMapping;
22  import org.kuali.ole.module.purap.PurapConstants;
23  import org.kuali.ole.module.purap.PurapConstants.CMDocumentsStrings;
24  import org.kuali.ole.module.purap.PurapKeyConstants;
25  import org.kuali.ole.module.purap.businessobject.PurApAccountingLine;
26  import org.kuali.ole.module.purap.businessobject.PurApItem;
27  import org.kuali.ole.module.purap.document.*;
28  import org.kuali.ole.module.purap.document.service.CreditMemoService;
29  import org.kuali.ole.module.purap.document.service.PaymentRequestService;
30  import org.kuali.ole.module.purap.document.service.PurapService;
31  import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
32  import org.kuali.ole.module.purap.document.validation.event.AttributedCalculateAccountsPayableEvent;
33  import org.kuali.ole.module.purap.document.validation.event.AttributedContinuePurapEvent;
34  import org.kuali.ole.module.purap.util.PurQuestionCallback;
35  import org.kuali.ole.sys.OLEConstants;
36  import org.kuali.ole.sys.context.SpringContext;
37  import org.kuali.rice.core.api.util.type.KualiDecimal;
38  import org.kuali.rice.kew.api.KewApiConstants;
39  import org.kuali.rice.kew.api.exception.WorkflowException;
40  import org.kuali.rice.kim.api.KimConstants;
41  import org.kuali.rice.kns.document.authorization.DocumentAuthorizer;
42  import org.kuali.rice.kns.question.ConfirmationQuestion;
43  import org.kuali.rice.kns.service.DocumentHelperService;
44  import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
45  import org.kuali.rice.krad.document.Document;
46  import org.kuali.rice.krad.service.KualiRuleService;
47  import org.kuali.rice.krad.util.GlobalVariables;
48  import org.kuali.rice.krad.util.KRADConstants;
49  import org.kuali.rice.krad.util.ObjectUtils;
50  
51  import javax.servlet.http.HttpServletRequest;
52  import javax.servlet.http.HttpServletResponse;
53  import java.util.HashMap;
54  import java.util.List;
55  import java.util.Map;
56  
57  /**
58   * Struts Action for Credit Memo document.
59   */
60  public class VendorCreditMemoAction extends AccountsPayableActionBase {
61      protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(VendorCreditMemoAction.class);
62  
63      /**
64       * Do initialization for a new credit memo.
65       *
66       * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
67       */
68      @Override
69      protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
70          super.createDocument(kualiDocumentFormBase);
71          ((VendorCreditMemoDocument) kualiDocumentFormBase.getDocument()).initiateDocument();
72      }
73  
74      /**
75       * Handles continue request. This request comes from the initial screen which gives indicates whether the type is payment
76       * request, purchase order, or vendor. Based on that, the credit memo is initially populated and the remaining tabs shown.
77       *
78       * @param mapping  An ActionMapping
79       * @param form     An ActionForm
80       * @param request  The HttpServletRequest
81       * @param response The HttpServletResponse
82       * @return An ActionForward
83       * @throws Exception
84       */
85      public ActionForward continueCreditMemo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
86          VendorCreditMemoForm cmForm = (VendorCreditMemoForm) form;
87          VendorCreditMemoDocument creditMemoDocument = (VendorCreditMemoDocument) cmForm.getDocument();
88  
89          // OLE-3405 : disabling the distribution method choice
90  //        String defaultDistributionMethod = SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurapConstants.PURAP_NAMESPACE, "Document", PurapParameterConstants.DISTRIBUTION_METHOD_FOR_ACCOUNTING_LINES);
91  //
92  //        String preqId = request.getParameter("document.paymentRequestIdentifier");
93  //        if (! StringUtils.isEmpty(preqId)) {
94  //            //get the po document and get the account distribution method code....
95  //            String distributionCode = getDistributionMethodFromPReq(preqId);
96  //            if (ObjectUtils.isNotNull(distributionCode)) {
97  //                defaultDistributionMethod = distributionCode;
98  //            }
99  //        } else {
100 //            String poId = request.getParameter("document.purchaseOrderIdentifier");
101 //            if (! StringUtils.isEmpty(poId)) {
102 //                //get the po document and get the account distribution method code....
103 //                String distributionCode = getDistributionMethodFromPO(poId);
104 //                if (ObjectUtils.isNotNull(distributionCode)) {
105 //                    defaultDistributionMethod = distributionCode;
106 //                }
107 //            }
108 //        }
109 //
110 //        //set the account distribution method code on the document.
111 //        creditMemoDocument.setAccountDistributionMethod(defaultDistributionMethod);
112 
113         boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedContinuePurapEvent(creditMemoDocument));
114         if (!rulePassed) {
115             return mapping.findForward(OLEConstants.MAPPING_BASIC);
116         }
117 
118         if (creditMemoDocument.isSourceDocumentPaymentRequest()) {
119             PaymentRequestDocument preq = SpringContext.getBean(PaymentRequestService.class).getPaymentRequestById(creditMemoDocument.getPaymentRequestIdentifier());
120             if (ObjectUtils.isNotNull(preq)) {
121                 // 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
122                 creditMemoDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(preq.getAccountsPayablePurchasingDocumentLinkIdentifier());
123 
124                 if (!SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(creditMemoDocument).isAuthorizedByTemplate(creditMemoDocument, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, GlobalVariables.getUserSession().getPrincipalId())) {
125                     throw buildAuthorizationException("initiate document", creditMemoDocument);
126                 }
127             }
128         } else if (creditMemoDocument.isSourceDocumentPurchaseOrder()) {
129             PurchaseOrderDocument po = SpringContext.getBean(PurchaseOrderService.class).getCurrentPurchaseOrder(creditMemoDocument.getPurchaseOrderIdentifier());
130             if (ObjectUtils.isNotNull(po)) {
131                 // 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
132                 creditMemoDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(po.getAccountsPayablePurchasingDocumentLinkIdentifier());
133 
134                 if (!SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(creditMemoDocument).isAuthorizedByTemplate(creditMemoDocument, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, GlobalVariables.getUserSession().getPrincipalId())) {
135                     throw buildAuthorizationException("initiate document", creditMemoDocument);
136                 }
137             }
138         } else {
139             //do nothing for credit memos against a vendor; no link to PO means no need to hide doc based on sensitive data
140         }
141 
142 
143         // preform duplicate check which will forward to a question prompt if one is found
144         ActionForward forward = performDuplicateCreditMemoCheck(mapping, form, request, response, creditMemoDocument);
145         if (forward != null) {
146             return forward;
147         }
148 
149         // perform validation of init tab
150         SpringContext.getBean(CreditMemoService.class).populateAndSaveCreditMemo(creditMemoDocument);
151 
152         // sort below the line (doesn't really need to be done on CM, but will help if we ever bring btl from other docs)
153         SpringContext.getBean(PurapService.class).sortBelowTheLine(creditMemoDocument);
154 
155         // update the counts on the form
156         cmForm.updateItemCounts();
157 
158         //if source is (PREQ or PO) and the PO status is CLOSED, automatically reopen the PO
159         PurchaseOrderDocument po = creditMemoDocument.getPurchaseOrderDocument();
160         if ((creditMemoDocument.isSourceDocumentPaymentRequest() || creditMemoDocument.isSourceDocumentPurchaseOrder()) && PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED.equals(po.getApplicationDocumentStatus())) {
161             initiateReopenPurchaseOrder(po, cmForm.getAnnotation());
162         }
163 
164         // update the accounts amounts to zero.  The recalculate will calculate the totals...
165         List<PurApItem> items = creditMemoDocument.getItems();
166 
167         for (PurApItem item : items) {
168             for (PurApAccountingLine accountLine : item.getSourceAccountingLines()) {
169                 accountLine.setAmount(KualiDecimal.ZERO);
170             }
171         }
172 
173         return mapping.findForward(OLEConstants.MAPPING_BASIC);
174     }
175 
176 //    /**
177 //     * using preqId from vendor credit memo initiation screen, the corresponding
178 //     * preq documents are collected and then the distribution menthod is retrieved from it..
179 //     *
180 //     * @param preqId
181 //     * @return distributionMethod
182 //     */
183 //    protected String getDistributionMethodFromPReq(String preqId) {
184 //        String distributionMethod = "";
185 //
186 //        Map criteria = new HashMap();
187 //        criteria.put("purapDocumentIdentifier", preqId);
188 //
189 //        List<PaymentRequestDocument> preqDocuments = (List<PaymentRequestDocument>)SpringContext.getBean(BusinessObjectService.class).findMatching(PaymentRequestDocument.class, criteria);
190 //
191 //        for (PaymentRequestDocument preqDoc : preqDocuments) {
192 //            if (ObjectUtils.isNotNull(preqDoc.getAccountDistributionMethod())) {
193 //                distributionMethod = preqDoc.getAccountDistributionMethod();
194 //                return distributionMethod;
195 //            }
196 //        }
197 //
198 //        return distributionMethod;
199 //    }
200 //
201 //    /**
202 //     * using poId from vendor credit memo initiation screen, the corresponding
203 //     * po documents are collected and then the distribution menthod is retrieved from it..
204 //     *
205 //     * @param preqId
206 //     * @return distributionMethod
207 //     */
208 //    protected String getDistributionMethodFromPO(String poId) {
209 //        String distributionMethod = "";
210 //
211 //        Map criteria = new HashMap();
212 //        criteria.put("purapDocumentIdentifier", poId);
213 //
214 //        List<PurchaseOrderDocument> poDocuments = (List<PurchaseOrderDocument>)SpringContext.getBean(BusinessObjectService.class).findMatching(PurchaseOrderDocument.class, criteria);
215 //
216 //        for (PurchaseOrderDocument poDoc : poDocuments) {
217 //            if (ObjectUtils.isNotNull(poDoc.getAccountDistributionMethod())) {
218 //                distributionMethod = poDoc.getAccountDistributionMethod();
219 //                return distributionMethod;
220 //            }
221 //        }
222 //
223 //        return distributionMethod;
224 //    }
225 
226     /**
227      * Clears out fields of the init tab.
228      *
229      * @param mapping  An ActionMapping
230      * @param form     An ActionForm
231      * @param request  The HttpServletRequest
232      * @param response The HttpServletResponse
233      * @return An ActionForward
234      * @throws Exception
235      */
236     public ActionForward clearInitFields(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
237         VendorCreditMemoForm cmForm = (VendorCreditMemoForm) form;
238         VendorCreditMemoDocument creditMemoDocument = (VendorCreditMemoDocument) cmForm.getDocument();
239         creditMemoDocument.clearInitFields();
240 
241         return super.refresh(mapping, form, request, response);
242     }
243 
244     /**
245      * Calls <code>CreditMemoService</code> to perform the duplicate credit memo check. If one is found, a question is setup and
246      * control is forwarded to the question action method. Coming back from the question prompt, the button that was clicked is
247      * checked, and if 'no' was selected, they are forward back to the page still in init mode.
248      *
249      * @param mapping            An ActionMapping
250      * @param form               An ActionForm
251      * @param request            The HttpServletRequest
252      * @param response           The HttpServletResponse
253      * @param creditMemoDocument The CreditMemoDocument
254      * @return An ActionForward
255      * @throws Exception
256      * @see org.kuali.ole.module.purap.document.service.CreditMemoService
257      */
258     protected ActionForward performDuplicateCreditMemoCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, VendorCreditMemoDocument creditMemoDocument) throws Exception {
259         ActionForward forward = null;
260         String duplicateMessage = SpringContext.getBean(CreditMemoService.class).creditMemoDuplicateMessages(creditMemoDocument);
261         if (StringUtils.isNotBlank(duplicateMessage)) {
262             Object question = request.getParameter(OLEConstants.QUESTION_INST_ATTRIBUTE_NAME);
263             if (question == null) {
264 
265                 return this.performQuestionWithoutInput(mapping, form, request, response, PurapConstants.PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessage, OLEConstants.CONFIRMATION_QUESTION, "continueCreditMemo", "");
266             }
267 
268             Object buttonClicked = request.getParameter(OLEConstants.QUESTION_CLICKED_BUTTON);
269             if ((PurapConstants.PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
270                 forward = mapping.findForward(OLEConstants.MAPPING_BASIC);
271             }
272         }
273 
274         return forward;
275     }
276 
277     /**
278      * Calls methods to perform credit allowed calculation and total credit memo amount.
279      *
280      * @param apDoc An AccountsPayableDocument
281      */
282     @Override
283     protected void customCalculate(PurchasingAccountsPayableDocument apDoc) {
284         VendorCreditMemoDocument cmDocument = (VendorCreditMemoDocument) apDoc;
285 
286         // call service method to finish up calculation
287         SpringContext.getBean(CreditMemoService.class).calculateCreditMemo(cmDocument);
288 
289         // notice we're ignoring the boolean because these are just warnings they shouldn't halt anything
290         SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedCalculateAccountsPayableEvent(cmDocument));
291         // }
292     }
293 
294     /**
295      * Puts a credit memo on hold, prompting for a reason before hand. This stops further approvals or routing.
296      *
297      * @param mapping  An ActionMapping
298      * @param form     An ActionForm
299      * @param request  The HttpServletRequest
300      * @param response The HttpServletResponse
301      * @return An ActionForward
302      * @throws Exception
303      */
304     public ActionForward addHoldOnCreditMemo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
305         String operation = "Hold ";
306 
307         PurQuestionCallback callback = new PurQuestionCallback() {
308             @Override
309             public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
310                 VendorCreditMemoDocument cmDocument = SpringContext.getBean(CreditMemoService.class).addHoldOnCreditMemo((VendorCreditMemoDocument) document, noteText);
311                 return cmDocument;
312             }
313         };
314 
315         return askQuestionWithInput(mapping, form, request, response, CMDocumentsStrings.HOLD_CM_QUESTION, operation, CMDocumentsStrings.HOLD_NOTE_PREFIX, PurapKeyConstants.CREDIT_MEMO_QUESTION_HOLD_DOCUMENT, callback);
316     }
317 
318     /**
319      * Removes a hold on the credit memo.
320      *
321      * @param mapping  An ActionMapping
322      * @param form     An ActionForm
323      * @param request  The HttpServletRequest
324      * @param response The HttpServletResponse
325      * @return An ActionForward
326      * @throws Exception
327      */
328     public ActionForward removeHoldFromCreditMemo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
329         String operation = "Remove Hold ";
330 
331         PurQuestionCallback callback = new PurQuestionCallback() {
332             @Override
333             public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
334                 VendorCreditMemoDocument cmDocument = SpringContext.getBean(CreditMemoService.class).removeHoldOnCreditMemo((VendorCreditMemoDocument) document, noteText);
335                 return cmDocument;
336             }
337         };
338 
339         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);
340     }
341 
342     /**
343      * @see org.kuali.ole.module.purap.document.web.struts.AccountsPayableActionBase#cancelPOActionCallbackMethod()
344      */
345 //    @Override
346 //    protected PurQuestionCallback cancelPOActionCallbackMethod() {
347 //        return new PurQuestionCallback() {
348 //            public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
349 //                VendorCreditMemoDocument cmDocument = (VendorCreditMemoDocument) document;
350 //                cmDocument.setClosePurchaseOrderIndicator(true);
351 //                return cmDocument;
352 //            }
353 //        };
354 //    }
355 
356     /**
357      * @see org.kuali.ole.module.purap.document.web.struts.AccountsPayableActionBase#getActionName()
358      */
359     @Override
360     public String getActionName() {
361         return PurapConstants.CREDIT_MEMO_ACTION_NAME;
362     }
363 
364     @Override
365     protected void populateAdHocActionRequestCodes(KualiDocumentFormBase formBase) {
366         Document document = formBase.getDocument();
367         DocumentAuthorizer documentAuthorizer = getDocumentHelperService().getDocumentAuthorizer(document);
368         Map<String, String> adHocActionRequestCodes = new HashMap<String, String>();
369 
370         if (documentAuthorizer.canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, GlobalVariables.getUserSession().getPerson())) {
371             adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL);
372         }
373         if ((document.getDocumentHeader().getWorkflowDocument().isInitiated()
374                 || document.getDocumentHeader().getWorkflowDocument().isSaved()
375                 || document.getDocumentHeader().getWorkflowDocument().isEnroute()
376         ) && documentAuthorizer.canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, GlobalVariables.getUserSession().getPerson())) {
377             adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ_LABEL);
378         }
379         formBase.setAdHocActionRequestCodes(adHocActionRequestCodes);
380 
381     }
382 }