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.io.ByteArrayOutputStream;
019    import java.sql.Date;
020    import java.util.ArrayList;
021    import java.util.Calendar;
022    import java.util.HashMap;
023    import java.util.List;
024    import java.util.Map;
025    import java.util.Properties;
026    import java.util.StringTokenizer;
027    
028    import javax.servlet.ServletOutputStream;
029    import javax.servlet.http.HttpServletRequest;
030    import javax.servlet.http.HttpServletResponse;
031    
032    import org.apache.commons.lang.StringUtils;
033    import org.apache.struts.action.ActionForm;
034    import org.apache.struts.action.ActionForward;
035    import org.apache.struts.action.ActionMapping;
036    import org.apache.struts.action.ActionMessage;
037    import org.apache.struts.action.ActionMessages;
038    import org.kuali.kfs.module.purap.PurapAuthorizationConstants;
039    import org.kuali.kfs.module.purap.PurapConstants;
040    import org.kuali.kfs.module.purap.PurapConstants.PODocumentsStrings;
041    import org.kuali.kfs.module.purap.PurapConstants.PurchaseOrderDocTypes;
042    import org.kuali.kfs.module.purap.PurapConstants.PurchaseOrderStatuses;
043    import org.kuali.kfs.module.purap.PurapKeyConstants;
044    import org.kuali.kfs.module.purap.PurapPropertyConstants;
045    import org.kuali.kfs.module.purap.SingleConfirmationQuestion;
046    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem;
047    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderQuoteList;
048    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderQuoteListVendor;
049    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderSensitiveData;
050    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderVendorQuote;
051    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderVendorStipulation;
052    import org.kuali.kfs.module.purap.businessobject.SensitiveData;
053    import org.kuali.kfs.module.purap.businessobject.SensitiveDataAssignment;
054    import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
055    import org.kuali.kfs.module.purap.document.PurchaseOrderRetransmitDocument;
056    import org.kuali.kfs.module.purap.document.PurchaseOrderSplitDocument;
057    import org.kuali.kfs.module.purap.document.service.FaxService;
058    import org.kuali.kfs.module.purap.document.service.PurapService;
059    import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
060    import org.kuali.kfs.module.purap.document.validation.event.AttributedAddVendorToQuoteEvent;
061    import org.kuali.kfs.module.purap.document.validation.event.AttributedAssignSensitiveDataEvent;
062    import org.kuali.kfs.module.purap.document.validation.event.AttributedSplitPurchaseOrderEvent;
063    import org.kuali.kfs.module.purap.service.SensitiveDataService;
064    import org.kuali.kfs.sys.KFSConstants;
065    import org.kuali.kfs.sys.KFSPropertyConstants;
066    import org.kuali.kfs.sys.context.SpringContext;
067    import org.kuali.kfs.vnd.VendorConstants.AddressTypes;
068    import org.kuali.kfs.vnd.businessobject.VendorAddress;
069    import org.kuali.kfs.vnd.businessobject.VendorDetail;
070    import org.kuali.kfs.vnd.document.service.VendorService;
071    import org.kuali.rice.kew.exception.WorkflowException;
072    import org.kuali.rice.kns.bo.Note;
073    import org.kuali.rice.kns.document.authorization.DocumentAuthorizer;
074    import org.kuali.rice.kns.exception.ValidationException;
075    import org.kuali.rice.kns.question.ConfirmationQuestion;
076    import org.kuali.rice.kns.service.BusinessObjectService;
077    import org.kuali.rice.kns.service.DataDictionaryService;
078    import org.kuali.rice.kns.service.DateTimeService;
079    import org.kuali.rice.kns.service.DictionaryValidationService;
080    import org.kuali.rice.kns.service.DocumentHelperService;
081    import org.kuali.rice.kns.service.DocumentService;
082    import org.kuali.rice.kns.service.KualiConfigurationService;
083    import org.kuali.rice.kns.service.KualiRuleService;
084    import org.kuali.rice.kns.util.GlobalVariables;
085    import org.kuali.rice.kns.util.ObjectUtils;
086    import org.kuali.rice.kns.util.UrlFactory;
087    import org.kuali.rice.kns.web.struts.form.BlankFormFile;
088    import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
089    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
090    
091    /**
092     * Struts Action for Purchase Order document.
093     */
094    public class PurchaseOrderAction extends PurchasingActionBase {
095        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PurchaseOrderAction.class);
096    
097        /**
098         * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
099         *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
100         */
101        @Override
102        public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
103    
104            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
105            
106            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
107            BusinessObjectService businessObjectService = SpringContext.getBean(BusinessObjectService.class);
108    
109            // Handling lookups for alternate vendor for non-primary vendor payment that are only specific to Purchase Order.
110            if (request.getParameter("document.alternateVendorHeaderGeneratedIdentifier") != null && request.getParameter("document.alternateVendorDetailAssignedIdentifier") != null) {
111                Integer alternateVendorDetailAssignedId = document.getAlternateVendorDetailAssignedIdentifier();
112                Integer alternateVendorHeaderGeneratedId = document.getAlternateVendorHeaderGeneratedIdentifier();
113                VendorDetail refreshVendorDetail = new VendorDetail();
114                refreshVendorDetail.setVendorDetailAssignedIdentifier(alternateVendorDetailAssignedId);
115                refreshVendorDetail.setVendorHeaderGeneratedIdentifier(alternateVendorHeaderGeneratedId);
116                refreshVendorDetail = (VendorDetail) businessObjectService.retrieve(refreshVendorDetail);
117                document.templateAlternateVendor(refreshVendorDetail);
118            }
119    
120            // Handling lookups for quote list that is specific to Purchase Order.
121            if (request.getParameter("document.purchaseOrderQuoteListIdentifier") != null) {
122                // do a lookup and add all the vendors!
123                Integer poQuoteListIdentifier = document.getPurchaseOrderQuoteListIdentifier();
124                PurchaseOrderQuoteList poQuoteList = new PurchaseOrderQuoteList();
125                poQuoteList.setPurchaseOrderQuoteListIdentifier(poQuoteListIdentifier);
126                poQuoteList = (PurchaseOrderQuoteList) businessObjectService.retrieve(poQuoteList);
127                if (poQuoteList.isActive()) {
128                    for (PurchaseOrderQuoteListVendor poQuoteListVendor : poQuoteList.getQuoteListVendors()) {
129                        if ( poQuoteListVendor.isActive() ) {
130                            VendorDetail newVendor = poQuoteListVendor.getVendorDetail();
131                            if (newVendor.isActiveIndicator() && !newVendor.isVendorDebarred()) {
132                                PurchaseOrderVendorQuote newPOVendorQuote = SpringContext.getBean(PurchaseOrderService.class).populateQuoteWithVendor(newVendor.getVendorHeaderGeneratedIdentifier(), newVendor.getVendorDetailAssignedIdentifier(), document.getDocumentNumber());
133                                document.getPurchaseOrderVendorQuotes().add(newPOVendorQuote);
134                            }
135                        }
136                    }
137                }
138            }
139    
140            // Handling lookups for quote vendor search that is specific to Purchase Order.
141            String newVendorHeaderGeneratedIdentifier = request.getParameter("newPurchaseOrderVendorQuote.vendorHeaderGeneratedIdentifier");
142            String newVendorDetailAssignedIdentifier = request.getParameter("newPurchaseOrderVendorQuote.vendorDetailAssignedIdentifier");
143            if (newVendorHeaderGeneratedIdentifier != null && newVendorDetailAssignedIdentifier != null) {
144    
145                PurchaseOrderVendorQuote newPOVendorQuote = SpringContext.getBean(PurchaseOrderService.class).populateQuoteWithVendor(new Integer(newVendorHeaderGeneratedIdentifier), new Integer(newVendorDetailAssignedIdentifier), document.getDocumentNumber());
146                
147                poForm.setNewPurchaseOrderVendorQuote(newPOVendorQuote);
148            }
149    
150            String newStipulation = request.getParameter(KFSPropertyConstants.DOCUMENT + "." + PurapPropertyConstants.VENDOR_STIPULATION_DESCRIPTION);
151            if (StringUtils.isNotEmpty(newStipulation)) {
152                poForm.getNewPurchaseOrderVendorStipulationLine().setVendorStipulationDescription(newStipulation);
153            }
154    
155            return super.refresh(mapping, form, request, response);
156        }
157        
158        /**
159         * Inactivate an item from the purchase order document.
160         * 
161         * @param mapping An ActionMapping
162         * @param form An ActionForm
163         * @param request The HttpServletRequest
164         * @param response The HttpServletResponse
165         * @throws Exception
166         * @return An ActionForward
167         */
168        public ActionForward inactivateItem(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
169            PurchasingAccountsPayableFormBase purchasingForm = (PurchasingAccountsPayableFormBase) form;
170    
171            PurchaseOrderDocument purDocument = (PurchaseOrderDocument) purchasingForm.getDocument();
172            PurchaseOrderItem item = (PurchaseOrderItem) purDocument.getItem(getSelectedLine(request));
173            item.setItemActiveIndicator(false);
174    
175            return mapping.findForward(KFSConstants.MAPPING_BASIC);
176        }
177    
178        /**
179         * For use with a specific set of methods of this class that create new purchase order-derived document types in response to
180         * user actions, including <code>closePo</code>, <code>reopenPo</code>, <code>paymentHoldPo</code>, <code>removeHoldPo</code>, 
181         * <code>splitPo</code>, <code>amendPo</code>, and <code>voidPo</code>. It employs the question framework to ask
182         * the user for a response before creating and routing the new document. The response should consist of a note detailing a
183         * reason, and either yes or no. This method can be better understood if it is noted that it will be gone through twice (via the
184         * question framework); when each question is originally asked, and again when the yes/no response is processed, for
185         * confirmation.
186         * 
187         * @param mapping These are boiler-plate.
188         * @param form "
189         * @param request "
190         * @param response "
191         * @param questionType A string identifying the type of question being asked.
192         * @param confirmType A string identifying which type of question is being confirmed.
193         * @param documentType A string, the type of document to create
194         * @param notePrefix A string to appear before the note in the BO Notes tab
195         * @param messageType A string to appear on the PO once the question framework is done, describing the action taken
196         * @param operation A string, the verb to insert in the original question describing the action to be taken
197         * @return An ActionForward
198         * @throws Exception
199         */
200        protected ActionForward askQuestionsAndPerformDocumentAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionType, String confirmType, String documentType, String notePrefix, String messageType, String operation) throws Exception {
201            LOG.debug("askQuestionsAndPerformDocumentAction started.");
202            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
203            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
204            Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
205            String reason = request.getParameter(KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME);
206            String noteText = "";
207    
208            try {
209                KualiConfigurationService kualiConfiguration = SpringContext.getBean(KualiConfigurationService.class);
210    
211                // Start in logic for confirming the proposed operation.
212                if (ObjectUtils.isNull(question)) {
213                    String message = "";
214                    if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_SPLIT_DOCUMENT)) {
215                        message = kualiConfiguration.getPropertyString(PurapKeyConstants.PURCHASE_ORDER_SPLIT_QUESTION_TEXT);
216                    }
217                    else {
218                        String key = kualiConfiguration.getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_DOCUMENT);
219                        message = StringUtils.replace(key, "{0}", operation); 
220                    }
221                    // Ask question if not already asked.
222                    return this.performQuestionWithInput(mapping, form, request, response, questionType, message, KFSConstants.CONFIRMATION_QUESTION, questionType, "");
223                }
224                else {
225                    Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
226                    if (question.equals(questionType) && buttonClicked.equals(ConfirmationQuestion.NO)) {
227    
228                        // If 'No' is the button clicked, just reload the doc
229                        return returnToPreviousPage(mapping, kualiDocumentFormBase);
230                    }
231                    else if (question.equals(confirmType) && buttonClicked.equals(SingleConfirmationQuestion.OK)) {
232    
233                        // This is the case when the user clicks on "OK" in the end.
234                        // After we inform the user that the close has been rerouted, we'll redirect to the portal page.
235                        return mapping.findForward(KFSConstants.MAPPING_PORTAL);
236                    }
237                    else {
238                        // Have to check length on value entered.
239                        String introNoteMessage = notePrefix + KFSConstants.BLANK_SPACE;
240    
241                        // Build out full message.
242                        noteText = introNoteMessage + reason;
243                        int noteTextLength = noteText.length();
244    
245                        // Get note text max length from DD.
246                        int noteTextMaxLength = SpringContext.getBean(DataDictionaryService.class).getAttributeMaxLength(Note.class, KFSConstants.NOTE_TEXT_PROPERTY_NAME).intValue();
247    
248                        if (StringUtils.isBlank(reason) || (noteTextLength > noteTextMaxLength)) {
249                            // Figure out exact number of characters that the user can enter.
250                            int reasonLimit = noteTextMaxLength - noteTextLength;
251    
252                            if (ObjectUtils.isNull(reason)) {
253                                // Prevent a NPE by setting the reason to a blank string.
254                                reason = "";
255                            }
256    
257                            String message = "";
258                            String key = kualiConfiguration.getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_DOCUMENT);
259                            message = StringUtils.replace(key, "{0}", operation);
260    
261                            return this.performQuestionWithInputAgainBecauseOfErrors(mapping, form, request, response, questionType, message, KFSConstants.CONFIRMATION_QUESTION, questionType, "", reason, PurapKeyConstants.ERROR_PURCHASE_ORDER_REASON_REQUIRED, KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME, new Integer(reasonLimit).toString());
262                        }
263                    }
264                }
265                // Below used as a place holder to allow code to specify actionForward to return if not a 'success question'
266                ActionForward returnActionForward = null;
267                if (!po.isPendingActionIndicator()) {
268                    /*
269                     * Below if-else code block calls PurchaseOrderService methods that will throw ValidationException objects if errors
270                     * occur during any process in the attempt to perform its actions. Assume, if these return successfully, that the
271                     * PurchaseOrderDocument object returned from each is the newly created document and that all actions in the method
272                     * were run correctly. NOTE: IF BELOW IF-ELSE IS EDITED THE NEW METHODS CALLED MUST THROW ValidationException OBJECT
273                     * IF AN ERROR IS ADDED TO THE GlobalVariables
274                     */
275                    if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_SPLIT_DOCUMENT)) {
276                        po.setPendingSplit(true);                    
277                        // Save adding the note for after the items are picked.
278                        ((PurchaseOrderForm)kualiDocumentFormBase).setSplitNoteText(noteText);
279                        returnActionForward = mapping.findForward(KFSConstants.MAPPING_BASIC);
280                    }
281                    else {
282                        String newStatus = null;
283                        if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_AMENDMENT_DOCUMENT)) {
284                            newStatus = PurchaseOrderStatuses.AMENDMENT;
285                            po = SpringContext.getBean(PurchaseOrderService.class).createAndSavePotentialChangeDocument(kualiDocumentFormBase.getDocument().getDocumentNumber(), documentType, newStatus);
286                            returnActionForward = mapping.findForward(KFSConstants.MAPPING_BASIC);
287                        }
288                        else {
289                            if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT)) {
290                                newStatus = PurchaseOrderStatuses.PENDING_CLOSE;
291                            }
292                            else if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_REOPEN_DOCUMENT)) {
293                                newStatus = PurchaseOrderStatuses.PENDING_REOPEN;
294                            }
295                            else if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_VOID_DOCUMENT)) {
296                                newStatus = PurchaseOrderStatuses.PENDING_VOID;
297                            }
298                            else if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_PAYMENT_HOLD_DOCUMENT)) {
299                                newStatus = PurchaseOrderStatuses.PENDING_PAYMENT_HOLD;
300                            }
301                            else if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_REMOVE_HOLD_DOCUMENT)) {
302                                newStatus = PurchaseOrderStatuses.PENDING_REMOVE_HOLD;
303                            }
304                            else if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_RETRANSMIT_DOCUMENT)) {
305                                newStatus = PurchaseOrderStatuses.PENDING_RETRANSMIT;
306                            }
307                            po = SpringContext.getBean(PurchaseOrderService.class).createAndRoutePotentialChangeDocument(kualiDocumentFormBase.getDocument().getDocumentNumber(), documentType, kualiDocumentFormBase.getAnnotation(), combineAdHocRecipients(kualiDocumentFormBase), newStatus);
308                        }
309                        if (!GlobalVariables.getMessageMap().hasNoErrors()) {
310                            throw new ValidationException("errors occurred during new PO creation");
311                        }
312                        
313                        String previousDocumentId = kualiDocumentFormBase.getDocId();
314                        // Assume at this point document was created properly and 'po' variable is new PurchaseOrderDocument created
315                        kualiDocumentFormBase.setDocument(po);
316                        kualiDocumentFormBase.setDocId(po.getDocumentNumber());
317                        kualiDocumentFormBase.setDocTypeName(po.getDocumentHeader().getWorkflowDocument().getDocumentType());
318    
319                        Note newNote = new Note();
320                        if (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_AMENDMENT_DOCUMENT)) {
321                            noteText = noteText + " (Previous Document Id is " + previousDocumentId + ")";
322                        }
323                        newNote.setNoteText(noteText);
324                        newNote.setNoteTypeCode(KFSConstants.NoteTypeEnum.BUSINESS_OBJECT_NOTE_TYPE.getCode());
325                        kualiDocumentFormBase.setNewNote(newNote);
326                        
327                        kualiDocumentFormBase.setAttachmentFile(new BlankFormFile());
328        
329                        insertBONote(mapping, kualiDocumentFormBase, request, response);
330                    }
331                    if (StringUtils.isNotEmpty(messageType)) {
332                        GlobalVariables.getMessageList().add(messageType);
333                    }
334                }
335                if (ObjectUtils.isNotNull(returnActionForward)) {
336                    return returnActionForward;
337                }
338                else {
339    
340                    return this.performQuestionWithoutInput(mapping, form, request, response, confirmType, kualiConfiguration.getPropertyString(messageType), PODocumentsStrings.SINGLE_CONFIRMATION_QUESTION, questionType, "");
341                }
342            }
343            catch (ValidationException ve) {
344                throw ve;
345            }
346        }
347    
348        /**
349         * Invoked when the user pressed on the Close Order button on a Purchase Order page to Close the PO. It will
350         * display the question page to the user to ask whether the user really wants to close the PO and ask the user to enter a reason
351         * in the text area. If the user has entered the reason, it will invoke a service method to do the processing for closing a PO,
352         * then display a Single Confirmation page to inform the user that the PO Close Document has been routed.
353         * 
354         * @param mapping An ActionMapping
355         * @param form An ActionForm
356         * @param request The HttpServletRequest
357         * @param response The HttpServletResponse
358         * @throws Exception
359         * @return An ActionForward
360         */
361        public ActionForward closePo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
362            LOG.debug("ClosePO started.");
363            String operation = "Close ";
364            PurchaseOrderDocument po = ((PurchaseOrderForm)form).getPurchaseOrderDocument();
365            
366            if (po.canClosePOForTradeIn()) {
367                return askQuestionsAndPerformDocumentAction(mapping, form, request, response, PODocumentsStrings.CLOSE_QUESTION, PODocumentsStrings.CLOSE_CONFIRM, PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT, PODocumentsStrings.CLOSE_NOTE_PREFIX, PurapKeyConstants.PURCHASE_ORDER_MESSAGE_CLOSE_DOCUMENT, operation);
368            }
369            else {
370                return mapping.findForward(KFSConstants.MAPPING_BASIC);
371            }
372        }
373    
374        /**
375         * Is invoked when the user pressed on the Payment Hold button on a Purchase Order page to put the PO on hold. It
376         * will display the question page to the user to ask whether the user really wants to put the PO on hold and ask the user to
377         * enter a reason in the text area. If the user has entered the reason, it will invoke a service method to do the processing for
378         * putting a PO on hold, then display a Single Confirmation page to inform the user that the PO Payment Hold Document has been
379         * routed.
380         * 
381         * @param mapping An ActionMapping
382         * @param form An ActionForm
383         * @param request The HttpServletRequest
384         * @param response The HttpServletResponse
385         * @throws Exception
386         * @return An ActionForward
387         */
388        public ActionForward paymentHoldPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
389            LOG.debug("PaymentHoldPO started.");
390            String operation = "Hold Payment ";
391    
392            return askQuestionsAndPerformDocumentAction(mapping, form, request, response, PODocumentsStrings.PAYMENT_HOLD_QUESTION, PODocumentsStrings.PAYMENT_HOLD_CONFIRM, PurchaseOrderDocTypes.PURCHASE_ORDER_PAYMENT_HOLD_DOCUMENT, PODocumentsStrings.PAYMENT_HOLD_NOTE_PREFIX, PurapKeyConstants.PURCHASE_ORDER_MESSAGE_PAYMENT_HOLD, operation);
393        }
394    
395        /**
396         * Is invoked when the user pressed on the Remove Hold button on a Payment Hold PO page to remove the PO from hold.
397         * It will display the question page to the user to ask whether the user really wants to remove the PO from hold and ask the
398         * user to enter a reason in the text area. If the user has entered the reason, it will invoke a service method to do the
399         * processing for removing a PO from hold, then display a Single Confirmation page to inform the user that the PO Remove Hold
400         * Document has been routed.
401         * 
402         * @param mapping An ActionMapping
403         * @param form An ActionForm
404         * @param request The HttpServletRequest
405         * @param response The HttpServletResponse
406         * @throws Exception
407         * @return An ActionForward
408         */
409        public ActionForward removeHoldPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
410            LOG.debug("RemoveHoldPO started.");
411            String operation = "Remove Payment Hold ";
412            ActionForward forward = askQuestionsAndPerformDocumentAction(mapping, form, request, response, PODocumentsStrings.REMOVE_HOLD_QUESTION, PODocumentsStrings.REMOVE_HOLD_CONFIRM, PurchaseOrderDocTypes.PURCHASE_ORDER_REMOVE_HOLD_DOCUMENT, PODocumentsStrings.REMOVE_HOLD_NOTE_PREFIX, PurapKeyConstants.PURCHASE_ORDER_MESSAGE_REMOVE_HOLD, operation);
413    
414            return forward;
415        }
416    
417        /**
418         * Is invoked when the user pressed on the Open Order button on a Purchase Order page that has status "Close" to
419         * reopen the PO. It will display the question page to the user to ask whether the user really wants to reopen the PO and ask
420         * the user to enter a reason in the text area. If the user has entered the reason, it will invoke the a service method to do
421         * the processing for reopening a PO, then display a Single Confirmation page to inform the user that the
422         * <code>PurchaseOrderReopenDocument</code> has been routed.
423         * 
424         * @param mapping An ActionMapping
425         * @param form An ActionForm
426         * @param request The HttpServletRequest
427         * @param response The HttpServletResponse
428         * @throws Exception
429         * @return An ActionForward
430         * @see org.kuali.kfs.module.purap.document.PurchaseOrderReopenDocument
431         */
432        public ActionForward reopenPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
433            LOG.debug("Reopen PO started");
434            String operation = "Reopen ";
435    
436            return askQuestionsAndPerformDocumentAction(mapping, form, request, response, PODocumentsStrings.REOPEN_PO_QUESTION, PODocumentsStrings.CONFIRM_REOPEN_QUESTION, PurchaseOrderDocTypes.PURCHASE_ORDER_REOPEN_DOCUMENT, PODocumentsStrings.REOPEN_NOTE_PREFIX, PurapKeyConstants.PURCHASE_ORDER_MESSAGE_REOPEN_DOCUMENT, operation);
437        }
438    
439        /**
440         * Is invoked when the user pressed on the Amend button on a Purchase Order page to amend the PO. It will display
441         * the question page to the user to ask whether the user really wants to amend the PO and ask the user to enter a reason in the
442         * text area. If the user has entered the reason, it will invoke a service method to do the processing for amending the PO, then
443         * display a Single Confirmation page to inform the user that the <code>PurchaseOrderAmendmentDocument</code> has been routed.
444         * 
445         * @param mapping An ActionMapping
446         * @param form An ActionForm
447         * @param request The HttpServletRequest
448         * @param response The HttpServletResponse
449         * @throws Exception
450         * @return An ActionForward
451         * @see org.kuali.kfs.module.purap.document.PurchaseOrderAmendmentDocument
452         */
453        public ActionForward amendPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
454            LOG.debug("Amend PO started");
455            String operation = "Amend ";
456    
457            return askQuestionsAndPerformDocumentAction(mapping, form, request, response, PODocumentsStrings.AMENDMENT_PO_QUESTION, PODocumentsStrings.CONFIRM_AMENDMENT_QUESTION, PurchaseOrderDocTypes.PURCHASE_ORDER_AMENDMENT_DOCUMENT, PODocumentsStrings.AMENDMENT_NOTE_PREFIX, null, operation);
458        }
459    
460        /**
461         * Is invoked when the user pressed on the Void button on a Purchase Order page to void the PO. It will display the
462         * question page to the user to ask whether the user really wants to void the PO and ask the user to enter a reason in the text
463         * area. If the user has entered the reason, it will invoke a service method to do the processing for voiding the PO, then
464         * display a Single Confirmation page to inform the user that the <code>PurchaseOrderVoidDocument</code> has been routed.
465         * 
466         * @param mapping An ActionMapping
467         * @param form An ActionForm
468         * @param request The HttpServletRequest
469         * @param response The HttpServletResponse
470         * @throws Exception
471         * @return An ActionForward
472         * @see org.kuali.kfs.module.purap.document.PurchaseOrderVoidDocument
473         */
474        public ActionForward voidPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
475            LOG.debug("Void PO started");
476            String operation = "Void ";
477    
478            return askQuestionsAndPerformDocumentAction(mapping, form, request, response, PODocumentsStrings.VOID_QUESTION, PODocumentsStrings.VOID_CONFIRM, PurchaseOrderDocTypes.PURCHASE_ORDER_VOID_DOCUMENT, PODocumentsStrings.VOID_NOTE_PREFIX, PurapKeyConstants.PURCHASE_ORDER_MESSAGE_VOID_DOCUMENT, operation);
479        }
480        
481        /**
482         * Invoked to initiate the splitting of a Purchase Order.  Displays a question page to ask for a reason and confirmation
483         * of the user's desire to split the Purchase Order, and, if confirmed, a page on which the Split PO tab only is showing, 
484         * and the items to move to the new PO are chosen. If that is done, and the user continues, a new Split Purchase Order document 
485         * will be created, with the chosen items.  That same set of items will be deleted from the original Purchase Order.
486         * 
487         * @param mapping       An ActionMapping
488         * @param form          An ActionForm
489         * @param request       The HttpServeletRequest
490         * @param response      The HttpServeletResponse
491         * @return              An ActionForward
492         * @throws Exception
493         * @see org.kuali.kfs.module.purap.document.PurchaseOrderSplitDocument
494         */
495        public ActionForward splitPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
496            LOG.debug("Split PO started");
497            String operation = "Split ";
498            
499            return askQuestionsAndPerformDocumentAction(mapping, form, request, response, PODocumentsStrings.SPLIT_QUESTION, PODocumentsStrings.SPLIT_CONFIRM, PurchaseOrderDocTypes.PURCHASE_ORDER_SPLIT_DOCUMENT,PODocumentsStrings.SPLIT_NOTE_PREFIX_OLD_DOC,PurapKeyConstants.PURCHASE_ORDER_MESSAGE_SPLIT_DOCUMENT,operation);
500        }
501        
502        /**
503         * Invoked when only the Split Purchase Order tab is showing to continue the process of splitting the PO, once items are chosen
504         * to be moved to the new PO.
505         * 
506         * @param mapping       An ActionMapping
507         * @param form          An ActionForm
508         * @param request       The HttpServeletRequest
509         * @param response      The HttpServeletResponse
510         * @return              An ActionForward
511         * @throws Exception
512         */
513        public ActionForward continuePurchaseOrderSplit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception  {
514            LOG.debug("Continue Purchase Order Split started");
515            
516            PurchaseOrderForm purchaseOrderForm = (PurchaseOrderForm) form;
517            // This PO does not contain all data, but enough for our purposes; it has been reloaded with only the Split PO tab showing.
518            PurchaseOrderDocument poToSplit = (PurchaseOrderDocument)purchaseOrderForm.getDocument();
519            boolean copyNotes = poToSplit.isCopyingNotesWhenSplitting();
520    
521            // Check business rules before splitting.
522    
523            boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedSplitPurchaseOrderEvent(poToSplit));
524            if (!rulePassed) {
525                poToSplit.setPendingSplit(true);
526            }
527            else {
528                HashMap<String, List<PurchaseOrderItem>> categorizedItems = SpringContext.getBean(PurchaseOrderService.class).categorizeItemsForSplit((List<PurchaseOrderItem>)poToSplit.getItems());
529                List<PurchaseOrderItem> movingPOItems = categorizedItems.get(PODocumentsStrings.ITEMS_MOVING_TO_SPLIT);
530                List<PurchaseOrderItem> remainingPOItems = categorizedItems.get(PODocumentsStrings.ITEMS_REMAINING);
531                
532                // Fetch the whole PO from the database, and reset and renumber the items on it.
533                poToSplit = (PurchaseOrderDocument)SpringContext.getBean(PurchaseOrderService.class).getCurrentPurchaseOrder(poToSplit.getPurapDocumentIdentifier());
534                poToSplit.setItems(remainingPOItems);
535                poToSplit.renumberItems(0);
536                
537                // Add the note that would normally have gone in after the confirmation page.
538                String noteText = purchaseOrderForm.getSplitNoteText();
539                try {
540                    Note splitNote = SpringContext.getBean(DocumentService.class).createNoteFromDocument(poToSplit, noteText);
541                    poToSplit.addNote(splitNote);
542                } catch ( Exception e ) {
543                    throw new RuntimeException(e);
544                }          
545                SpringContext.getBean(PurapService.class).saveDocumentNoValidation(poToSplit);
546                
547                PurchaseOrderSplitDocument splitPO = SpringContext.getBean(PurchaseOrderService.class).createAndSavePurchaseOrderSplitDocument(movingPOItems, poToSplit, copyNotes, noteText);
548                
549                purchaseOrderForm.setDocument(splitPO);
550                purchaseOrderForm.setDocId(splitPO.getDocumentNumber());
551                purchaseOrderForm.setDocTypeName(splitPO.getDocumentHeader().getWorkflowDocument().getDocumentType());
552                try {
553                    loadDocument(purchaseOrderForm);
554                }
555                catch (WorkflowException we) {
556                    throw new RuntimeException(we);
557                }
558            }
559                          
560            return mapping.findForward(KFSConstants.MAPPING_BASIC);
561        }
562        
563        /**
564         * Invoked from the page on which the Split PO tab is showing to cancel the splitting of the PO and return it to its original state.
565         * 
566         * @param mapping       An ActionMapping
567         * @param form          An ActionForm
568         * @param request       The HttpServeletRequest
569         * @param response      The HttpServeletResponse
570         * @return              An ActionForward
571         * @throws Exception
572         */
573        public ActionForward cancelPurchaseOrderSplit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
574            LOG.debug("Cancel Purchase Order Split started");
575            
576            PurchaseOrderForm purchaseOrderForm = (PurchaseOrderForm)form;
577            PurchaseOrderDocument po = (PurchaseOrderDocument)purchaseOrderForm.getDocument();
578            
579            po = SpringContext.getBean(PurchaseOrderService.class).getPurchaseOrderByDocumentNumber(po.getDocumentNumber());
580                   
581            po.setPendingSplit(false);
582            po.setCopyingNotesWhenSplitting(false);
583            purchaseOrderForm.setDocument(po);
584            reload(mapping, purchaseOrderForm, request, response);
585            
586            return mapping.findForward(KFSConstants.MAPPING_BASIC);
587        }
588        
589        /**
590         * Invoked when an authorized user presses "Sensitive Data" button on the purchase order page.
591         * 
592         * @param mapping       An ActionMapping
593         * @param form          An ActionForm
594         * @param request       The HttpServeletRequest
595         * @param response      The HttpServeletResponse
596         * @return              An ActionForward
597         * @throws Exception
598         */
599        public ActionForward assignSensitiveData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
600            LOG.debug("Assign Sensitive Data started");
601            
602            PurchaseOrderForm poForm = (PurchaseOrderForm)form;
603            PurchaseOrderDocument po = (PurchaseOrderDocument)poForm.getDocument();        
604            Integer poId = po.getPurapDocumentIdentifier();
605            SensitiveDataService sdService = SpringContext.getBean(SensitiveDataService.class);        
606            
607            // set the assignment flag and reset input fields
608            po.setAssigningSensitiveData(true);     
609            poForm.setSensitiveDataAssignmentReason("");
610            poForm.setNewSensitiveDataLine(new SensitiveData());
611            
612            // load previous assignment info
613            SensitiveDataAssignment sda = sdService.getLastSensitiveDataAssignment(poId);
614            poForm.setLastSensitiveDataAssignment(sda);
615            
616            // even though at this point, the sensitive data entries should have been loaded into the form already, 
617            // we still load them again in case that someone else has changed that during the time period 
618            List<SensitiveData> posds = sdService.getSensitiveDatasAssignedByPoId(poId);
619            poForm.setSensitiveDatasAssigned(posds);    
620                    
621            return mapping.findForward(KFSConstants.MAPPING_BASIC);
622        }
623            
624        /**
625         * Invoked when an authorized user presses "Submit" button on the "Assign Sensitive Data" page.
626         * 
627         * @param mapping       An ActionMapping
628         * @param form          An ActionForm
629         * @param request       The HttpServeletRequest
630         * @param response      The HttpServeletResponse
631         * @return              An ActionForward
632         * @throws Exception
633         */
634        public ActionForward submitSensitiveData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
635            LOG.debug("Submit Sensitive Data started");
636            
637            PurchaseOrderForm poForm = (PurchaseOrderForm)form;
638            PurchaseOrderDocument po = (PurchaseOrderDocument)poForm.getDocument();        
639            Integer poId = po.getPurapDocumentIdentifier();
640            List<SensitiveData> sds = poForm.getSensitiveDatasAssigned();
641            String sdaReason = poForm.getSensitiveDataAssignmentReason();
642            SensitiveDataService sdService = SpringContext.getBean(SensitiveDataService.class);        
643            
644            // check business rules
645            boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedAssignSensitiveDataEvent("", po, sdaReason, sds));
646            if (!rulePassed) {
647                return mapping.findForward(KFSConstants.MAPPING_BASIC);
648            }
649    
650            // update table SensitiveDataAssignment
651            SensitiveDataAssignment sda = new SensitiveDataAssignment(poId, poForm.getSensitiveDataAssignmentReason(), GlobalVariables.getUserSession().getPerson().getPrincipalName(), poForm.getSensitiveDatasAssigned());
652            SpringContext.getBean(BusinessObjectService.class).save(sda);
653    
654            // update table PurchaseOrderSensitiveData
655            sdService.deletePurchaseOrderSensitiveDatas(poId);
656            List<PurchaseOrderSensitiveData> posds = new ArrayList<PurchaseOrderSensitiveData>();
657            for (SensitiveData sd : sds) {
658                posds.add(new PurchaseOrderSensitiveData(poId, po.getRequisitionIdentifier(), sd.getSensitiveDataCode()));
659            }
660            SpringContext.getBean(BusinessObjectService.class).save(posds);
661    
662            // need this to update workflow doc for searching restrictions on sensitive data
663            SpringContext.getBean(PurapService.class).saveRoutingDataForRelatedDocuments(po.getAccountsPayablePurchasingDocumentLinkIdentifier());
664    
665            // reset the sensitive data related fields in the po form
666            po.setAssigningSensitiveData(false);
667            
668            return mapping.findForward(KFSConstants.MAPPING_BASIC);
669        }          
670    
671        /**
672         * Invoked when an authorized user presses "Cancel" button on the "Assign Sensitive Data" page.
673         * 
674         * @param mapping       An ActionMapping
675         * @param form          An ActionForm
676         * @param request       The HttpServeletRequest
677         * @param response      The HttpServeletResponse
678         * @return              An ActionForward
679         * @throws Exception
680         */
681        public ActionForward cancelSensitiveData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
682            LOG.debug("Cancel Sensitive Data started");
683            
684            // reset the sensitive data flag in the po form, reload sensitive data from database to undo the canceled changes
685            PurchaseOrderForm poForm = (PurchaseOrderForm)form;
686            PurchaseOrderDocument po = (PurchaseOrderDocument)poForm.getDocument();        
687            po.setAssigningSensitiveData(false);
688            List<SensitiveData> sds = SpringContext.getBean(SensitiveDataService.class).getSensitiveDatasAssignedByPoId(po.getPurapDocumentIdentifier());
689            poForm.setSensitiveDatasAssigned(sds);        
690            
691            return mapping.findForward(KFSConstants.MAPPING_BASIC);
692        }                  
693        
694        /**
695         * Invoked when an authorized user presses "Add" button on the "Assign Sensitive Data" page.
696         * 
697         * @param mapping       An ActionMapping
698         * @param form          An ActionForm
699         * @param request       The HttpServeletRequest
700         * @param response      The HttpServeletResponse
701         * @return              An ActionForward
702         * @throws Exception
703         */
704        public ActionForward addSensitiveData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
705            LOG.debug("Add Sensitive Data started");
706            
707            PurchaseOrderForm poForm = (PurchaseOrderForm)form;
708            SensitiveDataService sdService = SpringContext.getBean(SensitiveDataService.class);        
709            
710            // retrieve new sensitive data by code, add the new line
711            SensitiveData newsd = poForm.getNewSensitiveDataLine();
712            newsd = sdService.getSensitiveDataByCode(newsd.getSensitiveDataCode());
713            List<SensitiveData> sds = poForm.getSensitiveDatasAssigned();
714            sds.add(newsd);
715            
716            // reset new line
717            poForm.setNewSensitiveDataLine(new SensitiveData());        
718            
719            return mapping.findForward(KFSConstants.MAPPING_BASIC);
720        }                  
721        
722        /**
723         * Invoked when an authorized user presses "Delete" button on the "Assign Sensitive Data" page.
724         * 
725         * @param mapping       An ActionMapping
726         * @param form          An ActionForm
727         * @param request       The HttpServeletRequest
728         * @param response      The HttpServeletResponse
729         * @return              An ActionForward
730         * @throws Exception
731         */
732        public ActionForward deleteSensitiveData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
733            LOG.debug("Delete Sensitive Data started");
734            
735            // remove the selected sensitive data line 
736            PurchaseOrderForm poForm = (PurchaseOrderForm)form;
737            List<SensitiveData> sds = poForm.getSensitiveDatasAssigned();
738            sds.remove(getSelectedLine(request));      
739            
740            return mapping.findForward(KFSConstants.MAPPING_BASIC);
741        }                  
742        
743        /**
744         * This is a utility method used to prepare to and to return to a previous page, making sure that the buttons will be restored
745         * in the process.
746         * 
747         * @param kualiDocumentFormBase The Form, considered as a KualiDocumentFormBase, as it typically is here.
748         * @return An actionForward mapping back to the original page.
749         */
750        protected ActionForward returnToPreviousPage(ActionMapping mapping, KualiDocumentFormBase kualiDocumentFormBase) {
751    
752            return mapping.findForward(KFSConstants.MAPPING_BASIC);
753        }
754    
755        /**
756         * Is executed when the user clicks on the "print" button on a Purchase Order Print Document page. On a non
757         * javascript enabled browser, it will display a page with 2 buttons. One is to display the PDF, the other is to view the PO
758         * tabbed page where the PO document statuses, buttons, etc have already been updated (the updates of those occurred while the
759         * <code>performPurchaseOrderFirstTransmitViaPrinting</code> method is invoked. On a javascript enabled browser, it will
760         * display both the PO tabbed page containing the updated PO document info and the pdf on the next window/tab of the browser.
761         * 
762         * @param mapping An ActionMapping
763         * @param form An ActionForm
764         * @param request The HttpServletRequest
765         * @param response The HttpServletResponse
766         * @throws Exception
767         * @return An ActionForward
768         */
769        public ActionForward firstTransmitPrintPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
770            String poDocId = ((PurchaseOrderForm)form).getDocId();
771            ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
772            try {
773                SpringContext.getBean(PurchaseOrderService.class).performPurchaseOrderFirstTransmitViaPrinting(poDocId, baosPDF);
774            }
775            finally {
776                if (baosPDF != null) {
777                    baosPDF.reset();
778                }
779            }
780            String basePath = getBasePath(request);
781            String docId = ((PurchaseOrderForm) form).getDocId();
782            String methodToCallPrintPurchaseOrderPDF = "printPurchaseOrderPDFOnly";
783            String methodToCallDocHandler = "docHandler";
784            String printPOPDFUrl = getUrlForPrintPO(basePath, docId, methodToCallPrintPurchaseOrderPDF);
785            String displayPOTabbedPageUrl = getUrlForPrintPO(basePath, docId, methodToCallDocHandler);
786            request.setAttribute("printPOPDFUrl", printPOPDFUrl);
787            request.setAttribute("displayPOTabbedPageUrl", displayPOTabbedPageUrl);
788            String label = SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByTypeName(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER);
789            request.setAttribute("purchaseOrderLabel", label);
790    
791            return mapping.findForward("printPurchaseOrderPDF");
792        }
793    
794        /**
795         * Creates a URL to be used in printing the purchase order.
796         * 
797         * @param basePath String: The base path of the current URL
798         * @param docId String: The document ID of the document to be printed
799         * @param methodToCall String: The name of the method that will be invoked to do this particular print
800         * @return The URL
801         */
802        protected String getUrlForPrintPO(String basePath, String docId, String methodToCall) {
803            StringBuffer result = new StringBuffer(basePath);
804            result.append("/purapPurchaseOrder.do?methodToCall=");
805            result.append(methodToCall);
806            result.append("&docId=");
807            result.append(docId);
808            result.append("&command=displayDocSearchView");
809    
810            return result.toString();
811        }
812    
813        /**
814         * Prints the PDF only, as opposed to <code>firstTransmitPrintPo</code>, which calls this method (indirectly) to print the
815         * PDF, and calls the doc handler to display the PO tabbed page.
816         * 
817         * @param mapping An ActionMapping
818         * @param form An ActionForm
819         * @param request The HttpServletRequest
820         * @param response The HttpServletResponse
821         * @throws Exception
822         * @return An ActionForward
823         */
824        public ActionForward printPurchaseOrderPDFOnly(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
825            String poDocId = request.getParameter("docId");
826            ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
827            try {
828                // will throw validation exception if errors occur
829                SpringContext.getBean(PurchaseOrderService.class).performPrintPurchaseOrderPDFOnly(poDocId, baosPDF);
830    
831                response.setHeader("Cache-Control", "max-age=30");
832                response.setContentType("application/pdf");
833                StringBuffer sbContentDispValue = new StringBuffer();
834                String useJavascript = request.getParameter("useJavascript");
835                if (useJavascript == null || useJavascript.equalsIgnoreCase("false")) {
836                    sbContentDispValue.append("attachment");
837                }
838                else {
839                    sbContentDispValue.append("inline");
840                }
841                StringBuffer sbFilename = new StringBuffer();
842                sbFilename.append("PURAP_PO_");
843                sbFilename.append(poDocId);
844                sbFilename.append("_");
845                sbFilename.append(System.currentTimeMillis());
846                sbFilename.append(".pdf");
847                sbContentDispValue.append("; filename=");
848                sbContentDispValue.append(sbFilename);
849    
850                response.setHeader("Content-disposition", sbContentDispValue.toString());
851    
852                response.setContentLength(baosPDF.size());
853    
854                ServletOutputStream sos;
855    
856                sos = response.getOutputStream();
857    
858                baosPDF.writeTo(sos);
859    
860                sos.flush();
861    
862            }
863            finally {
864                if (baosPDF != null) {
865                    baosPDF.reset();
866                }
867            }
868    
869            return null;
870        }
871    
872        /**
873         * Print a particular selected PO Quote as a PDF.
874         * 
875         * @param mapping An ActionMapping
876         * @param form An ActionForm -- The PO Quote must be selected here.
877         * @param request The HttpServletRequest
878         * @param response The HttpServletResponse
879         * @throws Exception
880         * @return An ActionForward
881         */
882        public ActionForward printPoQuote(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
883            // String poDocId = request.getParameter("docId");
884            // PurchaseOrderDocument po = (PurchaseOrderDocument)
885            // SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(poDocId);
886            // Integer poSelectedVendorId = new Integer(request.getParameter("quoteVendorId"));
887            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
888            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
889            PurchaseOrderVendorQuote poVendorQuote = po.getPurchaseOrderVendorQuotes().get(getSelectedLine(request));
890            ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
891            poVendorQuote.setTransmitPrintDisplayed(false);
892            try {
893                StringBuffer sbFilename = new StringBuffer();
894                sbFilename.append("PURAP_PO_QUOTE_");
895                sbFilename.append(po.getPurapDocumentIdentifier());
896                sbFilename.append("_");
897                sbFilename.append(System.currentTimeMillis());
898                sbFilename.append(".pdf");
899    
900                boolean success = SpringContext.getBean(PurchaseOrderService.class).printPurchaseOrderQuotePDF(po, poVendorQuote, baosPDF);
901    
902                if (!success) {
903                    poVendorQuote.setTransmitPrintDisplayed(true);
904                    poVendorQuote.setPdfDisplayedToUserOnce(false);
905                    
906                    if (baosPDF != null) {
907                        baosPDF.reset();
908                    }
909                    return mapping.findForward(KFSConstants.MAPPING_BASIC);
910                }
911                response.setHeader("Cache-Control", "max-age=30");
912                response.setContentType("application/pdf");
913                StringBuffer sbContentDispValue = new StringBuffer();
914                // sbContentDispValue.append("inline");
915                sbContentDispValue.append("attachment");
916                sbContentDispValue.append("; filename=");
917                sbContentDispValue.append(sbFilename);
918    
919                response.setHeader("Content-disposition", sbContentDispValue.toString());
920    
921                response.setContentLength(baosPDF.size());
922    
923                ServletOutputStream sos;
924    
925                sos = response.getOutputStream();
926    
927                baosPDF.writeTo(sos);
928    
929                sos.flush();
930    
931            }
932            finally {
933                if (baosPDF != null) {
934                    baosPDF.reset();
935                }
936            }
937    
938            return null;
939        }
940    
941        public ActionForward printPoQuoteList(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
942            String poDocId = ((PurchaseOrderForm)form).getDocId();
943            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
944            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
945            SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
946            String basePath = getBasePath(request);
947            String methodToCallPrintPurchaseOrderPDF = "printPoQuoteListOnly";
948            String methodToCallDocHandler = "docHandler";
949            String printPOQuoteListPDFUrl = getUrlForPrintPO(basePath, poDocId, methodToCallPrintPurchaseOrderPDF);
950            String displayPOTabbedPageUrl = getUrlForPrintPO(basePath, poDocId, methodToCallDocHandler);
951            request.setAttribute("printPOQuoteListPDFUrl", printPOQuoteListPDFUrl);
952            request.setAttribute("displayPOTabbedPageUrl", displayPOTabbedPageUrl);
953            String label = SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByTypeName(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER);
954            request.setAttribute("purchaseOrderLabel", label);
955    
956            return mapping.findForward("printPOQuoteListPDF");        
957        }
958        
959        /**
960         * Print the list of PO Quote requests.
961         * 
962         * @param mapping An ActionMapping
963         * @param form An ActionForm
964         * @param request The HttpServletRequest
965         * @param response The HttpServletResponse
966         * @throws Exception
967         * @return An ActionForward
968         */
969        public ActionForward printPoQuoteListOnly(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
970            String poDocId = request.getParameter("docId");
971            ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
972            try {
973                StringBuffer sbFilename = new StringBuffer();
974                sbFilename.append("PURAP_PO_QUOTE_LIST_");
975                sbFilename.append(poDocId);
976                sbFilename.append("_");
977                sbFilename.append(System.currentTimeMillis());
978                sbFilename.append(".pdf");
979    
980                boolean success = SpringContext.getBean(PurchaseOrderService.class).printPurchaseOrderQuoteRequestsListPDF(poDocId, baosPDF);
981    
982                if (!success) {
983                    if (baosPDF != null) {
984                        baosPDF.reset();
985                    }
986                    return mapping.findForward(KFSConstants.MAPPING_PORTAL);
987                }
988                response.setHeader("Cache-Control", "max-age=30");
989                response.setContentType("application/pdf");
990                StringBuffer sbContentDispValue = new StringBuffer();
991                String useJavascript = request.getParameter("useJavascript");
992                if (useJavascript == null || useJavascript.equalsIgnoreCase("false")) {
993                    sbContentDispValue.append("attachment");
994                }
995                else {
996                    sbContentDispValue.append("inline");
997                }
998                sbContentDispValue.append("; filename=");
999                sbContentDispValue.append(sbFilename);
1000    
1001                response.setHeader("Content-disposition", sbContentDispValue.toString());
1002    
1003                response.setContentLength(baosPDF.size());
1004    
1005                ServletOutputStream sos;
1006    
1007                sos = response.getOutputStream();
1008    
1009                baosPDF.writeTo(sos);
1010    
1011                sos.flush();
1012    
1013            }
1014            finally {
1015                if (baosPDF != null) {
1016                    baosPDF.reset();
1017                }
1018            }
1019    
1020            return null;
1021        }
1022    
1023        /**
1024         * Initiates transmission of a PO Quote request.
1025         * 
1026         * @param mapping An ActionMapping
1027         * @param form An ActionForm
1028         * @param request The HttpServletRequest
1029         * @param response The HttpServletResponse
1030         * @throws Exception
1031         * @return An ActionForward
1032         */
1033        public ActionForward transmitPurchaseOrderQuote(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1034            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
1035            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
1036            PurchaseOrderVendorQuote vendorQuote = (PurchaseOrderVendorQuote) po.getPurchaseOrderVendorQuotes().get(getSelectedLine(request));
1037            if (PurapConstants.QuoteTransmitTypes.PRINT.equals(vendorQuote.getPurchaseOrderQuoteTransmitTypeCode())) {
1038                vendorQuote.setPurchaseOrderQuoteTransmitTimestamp(SpringContext.getBean(DateTimeService.class).getCurrentTimestamp());
1039                vendorQuote.setTransmitPrintDisplayed(true);
1040                vendorQuote.setPdfDisplayedToUserOnce(false);
1041                SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
1042            }
1043            else if (PurapConstants.QuoteTransmitTypes.FAX.equals(vendorQuote.getPurchaseOrderQuoteTransmitTypeCode())) {
1044                // call fax service
1045                GlobalVariables.getMessageMap().clear();
1046                FaxService faxService = SpringContext.getBean(FaxService.class);
1047                faxService.faxPurchaseOrderPdf(po, false);
1048                if (GlobalVariables.getMessageMap().size() == 0) {
1049                    vendorQuote.setPurchaseOrderQuoteTransmitTimestamp(SpringContext.getBean(DateTimeService.class).getCurrentTimestamp());
1050                    SpringContext.getBean(PurapService.class).saveDocumentNoValidation(po);
1051                }
1052            }
1053            else {
1054                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_QUOTES, PurapKeyConstants.ERROR_PURCHASE_ORDER_QUOTE_TRANSMIT_TYPE_NOT_SELECTED);
1055            }
1056    
1057            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1058        }
1059    
1060        /**
1061         * Is invoked when the user clicks on the Select All button on a Purchase Order Retransmit document. It will select
1062         * the checkboxes of all the items to be included in the retransmission of the PO.
1063         * 
1064         * @param mapping An ActionMapping
1065         * @param form An ActionForm
1066         * @param request The HttpServletRequest
1067         * @param response The HttpServletResponse
1068         * @throws Exception
1069         * @return An ActionForward
1070         */
1071        public ActionForward selectAllForRetransmit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1072            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
1073            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
1074            List<PurchaseOrderItem> items = po.getItems();
1075            for (PurchaseOrderItem item : items) {
1076                item.setItemSelectedForRetransmitIndicator(true);
1077            }
1078    
1079            return returnToPreviousPage(mapping, kualiDocumentFormBase);
1080        }
1081    
1082        /**
1083         * Is invoked when the user clicks on the Deselect All button on a Purchase Order Retransmit document. It will
1084         * uncheck the checkboxes of all the items to be excluded from the retransmission of the PO.
1085         * 
1086         * @param mapping An ActionMapping
1087         * @param form An ActionForm
1088         * @param request The HttpServletRequest
1089         * @param response The HttpServletResponse
1090         * @throws Exception
1091         * @return An ActionForward
1092         */
1093        public ActionForward deselectAllForRetransmit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1094            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
1095            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
1096            List<PurchaseOrderItem> items = po.getItems();
1097            for (PurchaseOrderItem item : items) {
1098                item.setItemSelectedForRetransmitIndicator(false);
1099            }
1100    
1101            return returnToPreviousPage(mapping, kualiDocumentFormBase);
1102        }
1103    
1104        /**
1105         * Is invoked when the user clicks on the Retransmit button on both the PO tabbed page and on the Purchase Order
1106         * Retransmit Document page, which is essentially a PO tabbed page with the other irrelevant tabs being hidden. If it was
1107         * invoked from the PO tabbed page, if the PO's pending indicator is false, this method will invoke a method in the
1108         * PurchaseOrderService to update the flags, create the PurchaseOrderRetransmitDocument and route it. If the routing was
1109         * successful, we'll display the Purchase Order Retransmit Document page to the user, containing the newly created and routed
1110         * PurchaseOrderRetransmitDocument and a retransmit button as well as a list of items that the user can select to be
1111         * retransmitted. If it was invoked from the Purchase Order Retransmit Document page, we'll invoke the
1112         * retransmitPurchaseOrderPDF method to create a PDF document based on the PO information and the items that were selected by
1113         * the user on the Purchase Order Retransmit Document page to be retransmitted, then display the PDF to the browser.
1114         * 
1115         * @param mapping An ActionMapping
1116         * @param form An ActionForm
1117         * @param request The HttpServletRequest
1118         * @param response The HttpServletResponse
1119         * @throws Exception
1120         * @return An ActionForward
1121         */
1122        public ActionForward retransmitPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1123            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
1124            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
1125    
1126            boolean success;
1127            if (po.isPendingActionIndicator()) {
1128                success = false;
1129                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_PURCHASE_ORDER_IS_PENDING);
1130            }
1131            else {
1132                po = SpringContext.getBean(PurchaseOrderService.class).createAndRoutePotentialChangeDocument(kualiDocumentFormBase.getDocument().getDocumentNumber(), PurchaseOrderDocTypes.PURCHASE_ORDER_RETRANSMIT_DOCUMENT, kualiDocumentFormBase.getAnnotation(), combineAdHocRecipients(kualiDocumentFormBase), PurchaseOrderStatuses.PENDING_RETRANSMIT);
1133                ((PurchaseOrderRetransmitDocument)po).setShouldDisplayRetransmitTab(true);
1134            }
1135    
1136            kualiDocumentFormBase.setDocument(po);
1137            // we only need to set the editing mode to displayRetransmitTab if it's not yet
1138            // in the editingMode.
1139            if (!kualiDocumentFormBase.getEditingMode().containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.DISPLAY_RETRANSMIT_TAB)) {
1140                DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(po);
1141             // TODO this method is gone, fix for kim
1142    //            kualiDocumentFormBase.populateAuthorizationFields(documentAuthorizer);
1143            }
1144    
1145            return returnToPreviousPage(mapping, kualiDocumentFormBase);
1146        }
1147    
1148    
1149        /**
1150         * Is invoked when the user clicks on the Retransmit button on both the PO tabbed page and on the Purchase Order
1151         * Retransmit Document page, which is essentially a PO tabbed page with the other irrelevant tabs being hidden. If it was
1152         * invoked from the PO tabbed page, if the PO's pending indicator is false, this method will invoke a method in the
1153         * PurchaseOrderService to update the flags, create the PurchaseOrderRetransmitDocument and route it. If the routing was
1154         * successful, we'll display the Purchase Order Retransmit Document page to the user, containing the newly created and routed
1155         * PurchaseOrderRetransmitDocument and a retransmit button as well as a list of items that the user can select to be
1156         * retransmitted. If it was invoked from the Purchase Order Retransmit Document page, we'll invoke the
1157         * retransmitPurchaseOrderPDF method to create a PDF document based on the PO information and the items that were selected by
1158         * the user on the Purchase Order Retransmit Document page to be retransmitted, then display the PDF to the browser.
1159         * 
1160         * @param mapping An ActionMapping
1161         * @param form An ActionForm
1162         * @param request The HttpServletRequest
1163         * @param response The HttpServletResponse
1164         * @throws Exception
1165         * @return An ActionForward
1166         */
1167        public ActionForward printingPreviewPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1168            String poDocId = ((PurchaseOrderForm)form).getDocId();
1169            ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
1170            try {
1171                SpringContext.getBean(PurchaseOrderService.class).performPurchaseOrderPreviewPrinting(poDocId, baosPDF);
1172            }
1173            finally {
1174                if (baosPDF != null) {
1175                    baosPDF.reset();
1176                }
1177            }
1178            String basePath = getBasePath(request);
1179            String docId = ((PurchaseOrderForm) form).getDocId();
1180            String methodToCallPrintPurchaseOrderPDF = "printPurchaseOrderPDFOnly";
1181            String methodToCallDocHandler = "docHandler";
1182            String printPOPDFUrl = getUrlForPrintPO(basePath, docId, methodToCallPrintPurchaseOrderPDF);
1183            String displayPOTabbedPageUrl = getUrlForPrintPO(basePath, docId, methodToCallDocHandler);
1184            request.setAttribute("printPOPDFUrl", printPOPDFUrl);
1185            request.setAttribute("displayPOTabbedPageUrl", displayPOTabbedPageUrl);
1186            String label = SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByTypeName(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER);
1187            request.setAttribute("purchaseOrderLabel", label);
1188            GlobalVariables.getUserSession().addObject("isPreview", new Boolean(true));
1189    
1190            return mapping.findForward("printPurchaseOrderPDF");
1191        }
1192    
1193        /**
1194         * Forwards to the RetransmitForward.jsp page so that we could open 2 windows for retransmit,
1195         * one is to display the PO tabbed page and the other one display the pdf document.
1196         * 
1197         * @param mapping
1198         * @param form
1199         * @param request
1200         * @param response
1201         * @return
1202         * @throws Exception
1203         */
1204        public ActionForward printingRetransmitPo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1205            String basePath = getBasePath(request);
1206            String docId = ((PurchaseOrderForm) form).getPurchaseOrderDocument().getDocumentNumber();
1207            String methodToCallPrintRetransmitPurchaseOrderPDF = "printingRetransmitPoOnly";
1208            String methodToCallDocHandler = "docHandler";
1209            String printPOPDFUrl = getUrlForPrintPO(basePath, docId, methodToCallPrintRetransmitPurchaseOrderPDF);
1210            String displayPOTabbedPageUrl = getUrlForPrintPO(basePath, docId, methodToCallDocHandler);
1211            
1212            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
1213            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
1214            
1215            StringBuffer itemIndexesBuffer = createSelectedItemIndexes(po.getItems());
1216            if (itemIndexesBuffer.length() > 0) {
1217                itemIndexesBuffer.deleteCharAt(itemIndexesBuffer.lastIndexOf(","));
1218                request.setAttribute("selectedItemIndexes", itemIndexesBuffer.toString());
1219            }
1220            
1221            request.setAttribute("printPOPDFUrl", printPOPDFUrl);
1222            request.setAttribute("displayPOTabbedPageUrl", displayPOTabbedPageUrl);
1223            request.setAttribute("docId", docId);
1224            String label = SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByTypeName(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER);
1225            request.setAttribute("purchaseOrderLabel", label);
1226            return mapping.findForward("retransmitPurchaseOrderPDF");
1227        }
1228        
1229        /**
1230         * Helper method to create a StringBuffer of the indexes of items that the user
1231         * has selected for retransmit to be passed in as an attribute to the RetransmitForward
1232         * page so that we could add these items later on to the pdf page.
1233         * 
1234         * @param items The List of items on the PurchaseOrderDocument.
1235         * @return
1236         */
1237        protected StringBuffer createSelectedItemIndexes(List<PurchaseOrderItem>items) {
1238            StringBuffer itemIndexesBuffer = new StringBuffer();
1239            int i = 0;
1240            for (PurchaseOrderItem item : items) {
1241                if (item.isItemSelectedForRetransmitIndicator()) {
1242                    itemIndexesBuffer.append(i);
1243                    itemIndexesBuffer.append(',');
1244                }
1245                i++;
1246            }
1247            return itemIndexesBuffer;
1248        }
1249        
1250        /**
1251         * Creates a PDF document based on the PO information and the items that were selected by the user on the Purchase Order
1252         * Retransmit Document page to be retransmitted, then display the PDF to the browser.
1253         * 
1254         * @param mapping An ActionMapping
1255         * @param form An ActionForm
1256         * @param request The HttpServletRequest
1257         * @param response The HttpServletResponse
1258         * @throws Exception
1259         * @return An ActionForward
1260         */
1261        public ActionForward printingRetransmitPoOnly(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1262    
1263            String selectedItemIndexes = (String)request.getParameter("selectedItemIndexes");
1264            String documentNumber = (String)request.getParameter("poDocumentNumberForRetransmit");
1265            PurchaseOrderDocument po = SpringContext.getBean(PurchaseOrderService.class).getPurchaseOrderByDocumentNumber(documentNumber);
1266            String retransmitHeader = (String)request.getParameter("retransmitHeader");
1267            
1268            // setting the isItemSelectedForRetransmitIndicator items of the PO obtained from the database based on its value from
1269            // the po from the form
1270            
1271            setItemSelectedForRetransmitIndicatorFromPOInForm(selectedItemIndexes, po.getItems());
1272            po.setRetransmitHeader(retransmitHeader);
1273            ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
1274            try {
1275                StringBuffer sbFilename = new StringBuffer();
1276                sbFilename.append("PURAP_PO_");
1277                sbFilename.append(po.getPurapDocumentIdentifier());
1278                sbFilename.append("_");
1279                sbFilename.append(System.currentTimeMillis());
1280                sbFilename.append(".pdf");
1281    
1282                // below method will throw ValidationException if errors are found
1283                SpringContext.getBean(PurchaseOrderService.class).retransmitPurchaseOrderPDF(po, baosPDF);
1284    
1285                response.setHeader("Cache-Control", "max-age=30");
1286                response.setContentType("application/pdf");
1287                StringBuffer sbContentDispValue = new StringBuffer();
1288                sbContentDispValue.append("inline");
1289                sbContentDispValue.append("; filename=");
1290                sbContentDispValue.append(sbFilename);
1291    
1292                response.setHeader("Content-disposition", sbContentDispValue.toString());
1293    
1294                response.setContentLength(baosPDF.size());
1295    
1296                ServletOutputStream sos;
1297    
1298                sos = response.getOutputStream();
1299    
1300                baosPDF.writeTo(sos);
1301    
1302                sos.flush();
1303    
1304            }
1305            catch (ValidationException e) {
1306                LOG.warn("Caught ValidationException while trying to retransmit PO with doc id " + po.getDocumentNumber());
1307                return mapping.findForward(KFSConstants.MAPPING_ERROR);
1308            }
1309            finally {
1310                if (baosPDF != null) {
1311                    baosPDF.reset();
1312                }
1313            }
1314    
1315            return null;
1316        }
1317    
1318        /**
1319         * Sets the itemSelectedForRetransmitIndicator to true to the items that the
1320         * user has selected for retransmit.
1321         * 
1322         * @param selectedItemIndexes  The String containing the indexes of items selected to be retransmitted, separated by comma.
1323         * @param itemsFromDB          The List of items of the PurchaseOrderDocument obtained from the database.
1324         */
1325        protected void setItemSelectedForRetransmitIndicatorFromPOInForm(String selectedItemIndexes, List itemsFromDB) {
1326            int i = 0;
1327            StringTokenizer tok = new StringTokenizer(selectedItemIndexes, ",");
1328            while (tok.hasMoreTokens()) {
1329                i = Integer.parseInt(tok.nextToken());
1330                ((PurchaseOrderItem) (itemsFromDB.get(i))).setItemSelectedForRetransmitIndicator(true);
1331            }
1332        }
1333        
1334        /**
1335         * Checks on a few conditions that would cause a warning message to be displayed on top of the Purchase Order page.
1336         * 
1337         * @param po the PurchaseOrderDocument whose status and indicators are to be checked in the conditions
1338         * @return boolean true if the Purchase Order doesn't have any warnings and false otherwise.
1339         */
1340        protected void checkForPOWarnings(PurchaseOrderDocument po, ActionMessages messages) {
1341            // "This is not the current version of this Purchase Order." (curr_ind = N and doc status is not enroute)
1342            if (!po.isPurchaseOrderCurrentIndicator() && !po.getDocumentHeader().getWorkflowDocument().stateIsEnroute()) {
1343                GlobalVariables.getMessageList().add(PurapKeyConstants.WARNING_PURCHASE_ORDER_NOT_CURRENT);
1344            }
1345            // "This document is a pending action. This is not the current version of this Purchase Order" (curr_ind = N and doc status
1346            // is enroute)
1347            if (!po.isPurchaseOrderCurrentIndicator() && po.getDocumentHeader().getWorkflowDocument().stateIsEnroute()) {
1348                GlobalVariables.getMessageList().add(PurapKeyConstants.WARNING_PURCHASE_ORDER_PENDING_ACTION_NOT_CURRENT);
1349            }
1350            // "There is a pending action on this Purchase Order." (pend_action = Y)
1351            if (po.isPendingActionIndicator()) {
1352                GlobalVariables.getMessageList().add(PurapKeyConstants.WARNING_PURCHASE_ORDER_PENDING_ACTION);
1353            }
1354    
1355            if (!po.isPurchaseOrderCurrentIndicator()) {
1356                ActionMessage noteMessage = new ActionMessage(PurapKeyConstants.WARNING_PURCHASE_ORDER_ALL_NOTES);
1357                messages.add(PurapConstants.NOTE_TAB_WARNING, noteMessage);
1358            }
1359        }
1360    
1361        /**
1362         * Add a stipulation to the document.
1363         * 
1364         * @param mapping An ActionMapping
1365         * @param form An ActionForm
1366         * @param request The HttpServletRequest
1367         * @param response The HttpServletResponse
1368         * @throws Exception
1369         * @return An ActionForward
1370         */
1371        public ActionForward addStipulation(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1372            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1373            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
1374    
1375            if (StringUtils.isBlank(poForm.getNewPurchaseOrderVendorStipulationLine().getVendorStipulationDescription())) {
1376                GlobalVariables.getMessageMap().putError(KFSConstants.DOCUMENT_PROPERTY_NAME + "." + PurapPropertyConstants.VENDOR_STIPULATION, PurapKeyConstants.ERROR_STIPULATION_DESCRIPTION);
1377            }
1378            else {
1379                PurchaseOrderVendorStipulation newStipulation = poForm.getAndResetNewPurchaseOrderVendorStipulationLine();
1380                document.getPurchaseOrderVendorStipulations().add(newStipulation);
1381            }
1382    
1383            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1384        }
1385    
1386        /**
1387         * Delete a stipulation from the document.
1388         * 
1389         * @param mapping An ActionMapping
1390         * @param form An ActionForm
1391         * @param request The HttpServletRequest
1392         * @param response The HttpServletResponse
1393         * @throws Exception
1394         * @return An ActionForward
1395         */
1396        public ActionForward deleteStipulation(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1397            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1398            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
1399            document.getPurchaseOrderVendorStipulations().remove(getSelectedLine(request));
1400    
1401            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1402        }
1403    
1404        /**
1405         * Overrides the docHandler method in the superclass. In addition to doing the normal process in the superclass and returning
1406         * its action forward from the superclass, it also invokes the <code>checkForPOWarnings</code> method to check on a few
1407         * conditions that could have caused warning messages to be displayed on top of Purchase Order page.
1408         * 
1409         * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#docHandler(org.apache.struts.action.ActionMapping,
1410         *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
1411         */
1412        @Override
1413        public ActionForward docHandler(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1414            ActionForward forward = super.docHandler(mapping, form, request, response);
1415            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1416            PurchaseOrderDocument po = (PurchaseOrderDocument) poForm.getDocument();
1417            
1418            ActionMessages messages = new ActionMessages();
1419            checkForPOWarnings(po, messages);
1420            saveMessages(request, messages);
1421            return forward;
1422        }
1423        
1424        /**
1425         * Sets up the PO document for Quote processing.
1426         * 
1427         * @param mapping An ActionMapping
1428         * @param form An ActionForm
1429         * @param request The HttpServletRequest
1430         * @param response The HttpServletResponse
1431         * @throws Exception
1432         * @return An ActionForward
1433         */
1434        public ActionForward initiateQuote(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1435            DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
1436            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1437            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
1438            if (!PurchaseOrderStatuses.IN_PROCESS.equals(document.getStatusCode())) {
1439                // PO must be "in process" in order to initiate a quote
1440                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_QUOTES, PurapKeyConstants.ERROR_PURCHASE_ORDER_QUOTE_NOT_IN_PROCESS);
1441                return mapping.findForward(KFSConstants.MAPPING_BASIC);
1442            }
1443            Calendar currentCalendar = dateTimeService.getCurrentCalendar();
1444            Date currentSqlDate = new java.sql.Date(currentCalendar.getTimeInMillis());
1445            document.setPurchaseOrderQuoteInitializationDate(currentSqlDate);
1446            document.setStatusCode(PurchaseOrderStatuses.QUOTE);
1447            document.setStatusChange(PurchaseOrderStatuses.QUOTE);
1448            document.refreshReferenceObject(PurapPropertyConstants.STATUS);
1449            
1450            //TODO this needs to be done better, and probably make it a parameter
1451            Calendar expCalendar = (Calendar) currentCalendar.clone();
1452            expCalendar.add(Calendar.DAY_OF_MONTH, 10);
1453            java.sql.Date expDate = new java.sql.Date(expCalendar.getTimeInMillis());
1454    
1455            document.setPurchaseOrderQuoteDueDate(expDate);
1456            document.getPurchaseOrderVendorQuotes().clear();
1457            SpringContext.getBean(PurapService.class).saveDocumentNoValidation(document);
1458    
1459            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1460        }
1461    
1462        /**
1463         * Add to the Quotes a line to contain a Vendor.
1464         * 
1465         * @param mapping An ActionMapping
1466         * @param form An ActionForm
1467         * @param request The HttpServletRequest
1468         * @param response The HttpServletResponse
1469         * @throws Exception
1470         * @return An ActionForward
1471         */
1472        public ActionForward addVendor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1473            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1474            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
1475            PurchaseOrderVendorQuote vendorQuote = poForm.getNewPurchaseOrderVendorQuote();
1476            String errorPrefix = PurapPropertyConstants.NEW_PURCHASE_ORDER_VENDOR_QUOTE_TEXT;
1477            boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedAddVendorToQuoteEvent(errorPrefix, document, vendorQuote));
1478            if (rulePassed) {
1479                poForm.getNewPurchaseOrderVendorQuote().setDocumentNumber(document.getDocumentNumber());
1480                document.getPurchaseOrderVendorQuotes().add(vendorQuote);
1481                poForm.setNewPurchaseOrderVendorQuote(new PurchaseOrderVendorQuote());
1482            }
1483            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1484        }
1485    
1486        /**
1487         * Deletes a Vendor from the list of those from which a Quote should be obtained.
1488         * 
1489         * @param mapping An ActionMapping
1490         * @param form An ActionForm
1491         * @param request The HttpServletRequest
1492         * @param response The HttpServletResponse
1493         * @throws Exception
1494         * @return An ActionForward
1495         */
1496        public ActionForward deleteVendor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1497            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1498            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
1499            document.getPurchaseOrderVendorQuotes().remove(getSelectedLine(request));
1500    
1501            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1502        }
1503    
1504        /**
1505         * Once an awarded Vendor number is present on the PO, verifies the fact, asks the user for confirmation to complete the quoting
1506         * process with the awarded Vendor, and sets the Vendor information on the purchase order, if confirmation is obtained.
1507         * 
1508         * @param mapping An ActionMapping
1509         * @param form An ActionForm
1510         * @param request The HttpServletRequest
1511         * @param response The HttpServletResponse
1512         * @throws Exception
1513         * @return An ActionForward
1514         */
1515        public ActionForward completeQuote(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1516            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1517            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
1518            PurchaseOrderVendorQuote awardedQuote = new PurchaseOrderVendorQuote();
1519    
1520            // verify that all vendors have a quote status
1521            // also run dictionary validations to validate against the DD.
1522            boolean dictionaryValid = true;
1523            for (PurchaseOrderVendorQuote poQuote : document.getPurchaseOrderVendorQuotes()) {
1524                if (poQuote.getPurchaseOrderQuoteStatusCode() == null) {
1525                    GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_QUOTES, PurapKeyConstants.ERROR_PURCHASE_ORDER_QUOTE_STATUS_NOT_SELECTED);
1526                    return mapping.findForward(KFSConstants.MAPPING_BASIC);
1527                } 
1528                else {
1529                    dictionaryValid &= SpringContext.getBean(DictionaryValidationService.class).isBusinessObjectValid(poQuote, PurapPropertyConstants.VENDOR_QUOTES);
1530                }
1531            }
1532            
1533            if (!dictionaryValid) {
1534                return mapping.findForward(KFSConstants.MAPPING_BASIC);
1535            }
1536            
1537            // verify quote status fields
1538            if (poForm.getAwardedVendorNumber() == null) {
1539                GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_QUOTES, PurapKeyConstants.ERROR_PURCHASE_ORDER_QUOTE_NO_VENDOR_AWARDED);
1540    
1541                return mapping.findForward(KFSConstants.MAPPING_BASIC);
1542            }
1543            else {
1544                awardedQuote = document.getPurchaseOrderVendorQuote(poForm.getAwardedVendorNumber().intValue());
1545                if (awardedQuote.getPurchaseOrderQuoteStatusCode() == null) {
1546                    GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_QUOTES, PurapKeyConstants.ERROR_PURCHASE_ORDER_QUOTE_NOT_TRANSMITTED);
1547    
1548                    return mapping.findForward(KFSConstants.MAPPING_BASIC);
1549                }
1550                else {
1551                    VendorDetail awardedVendor = SpringContext.getBean(VendorService.class).getVendorDetail(awardedQuote.getVendorHeaderGeneratedIdentifier(), awardedQuote.getVendorDetailAssignedIdentifier());
1552                    if (!awardedVendor.getVendorHeader().getVendorTypeCode().equals("PO")) {
1553                        GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_QUOTES, PurapKeyConstants.ERROR_PURCHASE_ORDER_QUOTE_AWARD_NON_PO);
1554                        
1555                        return mapping.findForward(KFSConstants.MAPPING_BASIC);
1556                    }
1557                }
1558            }
1559            
1560            // use question framework to make sure they REALLY want to complete the quote...
1561            // since the html table tags are not supported for now, the awarded vendor info is displayed without them.   
1562    //        String message = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_CONFIRM_AWARD);
1563    //        String vendorRow = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_CONFIRM_AWARD_ROW);
1564    //
1565    //        String tempRows = "";
1566    //        for (PurchaseOrderVendorQuote poQuote : document.getPurchaseOrderVendorQuotes()) {
1567    //            String tempRow = vendorRow;
1568    //            tempRow = StringUtils.replace(tempRow, "{0}", poQuote.getVendorName());
1569    //            if (poQuote.getPurchaseOrderQuoteAwardTimestamp() == null) {
1570    //                if (awardedQuote.getVendorNumber().equals(poQuote.getVendorNumber())) {
1571    //                    tempRow = StringUtils.replace(tempRow, "{1}", SpringContext.getBean(DateTimeService.class).getCurrentSqlDate().toString());
1572    //                }
1573    //                else {
1574    //                    tempRow = StringUtils.replace(tempRow, "{1}", "");
1575    //                }
1576    //            }
1577    //            else {
1578    //                tempRow = StringUtils.replace(tempRow, "{1}", poQuote.getPurchaseOrderQuoteAwardTimestamp().toString());
1579    //            }
1580    //            if (poQuote.getPurchaseOrderQuoteStatusCode() != null) {
1581    //                poQuote.refreshReferenceObject(PurapPropertyConstants.PURCHASE_ORDER_QUOTE_STATUS);
1582    //                tempRow = StringUtils.replace(tempRow, "{2}", poQuote.getPurchaseOrderQuoteStatus().getStatusDescription());
1583    //            }
1584    //            else {
1585    //                tempRow = StringUtils.replace(tempRow, "{2}", "N/A");
1586    //            }
1587    //            if (poQuote.getPurchaseOrderQuoteRankNumber() != null) {
1588    //                tempRow = StringUtils.replace(tempRow, "{3}", poQuote.getPurchaseOrderQuoteRankNumber());
1589    //            }
1590    //            else {
1591    //                tempRow = StringUtils.replace(tempRow, "{3}", "N/A");
1592    //            }
1593    //            tempRows += tempRow;
1594    //        }
1595    //        message = StringUtils.replace(message, "{0}", tempRows);
1596            // without the html table tags
1597            StringBuffer awardedVendorInfo = new StringBuffer(SpringContext.getBean(KualiConfigurationService.class).getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_CONFIRM_AWARD));
1598            int awardNbr = 0;
1599            for (PurchaseOrderVendorQuote poQuote : document.getPurchaseOrderVendorQuotes()) {
1600                
1601                // vendor name
1602                awardedVendorInfo.append(++awardNbr + ". ").append("Vendor Name: ");
1603                awardedVendorInfo.append(poQuote.getVendorName()).append("[br]");
1604                
1605                // awarded date
1606                awardedVendorInfo.append("Awarded Date: ");
1607                if (poQuote.getPurchaseOrderQuoteAwardTimestamp() == null) {
1608                    if (awardedQuote.getVendorNumber().equals(poQuote.getVendorNumber())) {
1609                        awardedVendorInfo.append(SpringContext.getBean(DateTimeService.class).getCurrentSqlDate().toString());
1610                    }
1611                }
1612                else {
1613                    awardedVendorInfo.append(poQuote.getPurchaseOrderQuoteAwardTimestamp().toString());
1614                }
1615                awardedVendorInfo.append("[br]");
1616                
1617                // quote status
1618                awardedVendorInfo.append("Quote Status: ");
1619                if (poQuote.getPurchaseOrderQuoteStatusCode() != null) {
1620                    poQuote.refreshReferenceObject(PurapPropertyConstants.PURCHASE_ORDER_QUOTE_STATUS);
1621                    awardedVendorInfo.append(poQuote.getPurchaseOrderQuoteStatus().getStatusDescription());
1622                }
1623                else {
1624                    awardedVendorInfo.append("N/A");
1625                }
1626                awardedVendorInfo.append("[br]");
1627                
1628                // rank
1629                awardedVendorInfo.append("Rank: ");
1630                if (poQuote.getPurchaseOrderQuoteRankNumber() != null) {
1631                    awardedVendorInfo.append(poQuote.getPurchaseOrderQuoteRankNumber());
1632                }
1633                else {
1634                    awardedVendorInfo.append("N/A");
1635                }
1636                awardedVendorInfo.append("[br][br]");               
1637            }
1638            
1639            Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
1640            if (question == null) {
1641                // ask question if not already asked
1642                return performQuestionWithoutInput(mapping, form, request, response, PODocumentsStrings.CONFIRM_AWARD_QUESTION, awardedVendorInfo.toString(), KFSConstants.CONFIRMATION_QUESTION, PODocumentsStrings.CONFIRM_AWARD_RETURN, "");
1643            }
1644            else {
1645                Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
1646                if ((PODocumentsStrings.CONFIRM_AWARD_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) {
1647                    // set awarded date
1648                    awardedQuote.setPurchaseOrderQuoteAwardTimestamp(SpringContext.getBean(DateTimeService.class).getCurrentTimestamp());
1649    
1650                    Date currentSqlDate = SpringContext.getBean(DateTimeService.class).getCurrentSqlDate();
1651                    document.setPurchaseOrderQuoteAwardedDate(currentSqlDate);
1652    
1653                    // PO vendor information updated with awarded vendor
1654                    document.setVendorName(awardedQuote.getVendorName());
1655                    document.setVendorNumber(awardedQuote.getVendorNumber());
1656                    Integer headID = awardedQuote.getVendorHeaderGeneratedIdentifier();
1657                    Integer detailID = awardedQuote.getVendorDetailAssignedIdentifier();
1658                    document.setVendorHeaderGeneratedIdentifier(headID);
1659                    document.setVendorDetailAssignedIdentifier(detailID);
1660                    
1661                    // use PO type address to fill in vendor address 
1662                    String campusCode = GlobalVariables.getUserSession().getPerson().getCampusCode();
1663                    VendorAddress pova = SpringContext.getBean(VendorService.class).getVendorDefaultAddress(headID, detailID, AddressTypes.PURCHASE_ORDER, campusCode);
1664                    document.setVendorLine1Address(pova.getVendorLine1Address());
1665                    document.setVendorLine2Address(pova.getVendorLine2Address());
1666                    document.setVendorCityName(pova.getVendorCityName());
1667                    document.setVendorStateCode(pova.getVendorStateCode());
1668                    document.setVendorPostalCode(pova.getVendorZipCode());
1669                    document.setVendorCountryCode(pova.getVendorCountryCode());
1670                    document.setVendorFaxNumber(pova.getVendorFaxNumber());
1671    
1672                    document.setStatusCode(PurapConstants.PurchaseOrderStatuses.IN_PROCESS);
1673                    SpringContext.getBean(PurapService.class).saveDocumentNoValidation(document);
1674                }
1675            }
1676    
1677            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1678        }
1679    
1680        /**
1681         * Cancels the process of obtaining quotes. Checks whether any of the quote requests have been transmitted. If none have, tries
1682         * to obtain confirmation from the user for the cancellation. If confirmation is obtained, clears out the list of Vendors from
1683         * which to obtain quotes and writes the given reason to a note on the PO.
1684         * 
1685         * @param mapping An ActionMapping
1686         * @param form An ActionForm
1687         * @param request The HttpServletRequest
1688         * @param response The HttpServletResponse
1689         * @throws Exception
1690         * @return An ActionForward
1691         */
1692        public ActionForward cancelQuote(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1693            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1694            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
1695    
1696            for (PurchaseOrderVendorQuote quotedVendors : document.getPurchaseOrderVendorQuotes()) {
1697                if (quotedVendors.getPurchaseOrderQuoteTransmitTimestamp() != null) {
1698                    GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_QUOTES, PurapKeyConstants.ERROR_PURCHASE_ORDER_QUOTE_ALREADY_TRASNMITTED);
1699    
1700                    return mapping.findForward(KFSConstants.MAPPING_BASIC);
1701                }
1702            }
1703    
1704            String message = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_CONFIRM_CANCEL_QUOTE);
1705            Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
1706    
1707            if (question == null) {
1708    
1709                // ask question if not already asked
1710                return performQuestionWithInput(mapping, form, request, response, PODocumentsStrings.CONFIRM_CANCEL_QUESTION, message, KFSConstants.CONFIRMATION_QUESTION, PODocumentsStrings.CONFIRM_CANCEL_RETURN, "");
1711            }
1712            else {
1713                Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
1714                if ((PODocumentsStrings.CONFIRM_CANCEL_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) {
1715                    String reason = request.getParameter(KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME);
1716    
1717                    if (StringUtils.isEmpty(reason)) {
1718    
1719                        return performQuestionWithInputAgainBecauseOfErrors(mapping, form, request, response, PODocumentsStrings.CONFIRM_CANCEL_QUESTION, message, KFSConstants.CONFIRMATION_QUESTION, PODocumentsStrings.CONFIRM_CANCEL_RETURN, "", "", PurapKeyConstants.ERROR_PURCHASE_ORDER_REASON_REQUIRED, KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME, "250");
1720                    }
1721                    document.getPurchaseOrderVendorQuotes().clear();
1722                    Note cancelNote = new Note();
1723                    cancelNote.setAuthorUniversalIdentifier(GlobalVariables.getUserSession().getPerson().getPrincipalId());
1724                    String reasonPrefix = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(PurapKeyConstants.PURCHASE_ORDER_CANCEL_QUOTE_NOTE_TEXT);
1725                    cancelNote.setNoteText(reasonPrefix + reason);
1726                    document.addNote(cancelNote);
1727                    document.setStatusCode(PurapConstants.PurchaseOrderStatuses.IN_PROCESS);
1728                    //being required to add notes about changing po status even though i'm not changing status
1729                    document.setStatusChange(null);
1730                    SpringContext.getBean(PurapService.class).saveDocumentNoValidation(document);
1731                }
1732            }
1733    
1734            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1735        }
1736    
1737        /**
1738         * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#cancel(org.apache.struts.action.ActionMapping,
1739         *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
1740         */
1741        @Override
1742        public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1743            Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
1744            // this should probably be moved into a protected instance variable
1745            KualiConfigurationService kualiConfiguration = SpringContext.getBean(KualiConfigurationService.class);
1746    
1747            // logic for cancel question
1748            if (question == null) {
1749    
1750                // ask question if not already asked
1751                return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.DOCUMENT_CANCEL_QUESTION, kualiConfiguration.getPropertyString("document.question.cancel.text"), KFSConstants.CONFIRMATION_QUESTION, KFSConstants.MAPPING_CANCEL, "");
1752            }
1753            else {
1754                Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
1755                if ((KFSConstants.DOCUMENT_CANCEL_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
1756    
1757                    // if no button clicked just reload the doc
1758                    return mapping.findForward(KFSConstants.MAPPING_BASIC);
1759                }
1760                // else go to cancel logic below
1761            }
1762    
1763            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
1764            SpringContext.getBean(DocumentService.class).cancelDocument(kualiDocumentFormBase.getDocument(), kualiDocumentFormBase.getAnnotation());
1765    
1766            return returnToSender(request, mapping, kualiDocumentFormBase);
1767        }
1768    
1769        /**
1770         * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#save(org.apache.struts.action.ActionMapping,
1771         *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
1772         */
1773        @Override
1774        public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1775            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1776            PurchaseOrderDocument po = poForm.getPurchaseOrderDocument();
1777    
1778            if (StringUtils.isNotBlank(po.getStatusCode()) && StringUtils.isNotBlank(po.getStatusChange()) && (!StringUtils.equals(po.getStatusCode(), po.getStatusChange()))) {
1779    
1780                KualiWorkflowDocument workflowDocument = po.getDocumentHeader().getWorkflowDocument();
1781                if (ObjectUtils.isNull(workflowDocument) || workflowDocument.stateIsInitiated() || workflowDocument.stateIsSaved()) {
1782    
1783                    return this.askSaveQuestions(mapping, form, request, response, PODocumentsStrings.MANUAL_STATUS_CHANGE_QUESTION);
1784                }
1785            }
1786    
1787            return super.save(mapping, form, request, response);
1788        }
1789    
1790        /**
1791         * Obtains confirmation and records reasons for the manual status changes which can take place before the purchase order has
1792         * been routed. If confirmation is given, changes the status, saves, and records the given reason in an note on the purchase
1793         * order.
1794         * 
1795         * @param mapping An ActionMapping
1796         * @param form An ActionForm
1797         * @param request The HttpServletRequest
1798         * @param response The HttpServletResponse
1799         * @return An ActionForward
1800         */
1801        protected ActionForward askSaveQuestions(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionType) {
1802            KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
1803            PurchaseOrderDocument po = (PurchaseOrderDocument) kualiDocumentFormBase.getDocument();
1804            Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
1805            String reason = request.getParameter(KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME);
1806            KualiConfigurationService kualiConfiguration = SpringContext.getBean(KualiConfigurationService.class);
1807            ActionForward forward = mapping.findForward(KFSConstants.MAPPING_BASIC);
1808            String notePrefix = "";
1809    
1810            if (StringUtils.equals(questionType, PODocumentsStrings.MANUAL_STATUS_CHANGE_QUESTION) && ObjectUtils.isNull(question)) {
1811                String message = kualiConfiguration.getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_MANUAL_STATUS_CHANGE);
1812                try {
1813    
1814                    return this.performQuestionWithInput(mapping, form, request, response, questionType, message, KFSConstants.CONFIRMATION_QUESTION, questionType, "");
1815                }
1816                catch (Exception e) {
1817                    throw new RuntimeException(e);
1818                }
1819            }
1820            else {
1821                Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
1822                if (question.equals(questionType) && buttonClicked.equals(ConfirmationQuestion.NO)) {
1823                    // If 'No' is the button clicked, just reload the doc
1824                    return forward;
1825                }
1826    
1827                // Build out full message.
1828                if (StringUtils.equals(questionType, PODocumentsStrings.MANUAL_STATUS_CHANGE_QUESTION)) {
1829                    Map<String, String> manuallyChangeableStatuses = new HashMap<String, String>();
1830                    manuallyChangeableStatuses.put(PurchaseOrderStatuses.IN_PROCESS, "In Process");
1831                    manuallyChangeableStatuses.put(PurchaseOrderStatuses.WAITING_FOR_VENDOR, "Waiting for Vendor");
1832                    manuallyChangeableStatuses.put(PurchaseOrderStatuses.WAITING_FOR_DEPARTMENT, "Waiting for Department");
1833    
1834                    String key = kualiConfiguration.getPropertyString(PurapKeyConstants.PURCHASE_ORDER_MANUAL_STATUS_CHANGE_NOTE_PREFIX);
1835                    String oldStatus = manuallyChangeableStatuses.get(po.getStatusCode());
1836                    String newStatus = manuallyChangeableStatuses.get(po.getStatusChange());
1837                    key = StringUtils.replace(key, "{0}", (StringUtils.isBlank(oldStatus) ? " " : oldStatus));
1838                    notePrefix = StringUtils.replace(key, "{1}", (StringUtils.isBlank(newStatus) ? " " : newStatus));
1839                }
1840                String noteText = notePrefix + KFSConstants.BLANK_SPACE + reason;
1841                int noteTextLength = noteText.length();
1842    
1843                // Get note text max length from DD.
1844                int noteTextMaxLength = SpringContext.getBean(DataDictionaryService.class).getAttributeMaxLength(Note.class, KFSConstants.NOTE_TEXT_PROPERTY_NAME).intValue();
1845    
1846                if (StringUtils.isBlank(reason) || (noteTextLength > noteTextMaxLength)) {
1847                    // Figure out exact number of characters that the user can enter.
1848                    int reasonLimit = noteTextMaxLength - noteTextLength;
1849    
1850                    if (ObjectUtils.isNull(reason)) {
1851                        // Prevent a NPE by setting the reason to a blank string.
1852                        reason = "";
1853                    }
1854    
1855                    try {
1856                        if (StringUtils.equals(questionType, PODocumentsStrings.MANUAL_STATUS_CHANGE_QUESTION)) {
1857    
1858                            return this.performQuestionWithInputAgainBecauseOfErrors(mapping, form, request, response, questionType, kualiConfiguration.getPropertyString(PurapKeyConstants.PURCHASE_ORDER_QUESTION_MANUAL_STATUS_CHANGE), KFSConstants.CONFIRMATION_QUESTION, questionType, "", reason, PurapKeyConstants.ERROR_PURCHASE_ORDER_REASON_REQUIRED, KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME, new Integer(reasonLimit).toString());
1859                        }
1860                    }
1861                    catch (Exception e) {
1862                        throw new RuntimeException(e);
1863                    }
1864                }
1865                else if (StringUtils.equals(questionType, PODocumentsStrings.MANUAL_STATUS_CHANGE_QUESTION)) {
1866                    executeManualStatusChange(po);
1867                    try {
1868                        forward = super.save(mapping, form, request, response);
1869                    }
1870                    catch (Exception e) {
1871                        throw new RuntimeException(e);
1872                    }
1873                }
1874                Note newNote = new Note();
1875                newNote.setNoteText(noteText);
1876                newNote.setNoteTypeCode(KFSConstants.NoteTypeEnum.BUSINESS_OBJECT_NOTE_TYPE.getCode());
1877                kualiDocumentFormBase.setNewNote(newNote);
1878                try {
1879                    insertBONote(mapping, kualiDocumentFormBase, request, response);
1880                }
1881                catch (Exception e) {
1882                    throw new RuntimeException(e);
1883                }
1884            }
1885    
1886            return forward;
1887        }
1888    
1889        /**
1890         * Applies a manual change of status to the given purchase order document.
1891         * 
1892         * @param po A PurchaseOrderDocument
1893         */
1894        protected void executeManualStatusChange(PurchaseOrderDocument po) {
1895            try {
1896                SpringContext.getBean(PurapService.class).updateStatus(po, po.getStatusChange());
1897            }
1898            catch (Exception e) {
1899                throw new RuntimeException(e);
1900            }
1901        }
1902    
1903        /**
1904         * @see org.kuali.kfs.module.purap.document.web.struts.PurchasingAccountsPayableActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
1905         */
1906        @Override
1907        protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
1908            super.loadDocument(kualiDocumentFormBase);
1909            PurchaseOrderForm poForm = (PurchaseOrderForm) kualiDocumentFormBase;
1910            PurchaseOrderDocument po = (PurchaseOrderDocument) poForm.getDocument();
1911            po.setInternalPurchasingLimit(SpringContext.getBean(PurchaseOrderService.class).getInternalPurchasingDollarLimit(po));
1912        }
1913        
1914        /**
1915         * Adds a PurchasingItemCapitalAsset (a container for the Capital Asset Number) to the selected 
1916         * item's list.
1917         * 
1918         * @param mapping       An ActionMapping
1919         * @param form          The Form
1920         * @param request       An HttpServletRequest
1921         * @param response      The HttpServletResponse
1922         * @return      An ActionForward
1923         * @throws Exception
1924         */
1925        public ActionForward addAsset(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1926            PurchaseOrderForm poForm = (PurchaseOrderForm)form;
1927            PurchaseOrderDocument document = (PurchaseOrderDocument)poForm.getDocument();
1928            PurchaseOrderItem item = (PurchaseOrderItem)document.getItemByLineNumber(getSelectedLine(request) + 1);
1929            //TODO: Add a new way to add assets to the system.
1930            //item.addAsset();
1931            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1932        }
1933    
1934        public ActionForward removeAlternateVendor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1935            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1936            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();
1937            
1938            document.setAlternateVendorDetailAssignedIdentifier(null);
1939            document.setAlternateVendorHeaderGeneratedIdentifier(null);
1940            document.setAlternateVendorName(null);
1941            document.setAlternateVendorNumber(null);
1942            
1943            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1944        }
1945        
1946        public ActionForward createReceivingLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1947            PurchaseOrderForm poForm = (PurchaseOrderForm) form;
1948            PurchaseOrderDocument document = (PurchaseOrderDocument) poForm.getDocument();        
1949            
1950            String basePath = getBasePath(request);
1951            String methodToCallDocHandler = "docHandler";
1952            String methodToCallReceivingLine = "initiate";
1953                            
1954            //set parameters
1955            Properties parameters = new Properties();
1956            parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, methodToCallDocHandler);
1957            parameters.put(KFSConstants.PARAMETER_COMMAND, methodToCallReceivingLine);
1958            parameters.put(KFSConstants.DOCUMENT_TYPE_NAME, "RCVL");        
1959            parameters.put("purchaseOrderId", document.getPurapDocumentIdentifier().toString() );
1960            
1961            //create url
1962            String receivingUrl = UrlFactory.parameterizeUrl(basePath + "/" + "purapLineItemReceiving.do", parameters);
1963            
1964            //create forward
1965            ActionForward forward = new ActionForward(receivingUrl, true);
1966            
1967            return forward;      
1968        }
1969        
1970        public ActionForward resendPoCxml(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1971            PurchaseOrderDocument po = (PurchaseOrderDocument) ((PurchaseOrderForm) form).getDocument();
1972            SpringContext.getBean(PurchaseOrderService.class).retransmitB2BPurchaseOrder(po);
1973            return mapping.findForward(KFSConstants.MAPPING_BASIC);
1974        }
1975    
1976    }
1977