/* * 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.module.tem.document.web.struts; import static org.kuali.kfs.module.tem.TemConstants.COVERSHEET_FILENAME_FORMAT; import static org.kuali.kfs.module.tem.TemConstants.REMAINING_DISTRIBUTION_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.SHOW_REPORTS_ATTRIBUTE; import static org.kuali.kfs.sys.KFSPropertyConstants.DOCUMENT_NUMBER; import java.io.ByteArrayOutputStream; import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.kuali.kfs.fp.document.DisbursementVoucherDocument; import org.kuali.kfs.fp.document.web.struts.DisbursementVoucherForm; import org.kuali.kfs.module.tem.TemConstants; import org.kuali.kfs.module.tem.TemPropertyConstants; import org.kuali.kfs.module.tem.businessobject.AccountingDistribution; import org.kuali.kfs.module.tem.businessobject.AccountingDocumentRelationship; import org.kuali.kfs.module.tem.document.TravelDocument; import org.kuali.kfs.module.tem.document.TravelRelocationDocument; import org.kuali.kfs.module.tem.document.authorization.TravelRelocationAuthorizer; import org.kuali.kfs.module.tem.document.service.TravelRelocationService; import org.kuali.kfs.module.tem.document.web.bean.TravelRelocationMvcWrapperBean; import org.kuali.kfs.module.tem.pdf.Coversheet; import org.kuali.kfs.module.tem.report.ExpenseSummaryReport; import org.kuali.kfs.module.tem.report.NonEmployeeCertificationReport; import org.kuali.kfs.module.tem.report.SummaryByDayReport; import org.kuali.kfs.module.tem.report.service.ExpenseSummaryReportService; import org.kuali.kfs.module.tem.report.service.NonEmployeeCertificationReportService; import org.kuali.kfs.module.tem.report.service.SummaryByDayReportService; import org.kuali.kfs.module.tem.report.util.BarcodeHelper; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.kew.api.KewApiConstants; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kns.util.WebUtils; import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; import org.kuali.rice.krad.bo.Note; import org.kuali.rice.krad.document.Document; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; import org.kuali.rice.krad.util.UrlFactory; public class TravelRelocationAction extends TravelActionBase { public static Logger LOG = Logger.getLogger(TravelRelocationAction.class); private static final String[] reloMethodToCallExclusionArray = { "recalculate", "calculate", "recalculateTripDetailTotal" }; /** * Refreshes collections on the document * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase) */ @Override protected void loadDocument(KualiDocumentFormBase form) throws WorkflowException { super.loadDocument(form); final TravelRelocationForm reloForm = (TravelRelocationForm) form; final TravelRelocationDocument document = reloForm.getTravelRelocationDocument(); refreshCollectionsFor(document); reloForm.setDistribution(getAccountingDistributionService().buildDistributionFrom(reloForm.getTravelDocument())); initializeAssignAccounts(reloForm); } /** * @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 { final ActionForward retval = super.execute(mapping, form, request, response); final TravelRelocationForm reloForm = (TravelRelocationForm) form; final TravelRelocationDocument document = ((TravelRelocationForm) form).getTravelRelocationDocument(); final String travelIdentifier = document.getTravelDocumentIdentifier(); setButtonPermissions(reloForm); setContactMasking(reloForm); setTaxSelectable(reloForm); if (document.getTraveler() != null && document.getTraveler().getPrincipalId() != null) { document.getTraveler().setPrincipalName(getPersonService().getPerson(document.getTraveler().getPrincipalId()).getPrincipalName()); } if (ObjectUtils.isNotNull(document.getActualExpenses())) { document.enableExpenseTypeSpecificFields(document.getActualExpenses()); } refreshRelatedDocuments(reloForm); if (!reloForm.getMethodToCall().equalsIgnoreCase("dochandler")) { if (!getCalculateIgnoreList().contains(reloForm.getMethodToCall())) { recalculateTripDetailTotalOnly(mapping, form, request, response); } KualiDecimal totalRemaining = KualiDecimal.ZERO; for (final AccountingDistribution dist : reloForm.getDistribution()) { totalRemaining = totalRemaining.add(dist.getRemainingAmount()); } request.setAttribute(REMAINING_DISTRIBUTION_ATTRIBUTE, totalRemaining); } showAccountDistribution(request, document); request.setAttribute(SHOW_REPORTS_ATTRIBUTE, !document.getDocumentHeader().getWorkflowDocument().isInitiated()); final KualiDecimal paymentTotal = document.getPaymentAmount(); if (paymentTotal != null && !ObjectUtils.isNull(document.getTravelPayment())) { document.getTravelPayment().setCheckTotalAmount(paymentTotal); } if (reloForm.getAccountDistributionsourceAccountingLines() == null || reloForm.getAccountDistributionsourceAccountingLines().isEmpty()) { initializeAssignAccounts(reloForm); } return retval; } protected void setContactMasking(TravelRelocationForm reloForm) { reloForm.setCanUnmask(reloForm.isUserDocumentInitiator()); } /** * This method sets all the boolean properties on the form to determine what buttons can be displayed depending on what is going * on */ protected void setButtonPermissions(TravelRelocationForm form) { final TravelRelocationAuthorizer authorizer = getDocumentAuthorizer(form); form.setCanCertify(authorizer.canCertify(form.getTravelRelocationDocument(), GlobalVariables.getUserSession().getPerson())); setCanCalculate(form); } protected void setTaxSelectable(final TravelRelocationForm form) { final TravelRelocationAuthorizer authorizer = getDocumentAuthorizer(form); form.getTravelRelocationDocument().setTaxSelectable(authorizer.canTaxSelectable(GlobalVariables.getUserSession().getPerson())); } @Override protected Class getMvcWrapperInterface() { return TravelRelocationMvcWrapperBean.class; } /** * Do initialization for a new {@link TravelRelocationDocument} * * @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); final TravelRelocationForm travelForm = (TravelRelocationForm) kualiDocumentFormBase; final TravelRelocationDocument document = (TravelRelocationDocument) travelForm.getDocument(); getTravelRelocationService().addListenersTo(document); if (!StringUtils.isBlank(travelForm.getTravelDocumentIdentifier())) { LOG.debug("Creating relocation for document number " + travelForm.getTravelDocumentIdentifier()); final TravelRelocationDocument oldRelocation = getTravelRelocation(travelForm.getTravelDocumentIdentifier()); if (oldRelocation != null) { LOG.debug("Setting traveler with id " + oldRelocation.getTravelerDetailId()); document.setTravelerDetailId(oldRelocation.getTravelerDetailId()); document.refreshReferenceObject(TemPropertyConstants.TRAVELER); LOG.debug("Traveler is "+ document.getTraveler()+ " with customer number "+ document.getTraveler().getCustomerNumber()); if (document.getTraveler().getPrincipalId() != null) { document.getTraveler().setPrincipalName(getPersonService().getPerson(document.getTraveler().getPrincipalId()).getPrincipalName()); } document.setProfileId(oldRelocation.getTemProfileId()); document.updatePayeeTypeForReimbursable(); document.setTripDescription(oldRelocation.getTripDescription()); document.setPrimaryDestinationName(oldRelocation.getPrimaryDestinationName()); document.setTripBegin(oldRelocation.getTripBegin()); document.setTripEnd(oldRelocation.getTripEnd()); document.setJobClsCode(oldRelocation.getJobClsCode()); document.setReasonCode(oldRelocation.getReasonCode()); document.setFromAddress1(oldRelocation.getFromAddress1()); document.setFromAddress2(oldRelocation.getFromAddress2()); document.setFromCity(oldRelocation.getFromCity()); document.setFromCountryCode(oldRelocation.getFromCountryCode()); document.setFromStateCode(oldRelocation.getFromStateCode()); document.setToAddress1(oldRelocation.getToAddress1()); document.setToAddress2(oldRelocation.getToAddress2()); document.setToCity(oldRelocation.getToCity()); document.setToCountryCode(oldRelocation.getToCountryCode()); document.setToStateCode(oldRelocation.getToStateCode()); document.setTravelDocumentIdentifier(oldRelocation.getTravelDocumentIdentifier()); document.getDocumentHeader().setOrganizationDocumentNumber(oldRelocation.getDocumentHeader().getOrganizationDocumentNumber()); final AccountingDocumentRelationship relationship = buildRelationshipToProgenitorDocument(oldRelocation, document); getBusinessObjectService().save(relationship); // we're not the progenitor so let's force a refresh of notes final List<Note> notes = getNoteService().getByRemoteObjectId(oldRelocation.getNoteTarget().getObjectId()); document.setNotes(notes); } } else { document.setTripProgenitor(true); // this is the trip progenitor } initializeAssignAccounts(travelForm); } protected void createDVDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException { Document doc = getDocumentService().getNewDocument(kualiDocumentFormBase.getDocTypeName()); kualiDocumentFormBase.setDocument(doc); kualiDocumentFormBase.setDocTypeName(doc.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); ((DisbursementVoucherDocument) kualiDocumentFormBase.getDocument()).initiateDocument(); // set wire charge message in form ((DisbursementVoucherForm) kualiDocumentFormBase).setWireChargeMessage(retrieveWireChargeMessage()); } /** * Performs necessary updates after the requester on the relocation document was updated, such as updating the payee type * @param document the document to update */ @Override protected void performRequesterRefresh(TravelDocument document, TravelFormBase travelForm, HttpServletRequest request) { ((TravelRelocationDocument)document).updatePayeeTypeForReimbursable(); updateAccountsWithNewProfile(travelForm, document.getTemProfile()); } protected TravelRelocationService getTravelRelocationService() { return SpringContext.getBean(TravelRelocationService.class); } /** * Recalculates the Expenses Total Tab * * @param mapping * @param form * @param request * @param response * @throws Exception */ public ActionForward recalculate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return recalculateTripDetailTotal(mapping, form, request, response); } protected void refreshCollectionsFor(final TravelRelocationDocument relocation) { if (!relocation.getDocumentHeader().getWorkflowDocument().isInitiated()) { LOG.debug("Refreshing objects in relocation"); relocation.refreshReferenceObject(TemPropertyConstants.TRAVELER); relocation.refreshReferenceObject(TemPropertyConstants.ACTUAL_EXPENSES); relocation.refreshReferenceObject(TemPropertyConstants.SPECIAL_CIRCUMSTANCES); } } /** * Uses the {@link TravelRelocationService} to lookup a {@link TravelRelocationDocument} instance via its * <code>travelDocumentIdentifier</code> * * @param travelDocumentIdentifier to location a {@link TravelRelocationDocument} with * @return {@link TravelRelocationDocument} instance */ protected TravelRelocationDocument getTravelRelocation(final String travelDocumentIdentifier) { Collection<TravelRelocationDocument> reloList = getTravelRelocationService().findByIdentifier(travelDocumentIdentifier); if (ObjectUtils.isNotNull(reloList) && reloList.iterator().hasNext()) { return reloList.iterator().next(); } return null; } /** * Action method for creating a {@link ExpenseSummaryReport} and producing a PDF from it */ public ActionForward viewExpenseSummary(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelRelocationForm reloForm = (TravelRelocationForm) form; reloForm.setDocument(getTravelRelocationService().find(request.getParameter(DOCUMENT_NUMBER))); final TravelRelocationDocument relocation = reloForm.getTravelRelocationDocument(); final ExpenseSummaryReport report = getExpenseSummaryReportService().buildReport(relocation); report.setReportTitle("Moving and Relocation"); final ByteArrayOutputStream baos = getTravelReportService().buildReport(report); WebUtils.saveMimeOutputStreamAsFile(response, "application/pdf", baos, String.format(TemConstants.EXPENSE_SUMMARY_REPORT_TITLE, relocation.getTravelDocumentIdentifier())); return null; } /** * Action method for creating a {@link SummaryByDayReport} and producing a PDF from it. */ public ActionForward viewSummaryByDay(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelRelocationForm reloForm = (TravelRelocationForm) form; reloForm.setDocument(getTravelRelocationService().find(request.getParameter(DOCUMENT_NUMBER))); final TravelRelocationDocument relocation = reloForm.getTravelRelocationDocument(); final SummaryByDayReport report = getSummaryByDayReportService().buildReport(relocation); final ByteArrayOutputStream baos = getTravelReportService().buildReport(report); WebUtils.saveMimeOutputStreamAsFile(response, "application/pdf", baos, String.format(TemConstants.SUMMARY_BY_DAY_TITLE, relocation.getTravelDocumentIdentifier())); return null; } public ActionForward printCoversheet(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelRelocationForm reloForm = (TravelRelocationForm) form; final String documentNumber = request.getParameter(DOCUMENT_NUMBER); if (documentNumber != null && !documentNumber.isEmpty()) { reloForm.setDocument(getTravelRelocationService().find(documentNumber)); } final TravelRelocationDocument relocation = reloForm.getTravelRelocationDocument(); final Coversheet cover = getTravelRelocationService().generateCoversheetFor(relocation); final ByteArrayOutputStream stream = new ByteArrayOutputStream(); cover.print(stream); WebUtils.saveMimeOutputStreamAsFile(response, "application/pdf", stream, String.format(COVERSHEET_FILENAME_FORMAT, relocation.getTravelDocumentIdentifier())); return null; } /** * Action method for creating a {@link Non Employee forms} and producing a PDF from it */ public ActionForward viewNonEmployeeForms(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelRelocationForm reloForm = (TravelRelocationForm) form; reloForm.setDocument(getTravelRelocationService().find(request.getParameter(DOCUMENT_NUMBER))); final TravelRelocationDocument relocation = reloForm.getTravelRelocationDocument(); final NonEmployeeCertificationReport report = getNonEmployeeCertificationReportService().buildReport(relocation); BarcodeHelper barcode = new BarcodeHelper(); report.setBarcodeImage(barcode.generateBarcodeImage(relocation.getDocumentNumber())); File reportFile = getNonEmployeeCertificationReportService().generateReport(report); StringBuilder fileName = new StringBuilder(); fileName.append(relocation.getTravelDocumentIdentifier()); fileName.append(TemConstants.NON_EMPLOYEE_CERTIFICATION_REPORT_TITLE); fileName.append(KFSConstants.ReportGeneration.PDF_FILE_EXTENSION); if (reportFile.length() == 0) { return mapping.findForward(KFSConstants.MAPPING_BASIC); } displayPDF(request, response, reportFile, fileName); return null; } /** * Redirects to create a new relocation document * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward newRelocation(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelRelocationDocument reloDoc = ((TravelRelocationForm)form).getTravelRelocationDocument(); final String url = buildNewRelocationUrl(reloDoc); return new ActionForward(url, true); } /** * Builds a new relocation url for the given travel document * @param travelDoc the travel document to create a new relocation for * @return the url to redirect to to create a new relocation */ protected String buildNewRelocationUrl(TravelRelocationDocument travelRelo) { Properties props = new Properties(); props.put(TemPropertyConstants.TRAVEL_DOCUMENT_IDENTIFIER, travelRelo.getTravelDocumentIdentifier()); props.put(KFSConstants.DOCUMENT_TYPE_NAME, TemConstants.TravelDocTypes.TRAVEL_RELOCATION_DOCUMENT); props.put(KFSConstants.PARAMETER_COMMAND, KewApiConstants.INITIATE_COMMAND); final String docUrlBase = getResolvedUrlForDocumentType(TemConstants.TravelDocTypes.TRAVEL_RELOCATION_DOCUMENT); final String url = UrlFactory.parameterizeUrl(docUrlBase, props); return url; } protected NonEmployeeCertificationReportService getNonEmployeeCertificationReportService() { return SpringContext.getBean(NonEmployeeCertificationReportService.class); } protected ExpenseSummaryReportService getExpenseSummaryReportService() { return SpringContext.getBean(ExpenseSummaryReportService.class); } protected SummaryByDayReportService getSummaryByDayReportService() { return SpringContext.getBean(SummaryByDayReportService.class); } @Override protected List<String> getCalculateIgnoreList() { return Arrays.asList(reloMethodToCallExclusionArray); } }