/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.fp.document.web.struts; import java.io.ByteArrayOutputStream; import java.text.MessageFormat; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.kuali.kfs.fp.businessobject.DisbursementVoucherNonEmployeeExpense; import org.kuali.kfs.fp.businessobject.DisbursementVoucherNonEmployeeTravel; import org.kuali.kfs.fp.businessobject.DisbursementVoucherPreConferenceRegistrant; import org.kuali.kfs.fp.document.DisbursementVoucherConstants; import org.kuali.kfs.fp.document.DisbursementVoucherConstants.TabByReasonCode; import org.kuali.kfs.fp.document.DisbursementVoucherDocument; import org.kuali.kfs.fp.document.service.DisbursementVoucherCoverSheetService; import org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService; import org.kuali.kfs.fp.document.service.DisbursementVoucherTaxService; import org.kuali.kfs.fp.document.service.DisbursementVoucherTravelService; import org.kuali.kfs.integration.ar.AccountsReceivableCustomer; import org.kuali.kfs.integration.ar.AccountsReceivableCustomerAddress; import org.kuali.kfs.integration.ar.AccountsReceivableModuleService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.batch.service.PaymentSourceExtractionService; import org.kuali.kfs.sys.businessobject.WireCharge; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.service.UniversityDateService; import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase; import org.kuali.kfs.vnd.businessobject.VendorAddress; import org.kuali.kfs.vnd.businessobject.VendorDetail; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.kew.api.document.DocumentStatus; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.kim.api.identity.PersonService; import org.kuali.rice.kim.api.identity.entity.Entity; import org.kuali.rice.kim.api.services.KimApiServiceLocator; import org.kuali.rice.kns.document.authorization.TransactionalDocumentAuthorizer; import org.kuali.rice.kns.document.authorization.TransactionalDocumentPresentationController; import org.kuali.rice.kns.service.DictionaryValidationService; import org.kuali.rice.kns.util.WebUtils; import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krad.util.ObjectUtils; import org.kuali.rice.krad.util.UrlFactory; /** * This class handles Actions for the DisbursementVoucher. */ public class DisbursementVoucherAction extends KualiAccountingDocumentActionBase { protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherAction.class); /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase) */ @Override protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException { super.loadDocument(kualiDocumentFormBase); DisbursementVoucherForm dvForm = (DisbursementVoucherForm) kualiDocumentFormBase; DisbursementVoucherDocument dvDoc = (DisbursementVoucherDocument) dvForm.getDocument(); // do not execute the further refreshing logic if a payee is not selected String payeeIdNumber = dvDoc.getDvPayeeDetail().getDisbVchrPayeeIdNumber(); // KFSCNTRB-1735: no need to check for identity and issue a message per KFSMI-8935 if there's no payeeId and the document is saved. On other statuses (e.g. enroute) throw exception if there's no payee if( (payeeIdNumber != null && !payeeIdNumber.isEmpty()) || (!dvDoc.getDocumentHeader().getWorkflowDocument().checkStatus(DocumentStatus.SAVED)) ){ Entity entity = KimApiServiceLocator.getIdentityService().getEntityByEmployeeId(payeeIdNumber); //KFSMI-8935: When an employee is inactive, the Payment Type field on DV documents should display the message "Is this payee an employee" = No if (entity != null && entity.isActive()) { dvDoc.getDvPayeeDetail().setDisbVchrPayeeEmployeeCode(true); } else { dvDoc.getDvPayeeDetail().setDisbVchrPayeeEmployeeCode(false); } } } /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#execute(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward dest = super.execute(mapping, form, request, response); DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; if (form != null) { DisbursementVoucherDocument dvDoc = (DisbursementVoucherDocument) dvForm.getDocument(); if (dvDoc != null) { DisbursementVoucherNonEmployeeTravel dvNet = dvDoc.getDvNonEmployeeTravel(); if (dvNet != null) { // clear values derived from travelMileageAmount if that amount has been (manually) cleared Integer amount = dvNet.getDvPersonalCarMileageAmount(); if ((amount == null) || (amount.intValue() == 0)) { clearTravelMileageAmount(dvNet); } // clear values derived from perDiemRate if that amount has been (manually) cleared KualiDecimal rate = dvNet.getDisbVchrPerdiemRate(); if ((rate == null) || rate.isZero()) { clearTravelPerDiem(dvNet); } } } } return dest; } /** * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#approve(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward approve(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; SpringContext.getBean(DisbursementVoucherPayeeService.class).checkPayeeAddressForChanges((DisbursementVoucherDocument) dvForm.getDocument()); return super.approve(mapping, form, request, response); } /** * Do initialization for a new disbursement voucher * * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase) */ @Override protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException { super.createDocument(kualiDocumentFormBase); ((DisbursementVoucherDocument) kualiDocumentFormBase.getDocument()).initiateDocument(); // set wire charge message in form ((DisbursementVoucherForm) kualiDocumentFormBase).setWireChargeMessage(retrieveWireChargeMessage()); } /** * Calls service to generate the disbursement voucher cover sheet as a pdf. */ public ActionForward printDisbursementVoucherCoverSheet(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; // get directory of template String directory = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(KFSConstants.EXTERNALIZABLE_HELP_URL_KEY); DisbursementVoucherDocument document = (DisbursementVoucherDocument) SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(request.getParameter(KFSPropertyConstants.DOCUMENT_NUMBER)); // set workflow document back into form to prevent document authorizer "invalid (null) // document.documentHeader.workflowDocument" since we are bypassing form submit and just linking directly to the action dvForm.getDocument().getDocumentHeader().setWorkflowDocument(document.getDocumentHeader().getWorkflowDocument()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DisbursementVoucherCoverSheetService coverSheetService = SpringContext.getBean(DisbursementVoucherCoverSheetService.class); coverSheetService.generateDisbursementVoucherCoverSheet(directory, DisbursementVoucherConstants.DV_COVER_SHEET_TEMPLATE_NM, document, baos); String fileName = document.getDocumentNumber() + "_cover_sheet.pdf"; WebUtils.saveMimeOutputStreamAsFile(response, "application/pdf", baos, fileName); return (null); } /** * Calculates the travel per diem amount. */ public ActionForward calculateTravelPerDiem(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; try { // call service to calculate per diem DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); KualiDecimal perDiemAmount = SpringContext.getBean(DisbursementVoucherTravelService.class).calculatePerDiemAmount(dvDocument.getDvNonEmployeeTravel().getDvPerdiemStartDttmStamp(), dvDocument.getDvNonEmployeeTravel().getDvPerdiemEndDttmStamp(), dvDocument.getDvNonEmployeeTravel().getDisbVchrPerdiemRate()); dvDocument.getDvNonEmployeeTravel().setDisbVchrPerdiemCalculatedAmt(perDiemAmount); dvDocument.getDvNonEmployeeTravel().setDisbVchrPerdiemActualAmount(perDiemAmount); } catch (RuntimeException e) { String errorMessage = e.getMessage(); if (StringUtils.isBlank(errorMessage)) { 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."; } LOG.error("Error in calculating travel per diem: " + errorMessage); GlobalVariables.getMessageMap().putError("DVNonEmployeeTravelErrors", KFSKeyConstants.ERROR_CUSTOM, errorMessage); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Clears the travel per diem amount */ public ActionForward clearTravelPerDiem(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); DisbursementVoucherNonEmployeeTravel dvNet = dvDocument.getDvNonEmployeeTravel(); if (dvNet != null) { clearTravelPerDiem(dvNet); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * clear travel perdiem amounts */ protected void clearTravelPerDiem(DisbursementVoucherNonEmployeeTravel dvNet) { dvNet.setDisbVchrPerdiemCalculatedAmt(null); dvNet.setDisbVchrPerdiemActualAmount(null); } /** * Calculates the travel mileage amount. */ public ActionForward calculateTravelMileageAmount(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); if (dvDocument.getDvNonEmployeeTravel().getDvPersonalCarMileageAmount() == null) { LOG.error("Total Mileage must be given"); GlobalVariables.getMessageMap().putError("DVNonEmployeeTravelErrors", KFSKeyConstants.ERROR_REQUIRED, "Total Mileage"); } if (dvDocument.getDvNonEmployeeTravel().getDvPerdiemStartDttmStamp() == null) { LOG.error("Travel Start Date must be given"); GlobalVariables.getMessageMap().putError("DVNonEmployeeTravelErrors", KFSKeyConstants.ERROR_REQUIRED, "Travel Start Date"); } if (!GlobalVariables.getMessageMap().hasErrors()) { // call service to calculate mileage amount KualiDecimal mileageAmount = SpringContext.getBean(DisbursementVoucherTravelService.class).calculateMileageAmount(dvDocument.getDvNonEmployeeTravel().getDvPersonalCarMileageAmount(), dvDocument.getDvNonEmployeeTravel().getDvPerdiemStartDttmStamp()); dvDocument.getDvNonEmployeeTravel().setDisbVchrMileageCalculatedAmt(mileageAmount); dvDocument.getDvNonEmployeeTravel().setDisbVchrPersonalCarAmount(mileageAmount); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Clears the travel mileage amount */ public ActionForward clearTravelMileageAmount(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); DisbursementVoucherNonEmployeeTravel dvNet = dvDocument.getDvNonEmployeeTravel(); if (dvNet != null) { clearTravelMileageAmount(dvNet); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * reset the travel mileage amount as null */ protected void clearTravelMileageAmount(DisbursementVoucherNonEmployeeTravel dvNet) { dvNet.setDisbVchrMileageCalculatedAmt(null); dvNet.setDisbVchrPersonalCarAmount(null); } /** * Adds a new employee travel expense line. */ public ActionForward addNonEmployeeExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); DisbursementVoucherNonEmployeeExpense newExpenseLine = dvForm.getNewNonEmployeeExpenseLine(); // validate line GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.NEW_NONEMPLOYEE_EXPENSE_LINE); SpringContext.getBean(DictionaryValidationService.class).validateBusinessObject(newExpenseLine); // Ensure all fields are filled in before attempting to add a new expense line if (StringUtils.isBlank(newExpenseLine.getDisbVchrPrePaidExpenseCode())) { GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_EXPENSE_CODE, KFSKeyConstants.ERROR_DV_EXPENSE_CODE); } if (StringUtils.isBlank(newExpenseLine.getDisbVchrPrePaidExpenseCompanyName())) { GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_EXPENSE_COMPANY_NAME, KFSKeyConstants.ERROR_DV_EXPENSE_COMPANY_NAME); } if (ObjectUtils.isNull(newExpenseLine.getDisbVchrExpenseAmount())) { GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_EXPENSE_AMOUNT, KFSKeyConstants.ERROR_DV_EXPENSE_AMOUNT); } GlobalVariables.getMessageMap().removeFromErrorPath(KFSPropertyConstants.NEW_NONEMPLOYEE_EXPENSE_LINE); //KFSMI-9523 //no errors so go ahead and add the record to the list. Need to set the document number //and recalculate the next line number for the new record that is created after adding the //current one. if (!GlobalVariables.getMessageMap().hasErrors()) { newExpenseLine.setDocumentNumber(dvDocument.getDocumentNumber()); dvDocument.getDvNonEmployeeTravel().addDvNonEmployeeExpenseLine(newExpenseLine); DisbursementVoucherNonEmployeeExpense newNewNonEmployeeExpenseLine = new DisbursementVoucherNonEmployeeExpense(); newNewNonEmployeeExpenseLine.setFinancialDocumentLineNumber(newExpenseLine.getFinancialDocumentLineNumber() + 1); dvForm.setNewNonEmployeeExpenseLine(newNewNonEmployeeExpenseLine); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Adds a new employee pre paid travel expense line. */ public ActionForward addPrePaidNonEmployeeExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); DisbursementVoucherNonEmployeeExpense newExpenseLine = dvForm.getNewPrePaidNonEmployeeExpenseLine(); // validate line GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.NEW_PREPAID_EXPENSE_LINE); SpringContext.getBean(DictionaryValidationService.class).validateBusinessObject(newExpenseLine); // Ensure all fields are filled in before attempting to add a new expense line if (StringUtils.isBlank(newExpenseLine.getDisbVchrPrePaidExpenseCode())) { GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_PRE_PAID_EXPENSE_CODE, KFSKeyConstants.ERROR_DV_PREPAID_EXPENSE_CODE); } if (StringUtils.isBlank(newExpenseLine.getDisbVchrPrePaidExpenseCompanyName())) { GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_PRE_PAID_EXPENSE_COMPANY_NAME, KFSKeyConstants.ERROR_DV_PREPAID_EXPENSE_COMPANY_NAME); } if (ObjectUtils.isNull(newExpenseLine.getDisbVchrExpenseAmount())) { GlobalVariables.getMessageMap().putError(KFSPropertyConstants.DISB_VCHR_EXPENSE_AMOUNT, KFSKeyConstants.ERROR_DV_PREPAID_EXPENSE_AMOUNT); } GlobalVariables.getMessageMap().removeFromErrorPath(KFSPropertyConstants.NEW_PREPAID_EXPENSE_LINE); //KFSMI-9523 //no errors so go ahead and add the record to the list. Need to set the document number //and recalculate the next line number for the new record that is created after adding the //current one. if (!GlobalVariables.getMessageMap().hasErrors()) { newExpenseLine.setDocumentNumber(dvDocument.getDocumentNumber()); dvDocument.getDvNonEmployeeTravel().addDvPrePaidEmployeeExpenseLine(newExpenseLine); DisbursementVoucherNonEmployeeExpense newNewNonEmployeeExpenseLine = new DisbursementVoucherNonEmployeeExpense(); newNewNonEmployeeExpenseLine.setFinancialDocumentLineNumber(newExpenseLine.getFinancialDocumentLineNumber() + 1); dvForm.setNewPrePaidNonEmployeeExpenseLine(newNewNonEmployeeExpenseLine); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Deletes a non employee travel expense line. */ public ActionForward deleteNonEmployeeExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); int deleteIndex = getLineToDelete(request); dvDocument.getDvNonEmployeeTravel().getDvNonEmployeeExpenses().remove(deleteIndex); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Deletes a pre paid travel expense line. */ public ActionForward deletePrePaidEmployeeExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); int deleteIndex = getLineToDelete(request); dvDocument.getDvNonEmployeeTravel().getDvPrePaidEmployeeExpenses().remove(deleteIndex); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Adds a new pre conference registrant line. */ public ActionForward addPreConfRegistrantLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); DisbursementVoucherPreConferenceRegistrant newRegistrantLine = dvForm.getNewPreConferenceRegistrantLine(); // validate line GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.NEW_PRECONF_REGISTRANT_LINE); SpringContext.getBean(DictionaryValidationService.class).validateBusinessObject(newRegistrantLine); GlobalVariables.getMessageMap().removeFromErrorPath(KFSPropertyConstants.NEW_PRECONF_REGISTRANT_LINE); if (!GlobalVariables.getMessageMap().hasErrors()) { dvDocument.addDvPrePaidRegistrantLine(newRegistrantLine); dvForm.setNewPreConferenceRegistrantLine(new DisbursementVoucherPreConferenceRegistrant()); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Deletes a pre conference registrant line. */ public ActionForward deletePreConfRegistrantLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); int deleteIndex = getLineToDelete(request); dvDocument.getDvPreConferenceDetail().getDvPreConferenceRegistrants().remove(deleteIndex); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Calls service to generate tax accounting lines and updates nra tax line string in action form. */ public ActionForward generateNonResidentAlienTaxLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument(); DisbursementVoucherTaxService taxService = SpringContext.getBean(DisbursementVoucherTaxService.class); /* call service to generate new tax lines */ GlobalVariables.getMessageMap().addToErrorPath("document"); taxService.processNonResidentAlienTax(document); GlobalVariables.getMessageMap().removeFromErrorPath("document"); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Calls service to clear tax accounting lines and updates nra tax line string in action form. */ public ActionForward clearNonResidentAlienTaxLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument(); DisbursementVoucherTaxService taxService = SpringContext.getBean(DisbursementVoucherTaxService.class); /* call service to clear previous lines */ taxService.clearNRATaxLines(document); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Calls service to clear tax info. */ public ActionForward clearNonResidentAlienTaxInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument(); DisbursementVoucherTaxService taxService = SpringContext.getBean(DisbursementVoucherTaxService.class); /* call service to clear previous lines */ taxService.clearNRATaxInfo(document); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Builds the wire charge message for the current fiscal year. * * @return the wire charge message for the current fiscal year */ protected String retrieveWireChargeMessage() { String message = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(KFSKeyConstants.MESSAGE_PAYMENT_WIRE_CHARGE); WireCharge wireCharge = new WireCharge(); wireCharge.setUniversityFiscalYear(SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear()); wireCharge = (WireCharge) SpringContext.getBean(BusinessObjectService.class).retrieve(wireCharge); Object[] args = { wireCharge.getDomesticChargeAmt(), wireCharge.getForeignChargeAmt() }; return MessageFormat.format(message, args); } /** * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; ActionForward actionAfterPayeeLookup = this.refreshAfterPayeeSelection(mapping, dvForm, request); if (actionAfterPayeeLookup != null) { return actionAfterPayeeLookup; } return super.refresh(mapping, form, request, response); } // do refresh after a payee is selected protected ActionForward refreshAfterPayeeSelection(ActionMapping mapping, DisbursementVoucherForm dvForm, HttpServletRequest request) { String refreshCaller = dvForm.getRefreshCaller(); DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument(); boolean isPayeeLookupable = KFSConstants.KUALI_DISBURSEMENT_PAYEE_LOOKUPABLE_IMPL.equals(refreshCaller); boolean isAddressLookupable = KFSConstants.KUALI_VENDOR_ADDRESS_LOOKUPABLE_IMPL.equals(refreshCaller); boolean isKualiLookupable = KFSConstants.KUALI_LOOKUPABLE_IMPL.equals(refreshCaller); // if a cancel occurred on address lookup we need to reset the payee id and type, rest of fields will still have correct information if (refreshCaller == null && hasFullEdit(document)) { dvForm.setPayeeIdNumber(dvForm.getTempPayeeIdNumber()); dvForm.setHasMultipleAddresses(false); document.getDvPayeeDetail().setDisbVchrPayeeIdNumber(dvForm.getTempPayeeIdNumber()); document.getDvPayeeDetail().setDisbursementVoucherPayeeTypeCode(dvForm.getOldPayeeType()); return null; } // do not execute the further refreshing logic if the refresh caller is not a lookupable if (!isPayeeLookupable && !isAddressLookupable && !isKualiLookupable) { return null; } // do not execute the further refreshing logic if a payee is not selected String payeeIdNumber = document.getDvPayeeDetail().getDisbVchrPayeeIdNumber(); if (payeeIdNumber == null) { return null; } dvForm.setPayeeIdNumber(payeeIdNumber); dvForm.setHasMultipleAddresses(false); // determine whether the selected vendor has multiple addresses. If so, redirect to the address selection screen if (isPayeeLookupable && dvForm.isVendor()) { VendorDetail refreshVendorDetail = new VendorDetail(); refreshVendorDetail.setVendorNumber(payeeIdNumber); refreshVendorDetail = (VendorDetail) SpringContext.getBean(BusinessObjectService.class).retrieve(refreshVendorDetail); VendorAddress defaultVendorAddress = null; if (refreshVendorDetail != null) { List<VendorAddress> vendorAddresses = refreshVendorDetail.getVendorAddresses(); boolean hasMultipleAddresses = vendorAddresses != null && vendorAddresses.size() > 1; dvForm.setHasMultipleAddresses(hasMultipleAddresses); if (vendorAddresses != null) { defaultVendorAddress = vendorAddresses.get(0); } } if (dvForm.hasMultipleAddresses()) { return renderVendorAddressSelection(mapping, request, dvForm); } else if (defaultVendorAddress != null) { setupPayeeAsVendor(dvForm, payeeIdNumber, defaultVendorAddress.getVendorAddressGeneratedIdentifier().toString()); } return null; } String payeeAddressIdentifier = request.getParameter(KFSPropertyConstants.VENDOR_ADDRESS_GENERATED_ID); if (isAddressLookupable && StringUtils.isNotBlank(payeeAddressIdentifier)) { setupPayeeAsVendor(dvForm, payeeIdNumber, payeeAddressIdentifier); } if (isPayeeLookupable && dvForm.isEmployee()) { this.setupPayeeAsEmployee(dvForm, payeeIdNumber); } // check for multiple custom addresses if (isPayeeLookupable && dvForm.isCustomer()) { AccountsReceivableCustomer customer = SpringContext.getBean(AccountsReceivableModuleService.class).findCustomer(payeeIdNumber); AccountsReceivableCustomerAddress defaultCustomerAddress = null; if (customer != null) { defaultCustomerAddress = customer.getPrimaryAddress(); Map<String, String> addressSearch = new HashMap<String, String>(); addressSearch.put(KFSPropertyConstants.CUSTOMER_NUMBER, payeeIdNumber); List<AccountsReceivableCustomerAddress> customerAddresses = (List<AccountsReceivableCustomerAddress>) SpringContext.getBean(AccountsReceivableModuleService.class).searchForCustomerAddresses(addressSearch); if (customerAddresses != null && !customerAddresses.isEmpty()) { if (customerAddresses.size() > 1) { dvForm.setHasMultipleAddresses(true); } else if (defaultCustomerAddress == null) { defaultCustomerAddress = customerAddresses.get(0); } } } if (dvForm.hasMultipleAddresses()) { return renderCustomerAddressSelection(mapping, request, dvForm); } else if (defaultCustomerAddress != null) { setupPayeeAsCustomer(dvForm, payeeIdNumber, defaultCustomerAddress.getCustomerAddressIdentifier().toString()); } } String customerAddressIdentifier = request.getParameter(KFSPropertyConstants.CUSTOMER_ADDRESS_IDENTIFIER); if (isKualiLookupable && StringUtils.isNotBlank(customerAddressIdentifier)) { setupPayeeAsCustomer(dvForm, payeeIdNumber, customerAddressIdentifier); } String paymentReasonCode = document.getDvPayeeDetail().getDisbVchrPaymentReasonCode(); addPaymentCodeWarningMessage(dvForm, paymentReasonCode); return null; } /** * Determines if the current user has full edit permissions on the document, which would allow them to repopulate the payee * @param document the document to check for full edit permissions on * @return true if full edit is allowed on the document, false otherwise */ protected boolean hasFullEdit(DisbursementVoucherDocument document) { final Person user = GlobalVariables.getUserSession().getPerson(); final TransactionalDocumentPresentationController documentPresentationController = (TransactionalDocumentPresentationController)getDocumentHelperService().getDocumentPresentationController(document); final TransactionalDocumentAuthorizer documentAuthorizer = (TransactionalDocumentAuthorizer)getDocumentHelperService().getDocumentAuthorizer(document); Set<String> documentActions = documentPresentationController.getDocumentActions(document); documentActions = documentAuthorizer.getDocumentActions(document, user, documentActions); if (getDataDictionaryService().getDataDictionary().getDocumentEntry(document.getClass().getName()).getUsePessimisticLocking()) { documentActions = getPessimisticLockService().getDocumentActions(document, user, documentActions); } Set<String> editModes = documentPresentationController.getEditModes(document); editModes = documentAuthorizer.getEditModes(document, user, editModes); return documentActions.contains(KRADConstants.KUALI_ACTION_CAN_EDIT) && editModes.contains("fullEntry"); } /** * Hook into performLookup to switch the payee lookup based on the payee type selected. */ @Override public ActionForward performLookup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument document = (DisbursementVoucherDocument) dvForm.getDocument(); return super.performLookup(mapping, form, request, response); } /** * render the vendor address lookup results if there are multiple addresses for the selected vendor */ protected ActionForward renderVendorAddressSelection(ActionMapping mapping, HttpServletRequest request, DisbursementVoucherForm dvForm) { Properties props = new Properties(); props.put(KRADConstants.SUPPRESS_ACTIONS, Boolean.toString(true)); props.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, VendorAddress.class.getName()); props.put(KRADConstants.LOOKUP_ANCHOR, KRADConstants.ANCHOR_TOP_OF_FORM); props.put(KRADConstants.LOOKED_UP_COLLECTION_NAME, KFSPropertyConstants.VENDOR_ADDRESSES); String conversionPatttern = "{0}" + KFSConstants.FIELD_CONVERSION_PAIR_SEPERATOR + "{0}"; StringBuilder filedConversion = new StringBuilder(); filedConversion.append(MessageFormat.format(conversionPatttern, KFSPropertyConstants.VENDOR_ADDRESS_GENERATED_ID)).append(KFSConstants.FIELD_CONVERSIONS_SEPERATOR); filedConversion.append(MessageFormat.format(conversionPatttern, KFSPropertyConstants.VENDOR_HEADER_GENERATED_ID)).append(KFSConstants.FIELD_CONVERSIONS_SEPERATOR); filedConversion.append(MessageFormat.format(conversionPatttern, KFSPropertyConstants.VENDOR_DETAIL_ASSIGNED_ID)); props.put(KRADConstants.CONVERSION_FIELDS_PARAMETER, filedConversion); props.put(KFSPropertyConstants.VENDOR_HEADER_GENERATED_ID, dvForm.getVendorHeaderGeneratedIdentifier()); props.put(KFSPropertyConstants.VENDOR_DETAIL_ASSIGNED_ID, dvForm.getVendorDetailAssignedIdentifier()); props.put(KFSPropertyConstants.ACTIVE, KFSConstants.ACTIVE_INDICATOR); props.put(KRADConstants.RETURN_LOCATION_PARAMETER, this.getReturnLocation(request, mapping)); props.put(KRADConstants.BACK_LOCATION, this.getReturnLocation(request, mapping)); props.put(KRADConstants.LOOKUP_AUTO_SEARCH, "Yes"); props.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.SEARCH_METHOD); props.put(KRADConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(dvForm)); props.put(KRADConstants.DOC_NUM, dvForm.getDocument().getDocumentNumber()); // TODO: how should this forward be handled String url = UrlFactory.parameterizeUrl(getApplicationBaseUrl() + "/kr/" + KRADConstants.LOOKUP_ACTION, props); dvForm.registerEditableProperty("methodToCall"); return new ActionForward(url, true); } /** * setup the payee as an employee with the given id number */ protected void setupPayeeAsEmployee(DisbursementVoucherForm dvForm, String payeeIdNumber) { Person person = SpringContext.getBean(PersonService.class).getPersonByEmployeeId(payeeIdNumber); if (person != null) { ((DisbursementVoucherDocument) dvForm.getDocument()).templateEmployee(person); dvForm.setTempPayeeIdNumber(payeeIdNumber); dvForm.setOldPayeeType(KFSConstants.PaymentPayeeTypes.EMPLOYEE); } else { LOG.error("Exception while attempting to retrieve universal user by universal user id " + payeeIdNumber); } } /** * setup the payee as a vendor with the given id number and address id */ protected void setupPayeeAsVendor(DisbursementVoucherForm dvForm, String payeeIdNumber, String payeeAddressIdentifier) { VendorDetail vendorDetail = new VendorDetail(); vendorDetail.setVendorNumber(payeeIdNumber); vendorDetail = (VendorDetail) SpringContext.getBean(BusinessObjectService.class).retrieve(vendorDetail); VendorAddress vendorAddress = new VendorAddress(); if (StringUtils.isNotBlank(payeeAddressIdentifier)) { try { vendorAddress.setVendorAddressGeneratedIdentifier(new Integer(payeeAddressIdentifier)); vendorAddress = (VendorAddress) SpringContext.getBean(BusinessObjectService.class).retrieve(vendorAddress); dvForm.setTempPayeeIdNumber(payeeIdNumber); dvForm.setOldPayeeType(KFSConstants.PaymentPayeeTypes.VENDOR); } catch (Exception e) { LOG.error("Exception while attempting to retrieve vendor address for vendor address id " + payeeAddressIdentifier + ": " + e); } } ((DisbursementVoucherDocument) dvForm.getDocument()).templateVendor(vendorDetail, vendorAddress); } /** * render the customer address lookup results if there are multiple addresses for the selected customer */ protected ActionForward renderCustomerAddressSelection(ActionMapping mapping, HttpServletRequest request, DisbursementVoucherForm dvForm) { Properties props = new Properties(); props.put(KRADConstants.SUPPRESS_ACTIONS, Boolean.toString(true)); props.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, AccountsReceivableCustomerAddress.class.getName()); props.put(KRADConstants.LOOKUP_ANCHOR, KRADConstants.ANCHOR_TOP_OF_FORM); props.put(KRADConstants.LOOKED_UP_COLLECTION_NAME, KFSPropertyConstants.VENDOR_ADDRESSES); String conversionPatttern = "{0}" + KFSConstants.FIELD_CONVERSION_PAIR_SEPERATOR + "{0}"; StringBuilder filedConversion = new StringBuilder(); filedConversion.append(MessageFormat.format(conversionPatttern, KFSPropertyConstants.CUSTOMER_NUMBER)).append(KFSConstants.FIELD_CONVERSIONS_SEPERATOR); filedConversion.append(MessageFormat.format(conversionPatttern, KFSPropertyConstants.CUSTOMER_ADDRESS_IDENTIFIER)); props.put(KRADConstants.CONVERSION_FIELDS_PARAMETER, filedConversion); props.put(KFSPropertyConstants.CUSTOMER_NUMBER, dvForm.getPayeeIdNumber()); props.put(KFSPropertyConstants.ACTIVE, KFSConstants.ACTIVE_INDICATOR); props.put(KRADConstants.RETURN_LOCATION_PARAMETER, this.getReturnLocation(request, mapping)); props.put(KRADConstants.BACK_LOCATION, this.getReturnLocation(request, mapping)); props.put(KRADConstants.LOOKUP_AUTO_SEARCH, "Yes"); props.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.SEARCH_METHOD); props.put(KRADConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(dvForm)); props.put(KRADConstants.DOC_NUM, dvForm.getDocument().getDocumentNumber()); // TODO: how should this forward be handled String url = UrlFactory.parameterizeUrl(getApplicationBaseUrl() + "/kr/" + KRADConstants.LOOKUP_ACTION, props); dvForm.registerEditableProperty("methodToCall"); return new ActionForward(url, true); } /** * setup the payee as a customer with the given id number and address id */ protected void setupPayeeAsCustomer(DisbursementVoucherForm dvForm, String payeeIdNumber, String payeeAddressIdentifier) { AccountsReceivableCustomer customer = SpringContext.getBean(AccountsReceivableModuleService.class).findCustomer(payeeIdNumber); AccountsReceivableCustomerAddress customerAddress = null; if (StringUtils.isNotBlank(payeeAddressIdentifier)) { customerAddress = SpringContext.getBean(AccountsReceivableModuleService.class).findCustomerAddress(payeeIdNumber, payeeAddressIdentifier); } dvForm.setTempPayeeIdNumber(payeeIdNumber); dvForm.setOldPayeeType(KFSConstants.PaymentPayeeTypes.CUSTOMER); ((DisbursementVoucherDocument) dvForm.getDocument()).templateCustomer(customer, customerAddress); } /** * add warning message based on the given reason code */ protected void addPaymentCodeWarningMessage(DisbursementVoucherForm dvForm, String paymentReasonCode) { // clear up the warning message and tab state carried from previous screen for (String tabKey : TabByReasonCode.getAllTabKeys()) { dvForm.getTabStates().remove(tabKey); } for (String propertyKey : TabByReasonCode.getAllDocumentPropertyKeys()) { GlobalVariables.getMessageMap().removeAllWarningMessagesForProperty(propertyKey); } String reasonCodeProperty = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.DV_PAYEE_DETAIL + "." + KFSPropertyConstants.DISB_VCHR_PAYMENT_REASON_CODE; GlobalVariables.getMessageMap().removeAllWarningMessagesForProperty(reasonCodeProperty); // add warning message and reset tab state as open if any TabByReasonCode tab = TabByReasonCode.getTabByReasonCode(paymentReasonCode); if (tab != null) { dvForm.getTabStates().put(tab.tabKey, "OPEN"); GlobalVariables.getMessageMap().putWarning(reasonCodeProperty, tab.messageKey); GlobalVariables.getMessageMap().putWarning(tab.getDocumentPropertyKey(), tab.messageKey); } } /** * Extracts the DV as immediate payment upon user's request after it routes to FINAL. */ public ActionForward extractNow(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DisbursementVoucherForm dvForm = (DisbursementVoucherForm) form; DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) dvForm.getDocument(); PaymentSourceExtractionService disbursementVoucherExtractService = DisbursementVoucherDocument.getDisbursementVoucherExtractService(); dvDocument.setImmediatePaymentIndicator(true); disbursementVoucherExtractService.extractSingleImmediatePayment(dvDocument); return mapping.findForward(KFSConstants.MAPPING_BASIC); } }