/* * 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.bc.document.web.struts; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringUtils; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.kuali.kfs.fp.service.FiscalYearFunctionControlService; import org.kuali.kfs.module.bc.BCConstants; import org.kuali.kfs.module.bc.BCKeyConstants; import org.kuali.kfs.module.bc.BCPropertyConstants; import org.kuali.kfs.module.bc.BCConstants.OrgSelOpMode; import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAccountOrganizationHierarchy; import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAccountSelect; import org.kuali.kfs.module.bc.businessobject.BudgetConstructionHeader; import org.kuali.kfs.module.bc.businessobject.BudgetConstructionLockSummary; import org.kuali.kfs.module.bc.document.BudgetConstructionDocument; import org.kuali.kfs.module.bc.document.service.BudgetDocumentService; import org.kuali.kfs.module.bc.document.service.OrganizationBCDocumentSearchService; import org.kuali.kfs.module.bc.document.validation.event.AddBudgetConstructionDocumentEvent; import org.kuali.kfs.module.bc.report.ReportControlListBuildHelper; import org.kuali.kfs.module.bc.util.BudgetUrlUtil; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.kns.question.ConfirmationQuestion; import org.kuali.rice.kns.util.KNSGlobalVariables; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.service.KualiRuleService; import org.kuali.rice.krad.service.PersistenceService; import org.kuali.rice.krad.util.GlobalVariables; /** * This class... */ public class BudgetConstructionSelectionAction extends BudgetExpansionAction { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BudgetConstructionSelectionAction.class); /** * @see org.kuali.rice.kns.web.struts.action.KualiAction#execute(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward forward = super.execute(mapping, form, request, response); BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; // set force rebuild on report build helper so each time we go out of report screen and come back the list will be rebuilt ReportControlListBuildHelper buildHelper = (ReportControlListBuildHelper) GlobalVariables.getUserSession().retrieveObject(BCConstants.Report.CONTROL_BUILD_HELPER_SESSION_NAME); if (buildHelper == null) { buildHelper = new ReportControlListBuildHelper(); } buildHelper.setForceRebuild(true); GlobalVariables.getUserSession().addObject(BCConstants.Report.CONTROL_BUILD_HELPER_SESSION_NAME, buildHelper); return forward; } /** * Performs the initial load of the selection screen. Checks for the active BC fiscal year and initializes the fiscal year to be * budgeted and used for all other operations throughout the system * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward loadExpansionScreen(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; FiscalYearFunctionControlService fiscalYearFunctionControlService = SpringContext.getBean(FiscalYearFunctionControlService.class); ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.class); Boolean isBCInProgress = (Boolean) GlobalVariables.getUserSession().retrieveObject(BCConstants.BC_IN_PROGRESS_SESSIONFLAG); if (isBCInProgress != null && isBCInProgress) { Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME); if (question == null) { // ask question if not already asked return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.DOCUMENT_DELETE_QUESTION, kualiConfiguration.getPropertyValueAsString(BCKeyConstants.QUESTION_CONFIRM_CLEANUP), KFSConstants.CONFIRMATION_QUESTION, "loadExpansionScreen", ""); } else { Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON); if ((KFSConstants.DOCUMENT_DELETE_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) { // clear out all BC related Objects(forms) stored in GlobalVariables.UserSession // to help prevent memory leaks if the user fails to use application control flow GlobalVariables.getUserSession().removeObjectsByPrefix(BCConstants.FORMKEY_PREFIX); // clear out any session object form attribute HttpSession sess = request.getSession(Boolean.FALSE); sess.removeAttribute(BCConstants.MAPPING_ATTRIBUTE_KUALI_FORM); } else { budgetConstructionSelectionForm.setSessionInProgressDetected(true); KNSGlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_PREVIOUS_SESSION_NOTCLEANED); return mapping.findForward(KFSConstants.MAPPING_BASIC); } } } else { // cleanup anyway to handle back door lost session case GlobalVariables.getUserSession().removeObjectsByPrefix(BCConstants.FORMKEY_PREFIX); // clear out any session object form attribute HttpSession sess = request.getSession(Boolean.FALSE); sess.removeAttribute(BCConstants.MAPPING_ATTRIBUTE_KUALI_FORM); } // get active BC year and complain when anything other than one year active for now List<Integer> activeBCYears = fiscalYearFunctionControlService.getActiveBudgetYear(); if (activeBCYears.size() != 1) { budgetConstructionSelectionForm.setUniversityFiscalYear(null); if (activeBCYears.size() < 1) { KNSGlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_SYSTEM_NOT_ACTIVE); } else { KNSGlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_SYSTEM_MULTIPLE_ACTIVE); } } else { budgetConstructionSelectionForm.setUniversityFiscalYear(activeBCYears.get(0)); } budgetConstructionSelectionForm.getBudgetConstructionHeader().setUniversityFiscalYear(budgetConstructionSelectionForm.getUniversityFiscalYear()); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Opens a Budget Construction document. Creates a new (blank) BC document, if one does not exist. The new BC document is * created at level zero and the associated account organization hierarchy is built. * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward performBCDocumentOpen(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // do lookup of header and call open if found, otherwise create blank doc and account hierarchy, then open if no error BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; BudgetConstructionHeader bcHeader = budgetConstructionSelectionForm.getBudgetConstructionHeader(); Integer universityFiscalYear = bcHeader.getUniversityFiscalYear(); String chartOfAccountsCode = bcHeader.getChartOfAccountsCode(); String accountNumber = bcHeader.getAccountNumber(); String subAccountNumber; if (StringUtils.isBlank(bcHeader.getSubAccountNumber())) { subAccountNumber = KFSConstants.getDashSubAccountNumber(); } else { subAccountNumber = bcHeader.getSubAccountNumber(); } BudgetConstructionHeader tHeader = SpringContext.getBean(BudgetDocumentService.class).getByCandidateKey(chartOfAccountsCode, accountNumber, subAccountNumber, universityFiscalYear); if (tHeader == null) { // get a bare bones BC document to run the rule engine against // if rulesPassed, use the document to instantiate to the DB BudgetConstructionDocument budgetConstructionDocument = (BudgetConstructionDocument) SpringContext.getBean(DocumentService.class).getNewDocument(BCConstants.BUDGET_CONSTRUCTION_DOCUMENT_NAME); budgetConstructionDocument.setUniversityFiscalYear(universityFiscalYear); budgetConstructionDocument.setChartOfAccountsCode(chartOfAccountsCode); budgetConstructionDocument.setAccountNumber(accountNumber); budgetConstructionDocument.setSubAccountNumber(subAccountNumber); List refreshFields = Collections.unmodifiableList(Arrays.asList(new String[] { KFSPropertyConstants.ACCOUNT, KFSPropertyConstants.SUB_ACCOUNT })); SpringContext.getBean(PersistenceService.class).retrieveReferenceObjects(budgetConstructionDocument, refreshFields); boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddBudgetConstructionDocumentEvent(BCPropertyConstants.BUDGET_CONSTRUCTION_HEADER, budgetConstructionDocument)); if (rulePassed) { List<BudgetConstructionAccountOrganizationHierarchy> newAccountOrganizationHierarchy = SpringContext.getBean(BudgetDocumentService.class).retrieveOrBuildAccountOrganizationHierarchy(universityFiscalYear, chartOfAccountsCode, accountNumber); if (newAccountOrganizationHierarchy == null || newAccountOrganizationHierarchy.isEmpty()) { GlobalVariables.getMessageMap().putError("budgetConstructionHeader", BCKeyConstants.ERROR_BUDGET_ACCOUNT_ORGANIZATION_HIERARCHY, chartOfAccountsCode + "-" + accountNumber); return mapping.findForward(KFSConstants.MAPPING_BASIC); } // hierarchy created - attempt to create BC document // SpringContext.getBean(BudgetDocumentService.class).instantiateNewBudgetConstructionDocument(universityFiscalYear, // chartOfAccountsCode, accountNumber, subAccountNumber); SpringContext.getBean(BudgetDocumentService.class).instantiateNewBudgetConstructionDocument(budgetConstructionDocument); tHeader = SpringContext.getBean(BudgetDocumentService.class).getByCandidateKey(chartOfAccountsCode, accountNumber, subAccountNumber, universityFiscalYear); if (tHeader == null) { GlobalVariables.getMessageMap().putError("budgetConstructionHeader", KFSKeyConstants.ERROR_EXISTENCE, "BC Document"); return mapping.findForward(KFSConstants.MAPPING_BASIC); } else { // drop to open the newly created document } } else { return mapping.findForward(KFSConstants.MAPPING_BASIC); } } this.flagBCInProgress(); // open the existing or newly created BC document Map<String, String> parameters = new HashMap<String, String>(); parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, BCConstants.BC_DOCUMENT_METHOD); parameters.put("universityFiscalYear", tHeader.getUniversityFiscalYear().toString()); parameters.put("chartOfAccountsCode", tHeader.getChartOfAccountsCode()); parameters.put("accountNumber", tHeader.getAccountNumber()); parameters.put("subAccountNumber", tHeader.getSubAccountNumber()); parameters.put("pickListMode", "false"); parameters.put(BCPropertyConstants.MAIN_WINDOW, "true"); String lookupUrl = BudgetUrlUtil.buildBudgetUrl(mapping, budgetConstructionSelectionForm, BCConstants.BC_DOCUMENT_ACTION, parameters); return new ActionForward(lookupUrl, true); } /** * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; String refreshCaller = request.getParameter(KFSConstants.REFRESH_CALLER); // returning from account lookup sets refreshCaller to accountLookupable, due to setting in account.xml if (refreshCaller != null && (refreshCaller.toUpperCase().endsWith(KFSConstants.LOOKUPABLE_SUFFIX.toUpperCase()))) { final List REFRESH_FIELDS = Collections.unmodifiableList(Arrays.asList(new String[] { "chartOfAccounts", "account", "subAccount", "budgetConstructionAccountReports" })); SpringContext.getBean(PersistenceService.class).retrieveReferenceObjects(budgetConstructionSelectionForm.getBudgetConstructionHeader(), REFRESH_FIELDS); } // clearout any BC inprogress semaphore, regardless of where we are returning from // this handles the lock monitor no refreshCaller return case GlobalVariables.getUserSession().removeObject(BCConstants.BC_IN_PROGRESS_SESSIONFLAG); // clear out any session object form attribute HttpSession sess = request.getSession(Boolean.FALSE); sess.removeAttribute(BCConstants.MAPPING_ATTRIBUTE_KUALI_FORM); return mapping.findForward(KFSConstants.MAPPING_BASIC); } @Override public ActionForward returnToCaller(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; return mapping.findForward(KFSConstants.MAPPING_PORTAL); } public ActionForward performOrgSalarySetting(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; ActionForward forward = performOrgSelectionTree(OrgSelOpMode.SALSET, mapping, form, request, response); return forward; } /** * This method sets up to forward to the BC Organization Selection screen using a specific operating mode. The various operating * modes include PULLUP, PUSHDOWN, REPORTS, SALSET, ACCOUNT. * * @param opMode * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward performOrgSelectionTree(OrgSelOpMode opMode, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; this.flagBCInProgress(); Map<String, String> parameters = new HashMap<String, String>(); parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, BCConstants.ORG_SEL_TREE_METHOD); parameters.put("operatingMode", opMode.toString()); parameters.put("universityFiscalYear", budgetConstructionSelectionForm.getUniversityFiscalYear().toString()); String lookupUrl = BudgetUrlUtil.buildBudgetUrl(mapping, budgetConstructionSelectionForm, BCConstants.ORG_SEL_TREE_ACTION, parameters); return new ActionForward(lookupUrl, true); } /** * Passes control to the Organization Selection to run the organization reports subsystem * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward performReportDump(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; ActionForward forward = performOrgSelectionTree(OrgSelOpMode.REPORTS, mapping, form, request, response); return forward; } /** * Passes control to the request import subsystem * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward performRequestImport(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; this.flagBCInProgress(); String lookupUrl = BudgetUrlUtil.buildBudgetUrl(mapping, budgetConstructionSelectionForm, BCConstants.REQUEST_IMPORT_ACTION, null); return new ActionForward(lookupUrl, true); } /** * Passes control to the Pay Rate import/export subsystem * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward performPayrateImportExport(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; this.flagBCInProgress(); String lookupUrl = BudgetUrlUtil.buildBudgetUrl(mapping, budgetConstructionSelectionForm, BCConstants.PAYRATE_IMPORT_EXPORT_ACTION, null); return new ActionForward(lookupUrl, true); } /** * Builds forward URL to lock monitor page, following expansion screen pattern. Also checks if the user has permission for the * unlock action and sets the show action column property accordingly. * * @see org.kuali.rice.kns.web.struts.action.KualiAction#execute(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ public ActionForward performLockMonitor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; this.flagBCInProgress(); Map<String, String> urlParms = new HashMap<String, String>(); // forward to temp list action for displaying results String url = BudgetUrlUtil.buildTempListLookupUrl(mapping, budgetConstructionSelectionForm, BCConstants.TempListLookupMode.LOCK_MONITOR, BudgetConstructionLockSummary.class.getName(), urlParms); return new ActionForward(url, true); } /** * Passes control to the Organization Selection to run the organization pullup subsystem * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward performOrgPullup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; ActionForward forward = performOrgSelectionTree(OrgSelOpMode.PULLUP, mapping, form, request, response); return forward; } /** * Passes control to the Organization Selection to run the organization pushdown subsystem * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward performOrgPushdown(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; ActionForward forward = performOrgSelectionTree(OrgSelOpMode.PUSHDOWN, mapping, form, request, response); return forward; } /** * Calls service to build the account list for which the user is a manager and delegate. Then forwards to temp list action to * display the results. * * @see org.kuali.rice.kns.web.struts.action.KualiAction#execute(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ public ActionForward performMyAccounts(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; // call service to build account list and give message if empty int rowCount = SpringContext.getBean(OrganizationBCDocumentSearchService.class).buildAccountManagerDelegateList(GlobalVariables.getUserSession().getPerson().getPrincipalId(), budgetConstructionSelectionForm.getUniversityFiscalYear()); if (rowCount == 0) { KNSGlobalVariables.getMessageList().add(BCKeyConstants.ERROR_NO_RECORDS_MY_ACCOUNTS); return mapping.findForward(KFSConstants.MAPPING_BASIC); } this.flagBCInProgress(); // forward to temp list action for displaying results String url = BudgetUrlUtil.buildTempListLookupUrl(mapping, budgetConstructionSelectionForm, BCConstants.TempListLookupMode.ACCOUNT_SELECT_MANAGER_DELEGATE, BudgetConstructionAccountSelect.class.getName(), null); return new ActionForward(url, true); } /** * Passes control to the Organization Selection to run the organization budgeted account list subsystem * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward performMyOrganization(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { BudgetConstructionSelectionForm budgetConstructionSelectionForm = (BudgetConstructionSelectionForm) form; ActionForward forward = performOrgSelectionTree(OrgSelOpMode.ACCOUNT, mapping, form, request, response); return forward; } public void flagBCInProgress() { // Overwrite or add the BC in progress flag // This is used as a semaphore to control cleanup of session BC Temp objects GlobalVariables.getUserSession().addObject(BCConstants.BC_IN_PROGRESS_SESSIONFLAG, Boolean.TRUE); } }