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.fp.document.web.struts;
017    
018    import java.io.ByteArrayOutputStream;
019    import java.text.MessageFormat;
020    import java.util.List;
021    import java.util.Properties;
022    import java.util.Set;
023    
024    import javax.servlet.http.HttpServletRequest;
025    import javax.servlet.http.HttpServletResponse;
026    
027    import org.apache.commons.lang.StringUtils;
028    import org.apache.struts.action.ActionForm;
029    import org.apache.struts.action.ActionForward;
030    import org.apache.struts.action.ActionMapping;
031    import org.kuali.kfs.fp.businessobject.DisbursementVoucherNonEmployeeExpense;
032    import org.kuali.kfs.fp.businessobject.DisbursementVoucherNonEmployeeTravel;
033    import org.kuali.kfs.fp.businessobject.DisbursementVoucherPreConferenceRegistrant;
034    import org.kuali.kfs.fp.businessobject.WireCharge;
035    import org.kuali.kfs.fp.document.DisbursementVoucherConstants;
036    import org.kuali.kfs.fp.document.DisbursementVoucherDocument;
037    import org.kuali.kfs.fp.document.DisbursementVoucherConstants.TabByReasonCode;
038    import org.kuali.kfs.fp.document.service.DisbursementVoucherCoverSheetService;
039    import org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService;
040    import org.kuali.kfs.fp.document.service.DisbursementVoucherTaxService;
041    import org.kuali.kfs.fp.document.service.DisbursementVoucherTravelService;
042    import org.kuali.kfs.sys.KFSConstants;
043    import org.kuali.kfs.sys.KFSKeyConstants;
044    import org.kuali.kfs.sys.KFSPropertyConstants;
045    import org.kuali.kfs.sys.context.SpringContext;
046    import org.kuali.kfs.sys.service.UniversityDateService;
047    import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase;
048    import org.kuali.kfs.vnd.businessobject.VendorAddress;
049    import org.kuali.kfs.vnd.businessobject.VendorDetail;
050    import org.kuali.rice.kew.exception.WorkflowException;
051    import org.kuali.rice.kim.bo.Person;
052    import org.kuali.rice.kim.service.PersonService;
053    import org.kuali.rice.kns.document.authorization.TransactionalDocumentAuthorizer;
054    import org.kuali.rice.kns.document.authorization.TransactionalDocumentPresentationController;
055    import org.kuali.rice.kns.service.BusinessObjectService;
056    import org.kuali.rice.kns.service.DictionaryValidationService;
057    import org.kuali.rice.kns.service.DocumentService;
058    import org.kuali.rice.kns.service.KualiConfigurationService;
059    import org.kuali.rice.kns.util.GlobalVariables;
060    import org.kuali.rice.kns.util.KNSConstants;
061    import org.kuali.rice.kns.util.KualiDecimal;
062    import org.kuali.rice.kns.util.ObjectUtils;
063    import org.kuali.rice.kns.util.UrlFactory;
064    import org.kuali.rice.kns.util.WebUtils;
065    import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
066    
067    /**
068     * This class handles Actions for the DisbursementVoucher.
069     */
070    public class DisbursementVoucherAction extends KualiAccountingDocumentActionBase {
071        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherAction.class);
072    
073        /**
074         * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#execute(org.apache.struts.action.ActionMapping,
075         *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
076         */
077        @Override
078        public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
079            ActionForward dest = super.execute(mapping, form, request, response);
080    
081            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
082            if (form != null) {
083                DisbursementVoucherDocument dvDoc = (DisbursementVoucherDocument) dvForm.getDocument();
084                if (dvDoc != null) {
085                    DisbursementVoucherNonEmployeeTravel dvNet = dvDoc.getDvNonEmployeeTravel();
086                    if (dvNet != null) {
087                        // clear values derived from travelMileageAmount if that amount has been (manually) cleared
088                        Integer amount = dvNet.getDvPersonalCarMileageAmount();
089                        if ((amount == null) || (amount.intValue() == 0)) {
090                            clearTravelMileageAmount(dvNet);
091                        }
092    
093                        // clear values derived from perDiemRate if that amount has been (manually) cleared
094                        KualiDecimal rate = dvNet.getDisbVchrPerdiemRate();
095                        if ((rate == null) || rate.isZero()) {
096                            clearTravelPerDiem(dvNet);
097                        }
098                    }
099                }
100            }
101    
102            return dest;
103        }
104    
105        /**
106         * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#approve(org.apache.struts.action.ActionMapping,
107         *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
108         */
109        @Override
110        public ActionForward approve(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
111            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
112            SpringContext.getBean(DisbursementVoucherPayeeService.class).checkPayeeAddressForChanges((DisbursementVoucherDocument) dvForm.getDocument());
113    
114            return super.approve(mapping, form, request, response);
115        }
116    
117        /**
118         * Do initialization for a new disbursement voucher
119         * 
120         * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
121         */
122        @Override
123        protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
124            super.createDocument(kualiDocumentFormBase);
125            ((DisbursementVoucherDocument) kualiDocumentFormBase.getDocument()).initiateDocument();
126    
127            // set wire charge message in form
128            ((DisbursementVoucherForm) kualiDocumentFormBase).setWireChargeMessage(retrieveWireChargeMessage());
129        }
130    
131        /**
132         * Calls service to generate the disbursement voucher cover sheet as a pdf.
133         */
134        public ActionForward printDisbursementVoucherCoverSheet(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
135            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
136    
137            // get directory of template
138            String directory = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.EXTERNALIZABLE_HELP_URL_KEY);
139    
140            DisbursementVoucherDocument document = (DisbursementVoucherDocument) SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(request.getParameter(KFSPropertyConstants.DOCUMENT_NUMBER));
141    
142            // set workflow document back into form to prevent document authorizer "invalid (null)
143            // document.documentHeader.workflowDocument" since we are bypassing form submit and just linking directly to the action
144    
145            dvForm.getDocument().getDocumentHeader().setWorkflowDocument(document.getDocumentHeader().getWorkflowDocument());
146    
147            ByteArrayOutputStream baos = new ByteArrayOutputStream();
148            DisbursementVoucherCoverSheetService coverSheetService = SpringContext.getBean(DisbursementVoucherCoverSheetService.class);
149    
150            coverSheetService.generateDisbursementVoucherCoverSheet(directory, DisbursementVoucherConstants.DV_COVER_SHEET_TEMPLATE_NM, document, baos);
151            String fileName = document.getDocumentNumber() + "_cover_sheet.pdf";
152            WebUtils.saveMimeOutputStreamAsFile(response, "application/pdf", baos, fileName);
153    
154            return (null);
155        }
156    
157        /**
158         * Calculates the travel per diem amount.
159         */
160        public ActionForward calculateTravelPerDiem(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
161            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
162    
163            try {
164                // call service to calculate per diem
165                DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
166                KualiDecimal perDiemAmount = SpringContext.getBean(DisbursementVoucherTravelService.class).calculatePerDiemAmount(dvDocument.getDvNonEmployeeTravel().getDvPerdiemStartDttmStamp(), dvDocument.getDvNonEmployeeTravel().getDvPerdiemEndDttmStamp(), dvDocument.getDvNonEmployeeTravel().getDisbVchrPerdiemRate());
167    
168                dvDocument.getDvNonEmployeeTravel().setDisbVchrPerdiemCalculatedAmt(perDiemAmount);
169                dvDocument.getDvNonEmployeeTravel().setDisbVchrPerdiemActualAmount(perDiemAmount);
170            }
171            catch (RuntimeException e) {
172                String errorMessage = e.getMessage();
173    
174                if (StringUtils.isBlank(errorMessage)) {
175                    errorMessage = "The per diem amount could not be calculated.  Please ensure all required per diem fields are filled in before attempting to calculate the per diem amount.";
176                }
177    
178                LOG.error("Error in calculating travel per diem: " + errorMessage);
179                GlobalVariables.getMessageMap().putError("DVNonEmployeeTravelErrors", KFSKeyConstants.ERROR_CUSTOM, errorMessage);
180            }
181    
182            return mapping.findForward(KFSConstants.MAPPING_BASIC);
183        }
184    
185        /**
186         * Clears the travel per diem amount
187         */
188        public ActionForward clearTravelPerDiem(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
189            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
190            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
191    
192            DisbursementVoucherNonEmployeeTravel dvNet = dvDocument.getDvNonEmployeeTravel();
193            if (dvNet != null) {
194                clearTravelPerDiem(dvNet);
195            }
196    
197            return mapping.findForward(KFSConstants.MAPPING_BASIC);
198        }
199    
200        /**
201         * clear travel perdiem amounts
202         */
203        protected void clearTravelPerDiem(DisbursementVoucherNonEmployeeTravel dvNet) {
204            dvNet.setDisbVchrPerdiemCalculatedAmt(null);
205            dvNet.setDisbVchrPerdiemActualAmount(null);
206        }
207    
208        /**
209         * Calculates the travel mileage amount.
210         */
211        public ActionForward calculateTravelMileageAmount(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
212            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
213            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
214    
215            if (dvDocument.getDvNonEmployeeTravel().getDvPersonalCarMileageAmount() == null) {
216                LOG.error("Total Mileage must be given");
217                GlobalVariables.getMessageMap().putError("DVNonEmployeeTravelErrors", KFSKeyConstants.ERROR_REQUIRED, "Total Mileage");
218            }
219    
220            if (dvDocument.getDvNonEmployeeTravel().getDvPerdiemStartDttmStamp() == null) {
221                LOG.error("Travel Start Date must be given");
222                GlobalVariables.getMessageMap().putError("DVNonEmployeeTravelErrors", KFSKeyConstants.ERROR_REQUIRED, "Travel Start Date");
223            }
224    
225            if (GlobalVariables.getMessageMap().isEmpty()) {
226                // call service to calculate mileage amount
227                KualiDecimal mileageAmount = SpringContext.getBean(DisbursementVoucherTravelService.class).calculateMileageAmount(dvDocument.getDvNonEmployeeTravel().getDvPersonalCarMileageAmount(), dvDocument.getDvNonEmployeeTravel().getDvPerdiemStartDttmStamp());
228    
229                dvDocument.getDvNonEmployeeTravel().setDisbVchrMileageCalculatedAmt(mileageAmount);
230                dvDocument.getDvNonEmployeeTravel().setDisbVchrPersonalCarAmount(mileageAmount);
231            }
232    
233            return mapping.findForward(KFSConstants.MAPPING_BASIC);
234        }
235    
236        /**
237         * Clears the travel mileage amount
238         */
239        public ActionForward clearTravelMileageAmount(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
240            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
241            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
242    
243            DisbursementVoucherNonEmployeeTravel dvNet = dvDocument.getDvNonEmployeeTravel();
244            if (dvNet != null) {
245                clearTravelMileageAmount(dvNet);
246            }
247    
248            return mapping.findForward(KFSConstants.MAPPING_BASIC);
249        }
250    
251        /**
252         * reset the travel mileage amount as null
253         */
254        protected void clearTravelMileageAmount(DisbursementVoucherNonEmployeeTravel dvNet) {
255            dvNet.setDisbVchrMileageCalculatedAmt(null);
256            dvNet.setDisbVchrPersonalCarAmount(null);
257        }
258    
259        /**
260         * Adds a new employee travel expense line.
261         */
262        public ActionForward addNonEmployeeExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
263            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
264            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
265    
266            DisbursementVoucherNonEmployeeExpense newExpenseLine = dvForm.getNewNonEmployeeExpenseLine();
267    
268            // validate line
269            GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.NEW_NONEMPLOYEE_EXPENSE_LINE);
270            SpringContext.getBean(DictionaryValidationService.class).validateBusinessObject(newExpenseLine);
271    
272            // Ensure all fields are filled in before attempting to add a new expense line
273            if (StringUtils.isBlank(newExpenseLine.getDisbVchrPrePaidExpenseCode())) {
274                GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_EXPENSE_CODE, KFSKeyConstants.ERROR_DV_EXPENSE_CODE);
275            }
276            if (StringUtils.isBlank(newExpenseLine.getDisbVchrPrePaidExpenseCompanyName())) {
277                GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_EXPENSE_COMPANY_NAME, KFSKeyConstants.ERROR_DV_EXPENSE_COMPANY_NAME);
278            }
279            if (ObjectUtils.isNull(newExpenseLine.getDisbVchrExpenseAmount())) {
280                GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_EXPENSE_AMOUNT, KFSKeyConstants.ERROR_DV_EXPENSE_AMOUNT);
281            }
282    
283            GlobalVariables.getMessageMap().removeFromErrorPath(KFSPropertyConstants.NEW_NONEMPLOYEE_EXPENSE_LINE);
284    
285            if (GlobalVariables.getMessageMap().isEmpty()) {
286                dvDocument.getDvNonEmployeeTravel().addDvNonEmployeeExpenseLine(newExpenseLine);
287                dvForm.setNewNonEmployeeExpenseLine(new DisbursementVoucherNonEmployeeExpense());
288            }
289    
290            return mapping.findForward(KFSConstants.MAPPING_BASIC);
291        }
292    
293        /**
294         * Adds a new employee pre paid travel expense line.
295         */
296        public ActionForward addPrePaidNonEmployeeExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
297            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
298            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
299    
300            DisbursementVoucherNonEmployeeExpense newExpenseLine = dvForm.getNewPrePaidNonEmployeeExpenseLine();
301    
302            // validate line
303            GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.NEW_PREPAID_EXPENSE_LINE);
304            SpringContext.getBean(DictionaryValidationService.class).validateBusinessObject(newExpenseLine);
305    
306            // Ensure all fields are filled in before attempting to add a new expense line
307            if (StringUtils.isBlank(newExpenseLine.getDisbVchrPrePaidExpenseCode())) {
308                GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_PRE_PAID_EXPENSE_CODE, KFSKeyConstants.ERROR_DV_PREPAID_EXPENSE_CODE);
309            }
310            if (StringUtils.isBlank(newExpenseLine.getDisbVchrPrePaidExpenseCompanyName())) {
311                GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_PRE_PAID_EXPENSE_COMPANY_NAME, KFSKeyConstants.ERROR_DV_PREPAID_EXPENSE_COMPANY_NAME);
312            }
313            if (ObjectUtils.isNull(newExpenseLine.getDisbVchrExpenseAmount())) {
314                GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_EXPENSE_AMOUNT, KFSKeyConstants.ERROR_DV_PREPAID_EXPENSE_AMOUNT);
315            }
316            GlobalVariables.getMessageMap().removeFromErrorPath(KFSPropertyConstants.NEW_PREPAID_EXPENSE_LINE);
317    
318            if (GlobalVariables.getMessageMap().isEmpty()) {
319                dvDocument.getDvNonEmployeeTravel().addDvPrePaidEmployeeExpenseLine(newExpenseLine);
320                dvForm.setNewPrePaidNonEmployeeExpenseLine(new DisbursementVoucherNonEmployeeExpense());
321            }
322    
323            return mapping.findForward(KFSConstants.MAPPING_BASIC);
324        }
325    
326        /**
327         * Deletes a non employee travel expense line.
328         */
329        public ActionForward deleteNonEmployeeExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
330            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
331            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
332    
333            int deleteIndex = getLineToDelete(request);
334            dvDocument.getDvNonEmployeeTravel().getDvNonEmployeeExpenses().remove(deleteIndex);
335    
336            return mapping.findForward(KFSConstants.MAPPING_BASIC);
337        }
338    
339        /**
340         * Deletes a pre paid travel expense line.
341         */
342        public ActionForward deletePrePaidEmployeeExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
343            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
344            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
345    
346            int deleteIndex = getLineToDelete(request);
347            dvDocument.getDvNonEmployeeTravel().getDvPrePaidEmployeeExpenses().remove(deleteIndex);
348    
349            return mapping.findForward(KFSConstants.MAPPING_BASIC);
350        }
351    
352        /**
353         * Adds a new pre conference registrant line.
354         */
355        public ActionForward addPreConfRegistrantLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
356            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
357            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
358    
359            DisbursementVoucherPreConferenceRegistrant newRegistrantLine = dvForm.getNewPreConferenceRegistrantLine();
360    
361            // validate line
362            GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.NEW_PRECONF_REGISTRANT_LINE);
363            SpringContext.getBean(DictionaryValidationService.class).validateBusinessObject(newRegistrantLine);
364            GlobalVariables.getMessageMap().removeFromErrorPath(KFSPropertyConstants.NEW_PRECONF_REGISTRANT_LINE);
365    
366            if (GlobalVariables.getMessageMap().isEmpty()) {
367                dvDocument.addDvPrePaidRegistrantLine(newRegistrantLine);
368                dvForm.setNewPreConferenceRegistrantLine(new DisbursementVoucherPreConferenceRegistrant());
369            }
370    
371            return mapping.findForward(KFSConstants.MAPPING_BASIC);
372        }
373    
374        /**
375         * Deletes a pre conference registrant line.
376         */
377        public ActionForward deletePreConfRegistrantLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
378            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
379            DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument();
380    
381            int deleteIndex = getLineToDelete(request);
382            dvDocument.getDvPreConferenceDetail().getDvPreConferenceRegistrants().remove(deleteIndex);
383    
384            return mapping.findForward(KFSConstants.MAPPING_BASIC);
385        }
386    
387        /**
388         * Calls service to generate tax accounting lines and updates nra tax line string in action form.
389         */
390        public ActionForward generateNonResidentAlienTaxLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
391            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
392            DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument();
393    
394            DisbursementVoucherTaxService taxService = SpringContext.getBean(DisbursementVoucherTaxService.class);
395    
396            /* call service to generate new tax lines */
397            GlobalVariables.getMessageMap().addToErrorPath("document");
398            taxService.processNonResidentAlienTax(document);
399            GlobalVariables.getMessageMap().removeFromErrorPath("document");
400    
401            return mapping.findForward(KFSConstants.MAPPING_BASIC);
402        }
403    
404        /**
405         * Calls service to clear tax accounting lines and updates nra tax line string in action form.
406         */
407        public ActionForward clearNonResidentAlienTaxLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
408            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
409            DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument();
410    
411            DisbursementVoucherTaxService taxService = SpringContext.getBean(DisbursementVoucherTaxService.class);
412    
413            /* call service to clear previous lines */
414            taxService.clearNRATaxLines(document);
415    
416            return mapping.findForward(KFSConstants.MAPPING_BASIC);
417        }
418    
419        /**
420         * Builds the wire charge message for the current fiscal year.
421         * 
422         * @return the wire charge message for the current fiscal year
423         */
424        protected String retrieveWireChargeMessage() {
425            String message = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSKeyConstants.MESSAGE_DV_WIRE_CHARGE);
426            WireCharge wireCharge = new WireCharge();
427            wireCharge.setUniversityFiscalYear(SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear());
428    
429            wireCharge = (WireCharge) SpringContext.getBean(BusinessObjectService.class).retrieve(wireCharge);
430            Object[] args = { wireCharge.getDomesticChargeAmt(), wireCharge.getForeignChargeAmt() };
431    
432            return MessageFormat.format(message, args);
433        }
434    
435        /**
436         * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
437         *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
438         */
439        @Override
440        public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
441            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
442    
443            ActionForward actionAfterPayeeLookup = this.refreshAfterPayeeSelection(mapping, dvForm, request);
444            if (actionAfterPayeeLookup != null) {
445                return actionAfterPayeeLookup;
446            }
447    
448            return super.refresh(mapping, form, request, response);
449        }
450    
451        // do refresh after a payee is selected
452        protected ActionForward refreshAfterPayeeSelection(ActionMapping mapping, DisbursementVoucherForm dvForm, HttpServletRequest request) {
453            String refreshCaller = dvForm.getRefreshCaller();
454            
455            DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument();
456    
457            boolean isPayeeLookupable = KFSConstants.KUALI_DISBURSEMENT_PAYEE_LOOKUPABLE_IMPL.equals(refreshCaller);
458            boolean isAddressLookupable = KFSConstants.KUALI_VENDOR_ADDRESS_LOOKUPABLE_IMPL.equals(refreshCaller);
459    
460            // if a cancel occurred on address lookup we need to reset the payee id and type, rest of fields will still have correct information
461            if (refreshCaller == null && hasFullEdit(document)) {
462                dvForm.setPayeeIdNumber(dvForm.getTempPayeeIdNumber());
463                dvForm.setHasMultipleAddresses(false);
464                document.getDvPayeeDetail().setDisbVchrPayeeIdNumber(dvForm.getTempPayeeIdNumber());
465                document.getDvPayeeDetail().setDisbursementVoucherPayeeTypeCode(dvForm.getOldPayeeType());
466                
467                return null;
468            }
469            
470            // do not execute the further refreshing logic if the refresh caller is not a lookupable
471            if (!isPayeeLookupable && !isAddressLookupable) {
472                return null;
473            }
474    
475            // do not execute the further refreshing logic if a payee is not selected
476            String payeeIdNumber = document.getDvPayeeDetail().getDisbVchrPayeeIdNumber();
477            if (payeeIdNumber == null) {
478                return null;
479            }
480    
481            dvForm.setPayeeIdNumber(payeeIdNumber);
482            dvForm.setHasMultipleAddresses(false);
483    
484            // determine whether the selected vendor has multiple addresses. If so, redirect to the address selection screen
485            if (isPayeeLookupable && dvForm.isVendor()) {
486                VendorDetail refreshVendorDetail = new VendorDetail();
487                refreshVendorDetail.setVendorNumber(payeeIdNumber);
488                refreshVendorDetail = (VendorDetail) SpringContext.getBean(BusinessObjectService.class).retrieve(refreshVendorDetail);
489    
490                VendorAddress defaultVendorAddress = null;
491                if (refreshVendorDetail != null) {
492                    List<VendorAddress> vendorAddresses = refreshVendorDetail.getVendorAddresses();
493                    boolean hasMultipleAddresses = vendorAddresses != null && vendorAddresses.size() > 1;
494                    dvForm.setHasMultipleAddresses(hasMultipleAddresses);
495    
496                    if (vendorAddresses != null) {
497                        defaultVendorAddress = vendorAddresses.get(0);
498                    }
499                }
500    
501                if (dvForm.hasMultipleAddresses()) {
502                    return renderVendorAddressSelection(mapping, request, dvForm);
503                }
504                else if (defaultVendorAddress != null) {
505                    setupPayeeAsVendor(dvForm, payeeIdNumber, defaultVendorAddress.getVendorAddressGeneratedIdentifier().toString());
506                }
507    
508                return null;
509            }
510    
511            if (isPayeeLookupable && dvForm.isEmployee()) {
512                this.setupPayeeAsEmployee(dvForm, payeeIdNumber);
513            }
514    
515            String payeeAddressIdentifier = request.getParameter(KFSPropertyConstants.VENDOR_ADDRESS_GENERATED_ID);
516            if (isAddressLookupable && StringUtils.isNotBlank(payeeAddressIdentifier)) {
517                setupPayeeAsVendor(dvForm, payeeIdNumber, payeeAddressIdentifier);
518            }
519    
520            String paymentReasonCode = document.getDvPayeeDetail().getDisbVchrPaymentReasonCode();
521            addPaymentCodeWarningMessage(dvForm, paymentReasonCode);
522    
523            return null;
524        }
525        
526        /**
527         * Determines if the current user has full edit permissions on the document, which would allow them to repopulate the payee
528         * @param document the document to check for full edit permissions on
529         * @return true if full edit is allowed on the document, false otherwise
530         */
531        protected boolean hasFullEdit(DisbursementVoucherDocument document) {
532            final Person user = GlobalVariables.getUserSession().getPerson();
533            final TransactionalDocumentPresentationController documentPresentationController = (TransactionalDocumentPresentationController)getDocumentHelperService().getDocumentPresentationController(document);
534            final TransactionalDocumentAuthorizer documentAuthorizer = (TransactionalDocumentAuthorizer)getDocumentHelperService().getDocumentAuthorizer(document);
535            Set<String> documentActions =  documentPresentationController.getDocumentActions(document);
536            documentActions = documentAuthorizer.getDocumentActions(document, user, documentActions);
537    
538            if (getDataDictionaryService().getDataDictionary().getDocumentEntry(document.getClass().getName()).getUsePessimisticLocking()) {
539                documentActions = getPessimisticLockService().getDocumentActions(document, user, documentActions);
540            }
541            
542            Set<String> editModes = documentPresentationController.getEditModes(document);
543            editModes = documentAuthorizer.getEditModes(document, user, editModes);
544            
545            return documentActions.contains(KNSConstants.KUALI_ACTION_CAN_EDIT) && editModes.contains("fullEntry");
546        }
547    
548        /**
549         * Hook into performLookup to switch the payee lookup based on the payee type selected.
550         */
551        public ActionForward performLookup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
552            DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form;
553            DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument();
554    
555            return super.performLookup(mapping, form, request, response);
556        }
557    
558        /**
559         * render the vendor address lookup results if there are multiple addresses for the selected vendor
560         */
561        protected ActionForward renderVendorAddressSelection(ActionMapping mapping, HttpServletRequest request, DisbursementVoucherForm dvForm) {
562            Properties props = new Properties();
563    
564            props.put(KNSConstants.SUPPRESS_ACTIONS, Boolean.toString(true));
565            props.put(KNSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, VendorAddress.class.getName());
566            props.put(KNSConstants.LOOKUP_ANCHOR, KNSConstants.ANCHOR_TOP_OF_FORM);
567            props.put(KNSConstants.LOOKED_UP_COLLECTION_NAME, KFSPropertyConstants.VENDOR_ADDRESSES);
568    
569            String conversionPatttern = "{0}" + KFSConstants.FIELD_CONVERSION_PAIR_SEPERATOR + "{0}";
570            StringBuilder filedConversion = new StringBuilder();
571            filedConversion.append(MessageFormat.format(conversionPatttern, KFSPropertyConstants.VENDOR_ADDRESS_GENERATED_ID)).append(KFSConstants.FIELD_CONVERSIONS_SEPERATOR);
572            filedConversion.append(MessageFormat.format(conversionPatttern, KFSPropertyConstants.VENDOR_HEADER_GENERATED_ID)).append(KFSConstants.FIELD_CONVERSIONS_SEPERATOR);
573            filedConversion.append(MessageFormat.format(conversionPatttern, KFSPropertyConstants.VENDOR_DETAIL_ASSIGNED_ID));
574            props.put(KNSConstants.CONVERSION_FIELDS_PARAMETER, filedConversion);
575    
576            props.put(KFSPropertyConstants.VENDOR_HEADER_GENERATED_ID, dvForm.getVendorHeaderGeneratedIdentifier());
577            props.put(KFSPropertyConstants.VENDOR_DETAIL_ASSIGNED_ID, dvForm.getVendorDetailAssignedIdentifier());
578            props.put(KFSPropertyConstants.ACTIVE, KFSConstants.ACTIVE_INDICATOR);
579    
580            props.put(KNSConstants.RETURN_LOCATION_PARAMETER, this.getReturnLocation(request, mapping));
581            props.put(KNSConstants.BACK_LOCATION, this.getReturnLocation(request, mapping));
582    
583            props.put(KNSConstants.LOOKUP_AUTO_SEARCH, "Yes");
584            props.put(KNSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.SEARCH_METHOD);
585    
586            props.put(KNSConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObject(dvForm));
587            props.put(KNSConstants.DOC_NUM, dvForm.getDocument().getDocumentNumber());
588    
589            // TODO: how should this forward be handled
590            String url = UrlFactory.parameterizeUrl(getBasePath(request) + "/kr/" + KNSConstants.LOOKUP_ACTION, props);
591    
592            dvForm.registerEditableProperty("methodToCall");
593    
594            return new ActionForward(url, true);
595        }
596    
597        /**
598         * setup the payee as an employee with the given id number
599         */
600        protected void setupPayeeAsEmployee(DisbursementVoucherForm dvForm, String payeeIdNumber) {
601            Person person = (Person) SpringContext.getBean(PersonService.class).getPersonByEmployeeId(payeeIdNumber);
602            if (person != null) {
603                ((DisbursementVoucherDocument) dvForm.getDocument()).templateEmployee(person);
604                dvForm.setTempPayeeIdNumber(payeeIdNumber);
605                dvForm.setOldPayeeType(DisbursementVoucherConstants.DV_PAYEE_TYPE_EMPLOYEE);
606    
607            }
608            else {
609                LOG.error("Exception while attempting to retrieve universal user by universal user id " + payeeIdNumber);
610            }
611        }
612    
613        /**
614         * setup the payee as a vendor with the given id number and address id
615         */
616        protected void setupPayeeAsVendor(DisbursementVoucherForm dvForm, String payeeIdNumber, String payeeAddressIdentifier) {
617            VendorDetail vendorDetail = new VendorDetail();
618            vendorDetail.setVendorNumber(payeeIdNumber);
619            vendorDetail = (VendorDetail) SpringContext.getBean(BusinessObjectService.class).retrieve(vendorDetail);
620    
621            VendorAddress vendorAddress = new VendorAddress();
622            if (StringUtils.isNotBlank(payeeAddressIdentifier)) {
623                try {
624                    vendorAddress.setVendorAddressGeneratedIdentifier(new Integer(payeeAddressIdentifier));
625                    vendorAddress = (VendorAddress) SpringContext.getBean(BusinessObjectService.class).retrieve(vendorAddress);
626                    dvForm.setTempPayeeIdNumber(payeeIdNumber);
627                    dvForm.setOldPayeeType(DisbursementVoucherConstants.DV_PAYEE_TYPE_VENDOR);
628    
629                }
630                catch (Exception e) {
631                    LOG.error("Exception while attempting to retrieve vendor address for vendor address id " + payeeAddressIdentifier + ": " + e);
632                }
633            }
634    
635            ((DisbursementVoucherDocument) dvForm.getDocument()).templateVendor(vendorDetail, vendorAddress);
636        }
637    
638        /**
639         * add warning message based on the given reason code
640         */
641        protected void addPaymentCodeWarningMessage(DisbursementVoucherForm dvForm, String paymentReasonCode) {
642            // clear up the warning message and tab state carried from previous screen
643            for (String tabKey : TabByReasonCode.getAllTabKeys()) {
644                dvForm.getTabStates().remove(tabKey);
645            }
646    
647            for (String propertyKey : TabByReasonCode.getAllDocumentPropertyKeys()) {
648                GlobalVariables.getMessageMap().removeAllWarningMessagesForProperty(propertyKey);
649            }
650    
651            String reasonCodeProperty = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.DV_PAYEE_DETAIL + "." + KFSPropertyConstants.DISB_VCHR_PAYMENT_REASON_CODE;
652            GlobalVariables.getMessageMap().removeAllWarningMessagesForProperty(reasonCodeProperty);
653    
654            // add warning message and reset tab state as open if any
655            TabByReasonCode tab = TabByReasonCode.getTabByReasonCode(paymentReasonCode);
656            if (tab != null) {
657                dvForm.getTabStates().put(tab.tabKey, "OPEN");
658                GlobalVariables.getMessageMap().putWarning(reasonCodeProperty, tab.messageKey);
659                GlobalVariables.getMessageMap().putWarning(tab.getDocumentPropertyKey(), tab.messageKey);
660            }
661        }
662        
663        
664    
665    }