/*
* 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.SHOW_REPORTS_ATTRIBUTE;
import static org.kuali.kfs.sys.KFSPropertyConstants.DOCUMENT_NUMBER;
import java.io.ByteArrayOutputStream;
import java.io.File;
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.module.tem.TemConstants;
import org.kuali.kfs.module.tem.TemPropertyConstants;
import org.kuali.kfs.module.tem.businessobject.AccountingDocumentRelationship;
import org.kuali.kfs.module.tem.businessobject.Attendee;
import org.kuali.kfs.module.tem.businessobject.TravelerDetail;
import org.kuali.kfs.module.tem.document.TravelDocument;
import org.kuali.kfs.module.tem.document.TravelEntertainmentDocument;
import org.kuali.kfs.module.tem.document.service.TravelEntertainmentDocumentService;
import org.kuali.kfs.module.tem.document.web.bean.TravelEntertainmentMvcWrapperBean;
import org.kuali.kfs.module.tem.document.web.bean.TravelMvcWrapperBean;
import org.kuali.kfs.module.tem.pdf.Coversheet;
import org.kuali.kfs.module.tem.report.EntertainmentHostCertificationReport;
import org.kuali.kfs.module.tem.report.NonEmployeeCertificationReport;
import org.kuali.kfs.module.tem.report.service.NonEmployeeCertificationReportService;
import org.kuali.kfs.module.tem.report.service.TravelEntertainmentHostCertificationService;
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.WorkflowDocument;
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.util.GlobalVariables;
import org.kuali.rice.krad.util.ObjectUtils;
import org.kuali.rice.krad.util.UrlFactory;
import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
/**
* This class...
*/
public class TravelEntertainmentAction extends TravelActionBase {
public static Logger LOG = Logger.getLogger(TravelEntertainmentAction.class);
public static final String[] ATTENDEE_ATTRIBUTE_NAMES = { TemPropertyConstants.AttendeeProperties.ATTENDEE_TYPE, TemPropertyConstants.AttendeeProperties.COMPANY, TemPropertyConstants.AttendeeProperties.TITLE,TemPropertyConstants.AttendeeProperties.NAME};
public static final Integer[] MAX_LENGTH={10,40,40,40};
/**
* Constructs a TravelEntertainmentDocumentAction.java.
*/
public TravelEntertainmentAction() {
}
@Override
public ActionForward docHandler(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final ActionForward retval = super.docHandler(mapping, form, request, response);
final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();
initializeNewAttendeeLines(entForm.getNewAttendeeLines(), document.getAttendee());
return retval;
}
/**
* Initiates the document based on another entertainment reimbursement if the expected query fields (needed: travelDocumentIdentifier; maybe: fromDocumentNumber) are filled in
* @see org.kuali.kfs.module.tem.document.web.struts.TravelActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
*/
@Override
protected void createDocument(KualiDocumentFormBase form) throws WorkflowException {
super.createDocument(form);
final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();
final String identifierStr = entForm.getTravelDocumentIdentifier();
final String fromDocumentNumber = entForm.getFromDocumentNumber();
if (!StringUtils.isBlank(identifierStr) && !StringUtils.isBlank(fromDocumentNumber)){
LOG.debug("Creating reimbursement for document number "+ identifierStr);
document.setTravelDocumentIdentifier(identifierStr);
TravelEntertainmentDocument travelDocument = (TravelEntertainmentDocument) getDocumentService().getByDocumentHeaderId(fromDocumentNumber);
LOG.debug("Setting traveler with id "+ travelDocument.getTravelerDetailId());
document.setTravelerDetailId(travelDocument.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.setHostProfileId(travelDocument.getHostProfileId());
document.setHostName(travelDocument.getHostName());
document.setHostAsPayee(travelDocument.getHostAsPayee());
document.setEventTitle(travelDocument.getEventTitle());
document.setPurposeCode(travelDocument.getPurposeCode());
document.setTripBegin(travelDocument.getTripBegin());
document.setTripEnd(travelDocument.getTripEnd());
document.setSpouseIncluded(travelDocument.getSpouseIncluded());
document.setDescription(travelDocument.getDescription());
document.setAttendeeListAttached(travelDocument.getAttendeeListAttached());
document.setAttendee(travelDocument.getAttendee());
document.setNumberOfAttendees(travelDocument.getNumberOfAttendees());
document.setPrimaryDestinationId(travelDocument.getPrimaryDestinationId());
document.setPaymentMethod(travelDocument.getPaymentMethod());
document.setExpenseLimit(travelDocument.getExpenseLimit());
document.configureTraveler(travelDocument.getTemProfileId(), travelDocument.getTraveler());
document.getDocumentHeader().setOrganizationDocumentNumber(travelDocument.getDocumentHeader().getOrganizationDocumentNumber());
document.updatePayeeTypeForReimbursable();
final AccountingDocumentRelationship relationship = buildRelationshipToProgenitorDocument(travelDocument, document);
getBusinessObjectService().save(relationship);
} else {
document.setTripProgenitor(true); // this is the trip progenitor
}
initializeAssignAccounts(entForm);
}
/**
* Refreshes the 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 TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();
refreshCollectionsFor(document);
entForm.setDistribution(getAccountingDistributionService().buildDistributionFrom(entForm.getTravelDocument()));
initializeAssignAccounts(entForm);
}
protected void populateFromPreviousENTDoc(TravelEntertainmentDocument document, String temDocId) {
TravelEntertainmentDocument entDocument = getBusinessObjectService().findBySinglePrimaryKey(TravelEntertainmentDocument.class, temDocId);
document.setTravelerDetailId(entDocument.getTravelerDetailId());
document.refreshReferenceObject(TemPropertyConstants.TRAVELER);
if (document.getAttendee() != null) {
document.setAttendee(entDocument.getAttendee());
}
if (document.getTraveler() != null) {
document.setTraveler(entDocument.getTraveler());
}
document.setHostProfileId(entDocument.getHostProfileId());
document.setTemProfileId(entDocument.getTemProfileId());
document.setEventTitle(entDocument.getEventTitle());
document.setPurposeCode(entDocument.getPurposeCode());
document.setPaymentMethod(entDocument.getPaymentMethod());
document.setTripBegin(entDocument.getTripBegin());
document.setTripEnd(entDocument.getTripEnd());
document.setSpouseIncluded(entDocument.getSpouseIncluded());
document.setDescription(entDocument.getDescription());
document.updatePayeeTypeForReimbursable();
try {
final WorkflowDocument entDocWorkflowDocument = SpringContext.getBean(WorkflowDocumentService.class).loadWorkflowDocument(entDocument.getDocumentNumber(), GlobalVariables.getUserSession().getPerson());
entDocument.getDocumentHeader().setWorkflowDocument(entDocWorkflowDocument);
final AccountingDocumentRelationship relationship = buildRelationshipToProgenitorDocument(entDocument, document);
getBusinessObjectService().save(relationship);
}
catch (WorkflowException we) {
throw new RuntimeException("Could not load workflow document for old entertainment document "+temDocId, we);
}
// we're not the progenitor so let's force a refresh of notes
final List<Note> notes = getNoteService().getByRemoteObjectId(entDocument.getNoteTarget().getObjectId());
document.setNotes(notes);
}
protected void initializeNewAttendeeLines(final List<Attendee> newAttendeeLines, List<Attendee> attendees) {
for (Attendee attendee : attendees) {
if (ObjectUtils.isNull(attendee)) {
Attendee newAttendeeLine = new Attendee();
newAttendeeLine.setAttendeeType(attendee.getAttendeeType());
newAttendeeLine.setCompany(attendee.getCompany());
newAttendeeLine.setName(attendee.getName());
newAttendeeLine.setTitle(attendee.getTitle());
newAttendeeLines.add(newAttendeeLine);
}
}
}
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final ActionForward retval = super.execute(mapping, form, request, response);
final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
final TravelEntertainmentDocument document = (TravelEntertainmentDocument) ((TravelEntertainmentForm) form).getDocument();
final String travelIdentifier = document.getTravelDocumentIdentifier();
initializeNames(entForm, document);
setButtonPermissions(entForm);
if(ObjectUtils.isNotNull(document.getActualExpenses())){
document.enableExpenseTypeSpecificFields(document.getActualExpenses());
}
if(!getCalculateIgnoreList().contains(entForm.getMethodToCall())){
recalculateTripDetailTotalOnly(mapping, form, request, response);
}
refreshRelatedDocuments(entForm);
showAccountDistribution(request, document);
request.setAttribute(SHOW_REPORTS_ATTRIBUTE, !document.getDocumentHeader().getWorkflowDocument().isInitiated());
entForm.setCanPrintHostCertification(document.canShowHostCertification());
final KualiDecimal paymentTotal = document.getPaymentAmount();
if (paymentTotal != null && !ObjectUtils.isNull(document.getTravelPayment())) {
document.getTravelPayment().setCheckTotalAmount(paymentTotal);
}
if (entForm.getAccountDistributionsourceAccountingLines() == null || entForm.getAccountDistributionsourceAccountingLines().isEmpty()) {
initializeAssignAccounts(entForm);
}
return retval;
}
private void initializeNames(final TravelEntertainmentForm entForm, final TravelEntertainmentDocument document) {
if (document.getHostProfile() != null) {
document.setHostName(document.getHostProfile().getLastName() + KFSConstants.COMMA + document.getHostProfile().getFirstName() + KFSConstants.BLANK_SPACE +
(document.getHostProfile().getMiddleName() == null ? KFSConstants.BLANK_SPACE : document.getHostProfile().getMiddleName()));
}
entForm.getNewAttendeeLines().get(0).setName(getTravelerCompleteName(document.getAttendeeDetail()));
}
private String getTravelerCompleteName(TravelerDetail travelerdetail) {
String completeName = KFSConstants.EMPTY_STRING;
if (validateTravelerDetailName(travelerdetail)) {
completeName = travelerdetail.getLastName() + KFSConstants.COMMA + travelerdetail.getFirstName() + KFSConstants.BLANK_SPACE +
(travelerdetail.getMiddleName() == null ? KFSConstants.BLANK_SPACE : travelerdetail.getMiddleName());
}
return completeName;
}
private boolean validateTravelerDetailName(TravelerDetail travelerdetail){
if (travelerdetail == null) {
return false;
}
if (travelerdetail.getLastName() == null) {
return false;
}
if (travelerdetail.getFirstName() == null) {
return false;
}
if (travelerdetail.getLastName().equals(KFSConstants.EMPTY_STRING) && travelerdetail.getFirstName().equals(KFSConstants.EMPTY_STRING)) {
return false;
}
return true;
}
/**
* 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 TravelEntertainmentDocument entDoc) {
if (!entDoc.getDocumentHeader().getWorkflowDocument().isInitiated()) {
LOG.debug("Refreshing objects in entertainment document");
entDoc.refreshReferenceObject(TemPropertyConstants.TRAVELER);
entDoc.refreshReferenceObject(TemPropertyConstants.ACTUAL_EXPENSES);
entDoc.refreshReferenceObject(TemPropertyConstants.SPECIAL_CIRCUMSTANCES);
}
}
/**
* 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) {
TravelEntertainmentDocument entDoc = (TravelEntertainmentDocument)document;
if(entDoc.getHostAsPayee()) {
entDoc.setHostName(document.getTraveler().getFirstName() + " " + document.getTraveler().getLastName());
}
else {
entDoc.setHostName(KFSConstants.EMPTY_STRING);
}
entDoc.updatePayeeTypeForReimbursable();
updateAccountsWithNewProfile(travelForm, document.getTemProfile());
}
public ActionForward printCoversheet(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
final String documentNumber = request.getParameter(DOCUMENT_NUMBER);
if (documentNumber != null && !documentNumber.isEmpty()) {
entForm.setDocument(getEntertainmentDocumentService().find(documentNumber));
}
final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();
final Coversheet cover = getEntertainmentDocumentService().generateCoversheetFor(document);
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
cover.print(stream);
WebUtils.saveMimeOutputStreamAsFile(response, KFSConstants.ReportGeneration.PDF_MIME_TYPE, stream, String.format(COVERSHEET_FILENAME_FORMAT, document.getTravelDocumentIdentifier()));
return null;
}
public ActionForward viewNonEmployeeForms(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
entForm.setDocument(getEntertainmentDocumentService().find(request.getParameter(DOCUMENT_NUMBER)));
final TravelEntertainmentDocument entertainment = entForm.getEntertainmentDocument();
final NonEmployeeCertificationReport report = getNonEmployeeCertificationReportService().buildReport(entertainment);
BarcodeHelper barcode = new BarcodeHelper();
report.setBarcodeImage(barcode.generateBarcodeImage(entertainment.getDocumentNumber()));
File reportFile = getNonEmployeeCertificationReportService().generateReport(report);
StringBuilder fileName = new StringBuilder();
fileName.append(entertainment.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;
}
public ActionForward viewEntertainmentCertification(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
final String documentNumber = request.getParameter(DOCUMENT_NUMBER);
if (documentNumber != null && !documentNumber.isEmpty()) {
entForm.setDocument(getEntertainmentDocumentService().find(documentNumber));
}
final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();
entForm.setDocument(getEntertainmentDocumentService().find(request.getParameter(DOCUMENT_NUMBER)));
final EntertainmentHostCertificationReport report = getEntertainmentHostCertificationService().buildReport(document);
BarcodeHelper barcode = new BarcodeHelper();
report.setBarcodeImage(barcode.generateBarcodeImage(document.getDocumentNumber()));
File reportFile = getEntertainmentHostCertificationService().generateEntertainmentHostCertReport(report);
StringBuilder fileName = new StringBuilder();
fileName.append(document.getTravelDocumentIdentifier());
fileName.append(TemConstants.ENTERTAINMENT_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;
}
/**
* @see org.kuali.kfs.module.tem.document.web.struts.TravelActionBase#route(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
//remove the emergency contacts so that it does not get validated
final TravelEntertainmentForm entertainment = (TravelEntertainmentForm) form;
TravelDocument document = entertainment.getTravelDocument();
document.getTraveler().getEmergencyContacts().clear();
return super.route(mapping, form, request, response);
}
public ActionForward addAttendeeLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final TravelFormBase travelForm = (TravelFormBase) form;
final TravelEntertainmentMvcWrapperBean mvcWrapper = newMvcDelegate(form);
mvcWrapper.setNewAttendeeLine(mvcWrapper.getNewAttendeeLines().get(getSelectedLine(request)));
travelForm.getObservable().notifyObservers(mvcWrapper);
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
public ActionForward deleteAttendeeLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final TravelFormBase travelForm = (TravelFormBase) form;
final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form);
travelForm.getObservable().notifyObservers(new Object[] { mvcWrapper, getSelectedLine(request) });
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* Import Attendees to the document from a spreadsheet.
*
* @param mapping An ActionMapping
* @param form An ActionForm
* @param request The HttpServletRequest
* @param response The HttpServletResponse
* @throws Exception
* @return An ActionForward
*/
public ActionForward importAttendees(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final TravelEntertainmentForm travelForm = (TravelEntertainmentForm) form;
final TravelEntertainmentMvcWrapperBean mvcWrapper = newMvcDelegate(form);
travelForm.getObservable().notifyObservers(new Object[] { mvcWrapper, new String(travelForm.getAttendeesImportFile().getFileData()) });
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* Forward to MAPPING_BASIC. The newEntertainment button is assumed to have java script
*
* @param mapping
* @param form
* @param request
* @param response
* @return
* @throws Exception
*/
public ActionForward newEntertainment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final TravelEntertainmentDocument entDoc = ((TravelEntertainmentForm)form).getEntertainmentDocument();
final String url = buildNewEntertainmentUrl(entDoc);
return new ActionForward(url, true);
}
/**
* Builds a new entertainment url for the given travel document
* @param travelDoc the travel document to create a new reimbursement for
* @return the url to redirect to to create a new entertainment
*/
protected String buildNewEntertainmentUrl(TravelEntertainmentDocument entDoc) {
Properties props = new Properties();
props.put(TemPropertyConstants.TRAVEL_DOCUMENT_IDENTIFIER, entDoc.getTravelDocumentIdentifier());
props.put(KFSConstants.DOCUMENT_TYPE_NAME, TemConstants.TravelDocTypes.TRAVEL_ENTERTAINMENT_DOCUMENT);
props.put(TemPropertyConstants.EntertainmentFields.FROM_DOCUMENT_NUMBER, entDoc.getDocumentNumber());
props.put(KFSConstants.PARAMETER_COMMAND, KewApiConstants.INITIATE_COMMAND);
final String docUrlBase = getResolvedUrlForDocumentType(TemConstants.TravelDocTypes.TRAVEL_ENTERTAINMENT_DOCUMENT);
final String url = UrlFactory.parameterizeUrl(docUrlBase, props);
return url;
}
/**
* 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(TravelEntertainmentForm form) {
setCanCalculate(form);
}
@Override
public ActionForward downloadBOAttachment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
return super.downloadBOAttachment(mapping, form, request, response);
}
protected void setContactMasking(TravelEntertainmentForm entForm) {
entForm.setCanUnmask(entForm.isUserDocumentInitiator());
}
protected TravelEntertainmentHostCertificationService getEntertainmentHostCertificationService() {
return SpringContext.getBean(TravelEntertainmentHostCertificationService.class);
}
protected TravelEntertainmentDocumentService getEntertainmentDocumentService() {
return SpringContext.getBean(TravelEntertainmentDocumentService.class);
}
protected NonEmployeeCertificationReportService getNonEmployeeCertificationReportService() {
return SpringContext.getBean(NonEmployeeCertificationReportService.class);
}
@Override
protected Class<? extends TravelMvcWrapperBean> getMvcWrapperInterface() {
return TravelEntertainmentMvcWrapperBean.class;
}
}