/* * 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.CERTIFICATION_STATEMENT_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.DELINQUENT_TEST_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.EMPLOYEE_TEST_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.FISCAL_OFFICER_TEST_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.PRIMARY_DESTINATION_LOOKUPABLE; import static org.kuali.kfs.module.tem.TemConstants.RETURN_TO_FO_QUESTION; import static org.kuali.kfs.module.tem.TemConstants.SHOW_ACCOUNT_DISTRIBUTION_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.SHOW_REPORTS_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.TRAVEL_ARRANGER_TEST_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.TRAVEL_MANAGER_TEST_ATTRIBUTE; import static org.kuali.kfs.module.tem.TemConstants.TravelParameters.EMPLOYEE_CERTIFICATION_STATEMENT; import static org.kuali.kfs.module.tem.TemConstants.TravelParameters.NON_EMPLOYEE_CERTIFICATION_STATEMENT; import static org.kuali.kfs.module.tem.TemConstants.TravelReimbursementParameters.DISPLAY_ACCOUNTING_DISTRIBUTION_TAB_IND; import static org.kuali.kfs.module.tem.TemConstants.TravelReimbursementParameters.FOREIGN_CURRENCY_URL; import static org.kuali.kfs.module.tem.TemPropertyConstants.TRIP_INFO_UPDATE_TRIP_DTL; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.math.BigDecimal; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; 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.TemConstants.TravelCustomSearchLinks; import org.kuali.kfs.module.tem.TemKeyConstants; import org.kuali.kfs.module.tem.TemParameterConstants; 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.businessobject.ActualExpense; import org.kuali.kfs.module.tem.businessobject.GroupTraveler; import org.kuali.kfs.module.tem.businessobject.HistoricalTravelExpense; import org.kuali.kfs.module.tem.businessobject.ImportedExpense; import org.kuali.kfs.module.tem.businessobject.PerDiem; import org.kuali.kfs.module.tem.businessobject.PerDiemExpense; import org.kuali.kfs.module.tem.businessobject.PrimaryDestination; import org.kuali.kfs.module.tem.businessobject.SpecialCircumstances; import org.kuali.kfs.module.tem.businessobject.TemDistributionAccountingLine; import org.kuali.kfs.module.tem.businessobject.TemExpense; import org.kuali.kfs.module.tem.businessobject.TemProfile; import org.kuali.kfs.module.tem.businessobject.TemSourceAccountingLine; import org.kuali.kfs.module.tem.businessobject.TravelerDetail; import org.kuali.kfs.module.tem.document.TravelAuthorizationDocument; import org.kuali.kfs.module.tem.document.TravelDocument; import org.kuali.kfs.module.tem.document.TravelDocumentBase; import org.kuali.kfs.module.tem.document.TravelReimbursementDocument; import org.kuali.kfs.module.tem.document.authorization.ReturnToFiscalOfficerAuthorizer; import org.kuali.kfs.module.tem.document.authorization.TravelArrangeableAuthorizer; import org.kuali.kfs.module.tem.document.service.AccountingDocumentRelationshipService; import org.kuali.kfs.module.tem.document.service.TravelDocumentService; import org.kuali.kfs.module.tem.document.validation.event.AddGroupTravelLineEvent; import org.kuali.kfs.module.tem.document.validation.event.RecalculateTripDetailTotalEvent; import org.kuali.kfs.module.tem.document.validation.event.UpdateTripDetailsEvent; import org.kuali.kfs.module.tem.document.web.bean.TravelMvcWrapperBean; import org.kuali.kfs.module.tem.report.service.TravelReportService; import org.kuali.kfs.module.tem.service.AccountingDistributionService; import org.kuali.kfs.module.tem.service.PerDiemService; import org.kuali.kfs.module.tem.service.TemProfileService; import org.kuali.kfs.module.tem.service.TemRoleService; import org.kuali.kfs.module.tem.service.TravelEncumbranceService; import org.kuali.kfs.module.tem.service.TravelService; import org.kuali.kfs.module.tem.service.TravelerService; import org.kuali.kfs.module.tem.util.ExpenseUtils; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.businessobject.AccountingLine; import org.kuali.kfs.sys.businessobject.SourceAccountingLine; import org.kuali.kfs.sys.businessobject.WireCharge; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.service.SegmentedLookupResultsService; import org.kuali.kfs.sys.service.UniversityDateService; import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase; import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.kew.api.KewApiConstants; import org.kuali.rice.kew.api.doctype.DocumentType; import org.kuali.rice.kew.api.doctype.DocumentTypeService; import org.kuali.rice.kew.api.document.node.RouteNodeInstance; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kim.api.identity.PersonService; import org.kuali.rice.kim.impl.KIMPropertyConstants; import org.kuali.rice.kns.util.KNSGlobalVariables; import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; import org.kuali.rice.kns.web.struts.form.KualiForm; import org.kuali.rice.krad.bo.PersistableBusinessObject; import org.kuali.rice.krad.document.Document; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.service.KualiRuleService; import org.kuali.rice.krad.uif.field.LinkField; import org.kuali.rice.krad.util.ErrorMessage; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krad.util.KRADPropertyConstants; import org.kuali.rice.krad.util.ObjectUtils; import org.kuali.rice.krad.util.UrlFactory; import org.springframework.web.util.HtmlUtils; import com.lowagie.text.pdf.PdfCopy; import com.lowagie.text.pdf.PdfImportedPage; import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.SimpleBookmark; /** * Common action class */ public abstract class TravelActionBase extends KualiAccountingDocumentActionBase { public static Logger LOG = Logger.getLogger(TravelActionBase.class); protected static final String[] methodToCallExclusionArray = { "recalculate", "calculate", "recalculateTripDetailTotal", "save", "route", "approve", "blanketApprove", "updatePerDiemExpenses" }; protected volatile static PerDiemService perDiemService; protected volatile static DocumentTypeService documentTypeService; protected static final String ACCOUNTING_LINES_TOTALS_VALIDATION_BEAN = "TravelDocument-accountingLineTotalsValidation"; @Override protected DocumentService getDocumentService() { return SpringContext.getBean(DocumentService.class); } protected TravelDocumentService getTravelDocumentService() { return SpringContext.getBean(TravelDocumentService.class); } protected TravelEncumbranceService getTravelEncumbranceService() { return SpringContext.getBean(TravelEncumbranceService.class); } protected TemRoleService getTemRoleService() { return SpringContext.getBean(TemRoleService.class); } public PersonService getPersonService() { return SpringContext.getBean(PersonService.class); } protected TravelReportService getTravelReportService() { return SpringContext.getBean(TravelReportService.class); } public AccountingDocumentRelationshipService getAccountingDocumentRelationshipService() { return SpringContext.getBean(AccountingDocumentRelationshipService.class); } protected TravelerService getTravelerService() { return SpringContext.getBean(TravelerService.class); } protected TravelService getTravelService() { return SpringContext.getBean(TravelService.class); } protected AccountingDistributionService getAccountingDistributionService() { return SpringContext.getBean(AccountingDistributionService.class); } protected TemProfileService getTemProfileService() { return SpringContext.getBean(TemProfileService.class); } protected PerDiemService getPerDiemService() { if (perDiemService == null) { perDiemService = SpringContext.getBean(PerDiemService.class); } return perDiemService; } protected DocumentTypeService getDocumentTypeService() { if (documentTypeService == null) { documentTypeService = SpringContext.getBean(DocumentTypeService.class); } return documentTypeService; } /** * When the approver only wants the accounting lines to be changed but the trip information is acceptable, routes the document * back to the Account Node (Fiscal Officer Reviewer) and removes the fiscal officer approvals and the approvals that are beyond * the Account node. The fiscal officer should be able to select the accounts outside of their organization like the PCDO * document. */ public ActionForward returnToFiscalOfficer(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { LOG.debug("Returning to Fiscal Officer"); final QuestionHandler<TravelDocument> questionHandler = getQuestionHandler(RETURN_TO_FO_QUESTION); final Inquisitive<TravelDocument, ActionForward> inq = new StrutsInquisitor<TravelDocument, TravelFormBase, TravelActionBase>(mapping, (TravelFormBase) form, this, request, response); if (inq.wasQuestionAsked()) { return questionHandler.handleResponse(inq); } return questionHandler.askQuestion(inq); } protected <T> T getQuestionHandler(final String question) { final T retval = (T) SpringContext.getService(question); return retval; } /** * For use with a specific set of methods of this class that create new purchase order-derived document types in response to * user actions, including <code>amendTa</code>. It employs the question framework to ask the user for a response before * creating and routing the new document. The response should consist of a note detailing a reason, and either yes or no. This * method can be better understood if it is noted that it will be gone through twice (via the question framework); when each * question is originally asked, and again when the yes/no response is processed, for confirmation. * * @param mapping These are boiler-plate. * @param form " * @param request " * @param response " * @param questionType A string identifying the type of question being asked. * @param confirmType A string identifying which type of question is being confirmed. * @param documentType A string, the type of document to create * @param notePrefix A string to appear before the note in the BO Notes tab * @param messageType A string to appear on the PO once the question framework is done, describing the action taken * @param operation A string, the verb to insert in the original question describing the action to be taken * @return An ActionForward * @throws Exception */ protected ActionForward askQuestionsAndPerformDocumentAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionType, String confirmType, String documentType, String notePrefix, String messageType, String operation) throws Exception { LOG.debug("askQuestionsAndPerformDocumentAction started."); TravelFormBase trForm = (TravelFormBase) form; TravelDocument document = trForm.getTravelDocument(); return null; } @Override public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { recalculateTripDetailTotalOnly(mapping, form, request, response); TravelFormBase travelForm = (TravelFormBase) form; if (requiresCalculate(travelForm)) { GlobalVariables.getMessageMap().putError(KFSConstants.DOCUMENT_ERRORS, TemKeyConstants.ERROR_REQUIRES_CALCULATE, new String[] { "routing" }); return mapping.findForward(KFSConstants.MAPPING_BASIC); } ActionForward forward = super.route(mapping, travelForm, request, response); getTravelDocumentService().attachImportedExpenses(travelForm.getTravelDocument()); return forward; } /** * Determines whether or not someone can return the document to fiscal officer * * @param form */ protected void setCanReturnToFisicalOfficer(TravelFormBase form) { boolean can = form.getTravelDocument().canReturn(); if (can) { ReturnToFiscalOfficerAuthorizer documentAuthorizer = getDocumentAuthorizer(form); can = documentAuthorizer.canReturnToFisicalOfficer(form.getTravelDocument(), GlobalVariables.getUserSession().getPerson()); } form.setCanReturn(can); } @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { GlobalVariables.getUserSession().removeObject(TemPropertyConstants.TemProfileProperties.PROFILE_ID); GlobalVariables.getUserSession().removeObject(KFSPropertyConstants.DOCUMENT_TYPE_CODE); TravelFormBase travelFormBase = (TravelFormBase) form; final String methodToCall = travelFormBase.getMethodToCall(); final TravelDocument document = (TravelDocument) travelFormBase.getDocument(); //set PerDiem categories and breakdown getPerDiemService().setPerDiemCategoriesAndBreakdown(travelFormBase); travelFormBase.setDisplayNonEmployeeForm(!isEmployee(document.getTraveler())); if (!StringUtils.isEmpty(methodToCall) && !methodToCall.equalsIgnoreCase("docHandler")) { // Setting the certification statement in the case that there is a validation error request.setAttribute(CERTIFICATION_STATEMENT_ATTRIBUTE, getCertificationStatement(document)); request.setAttribute(EMPLOYEE_TEST_ATTRIBUTE, isEmployee(document.getTraveler())); request.setAttribute(TRAVEL_ARRANGER_TEST_ATTRIBUTE, setTravelArranger((TravelFormBase) form)); request.setAttribute(TRAVEL_MANAGER_TEST_ATTRIBUTE, setTravelManager((TravelFormBase) form)); request.setAttribute(FISCAL_OFFICER_TEST_ATTRIBUTE, setFiscalOfficer((TravelFormBase) form)); request.setAttribute(DELINQUENT_TEST_ATTRIBUTE, document.getDelinquentAction()); } if (document.shouldRefreshExpenseTypeObjectCode()) { document.refreshExpenseTypeObjectCodesForExpenses(); } ExpenseUtils.calculateMileage(document, document.getActualExpenses()); updateActualExpenseConversionRates(document); populateForeignCurrencyUrl(travelFormBase); final ActionForward retval = super.execute(mapping, form, request, response); request.setAttribute(CERTIFICATION_STATEMENT_ATTRIBUTE, getCertificationStatement(document)); request.setAttribute(EMPLOYEE_TEST_ATTRIBUTE, isEmployee(document.getTraveler())); request.setAttribute(TRAVEL_ARRANGER_TEST_ATTRIBUTE, setTravelArranger((TravelFormBase) form)); request.setAttribute(TRAVEL_MANAGER_TEST_ATTRIBUTE, setTravelManager((TravelFormBase) form)); request.setAttribute(FISCAL_OFFICER_TEST_ATTRIBUTE, setFiscalOfficer((TravelFormBase) form)); request.setAttribute(DELINQUENT_TEST_ATTRIBUTE, document.getDelinquentAction()); populateAgencyLinks(travelFormBase); if (!StringUtils.isBlank(document.getDocumentNumber())) { final Map<String, List<Document>> relatedDocuments = getTravelDocumentService().getDocumentsRelatedTo(document); //we don't have a doc number yet...there's no related documents travelFormBase.setRelatedDocuments(relatedDocuments); travelFormBase.setDistribution(getAccountingDistributionService().buildDistributionFrom(travelFormBase.getTravelDocument())); // and likely, there's nothing to distribute either } return retval; } /** * Overridden to recalculate per diems and actual expenses in case per diem rate or mileage rates changed; if * @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); TravelDocument travelDoc = ((TravelFormBase)kualiDocumentFormBase).getTravelDocument(); if (travelDoc.getDocumentHeader().getWorkflowDocument().isEnroute() || travelDoc.getDocumentHeader().getWorkflowDocument().isCompletionRequested()) { // only update background rates if the document is still enroute if (travelDoc.getActualExpenses() != null && !travelDoc.getActualExpenses().isEmpty()) { ExpenseUtils.calculateMileage(travelDoc, travelDoc.getActualExpenses()); } } } /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#refresh(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override @SuppressWarnings("rawtypes") public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { super.refresh(mapping, form, request, response); TravelFormBase travelForm = (TravelFormBase) form; Collection<PersistableBusinessObject> rawValues = null; Map<String, Set<String>> segmentedSelection = new HashMap<String, Set<String>>(); // If multiple asset lookup was used to select the assets, then.... if (StringUtils.equals(KFSConstants.MULTIPLE_VALUE, travelForm.getRefreshCaller())) { String lookupResultsSequenceNumber = travelForm.getLookupResultsSequenceNumber(); if (StringUtils.isNotBlank(lookupResultsSequenceNumber)) { // actually returning from a multiple value lookup Set<String> selectedIds = SpringContext.getBean(SegmentedLookupResultsService.class).retrieveSetOfSelectedObjectIds(lookupResultsSequenceNumber, GlobalVariables.getUserSession().getPerson().getPrincipalId()); for (String selectedId : selectedIds) { String selectedObjId = StringUtils.substringBefore(selectedId, "."); String selectedMonthData = StringUtils.substringAfter(selectedId, "."); if (!segmentedSelection.containsKey(selectedObjId)) { segmentedSelection.put(selectedObjId, new HashSet<String>()); } segmentedSelection.get(selectedObjId).add(selectedMonthData); } // Retrieving selected data from table. LOG.debug("Asking segmentation service for object ids " + segmentedSelection.keySet()); rawValues = SpringContext.getBean(SegmentedLookupResultsService.class).retrieveSelectedResultBOs(lookupResultsSequenceNumber, segmentedSelection.keySet(), HistoricalTravelExpense.class, GlobalVariables.getUserSession().getPerson().getPrincipalId()); List<ImportedExpense> newImportedExpenses = ExpenseUtils.convertHistoricalToImportedExpense((List) rawValues, travelForm.getTravelDocument()); AddImportedExpenseEvent event = new AddImportedExpenseEvent(); for (ImportedExpense newImportedExpense : newImportedExpenses) { travelForm.setNewImportedExpenseLine(newImportedExpense); event.update(null, travelForm); } if (rawValues != null && rawValues.size() > 0) { this.save(mapping, travelForm, request, response); KNSGlobalVariables.getMessageList().add(TemKeyConstants.INFO_TEM_IMPORT_DOCUMENT_SAVE); } } } // set wire charge message in form ((TravelFormBase)form).setWireChargeMessage(retrieveWireChargeMessage()); final String refreshCaller = ((KualiForm)form).getRefreshCaller(); if (!StringUtils.isBlank(refreshCaller)) { final TravelDocument document = ((TravelFormBase)form).getTravelDocument(); if (TemConstants.TRAVELER_PROFILE_DOC_LOOKUPABLE.equals(refreshCaller)) { performRequesterRefresh(document, (TravelFormBase)form, request); } } return mapping.findForward(KFSConstants.MAPPING_BASIC); } @Override public ActionForward performLookup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase travelForm = (TravelFormBase) form; // parse out the important strings from our methodToCall parameter String fullParameter = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE); validateLookupInquiryFullParameter(request, form, fullParameter); String boClassName = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_BOPARM_LEFT_DEL, KRADConstants.METHOD_TO_CALL_BOPARM_RIGHT_DEL); if (!StringUtils.isBlank(boClassName) && boClassName.equals(HistoricalTravelExpense.class.getName())) { TravelDocument document = travelForm.getTravelDocument(); boolean success = true; if (document.getTemProfileId() == null) { String identifier = TemConstants.documentProfileNames().get(document.getFinancialDocumentTypeCode()); GlobalVariables.getMessageMap().putError(KRADPropertyConstants.DOCUMENT + "." + KIMPropertyConstants.Person.FIRST_NAME, TemKeyConstants.ERROR_TEM_IMPORT_EXPENSES_PROFILE_MISSING, identifier); success = false; } if (!success) { return mapping.findForward(KFSConstants.MAPPING_BASIC); } travelForm.setRefreshCaller(KFSConstants.MULTIPLE_VALUE); GlobalVariables.getUserSession().addObject(TemPropertyConstants.TemProfileProperties.PROFILE_ID, document.getTemProfileId()); GlobalVariables.getUserSession().addObject(TemPropertyConstants.ARRANGER_PROFILE_ID, getTemProfileService().findTemProfileByPrincipalId(GlobalVariables.getUserSession().getPrincipalId()).getProfileId()); GlobalVariables.getUserSession().addObject(KFSPropertyConstants.DOCUMENT_TYPE_CODE, document.getFinancialDocumentTypeCode()); } return super.performLookup(mapping, form, request, response); } /** * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#docHandler(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward docHandler(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final ActionForward retval = super.docHandler(mapping, form, request, response); final TravelFormBase travelForm = (TravelFormBase) form; final TravelDocument travelDocument = travelForm.getTravelDocument(); initializeNewActualExpenseLines(travelForm.getNewActualExpenseLines(), travelDocument.getActualExpenses()); //update TA and TR's custom primary destinations if ((travelDocument instanceof TravelAuthorizationDocument) || travelDocument instanceof TravelReimbursementDocument){ updateCustomPrimaryDestination(travelDocument); } return retval; } /** * Update the custom primary destination values and indicator * * This is only applicable to TR and TA docs, but we will keep it in the action base * * @param travelDocument */ protected void updateCustomPrimaryDestination(TravelDocument travelDocument){ //refresh and setup the custom primary destinations values and indicator if (travelDocument.getPrimaryDestinationId() != null && travelDocument.getPrimaryDestinationId().intValue() == TemConstants.CUSTOM_PRIMARY_DESTINATION_ID){ PrimaryDestination destination = travelDocument.getPrimaryDestination(); destination.setPrimaryDestinationName(travelDocument.getPrimaryDestinationName()); destination.setCounty(travelDocument.getPrimaryDestinationCounty()); destination.getRegion().setRegionName(travelDocument.getPrimaryDestinationCountryState()); travelDocument.setPrimaryDestinationIndicator(true); } } protected void initializeNewActualExpenseLines(List<ActualExpense> newActualExpenseLines, List<ActualExpense> actualExpenses) { if (actualExpenses != null && !actualExpenses.isEmpty()) { if (newActualExpenseLines == null) { newActualExpenseLines = new ArrayList<ActualExpense>(); } newActualExpenseLines.clear(); for (ActualExpense actualExpense : actualExpenses) { ActualExpense newActualExpenseLine = new ActualExpense(); newActualExpenseLine.setExpenseDate(actualExpense.getExpenseDate()); newActualExpenseLine.setExpenseTypeObjectCodeId(actualExpense.getExpenseTypeObjectCodeId()); newActualExpenseLine.setExpenseParentId(actualExpense.getId()); newActualExpenseLines.add(newActualExpenseLine); } } } /** * This method will be called when user clicks on Destination not found button on UI under Traveler information section, and * enables state code and county fields by setting primary destination indicator to true. * * @param mapping * @param form * @param request * @param response * @return ActionForward * @throws Exception */ public ActionForward enablePrimaryDestinationFields(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase baseForm = (TravelFormBase) form; TravelDocumentBase document = (TravelDocumentBase) baseForm.getDocument(); document.setPrimaryDestinationIndicator(true); document.setPrimaryDestinationId(TemConstants.CUSTOM_PRIMARY_DESTINATION_ID); // initialize as new primary dest object. if (document.getPrimaryDestination() != null) { document.getPrimaryDestination().setId(TemConstants.CUSTOM_PRIMARY_DESTINATION_ID); document.getPrimaryDestination().setVersionNumber(null); document.getPrimaryDestination().setObjectId(null); } else { document.setPrimaryDestination(new PrimaryDestination()); document.getPrimaryDestination().setId(TemConstants.CUSTOM_PRIMARY_DESTINATION_ID); document.getPrimaryDestination().setPrimaryDestinationName(document.getPrimaryDestinationName()); document.getPrimaryDestination().getRegion().setRegionName(document.getPrimaryDestinationCountryState()); document.getPrimaryDestination().setCounty(document.getPrimaryDestinationCounty()); document.getPrimaryDestination().getRegion().setTripTypeCode(document.getTripTypeCode()); document.getPrimaryDestination().getRegion().setTripType(document.getTripType()); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } protected String getCertificationStatement(final TravelDocument document) { if (isEmployee(document.getTraveler())) { return getEmployeeCertificationStatement(); } return getNonEmployeeCertificationStatement(); } protected String getEmployeeCertificationStatement() { return getCertificationStatementFrom(EMPLOYEE_CERTIFICATION_STATEMENT); } protected String getNonEmployeeCertificationStatement() { return getCertificationStatementFrom(NON_EMPLOYEE_CERTIFICATION_STATEMENT); } protected String getCertificationStatementFrom(final String parameter) { return getParameterService().getParameterValueAsString(TemParameterConstants.TEM_DOCUMENT.class, parameter); } /** * Uses the {@link TravelerService} to determine if the given {@link TravelerDetail} is that of an employee or not * * @param traveler is a {@link TravelerDetail} * @return true if employee or false otherwise * @see @see org.kuali.kfs.module.tem.service.TravelerService#isEmployee(org.kuali.kfs.module.tem.businessobject.TravelerDetail) */ protected boolean isEmployee(final TravelerDetail traveler) { if (traveler == null) { return false; } return getTravelerService().isEmployee(traveler); } /** * Do initialization for a new {@link TravelDocument} * * @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 TravelDocument document = (TravelDocument) kualiDocumentFormBase.getDocument(); document.initiateDocument(); final List<SpecialCircumstances> specialCircumstances = getTravelDocumentService().findActiveSpecialCircumstances(document.getDocumentHeader().getDocumentNumber(), kualiDocumentFormBase.getDocTypeName()); document.setSpecialCircumstances(specialCircumstances); } /** * * @param form * @return * @throws Exception */ @SuppressWarnings("rawtypes") public <T> T newMvcDelegate(final ActionForm form) throws Exception { T retval = (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { getMvcWrapperInterface() }, new TravelMvcWrapperInvocationHandler(form)); return retval; } /** * Forces inheriting classes to define their own MVC Wrappers * * @return some {@link Class} instance for an interface that inherits from the {@link TravelMvcWrapperBean}. That's right. It * has to be one of those. */ protected abstract Class<? extends TravelMvcWrapperBean> getMvcWrapperInterface(); /** * Checks if calculation is required. Currently it is required when it has not already been calculated and if the user can * perform calculate * * @return true if calculation is required, false otherwise */ protected boolean requiresCalculate(TravelFormBase travelForm) { boolean requiresCalculate = true; requiresCalculate = !travelForm.isCalculated(); return requiresCalculate; } /** * Uses generics to get whatever the authorizer is for the attached {@link KualiDocumentFormBase} * * @return some authorizer connected to the {@link Document} in <code>form</code> */ protected <T> T getDocumentAuthorizer(final KualiDocumentFormBase form) { return (T) getDocumentHelperService().getDocumentAuthorizer(form.getDocument()); } protected Integer getLineNumberFromParameter(String parameterKey) { int beginIndex = parameterKey.lastIndexOf("[") + 1; int endIndex = parameterKey.lastIndexOf("]"); return Integer.parseInt(parameterKey.substring(beginIndex, endIndex)); } public ActionForward updatePerDiemExpenses(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase reqForm = (TravelFormBase) form; TravelDocument document = reqForm.getTravelDocument(); ParameterService paramService = SpringContext.getBean(ParameterService.class); if (SpringContext.getBean(KualiRuleService.class).applyRules(new UpdateTripDetailsEvent(TRIP_INFO_UPDATE_TRIP_DTL, reqForm.getDocument()))) { getTravelDocumentService().updatePerDiemItemsFor(document, document.getPerDiemExpenses(), document.getPrimaryDestinationId(), document.getTripBegin(), document.getTripEnd()); } reqForm.getNewSourceLine().setAmount(this.getAccountingLineAmountToFillIn(reqForm)); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward clearPerDiemExpenses(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase reqForm = (TravelFormBase) form; TravelDocument document = reqForm.getTravelDocument(); document.setPerDiemExpenses(new ArrayList<PerDiemExpense>()); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward copyDownPerDiemExpenses(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase reqForm = (TravelFormBase) form; TravelDocument document = reqForm.getTravelDocument(); int copyIndex = getSelectedLine(request); getTravelDocumentService().copyDownPerDiemExpense(document, copyIndex, document.getPerDiemExpenses()); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward addActualExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelFormBase travelForm = (TravelFormBase) form; final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form); travelForm.getObservable().notifyObservers(mvcWrapper); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward addActualExpenseDetailLine(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); } public ActionForward deleteActualExpenseLine(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); } public ActionForward deleteActualExpenseDetailLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelFormBase travelForm = (TravelFormBase) form; final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form); int[] lineNumbers = getSelectedDetailLine(request); travelForm.getObservable().notifyObservers(new Object[] { mvcWrapper, lineNumbers[0], lineNumbers[1] }); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * * @param request * @param response * @param reportFile * @param fileName * @throws IOException */ @SuppressWarnings("rawtypes") protected void displayPDF(HttpServletRequest request, HttpServletResponse response, File reportFile, StringBuilder fileName) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); String contentDisposition = ""; try { ArrayList master = new ArrayList(); PdfCopy writer = null; // create a reader for the document String reportName = reportFile.getAbsolutePath(); PdfReader reader = new PdfReader(reportName); reader.consolidateNamedDestinations(); // retrieve the total number of pages int n = reader.getNumberOfPages(); List bookmarks = SimpleBookmark.getBookmark(reader); if (bookmarks != null) { master.addAll(bookmarks); } // step 1: create a document-object com.lowagie.text.Document pdfDoc = new com.lowagie.text.Document(reader.getPageSizeWithRotation(1)); // step 2: create a writer that listens to the document writer = new PdfCopy(pdfDoc, baos); // step 3: open the document pdfDoc.open(); // step 4: add content PdfImportedPage page; for (int i = 0; i < n;) { ++i; page = writer.getImportedPage(reader, i); writer.addPage(page); } writer.freeReader(reader); if (!master.isEmpty()) { writer.setOutlines(master); } // step 5: we close the document pdfDoc.close(); StringBuffer sbContentDispValue = new StringBuffer(); String useJavascript = request.getParameter("useJavascript"); if (useJavascript == null || useJavascript.equalsIgnoreCase("false")) { sbContentDispValue.append("attachment"); } else { sbContentDispValue.append("inline"); } sbContentDispValue.append("; filename="); sbContentDispValue.append(fileName); contentDisposition = sbContentDispValue.toString(); } catch (Exception e) { e.printStackTrace(); } response.setContentType("application/pdf"); response.setHeader("Content-Disposition", contentDisposition); response.setHeader("Expires", "0"); response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); response.setHeader("Pragma", "public"); response.setContentLength(baos.size()); // write to output ServletOutputStream sos; sos = response.getOutputStream(); baos.writeTo(sos); sos.flush(); sos.close(); } public ActionForward customPerDiemExpenses(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase reqForm = (TravelFormBase) form; TravelDocument document = reqForm.getTravelDocument(); int copyIndex = getSelectedLine(request); PerDiemExpense expense = document.getPerDiemExpenses().get(copyIndex); // now copy info over to expense expense.setPrimaryDestinationId(TemConstants.CUSTOM_PRIMARY_DESTINATION_ID); expense.setPrimaryDestination(""); expense.setCountryState(""); expense.setCounty(""); expense.setLodging(KualiDecimal.ZERO); expense.setIncidentalsValue(KualiDecimal.ZERO); expense.setBreakfastValue(KualiDecimal.ZERO); expense.setLunchValue(KualiDecimal.ZERO); expense.setDinnerValue(KualiDecimal.ZERO); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward refreshAfterPrimaryDestinationLookup(ActionMapping mapping, TravelFormBase reqForm, HttpServletRequest request) { String refreshCaller = reqForm.getRefreshCaller(); TravelDocument document = reqForm.getTravelDocument(); boolean isPrimaryDestinationLookupable = PRIMARY_DESTINATION_LOOKUPABLE.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) { return null; } // do not execute the further refreshing logic if the refresh caller is not a per diem lookupable if (!isPrimaryDestinationLookupable) { return null; } Map parameters = request.getParameterMap(); Set<String> parameterKeys = parameters.keySet(); for (String parameterKey : parameterKeys) { if (StringUtils.containsIgnoreCase(parameterKey, TemPropertyConstants.PER_DIEM_EXPENSES)) { // its one of the numbered lines, lets int estimateLineNum = getLineNumberFromParameter(parameterKey); PerDiemExpense expense = document.getPerDiemExpenses().get(estimateLineNum); String[] priDestId = (String[])parameters.get(parameterKey); PerDiem perDiem = null; if (expense.getPrimaryDestinationId() != TemConstants.CUSTOM_PRIMARY_DESTINATION_ID && expense.getPrimaryDestinationId().equals(new Integer(priDestId[0]))) { perDiem = getPerDiemService().getPerDiem(expense.getPrimaryDestinationId(), expense.getMileageDate(), document.getEffectiveDateForPerDiem(expense.getMileageDate())); } else { perDiem = getPerDiemService().getPerDiem(new Integer(priDestId[0]), expense.getMileageDate(), document.getEffectiveDateForPerDiem(expense.getMileageDate())); } // now copy info over to estimate if (perDiem != null) { expense.setPrimaryDestinationId(perDiem.getPrimaryDestinationId()); expense.setPrimaryDestination(perDiem.getPrimaryDestination().getPrimaryDestinationName()); expense.setCountryState(perDiem.getPrimaryDestination().getRegion().getRegionName()); expense.setCounty(perDiem.getPrimaryDestination().getCounty()); final boolean shouldProrate = document.isOnTripBegin(expense) || document.isOnTripEnd(expense); getTravelDocumentService().setPerDiemMealsAndIncidentals(expense, perDiem, document.getTripType(), document.getTripEnd(), shouldProrate); expense.setLodging(perDiem.getLodging()); } return null; } } Integer primaryDestinationId = document.getPrimaryDestinationId(); if (primaryDestinationId == null) { if (document.getPrimaryDestination().getId() != null) { document.setPerDiemExpenses(new ArrayList<PerDiemExpense>()); } } else if (document.getPrimaryDestination().getId() != null) { if (primaryDestinationId.intValue() != document.getPrimaryDestination().getId()) { document.setPerDiemExpenses(new ArrayList<PerDiemExpense>()); } } if (isPrimaryDestinationLookupable) { PrimaryDestination primaryDestination = new PrimaryDestination(); primaryDestination.setId(primaryDestinationId); document.setPrimaryDestinationIndicator(false); primaryDestination = (PrimaryDestination) SpringContext.getBean(BusinessObjectService.class).retrieve(primaryDestination); document.setPrimaryDestination(primaryDestination); document.setPrimaryDestinationId(primaryDestination.getId()); document.setTripType(primaryDestination.getRegion().getTripType()); document.setTripTypeCode(primaryDestination.getRegion().getTripTypeCode().toUpperCase()); return null; } return null; } /** * Just a passthru {@link InvocationHandler}. It's used when creating a proxy, to access methods in a class without knowing what * that class really is. This allows us to put a facade layer on top of whatever MVC we use; hence, the name * {@link TravelMvcWrapperInvocationHandler} */ class TravelMvcWrapperInvocationHandler<MvcClass> implements InvocationHandler { private MvcClass mvcObj; public TravelMvcWrapperInvocationHandler(final MvcClass mvcObj) { this.mvcObj = mvcObj; } @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Exception { return method.invoke(mvcObj, args); } } protected KualiDecimal getAccountingLineAmountToFillIn(TravelFormBase travelReqForm) { KualiDecimal amount = KualiDecimal.ZERO; TravelDocument travelDocument = travelReqForm.getTravelDocument(); KualiDecimal amountToBePaid = travelDocument.getTotalAccountLineAmount(); final List<TemSourceAccountingLine> accountingLines = travelDocument.getSourceAccountingLines(); KualiDecimal accountingTotal = KualiDecimal.ZERO; for (TemSourceAccountingLine accountingLine : accountingLines) { accountingTotal = accountingTotal.add(accountingLine.getAmount()); } if (!ObjectUtils.isNull(amountToBePaid) && amountToBePaid.isGreaterEqual(accountingTotal)) { amount = amountToBePaid.subtract(accountingTotal); } if (travelDocument.getExpenseLimit() != null && travelDocument.getExpenseLimit().isPositive()) { if (accountingTotal.isGreaterEqual(travelDocument.getExpenseLimit())) { return KualiDecimal.ZERO; // the accounting line total is greater than or equal to the expense limit, there's no more expense limit to spend } if (amount.isGreaterThan(travelDocument.getExpenseLimit())) { return travelDocument.getExpenseLimit().subtract(accountingTotal); // the amount to be paid - accounting total is still greater than the expense limit; so the amount we can actually pay is the expense limit - the accounting total } // we're under the expense limit; let's just return amount } return amount; } /** * This method calculates trip detail total for both TA and TR * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward recalculateTripDetailTotal(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { KNSGlobalVariables.getMessageList().remove(new ErrorMessage(TemKeyConstants.MESSAGE_RECALCULATE_SUCCESSFUL)); // check to make sure all the number fields in the Trip Detail Estimates section are not negative TravelFormBase travelReqForm = (TravelFormBase) form; TravelDocumentBase travelReqDoc = (TravelDocumentBase) travelReqForm.getDocument(); // Added to set values to zero when personal box checked to display correct values and totals if (SpringContext.getBean(KualiRuleService.class).applyRules(new RecalculateTripDetailTotalEvent("", travelReqForm.getDocument()))) { List<PerDiemExpense> estimates = travelReqDoc.getPerDiemExpenses(); if (estimates != null && !estimates.isEmpty()) { getTravelDocumentService().updatePerDiemItemsFor(travelReqDoc, estimates, null, travelReqDoc.getTripBegin(), travelReqDoc.getTripEnd()); } } if (!travelReqDoc.isValidExpenses()) { return mapping.findForward(KFSConstants.MAPPING_BASIC); } travelReqForm.getNewSourceLine().setAmount(this.getAccountingLineAmountToFillIn(travelReqForm)); // forcing a refresh does the same as recalculation (unless we change how we do it) LOG.debug("Recalculating travel auth document " + travelReqDoc.getTravelDocumentIdentifier()); travelReqForm.setCalculated(true); KNSGlobalVariables.getMessageList().add(TemKeyConstants.MESSAGE_RECALCULATE_SUCCESSFUL); showAccountDistribution(request, travelReqForm.getDocument()); // Flag to display reports (TR, ENT, RELO) request.setAttribute(SHOW_REPORTS_ATTRIBUTE, !travelReqDoc.getDocumentHeader().getWorkflowDocument().isInitiated()); if (travelReqDoc.getReimbursableTotal() != null && travelReqDoc.getExpenseLimit() != null && travelReqDoc.getReimbursableTotal().isGreaterThan(travelReqDoc.getExpenseLimit())) { GlobalVariables.getMessageMap().putWarning(KFSConstants.DOCUMENT_PROPERTY_NAME + "." + TemPropertyConstants.TRVL_AUTH_TOTAL_ESTIMATE, KFSKeyConstants.ERROR_CUSTOM, "Travel expense is exceeding the expense limit."); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } protected void showAccountDistribution(HttpServletRequest request, Document document) { if (document instanceof TravelDocumentBase) { final boolean showAccountDistribution = getParameterService().getParameterValueAsBoolean(document.getClass(), DISPLAY_ACCOUNTING_DISTRIBUTION_TAB_IND); request.setAttribute(SHOW_ACCOUNT_DISTRIBUTION_ATTRIBUTE, showAccountDistribution); } } /** * This method wraps recalculateTripDetailTotal and removes the success message * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward recalculateTripDetailTotalOnly(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // call recalculateTripDetailTotal where all the magic happens ActionForward actionForward = recalculateTripDetailTotal(mapping, form, request, response); KNSGlobalVariables.getMessageList().remove(new ErrorMessage(TemKeyConstants.MESSAGE_RECALCULATE_SUCCESSFUL)); return actionForward; } /** * This method determines if the user is a travel arranger for the document * * @return true if they are a travel arranger */ protected boolean setTravelArranger(TravelFormBase form) { // TODO shouldn't this be an "edit transactional document" permission? TravelDocument travelDocument = form.getTravelDocument(); // don't set "travelArranger" attribute if this isn't the base document if (!StringUtils.isBlank(travelDocument.getTravelDocumentIdentifier())) { final TravelDocument baseTravelDocument = getTravelDocumentService().getParentTravelDocument(travelDocument.getTravelDocumentIdentifier()); if (baseTravelDocument != null && !StringUtils.equals(baseTravelDocument.getDocumentNumber(), travelDocument.getDocumentNumber())) { return false; // this isn't the base document...so we can't change the traveler } } TemProfile profile = null; //default to nulls String profileId=null; String homeDepartment = null; if (ObjectUtils.isNotNull(travelDocument.getTemProfileId())) { profile = getBusinessObjectService().findBySinglePrimaryKey(TemProfile.class, travelDocument.getTemProfileId()); if (ObjectUtils.isNotNull(profile)) { homeDepartment = profile.getHomeDepartment(); profileId = profile.getProfileId().toString(); } } return getTemRoleService().isTravelArranger(GlobalVariables.getUserSession().getPerson(), homeDepartment, profileId, travelDocument.getDocumentTypeName()); } /** * This method determines if the user is a travel manager * * @return true if they are a travel manager */ protected boolean setTravelManager(TravelFormBase reqForm) { // Find if they have the role return getTravelDocumentService().isTravelManager(GlobalVariables.getUserSession().getPerson()); } /** * This method determines if the user is a fiscal officer * * @return true if they are a fiscal officer */ protected boolean setFiscalOfficer(TravelFormBase reqForm) { // Find if they have the role // checking this is causing a RuntimeException when the workflow document is null (when generating a report). // apparently even checking if a workflow document is null will cause it to send a RuntimeException - hence the try catch. boolean workflowCheck = false; try { List<RouteNodeInstance> nodes = reqForm.getWorkflowDocument().getRouteNodeInstances(); for (RouteNodeInstance routeNode : nodes){ if (routeNode.getName().equals(KFSConstants.RouteLevelNames.ACCOUNT)){ workflowCheck = true; } } workflowCheck &= reqForm.getWorkflowDocument().isEnroute(); } catch (RuntimeException e) { // Do not propagate this exception. LOG.info("Could not retrieve the workflow document. This is most likely normal and ok in this case."); } return getTravelDocumentService().isResponsibleForAccountsOn(reqForm.getTravelDocument(), GlobalVariables.getUserSession().getPerson().getPrincipalId()) && workflowCheck; } protected List<String> getCalculateIgnoreList() { return Arrays.asList(methodToCallExclusionArray); } /** * This method adds a new related document into the travel request document * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward addRelatedDocumentLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase travelReqForm = (TravelFormBase) form; AccountingDocumentRelationship adr = travelReqForm.getNewAccountingDocumentRelationship(); if (adr.getRelDocumentNumber() == null || !NumberUtils.isDigits(adr.getRelDocumentNumber())) { GlobalVariables.getMessageMap().putError( String.format("%s.%s", TemKeyConstants.TRVL_RELATED_DOCUMENT, TemPropertyConstants.TRVL_RELATED_DOCUMENT_NUM), TemKeyConstants.ERROR_TRVL_RELATED_DOCUMENT_REQUIRED); } else { if (getDocumentService().documentExists(adr.getRelDocumentNumber())) { adr.setDocumentNumber(travelReqForm.getDocument().getDocumentNumber()); adr.setPrincipalId(GlobalVariables.getUserSession().getPerson().getPrincipalId()); getAccountingDocumentRelationshipService().save(adr); travelReqForm.setNewAccountingDocumentRelationship(new AccountingDocumentRelationship()); } else { GlobalVariables.getMessageMap().putError( String.format("%s.%s", TemKeyConstants.TRVL_RELATED_DOCUMENT, TemPropertyConstants.TRVL_RELATED_DOCUMENT_NUM), TemKeyConstants.ERROR_TRVL_RELATED_DOCUMENT_NOT_FOUND, new String[] { adr.getRelDocumentNumber() }); } } return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward deleteRelatedDocumentLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase travelReqForm = (TravelFormBase) form; String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE); if (StringUtils.isNotBlank(parameterName)) { String relDocumentNumber = StringUtils.substringBetween(parameterName, "deleteRelatedDocumentLine.", "."); List<AccountingDocumentRelationship> adrList = getAccountingDocumentRelationshipService().find(new AccountingDocumentRelationship(travelReqForm.getDocument().getDocumentNumber(), relDocumentNumber)); if (adrList != null && adrList.size() == 1) { if (adrList.get(0).getPrincipalId().equals(GlobalVariables.getUserSession().getPerson().getPrincipalId())) { getAccountingDocumentRelationshipService().delete(adrList.get(0)); } } } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * This method adds a new group traveler into the travel document * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward addGroupTravelerLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase travelReqForm = (TravelFormBase) form; TravelDocumentBase travelReqDoc = (TravelDocumentBase) travelReqForm.getDocument(); GroupTraveler newGroupTravelerLine = travelReqForm.getNewGroupTravelerLine(); boolean rulePassed = true; // check any business rules rulePassed &= SpringContext.getBean(KualiRuleService.class).applyRules(new AddGroupTravelLineEvent("newGroupTravelerLine", travelReqForm.getDocument(), newGroupTravelerLine)); if (rulePassed) { travelReqDoc.addGroupTravelerLine(newGroupTravelerLine); travelReqForm.setNewGroupTravelerLine(new GroupTraveler()); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * This method removes a group traveler from this collection * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward deleteGroupTravelerLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase travelReqForm = (TravelFormBase) form; TravelDocumentBase travelReqDoc = (TravelDocumentBase) travelReqForm.getDocument(); int deleteIndex = getLineToDelete(request); travelReqDoc.getGroupTravelers().remove(deleteIndex); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Import group travel 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 uploadGroupTravelerImportFile(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, new String(travelForm.getGroupTravelerImportFile().getFileData()) }); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward payDVToVendor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final String url = getKualiConfigurationService().getPropertyValueAsString(KFSConstants.APPLICATION_URL_KEY)+"/"+TravelCustomSearchLinks.DV_URL + HtmlUtils.htmlEscape(((TravelFormBase)form).getTravelDocument().getDocumentNumber()); return new ActionForward(url, true); } public ActionForward addImportedExpenseLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelFormBase travelForm = (TravelFormBase) form; final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form); travelForm.getObservable().notifyObservers(mvcWrapper); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward addImportedExpenseDetailLine(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); } public ActionForward deleteImportedExpenseLine(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) }); //remove the imported expense accounting line if import expense list is empty checkImportedExpenseAccountingLine(travelForm.getTravelDocument()); this.save(mapping, travelForm, request, response); KNSGlobalVariables.getMessageList().add(TemKeyConstants.INFO_TEM_IMPORT_DOCUMENT_SAVE); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward deleteImportedExpenseDetailLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelFormBase travelForm = (TravelFormBase) form; final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form); int[] lineNumbers = getSelectedDetailLine(request); travelForm.getObservable().notifyObservers(new Object[] { mvcWrapper, lineNumbers[0], lineNumbers[1] }); return mapping.findForward(KFSConstants.MAPPING_BASIC); } protected int[] getSelectedDetailLine(HttpServletRequest request) { int[] selectedLines = new int[2]; String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE); if (StringUtils.isNotBlank(parameterName)) { String lineNumbers = StringUtils.substringBetween(parameterName, ".line", "."); selectedLines[0] = Integer.parseInt(lineNumbers.split("-")[0]); selectedLines[1] = Integer.parseInt(lineNumbers.split("-")[1]); } return selectedLines; } /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#deleteSourceLine(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward deleteSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward forward = super.deleteSourceLine(mapping, form, request, response); TravelFormBase travelForm = (TravelFormBase) form; travelForm.setAnchor(TemConstants.SOURCE_ANCHOR); travelForm.setDistribution(new ArrayList<AccountingDistribution>()); travelForm.setDistribution(getAccountingDistributionService().buildDistributionFrom(travelForm.getTravelDocument())); return forward; } public ActionForward deleteDistributionLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase travelForm = (TravelFormBase) form; travelForm.setAnchor(TemConstants.DISTRIBUTION_ANCHOR); final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form); int deleteIndex = getLineToDelete(request); travelForm.getObservable().notifyObservers(new Object[] { mvcWrapper, deleteIndex }); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward insertDistributionLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase travelForm = (TravelFormBase) form; TravelDocument travelDocument = travelForm.getTravelDocument(); travelForm.getAccountDistributionnewSourceLine().setCardType(travelDocument.getDefaultAccountingLineCardAgencyType()); travelForm.setAnchor(TemConstants.DISTRIBUTION_ANCHOR); final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form); travelForm.getObservable().notifyObservers(mvcWrapper); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#deleteAccountingLine(boolean, * org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase, int) */ @Override protected void deleteAccountingLine(boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, int deleteIndex) { financialDocumentForm.setAnchor(TemConstants.SOURCE_ANCHOR); super.deleteAccountingLine(isSource, financialDocumentForm, deleteIndex); } /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#insertAccountingLine(boolean, * org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase, org.kuali.kfs.sys.businessobject.AccountingLine) */ @Override protected void insertAccountingLine(boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, AccountingLine line) { financialDocumentForm.setAnchor(TemConstants.SOURCE_ANCHOR); super.insertAccountingLine(isSource, financialDocumentForm, line); } public ActionForward selectAllDistributions(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { request.setAttribute("anchoraccountingDistributionAnchor", "anchoraccountingDistributionAnchor"); TravelFormBase travelForm = (TravelFormBase) form; int index = getSelectedLine(request); boolean selected = false; if (index == Integer.parseInt(TemConstants.SELECT_ALL_INDEX)) { selected = true; } for (AccountingDistribution accountingDistribution : travelForm.getDistribution()) { accountingDistribution.setSelected(selected); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Action method that handles setting up the distribution of expenses. Expenses are distributed by object code across * {@link AccountingLine} instances. When a distribution is setup, the relevant information is added to the new * {@link AccountingLine} on the {@link TravelReimbursementForm} * * @param mapping * @param form * @param request * @param response * @return {@link ActionForward} */ protected void initializeAssignAccounts(TravelFormBase travelForm) { TravelDocument travelDocument = travelForm.getTravelDocument(); TemDistributionAccountingLine newLine = getAccountingDistributionService().distributionToDistributionAccountingLine(travelForm.getDistribution()); travelForm.setAccountDistributionsourceAccountingLines(new ArrayList<TemDistributionAccountingLine>()); travelForm.setAccountDistributionnextSourceLineNumber(new Integer(1)); newLine.setAccountLinePercent(new BigDecimal(100)); newLine.setCardType(travelDocument.getDefaultAccountingLineCardAgencyType()); if (!ObjectUtils.isNull(travelDocument.getTemProfile())) { newLine.setChartOfAccountsCode(travelDocument.getTemProfile().getDefaultChartCode()); newLine.setAccountNumber(travelDocument.getTemProfile().getDefaultAccount()); newLine.setSubAccountNumber(travelDocument.getTemProfile().getDefaultSubAccount()); newLine.setProjectCode(travelDocument.getTemProfile().getDefaultProjectCode()); } travelForm.setAccountDistributionnewSourceLine(newLine); } public ActionForward distributeAccountingLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { final TravelFormBase travelForm = (TravelFormBase) form; travelForm.setAnchor(TemConstants.DISTRIBUTION_ANCHOR); final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form); travelForm.getObservable().notifyObservers(mvcWrapper); return mapping.findForward(KFSConstants.MAPPING_BASIC); } public ActionForward resetAccountingLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { TravelFormBase travelForm = (TravelFormBase) form; TravelDocument document = travelForm.getTravelDocument(); document.setNextSourceLineNumber(new Integer(1)); document.setSourceAccountingLines(new ArrayList<TemSourceAccountingLine>()); travelForm.setDistribution(new ArrayList<AccountingDistribution>()); travelForm.setDistribution(getAccountingDistributionService().buildDistributionFrom(document)); travelForm.setAnchor(TemConstants.SOURCE_ANCHOR); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#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 { recalculateTripDetailTotalOnly(mapping, form, request, response); ActionForward forward = super.approve(mapping, form, request, response); return forward; } /** * is this document in a final workflow state * * @param reqForm * @return */ protected boolean isFinal(TravelFormBase reqForm) { return reqForm.getTransactionalDocument().getDocumentHeader().getWorkflowDocument().isFinal(); } /** * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#disapprove(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward disapprove(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // Document is disapproved. Free up imported expenses TravelFormBase travelForm = (TravelFormBase) form; TravelDocument document = travelForm.getTravelDocument(); getTravelDocumentService().detachImportedExpenses(document); return super.disapprove(mapping, form, request, response); } /** * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#cancel(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward forward = super.cancel(mapping, form, request, response); if (forward.getName() != null && forward.getName().equals(KRADConstants.MAPPING_PORTAL)) { // Document is cancelled. Free up imported expenses TravelFormBase travelForm = (TravelFormBase) form; TravelDocument document = travelForm.getTravelDocument(); getTravelDocumentService().detachImportedExpenses(document); } return forward; } /** * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#close(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward close(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward forward = super.close(mapping, form, request, response); TravelFormBase travelForm = (TravelFormBase) form; TravelDocument document = travelForm.getTravelDocument(); if (forward.getName() != null && forward.getName().equals(KRADConstants.MAPPING_PORTAL)) { // Document is not saved. Free up imported expenses. if (document.getDocumentHeader().getWorkflowDocument().isInitiated()) { getTravelDocumentService().detachImportedExpenses(document); } } return forward; } /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#save(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { recalculateTripDetailTotalOnly(mapping, form, request, response); TravelFormBase travelForm = (TravelFormBase) form; TravelDocument document = travelForm.getTravelDocument(); ActionForward forward = super.save(mapping, form, request, response); return forward; } /** * Remove the document accounting lines which were tied to import expenses * * @param document */ public void checkImportedExpenseAccountingLine(TravelDocument document){ //remove imported expenses accounting line if there is no import expense if (!document.getSourceAccountingLines().isEmpty() && document.getImportedExpenses().isEmpty()){ List<SourceAccountingLine> filteredAccountingLine = new ArrayList<SourceAccountingLine>(); //get the travel card type lists List<String> cardTypes = getTravelService().getTravelCardTypes(); for (TemSourceAccountingLine line : (List<TemSourceAccountingLine>)document.getSourceAccountingLines()){ //filter out any source accounting line that is of travel card type if (!cardTypes.contains(line.getCardType())){ filteredAccountingLine.add(line); } } document.setSourceAccountingLines(filteredAccountingLine); } } /** * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#blanketApprove(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward blanketApprove(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { recalculateTripDetailTotalOnly(mapping, form, request, response); TravelFormBase travelForm = (TravelFormBase) form; TravelDocument document = travelForm.getTravelDocument(); ActionForward forward = super.blanketApprove(mapping, form, request, response); getTravelDocumentService().attachImportedExpenses(document); return forward; } /** * is this document in a processed workflow state? * * @param reqForm * @return */ protected boolean isProcessed(TravelFormBase reqForm) { return reqForm.getTransactionalDocument().getDocumentHeader().getWorkflowDocument().isProcessed(); } protected void refreshRelatedDocuments(TravelFormBase form) { Map<String, List<Document>> relatedDocuments; try { relatedDocuments = getTravelDocumentService().getDocumentsRelatedTo(form.getTravelDocument()); form.setRelatedDocuments(relatedDocuments); form.setRelatedDocumentNotes(null); form.getRelatedDocumentNotes(); } catch (WorkflowException ex) { ex.printStackTrace(); } } /** * @return the message associated with this wire charge */ 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); } /** * Determines whether or not someone can calculate a travel document * * @param authForm */ protected void setCanCalculate(TravelFormBase form) { boolean can = !(isFinal(form) || isProcessed(form)); if (can) { TravelArrangeableAuthorizer documentAuthorizer = getDocumentAuthorizer(form); can = documentAuthorizer.canCalculate(form.getTravelDocument(), GlobalVariables.getUserSession().getPerson()); } form.setCanCalculate(can); } /** * Lookups the url for the currency url link on expense lines * @param form the form this action is acting on */ protected void populateForeignCurrencyUrl(TravelFormBase form) { final String currencyUrl = getParameterService().getParameterValueAsString(TemParameterConstants.TEM_DOCUMENT.class, FOREIGN_CURRENCY_URL); form.setForeignCurrencyUrl(currencyUrl); } /** * Populates the agency links on the form * @param form the form to populate links on */ protected void populateAgencyLinks(TravelFormBase form) { final List<LinkField> agencyLinks = getTravelDocumentService().getAgencyLinks(form.getTravelDocument()); form.setAgencyLinks(agencyLinks); final boolean shouldDisplay = getKualiConfigurationService().getPropertyValueAsBoolean(TemKeyConstants.ENABLE_AGENCY_SITES_URL); form.setShouldDisplayAgencyLinks(shouldDisplay); } /** * Goes through the actual expenses on the document and pushes the conversion rate of the parent expense down to the details * @param doc the travel document to update */ protected void updateActualExpenseConversionRates(TravelDocument doc) { for (ActualExpense expense : doc.getActualExpenses()) { if (expense.getExpenseDetails() != null && !expense.getExpenseDetails().isEmpty()) { for (TemExpense detail : expense.getExpenseDetails()) { detail.setCurrencyRate(expense.getCurrencyRate()); } } } } /** * Builds a relationship between the document we're creating and the one we're basing the document off of * @param progenitorDocument the original document * @param createdDocument the document we're creating now, based on that document * @return the accounting document relationship between the two documents */ protected AccountingDocumentRelationship buildRelationshipToProgenitorDocument(TravelDocument progenitorDocument, TravelDocument createdDocument) { final String progenitorType = progenitorDocument.getDocumentHeader().getWorkflowDocument().getDocumentTypeName(); final String createdType = createdDocument.getDocumentHeader().getWorkflowDocument().getDocumentTypeName(); AccountingDocumentRelationship relationship = new AccountingDocumentRelationship(progenitorDocument.getDocumentNumber(), createdDocument.getDocumentNumber(), progenitorType+" - "+createdType); relationship.setPrincipalId(GlobalVariables.getUserSession().getPrincipalId()); return relationship; } /** * Disables any per diem meals which have matching hosted or group actual expenses and displays messages about that * @param document the TA or TR to disable per diem expenses on */ protected void disablePerDiemExpenes(TravelDocument document) { for (ActualExpense actualExpense : document.getActualExpenses()){ getTravelDocumentService().disableDuplicateExpenses(document, actualExpense); } //Display any messages Iterator<String> it = document.getDisabledProperties().keySet().iterator(); while (it.hasNext()){ String key = it.next(); GlobalVariables.getMessageMap().putInfo(key, TemKeyConstants.MESSAGE_GENERIC,document.getDisabledProperties().get(key)); } } /** * Performs necessary updates after the requester on the travel document was updated * @param document the document to update * @param request the current web request */ protected abstract void performRequesterRefresh(TravelDocument document, TravelFormBase travelForm, HttpServletRequest request); /** * Updates new accounting lines on the document with default info from the profile if applicable * @param form the form holding new accounting lines * @param profile the profile to switch the lines over to the default accounting information of */ protected void updateAccountsWithNewProfile(TravelFormBase form, TemProfile profile) { if (profile != null) { // update new source accounting line if (form.getNewSourceLine() != null) { TemSourceAccountingLine acctLine = (TemSourceAccountingLine)form.getNewSourceLine(); acctLine.setChartOfAccountsCode(profile.getDefaultChartCode()); acctLine.setAccountNumber(profile.getDefaultAccount()); acctLine.setSubAccountNumber(profile.getDefaultSubAccount()); acctLine.setProjectCode(profile.getDefaultProjectCode()); } // update new distribution line if (form.getAccountDistributionnewSourceLine() != null) { TemDistributionAccountingLine acctLine = form.getAccountDistributionnewSourceLine(); acctLine.setChartOfAccountsCode(profile.getDefaultChartCode()); acctLine.setAccountNumber(profile.getDefaultAccount()); acctLine.setSubAccountNumber(profile.getDefaultSubAccount()); acctLine.setProjectCode(profile.getDefaultProjectCode()); } } } /** * looks up the resolved url for the given document type * @param documentType the document type to check * @return the resolved url */ protected String getResolvedUrlForDocumentType(String documentType) { final DocumentType docType = getDocumentTypeService().getDocumentTypeByName(documentType); return docType.getResolvedDocumentHandlerUrl(); } /** * Builds a new reimburesment 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 reimbursement */ protected String buildNewReimbursementUrl(TravelDocument travelDoc) { Properties props = new Properties(); props.put(TemPropertyConstants.TRAVEL_DOCUMENT_IDENTIFIER, travelDoc.getTravelDocumentIdentifier()); props.put(KFSConstants.DOCUMENT_TYPE_NAME, TemConstants.TravelDocTypes.TRAVEL_REIMBURSEMENT_DOCUMENT); props.put(KFSConstants.PARAMETER_COMMAND, KewApiConstants.INITIATE_COMMAND); final String docUrlBase = getResolvedUrlForDocumentType(TemConstants.TravelDocTypes.TRAVEL_REIMBURSEMENT_DOCUMENT); final String url = UrlFactory.parameterizeUrl(docUrlBase, props); return url; } }