001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.kfs.module.bc.document.web.struts;
017
018 import java.math.BigDecimal;
019 import java.util.Arrays;
020 import java.util.Collections;
021 import java.util.HashMap;
022 import java.util.List;
023 import java.util.Map;
024 import java.util.Properties;
025
026 import javax.servlet.http.HttpServletRequest;
027 import javax.servlet.http.HttpServletResponse;
028
029 import org.apache.commons.lang.StringUtils;
030 import org.apache.struts.action.ActionForm;
031 import org.apache.struts.action.ActionForward;
032 import org.apache.struts.action.ActionMapping;
033 import org.kuali.kfs.module.bc.BCConstants;
034 import org.kuali.kfs.module.bc.BCKeyConstants;
035 import org.kuali.kfs.module.bc.BCPropertyConstants;
036 import org.kuali.kfs.module.bc.BCConstants.LockStatus;
037 import org.kuali.kfs.module.bc.BCConstants.MonthSpreadDeleteType;
038 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAccountOrganizationHierarchy;
039 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAuthorizationStatus;
040 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionHeader;
041 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionLockStatus;
042 import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionGeneralLedger;
043 import org.kuali.kfs.module.bc.document.BudgetConstructionDocument;
044 import org.kuali.kfs.module.bc.document.service.BudgetConstructionMonthlyBudgetsCreateDeleteService;
045 import org.kuali.kfs.module.bc.document.service.BudgetDocumentService;
046 import org.kuali.kfs.module.bc.document.service.LockService;
047 import org.kuali.kfs.module.bc.document.validation.event.AddPendingBudgetGeneralLedgerLineEvent;
048 import org.kuali.kfs.module.bc.document.validation.event.DeletePendingBudgetGeneralLedgerLineEvent;
049 import org.kuali.kfs.module.bc.exception.BudgetConstructionDocumentAuthorizationException;
050 import org.kuali.kfs.module.bc.identity.BudgetConstructionNoAccessMessageSetting;
051 import org.kuali.kfs.sys.KFSConstants;
052 import org.kuali.kfs.sys.KFSKeyConstants;
053 import org.kuali.kfs.sys.KFSPropertyConstants;
054 import org.kuali.kfs.sys.context.SpringContext;
055 import org.kuali.kfs.sys.identity.KfsKimAttributes;
056 import org.kuali.rice.kew.exception.WorkflowException;
057 import org.kuali.rice.kim.bo.Person;
058 import org.kuali.rice.kim.bo.role.dto.KimRoleInfo;
059 import org.kuali.rice.kim.bo.types.dto.AttributeSet;
060 import org.kuali.rice.kim.bo.types.dto.KimTypeInfo;
061 import org.kuali.rice.kim.service.KimTypeInfoService;
062 import org.kuali.rice.kim.service.RoleManagementService;
063 import org.kuali.rice.kim.service.support.KimRoleTypeService;
064 import org.kuali.rice.kim.util.KimConstants;
065 import org.kuali.rice.kns.UserSession;
066 import org.kuali.rice.kns.document.Document;
067 import org.kuali.rice.kns.document.authorization.TransactionalDocumentAuthorizer;
068 import org.kuali.rice.kns.exception.AuthorizationException;
069 import org.kuali.rice.kns.exception.UnknownDocumentIdException;
070 import org.kuali.rice.kns.question.ConfirmationQuestion;
071 import org.kuali.rice.kns.service.BusinessObjectService;
072 import org.kuali.rice.kns.service.DocumentHelperService;
073 import org.kuali.rice.kns.service.KualiConfigurationService;
074 import org.kuali.rice.kns.service.KualiRuleService;
075 import org.kuali.rice.kns.service.PersistenceService;
076 import org.kuali.rice.kns.service.SessionDocumentService;
077 import org.kuali.rice.kns.util.GlobalVariables;
078 import org.kuali.rice.kns.util.KNSConstants;
079 import org.kuali.rice.kns.util.KualiDecimal;
080 import org.kuali.rice.kns.util.KualiInteger;
081 import org.kuali.rice.kns.util.UrlFactory;
082 import org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase;
083 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
084 import org.kuali.rice.kns.web.struts.form.KualiForm;
085 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
086
087 /**
088 * need to figure out if this should extend KualiAction, KualiDocumentActionBase or KualiTransactionDocumentActionBase
089 */
090 public class BudgetConstructionAction extends KualiTransactionalDocumentActionBase {
091 protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BudgetConstructionAction.class);
092
093 /**
094 * Entry point to all actions Checks for cases where methodToCall is loadDocument, performAccountPullup or
095 * performAccountPushdown and creates global messages to describe the new editingMode state. Also handles document locking if
096 * the editingMode is BudgetConstructionEditMode.FULL_ENTRY. (Re)Populates the pullup and pushdown selection controls based on
097 * the current level of the document and the user's approval access for the levels above and below the current level.
098 *
099 * @see org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase#execute(org.apache.struts.action.ActionMapping,
100 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
101 */
102 @Override
103 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
104 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
105
106 Boolean isBCHeartBeating = (Boolean) GlobalVariables.getUserSession().retrieveObject(BCConstants.BC_HEARTBEAT_SESSIONFLAG);
107 if (isBCHeartBeating == null) {
108 if (budgetConstructionForm.isPickListMode()) {
109 budgetConstructionForm.setPickListClose(true);
110 GlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_PREVIOUS_SESSION_TIMEOUT);
111 return mapping.findForward(KFSConstants.MAPPING_BASIC);
112
113 }
114
115 Properties parameters = new Properties();
116 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, BCConstants.LOAD_EXPANSION_SCREEN_METHOD_SESSION_TIMEOUT);
117
118 String lookupUrl = UrlFactory.parameterizeUrl("/" + BCConstants.BC_SELECTION_ACTION, parameters);
119
120 return new ActionForward(lookupUrl, true);
121 }
122
123 // this is only used to indicate to the rules the user has clicked save or close save-yes
124 // which forces tighter checks (nonZeroRequest amount) when access is cleanup mode
125 if (budgetConstructionForm.getBudgetConstructionDocument().isCleanupModeActionForceCheck()) {
126 budgetConstructionForm.getBudgetConstructionDocument().setCleanupModeActionForceCheck(Boolean.FALSE);
127 }
128
129 // TODO: the catch code comes from KualiDocumentActionBase.loadDocument()
130 // this allows the top portion of the document to be populated and the close button to function
131 // and also displays all the possible error messages for now
132 // we need to update this once KIM is adjusted to handle BC no access cases
133 // and maybe just show the authorization exception message
134 ActionForward forward = null;
135 try {
136 forward = super.execute(mapping, form, request, response);
137 }
138 catch (AuthorizationException e) {
139 forward = mapping.findForward(KFSConstants.MAPPING_BASIC);
140 String docId = budgetConstructionForm.getDocId();
141 Document doc = null;
142 doc = getDocumentService().getByDocumentHeaderId(docId);
143 if (doc == null) {
144 throw new UnknownDocumentIdException("Document no longer exists. It may have been cancelled before being saved.");
145 }
146 KualiWorkflowDocument workflowDocument = doc.getDocumentHeader().getWorkflowDocument();
147 // if (!getDocumentHelperService().getDocumentAuthorizer(doc).canOpen(doc,
148 // GlobalVariables.getUserSession().getPerson())) {
149 // throw buildAuthorizationException("open", doc);
150 // }
151 // re-retrieve the document using the current user's session - remove the system user from the WorkflowDcument object
152 if (workflowDocument != doc.getDocumentHeader().getWorkflowDocument()) {
153 LOG.warn("Workflow document changed via canOpen check");
154 doc.getDocumentHeader().setWorkflowDocument(workflowDocument);
155 }
156 budgetConstructionForm.setDocument(doc);
157 KualiWorkflowDocument workflowDoc = doc.getDocumentHeader().getWorkflowDocument();
158 budgetConstructionForm.setDocTypeName(workflowDoc.getDocumentType());
159 // KualiDocumentFormBase.populate() needs this updated in the session
160 GlobalVariables.getUserSession().setWorkflowDocument(workflowDoc);
161
162 budgetConstructionForm.setSecurityNoAccess(true);
163 setBudgetDocumentNoAccessMessage(budgetConstructionForm);
164 budgetConstructionForm.getDocumentActions().put(KNSConstants.KUALI_ACTION_CAN_CLOSE, Boolean.TRUE);
165
166 }
167
168 // apprise user of granted access
169 if (budgetConstructionForm.getMethodToCall().equals(BCConstants.BC_DOCUMENT_METHOD) || budgetConstructionForm.getMethodToCall().equals(BCConstants.BC_DOCUMENT_PULLUP_METHOD) || budgetConstructionForm.getMethodToCall().equals(BCConstants.BC_DOCUMENT_PUSHDOWN_METHOD)) {
170
171 // init the account org hier state on initial load only - this is stored as hiddens
172 if (budgetConstructionForm.getMethodToCall().equals(BCConstants.BC_DOCUMENT_METHOD)) {
173 budgetConstructionForm.setAccountOrgHierLevels(SpringContext.getBean(BudgetDocumentService.class).getPushPullLevelList(budgetConstructionForm.getBudgetConstructionDocument(), GlobalVariables.getUserSession().getPerson()));
174 }
175
176 if (budgetConstructionForm.isSystemViewOnly()) {
177 GlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_SYSTEM_VIEW_ONLY);
178 }
179
180 if (!budgetConstructionForm.isEditAllowed()) {
181 GlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_VIEW_ONLY);
182 }
183
184 if (budgetConstructionForm.isEditAllowed()) {
185 if (budgetConstructionForm.isSystemViewOnly()) {
186 GlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_VIEW_ONLY);
187 }
188 else {
189
190 // tell the user if the document is in not budgetable mode
191 budgetConstructionForm.getBudgetConstructionDocument().setBudgetableDocument(SpringContext.getBean(BudgetDocumentService.class).isBudgetableDocumentNoWagesCheck(budgetConstructionForm.getBudgetConstructionDocument()));
192 // budgetConstructionForm.setBudgetableDocument(SpringContext.getBean(BudgetDocumentService.class).isBudgetableDocumentNoWagesCheck(budgetConstructionForm.getBudgetConstructionDocument()));
193 if (!budgetConstructionForm.isBudgetableDocument()) {
194 GlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_DOCUMENT_NOT_BUDGETABLE);
195 }
196
197 GlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_EDIT_ACCESS);
198 }
199
200 if (!budgetConstructionForm.isSystemViewOnly()) {
201 LockService lockService = SpringContext.getBean(LockService.class);
202 HashMap primaryKey = new HashMap();
203 primaryKey.put(KFSPropertyConstants.DOCUMENT_NUMBER, budgetConstructionForm.getDocument().getDocumentNumber());
204
205 BudgetConstructionHeader budgetConstructionHeader = (BudgetConstructionHeader) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(BudgetConstructionHeader.class, primaryKey);
206 if (budgetConstructionHeader != null) {
207 // BudgetConstructionLockStatus bcLockStatus = lockService.lockAccount(budgetConstructionHeader,
208 // GlobalVariables.getUserSession().getPerson().getPrincipalId());
209 BudgetConstructionLockStatus bcLockStatus = lockService.lockAccountAndCommit(budgetConstructionHeader, GlobalVariables.getUserSession().getPerson().getPrincipalId());
210
211 if (bcLockStatus.getLockStatus() == LockStatus.SUCCESS) {
212
213 // update the document version number
214 // so the saved lock of header doesn't produce an optimistic lock error
215 // and has the info we just put in the header so doc save doesn't wipe out the lock
216 budgetConstructionForm.getBudgetConstructionDocument().setVersionNumber(bcLockStatus.getBudgetConstructionHeader().getVersionNumber());
217 budgetConstructionForm.getBudgetConstructionDocument().setBudgetLockUserIdentifier(bcLockStatus.getBudgetConstructionHeader().getBudgetLockUserIdentifier());
218 }
219 else {
220 if (bcLockStatus.getLockStatus() == LockStatus.BY_OTHER) {
221 String lockerName = SpringContext.getBean(org.kuali.rice.kim.service.PersonService.class).getPerson(bcLockStatus.getAccountLockOwner()).getName();
222 this.cleanupForLockError(budgetConstructionForm);
223 GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, BCKeyConstants.ERROR_BUDGET_DOCUMENT_LOCKED, lockerName);
224 return forward;
225 }
226 else {
227 if (bcLockStatus.getLockStatus() == LockStatus.FLOCK_FOUND) {
228 this.cleanupForLockError(budgetConstructionForm);
229 GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, BCKeyConstants.ERROR_BUDGET_FUNDING_LOCKED);
230 return forward;
231 }
232 else {
233 this.cleanupForLockError(budgetConstructionForm);
234 GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, BCKeyConstants.ERROR_BUDGET_DOCUMENT_OTHER);
235 return forward;
236 }
237 }
238 }
239 }
240 else {
241 // unlikely
242 throw new BudgetConstructionDocumentAuthorizationException(GlobalVariables.getUserSession().getPerson().getName(), "open", budgetConstructionForm.getDocument().getDocumentHeader().getDocumentNumber(), "(can't find document for locking)", budgetConstructionForm.isPickListMode());
243 }
244
245 // if editing, check if 2plg adjustment needed and calc benefits
246 // since checkTwoPlugAdjusmtent will only be set in docHandler during initial load
247 // if document is initially view only we want the 2plg adjustment to happen if the user does a pullup to edit
248 if (budgetConstructionForm.isCheckTwoPlugAdjustment() && budgetConstructionForm.getBudgetConstructionDocument().isContainsTwoPlug() && !budgetConstructionForm.getBudgetConstructionDocument().isSalarySettingOnly()) {
249 // do 2plg related benefits calc and adjust 2plg for any diff - reset checkTwoPlugAdjusment
250 budgetConstructionForm.setCheckTwoPlugAdjustment(false);
251 this.adjustForSalarySettingChanges(budgetConstructionForm);
252 }
253 }
254
255 // getting here implies a lock or system view mode, try to build a pullup list
256 // pushdown is only allowed if user has edit access (regardless of system view only mode)
257 if (budgetConstructionForm.getBudgetConstructionDocument().getOrganizationLevelCode() != 0) {
258 if (!budgetConstructionForm.getAccountOrgHierLevels().isEmpty()) {
259 budgetConstructionForm.populatePushPullLevelKeyLabels(budgetConstructionForm.getBudgetConstructionDocument(), budgetConstructionForm.getAccountOrgHierLevels(), false);
260 }
261 }
262 } // FULL_ENTRY
263
264 // pullup is allowed regardless of editMode
265 if (!budgetConstructionForm.getAccountOrgHierLevels().isEmpty()) {
266 budgetConstructionForm.populatePushPullLevelKeyLabels(budgetConstructionForm.getBudgetConstructionDocument(), budgetConstructionForm.getAccountOrgHierLevels(), true);
267 }
268 }
269
270 // cleanup the session edit mode store so we don't side effect organization salary setting
271 if (budgetConstructionForm.isClosingDocument()) {
272 GlobalVariables.getUserSession().removeObject(BCConstants.BC_DOC_AUTHORIZATION_STATUS_SESSIONKEY);
273 }
274
275 return forward;
276 }
277
278 /**
279 * Finds the role type service associated with the document viewer role, than calls method on role type service to set the no
280 * access message
281 *
282 * @param budgetConstructionForm form containing budget document
283 */
284 protected void setBudgetDocumentNoAccessMessage(BudgetConstructionForm budgetConstructionForm) {
285 KimRoleInfo roleInfo = SpringContext.getBean(RoleManagementService.class).getRoleByName(BCConstants.BUDGET_CONSTRUCTION_NAMESPACE, BCConstants.KimConstants.DOCUMENT_VIEWER_ROLE_NAME);
286 KimTypeInfo typeInfo = SpringContext.getBean(KimTypeInfoService.class).getKimType(roleInfo.getKimTypeId());
287
288 if (StringUtils.isNotBlank(typeInfo.getKimTypeServiceName())) {
289 KimRoleTypeService roleTypeService = (KimRoleTypeService) SpringContext.getService(typeInfo.getKimTypeServiceName());
290 if (roleTypeService instanceof BudgetConstructionNoAccessMessageSetting) {
291 ((BudgetConstructionNoAccessMessageSetting) roleTypeService).setNoAccessMessage(budgetConstructionForm.getBudgetConstructionDocument(), GlobalVariables.getUserSession().getPerson(), GlobalVariables.getMessageMap());
292 }
293 }
294 }
295
296 /**
297 * gwp - no call to super, need to work through command we will use randall - This method might be unnecessary, but putting it
298 * here allows URL to be consistent with Document URLs gwp - i think we still want this method, just need to figure out if we
299 * use command initiate or displayDocSearchView or something else. i expect we will get the account/subaccount or docnumber from
300 * the previous form and assume the document will already exist regardless of creation by genesis or
301 *
302 * @param mapping
303 * @param form
304 * @param request
305 * @param response
306 * @return
307 * @throws IOException
308 * @throws ServletException
309 */
310 @Override
311 public ActionForward docHandler(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
312 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
313
314 loadDocument(budgetConstructionForm);
315
316 // set flag to have execute perform 2plug adjusment if the doc goes into edit mode later
317 budgetConstructionForm.setCheckTwoPlugAdjustment(true);
318
319 this.initAuthorization(budgetConstructionForm);
320
321 return mapping.findForward(KFSConstants.MAPPING_BASIC);
322 }
323
324 /**
325 * Initially load the document from the DB Coded this to look like KualiDocumentActionBase.loadDocument()
326 *
327 * @param budgetConstructionForm
328 * @throws WorkflowException
329 */
330 @Override
331 protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
332 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) kualiDocumentFormBase;
333
334 BudgetConstructionHeader budgetConstructionHeader;
335 if (budgetConstructionForm.getDocId() != null) {
336 Map<String, Object> primaryKey = new HashMap<String, Object>();
337 primaryKey.put(KFSPropertyConstants.DOCUMENT_NUMBER, budgetConstructionForm.getDocId());
338
339 budgetConstructionHeader = (BudgetConstructionHeader) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(BudgetConstructionHeader.class, primaryKey);
340
341 }
342 else {
343 // use the passed url autoloaded parms to get the record from DB
344 // BudgetConstructionDaoOjb bcHeaderDao;
345 String chartOfAccountsCode = budgetConstructionForm.getChartOfAccountsCode();
346 String accountNumber = budgetConstructionForm.getAccountNumber();
347 String subAccountNumber = budgetConstructionForm.getSubAccountNumber();
348 Integer universityFiscalYear = budgetConstructionForm.getUniversityFiscalYear();
349
350 budgetConstructionHeader = (BudgetConstructionHeader) SpringContext.getBean(BudgetDocumentService.class).getByCandidateKey(chartOfAccountsCode, accountNumber, subAccountNumber, universityFiscalYear);
351 }
352
353 kualiDocumentFormBase.setDocId(budgetConstructionHeader.getDocumentNumber());
354 super.loadDocument(kualiDocumentFormBase);
355
356 BudgetConstructionDocument budgetConstructionDocument = (BudgetConstructionDocument) kualiDocumentFormBase.getDocument();
357
358 // init the benefits calc flags
359 budgetConstructionDocument.setBenefitsCalcNeeded(false);
360 budgetConstructionDocument.setMonthlyBenefitsCalcNeeded(false);
361
362 // init the new line objects
363 budgetConstructionForm.initNewLine(budgetConstructionForm.getNewRevenueLine(), true);
364 budgetConstructionForm.initNewLine(budgetConstructionForm.getNewExpenditureLine(), false);
365
366 // need this here to do totaling on initial load
367 budgetConstructionForm.populatePBGLLines();
368 budgetConstructionForm.initializePersistedRequestAmounts();
369 }
370
371 /**
372 * Cleans up state info to handle no access lock errors
373 *
374 * @param budgetConstructionForm
375 */
376 protected void cleanupForLockError(BudgetConstructionForm budgetConstructionForm) {
377 budgetConstructionForm.setSecurityNoAccess(true);
378 budgetConstructionForm.getDocumentActions().remove(KNSConstants.KUALI_ACTION_CAN_EDIT);
379 budgetConstructionForm.getDocumentActions().remove(KNSConstants.KUALI_ACTION_CAN_SAVE);
380 GlobalVariables.getMessageList().remove(BCKeyConstants.MESSAGE_BUDGET_EDIT_ACCESS);
381 }
382
383 /**
384 * Override to set authorization Maps from session
385 *
386 * @see org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase#populateAuthorizationFields(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
387 */
388 @Override
389 protected void populateAuthorizationFields(KualiDocumentFormBase formBase) {
390 BudgetConstructionAuthorizationStatus authorizationStatus = (BudgetConstructionAuthorizationStatus) GlobalVariables.getUserSession().retrieveObject(BCConstants.BC_DOC_AUTHORIZATION_STATUS_SESSIONKEY);
391
392 if (authorizationStatus == null) {
393 // execute handles any session timeout before this is called
394 return;
395 }
396
397 formBase.setDocumentActions(authorizationStatus.getDocumentActions());
398 formBase.setEditingMode(authorizationStatus.getEditingMode());
399 }
400
401 /**
402 * Calls authorizer to determine if the user has edit permission and checks if budget construction is active is fiscal year
403 * function table. Then updates the <code>BudgetConstructionEditStatus</code> in session. Finally updates authorization in the
404 * form
405 *
406 * @param budgetConstructionForm current bc action form that will be updated
407 */
408 protected void initAuthorization(BudgetConstructionForm budgetConstructionForm) {
409 // GlobalVariables.setRequestCache(ROLE_QUALIFICATION_CACHE_NAME, budgetConstructionForm)
410 super.populateAuthorizationFields(budgetConstructionForm);
411
412 BudgetConstructionAuthorizationStatus editStatus = new BudgetConstructionAuthorizationStatus();
413 editStatus.setDocumentActions(budgetConstructionForm.getDocumentActions());
414 editStatus.setEditingMode(budgetConstructionForm.getEditingMode());
415
416 GlobalVariables.getUserSession().addObject(BCConstants.BC_DOC_AUTHORIZATION_STATUS_SESSIONKEY, editStatus);
417 }
418
419 /**
420 * Applies adjustments due to 2plg existence at initial load or detected salary setting changes upon returning from the Quick
421 * Salary Setting screen. The adjustments consist of calculating benefits and adding any expenditure total before/after
422 * difference back into a 2plg row, creating or updating as needed. Then, validation is performed. Sucessful validation removes
423 * the 2plg row if the final, post benefits calc, adjusted amount is zero. This method assumes the set of expenditure rows in
424 * memory currently matches the DB.
425 *
426 * @param bcForm
427 */
428 protected void adjustForSalarySettingChanges(BudgetConstructionForm bcForm) {
429
430 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
431 BudgetConstructionDocument bcDoc = (BudgetConstructionDocument) bcForm.getDocument();
432 KualiInteger oldRequestAmount = bcDoc.getExpenditureAccountLineAnnualBalanceAmountTotal();
433
434 // calc benefits also handles setting persisted amounts and populating reloaded benefit rows
435 budgetDocumentService.calculateBenefits(bcDoc);
436 // bcForm.initializePersistedRequestAmounts();
437
438 // repop and refresh refs - esp monthly so jsp can properly display state
439 // bcForm.populatePBGLLines();
440
441 // need 2plg adjustment and save, even if it is zero
442 KualiInteger newRquestAmount = bcForm.getBudgetConstructionDocument().getExpenditureAccountLineAnnualBalanceAmountTotal();
443 PendingBudgetConstructionGeneralLedger twoPlugRow = budgetDocumentService.updatePendingBudgetGeneralLedgerPlug(bcDoc, newRquestAmount.subtract(oldRequestAmount));
444 }
445
446 /**
447 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#close(org.apache.struts.action.ActionMapping,
448 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
449 */
450 @Override
451 public ActionForward close(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
452
453 // return super.close(mapping, form, request, response);
454 BudgetConstructionForm docForm = (BudgetConstructionForm) form;
455
456 // only want to prompt them to save if they already can save
457 if (docForm.getDocumentActions().keySet().contains(KNSConstants.KUALI_ACTION_CAN_SAVE)) {
458 Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
459 KualiConfigurationService kualiConfiguration = SpringContext.getBean(KualiConfigurationService.class);
460
461 // logic for close question
462 if (question == null) {
463 // ask question if not already asked
464 return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.DOCUMENT_SAVE_BEFORE_CLOSE_QUESTION, kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_SAVE_BEFORE_CLOSE), KFSConstants.CONFIRMATION_QUESTION, KFSConstants.MAPPING_CLOSE, "");
465 }
466 else {
467 Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
468 if ((KFSConstants.DOCUMENT_SAVE_BEFORE_CLOSE_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) {
469 // if yes button clicked - save the doc
470 BudgetConstructionDocument bcDoc = (BudgetConstructionDocument) docForm.getDocument();
471
472 // force tighter checks when saving in cleanup mode
473 if (!bcDoc.isBudgetableDocument()) {
474 bcDoc.setCleanupModeActionForceCheck(Boolean.TRUE);
475 }
476
477 // SpringContext.getBean(DocumentService.class).updateDocument(docForm.getDocument());
478 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
479 budgetDocumentService.saveDocument(bcDoc);
480 docForm.initializePersistedRequestAmounts();
481 if (bcDoc.isBenefitsCalcNeeded() || bcDoc.isMonthlyBenefitsCalcNeeded()) {
482 budgetDocumentService.calculateBenefitsIfNeeded(bcDoc);
483
484 GlobalVariables.getMessageList().add(KFSKeyConstants.MESSAGE_SAVED);
485 return mapping.findForward(KFSConstants.MAPPING_BASIC);
486 }
487 else {
488 // else drop to close logic below
489 }
490
491 }
492 // else drop to close logic below
493 }
494 }
495
496 // do the unlock if they have full access and not system view mode
497 if (docForm.isEditAllowed() && !docForm.isSystemViewOnly()) {
498 LockService lockService = SpringContext.getBean(LockService.class);
499 HashMap primaryKey = new HashMap();
500 primaryKey.put(KFSPropertyConstants.DOCUMENT_NUMBER, docForm.getDocument().getDocumentNumber());
501
502 BudgetConstructionHeader budgetConstructionHeader = (BudgetConstructionHeader) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(BudgetConstructionHeader.class, primaryKey);
503 if (budgetConstructionHeader != null) {
504 LockStatus lockStatus = lockService.unlockAccount(budgetConstructionHeader);
505 }
506 else {
507 // unlikely, but benign problem here
508 }
509 }
510
511 // flag to cleanup the session edit mode store so we don't side effect organization salary setting
512 // used in the bottom of execute()
513 docForm.setClosingDocument(Boolean.TRUE);
514
515 if (docForm.isPickListMode()) {
516 // redisplay with a message
517 GlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_BUDGET_SUCCESSFUL_CLOSE);
518 docForm.setPickListClose(true);
519
520 // this is a hack to do our own session document cleanup since refreshCaller=QuestionRefresh
521 // prevents proper cleanup in KualiRequestProcessor.processActionPerform()
522 UserSession userSession = (UserSession) request.getSession().getAttribute(KNSConstants.USER_SESSION_KEY);
523 String docFormKey = docForm.getFormKey();
524 SpringContext.getBean(SessionDocumentService.class).purgeDocumentForm(docForm.getDocument().getDocumentNumber(), docFormKey, userSession, request.getRemoteAddr());
525
526 return mapping.findForward(KFSConstants.MAPPING_BASIC);
527
528 }
529 else {
530 if (docForm.getReturnFormKey() == null) {
531
532 // assume called from doc search or lost the session - go back to main
533 return returnToSender(request, mapping, docForm);
534 }
535 else {
536 // setup the return parms for the document and anchor and go back to doc select
537 Properties parameters = new Properties();
538 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, BCConstants.BC_SELECTION_REFRESH_METHOD);
539 parameters.put(KFSConstants.DOC_FORM_KEY, docForm.getReturnFormKey());
540 parameters.put(KFSConstants.ANCHOR, docForm.getReturnAnchor());
541 parameters.put(KFSConstants.REFRESH_CALLER, BCConstants.BC_DOCUMENT_REFRESH_CALLER);
542
543 String lookupUrl = UrlFactory.parameterizeUrl("/" + BCConstants.BC_SELECTION_ACTION, parameters);
544
545 // this is a hack to do our own session document cleanup since refreshCaller=QuestionRefresh
546 // prevents proper cleanup in KualiRequestProcessor.processActionPerform()
547 UserSession userSession = (UserSession) request.getSession().getAttribute(KNSConstants.USER_SESSION_KEY);
548 String docFormKey = docForm.getFormKey();
549 SpringContext.getBean(SessionDocumentService.class).purgeDocumentForm(docForm.getDocument().getDocumentNumber(), docFormKey, userSession, request.getRemoteAddr());
550
551 return new ActionForward(lookupUrl, true);
552 }
553 }
554 }
555
556 /**
557 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#save(org.apache.struts.action.ActionMapping,
558 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
559 */
560 @Override
561 public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
562
563 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
564 BudgetConstructionDocument bcDocument = (BudgetConstructionDocument) budgetConstructionForm.getDocument();
565 // DocumentService documentService = SpringContext.getBean(DocumentService.class);
566 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
567
568 // force tighter checks when saving in cleanup mode
569 if (!bcDocument.isBudgetableDocument()) {
570 bcDocument.setCleanupModeActionForceCheck(Boolean.TRUE);
571 }
572
573 budgetDocumentService.saveDocument(bcDocument);
574 budgetConstructionForm.initializePersistedRequestAmounts();
575 budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
576 GlobalVariables.getMessageList().add(KFSKeyConstants.MESSAGE_SAVED);
577
578 budgetConstructionForm.setAnnotation("");
579
580 // redisplay the document along with document saved message
581 return mapping.findForward(KFSConstants.MAPPING_BASIC);
582 }
583
584 /**
585 * Calls the single line benefits impact screen by setting up the required parameters and feeding them to the temporary list
586 * lookup action for the expenditure line selected. This is called from the ShowBenefits button on the BC document screen when
587 * an expenditure line is associated with benefits and benefits calculation is enabled.
588 *
589 * @param mapping
590 * @param form
591 * @param request
592 * @param response
593 * @return
594 * @throws Exception
595 */
596 public ActionForward performShowBenefits(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
597
598 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
599 BudgetConstructionDocument tDoc = tForm.getBudgetConstructionDocument();
600 int selectIndex = this.getSelectedLine(request);
601 PendingBudgetConstructionGeneralLedger expLine = tDoc.getPendingBudgetConstructionGeneralLedgerExpenditureLines().get(selectIndex);
602
603 // when we return from the lookup, our next request's method to call is going to be refresh
604 tForm.registerEditableProperty(KNSConstants.DISPATCH_REQUEST_PARAMETER);
605
606 Properties parameters = new Properties();
607 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
608
609 String basePath = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.APPLICATION_URL_KEY);
610 parameters.put(KFSConstants.BACK_LOCATION, basePath + mapping.getPath() + ".do");
611
612 if (StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
613 parameters.put(BCConstants.RETURN_ANCHOR, ((KualiForm) form).getAnchor());
614 }
615
616 // this hack sets the return anchor we want to return too after the inquiry
617 // do this here so it gets into the session stored form version
618 // refresh checks for this after and resets the anchor
619 if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
620 tForm.setBalanceInquiryReturnAnchor(((KualiForm) form).getAnchor());
621 }
622
623 parameters.put(KNSConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObject(form, BCConstants.FORMKEY_PREFIX));
624 parameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, BCConstants.REQUEST_BENEFITS_BO);
625 parameters.put(KFSConstants.HIDE_LOOKUP_RETURN_LINK, "true");
626 parameters.put(KFSConstants.SUPPRESS_ACTIONS, "true");
627 parameters.put(BCConstants.SHOW_INITIAL_RESULTS, "true");
628 parameters.put(BCConstants.TempListLookupMode.TEMP_LIST_LOOKUP_MODE, Integer.toString(BCConstants.TempListLookupMode.SHOW_BENEFITS));
629
630 parameters.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, expLine.getUniversityFiscalYear().toString());
631 parameters.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, expLine.getChartOfAccountsCode());
632 parameters.put(KFSConstants.FINANCIAL_OBJECT_CODE_PROPERTY_NAME, expLine.getFinancialObjectCode());
633 parameters.put(KFSPropertyConstants.ACCOUNT_LINE_ANNUAL_BALANCE_AMOUNT, expLine.getAccountLineAnnualBalanceAmount().toString());
634 parameters.put(KNSConstants.LOOKUP_READ_ONLY_FIELDS, KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR + "," + KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE + "," + KFSConstants.FINANCIAL_OBJECT_CODE_PROPERTY_NAME + "," + KFSPropertyConstants.ACCOUNT_LINE_ANNUAL_BALANCE_AMOUNT);
635
636 String url = UrlFactory.parameterizeUrl(basePath + "/" + BCConstants.ORG_TEMP_LIST_LOOKUP, parameters);
637 this.setupDocumentExit();
638 return new ActionForward(url, true);
639 }
640
641 public ActionForward performBalanceInquiryForRevenueLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
642 return performBalanceInquiry(true, mapping, form, request, response);
643 }
644
645 public ActionForward performBalanceInquiryForExpenditureLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
646 return performBalanceInquiry(false, mapping, form, request, response);
647 }
648
649 /**
650 * This method is similar to org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase.performBalanceInquiry()
651 *
652 * @param isRevenue
653 * @param mapping
654 * @param form
655 * @param request
656 * @param response
657 * @return
658 * @throws Exception
659 */
660 public ActionForward performBalanceInquiry(boolean isRevenue, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
661 final String docNumber;
662
663 // get the selected line, setup parms and redirect to balance inquiry
664 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
665 BudgetConstructionDocument bcDocument = (BudgetConstructionDocument) budgetConstructionForm.getDocument();
666
667 // when we return from the lookup, our next request's method to call is going to be refresh
668 budgetConstructionForm.registerEditableProperty(KNSConstants.DISPATCH_REQUEST_PARAMETER);
669
670 PendingBudgetConstructionGeneralLedger pbglLine;
671 if (isRevenue) {
672 pbglLine = bcDocument.getPendingBudgetConstructionGeneralLedgerRevenueLines().get(this.getSelectedLine(request));
673 }
674 else {
675 pbglLine = bcDocument.getPendingBudgetConstructionGeneralLedgerExpenditureLines().get(this.getSelectedLine(request));
676 }
677
678 // build out base path for return location, use config service
679 String basePath = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.APPLICATION_URL_KEY);
680
681 // this hack sets the return anchor we want to return too after the inquiry
682 // do this here so it gets into the session stored form version
683 // refresh checks for this after and resets the anchor
684 if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
685 budgetConstructionForm.setBalanceInquiryReturnAnchor(((KualiForm) form).getAnchor());
686 }
687
688 // build out the actual form key that will be used to retrieve the form on refresh
689 String callerDocFormKey = GlobalVariables.getUserSession().addObject(form, BCConstants.FORMKEY_PREFIX);
690
691 // now add required parameters
692 Properties parameters = new Properties();
693 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
694 // need this next param b/c the lookup's return back will overwrite
695 // the original doc form key
696 parameters.put(KFSConstants.BALANCE_INQUIRY_REPORT_MENU_CALLER_DOC_FORM_KEY, callerDocFormKey);
697 parameters.put(KFSConstants.DOC_FORM_KEY, callerDocFormKey);
698 parameters.put(KFSConstants.BACK_LOCATION, basePath + mapping.getPath() + ".do");
699
700 // anchor, if it exists
701 // this doesn't seem to work with the balance inquiry infrastructure, so added hack above
702 if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
703 parameters.put(BCConstants.RETURN_ANCHOR, ((KualiForm) form).getAnchor());
704 }
705
706 if (StringUtils.isNotBlank(pbglLine.getChartOfAccountsCode())) {
707 parameters.put("chartOfAccountsCode", pbglLine.getChartOfAccountsCode());
708 }
709 if (StringUtils.isNotBlank(pbglLine.getAccountNumber())) {
710 parameters.put("accountNumber", pbglLine.getAccountNumber());
711 }
712 if (StringUtils.isNotBlank(pbglLine.getFinancialObjectCode())) {
713 parameters.put("financialObjectCode", pbglLine.getFinancialObjectCode());
714 }
715 if (StringUtils.isNotBlank(pbglLine.getSubAccountNumber())) {
716 parameters.put("subAccountNumber", pbglLine.getSubAccountNumber());
717 }
718 if (StringUtils.isNotBlank(pbglLine.getFinancialSubObjectCode())) {
719 parameters.put("financialSubObjectCode", pbglLine.getFinancialSubObjectCode());
720 }
721
722 String lookupUrl = UrlFactory.parameterizeUrl(basePath + "/" + KFSConstants.BALANCE_INQUIRY_REPORT_MENU_ACTION, parameters);
723
724 this.setupDocumentExit();
725 return new ActionForward(lookupUrl, true);
726 }
727
728 /**
729 * Calls performMonthlyBudget for the selected revenue line
730 *
731 * @param mapping
732 * @param form
733 * @param request
734 * @param response
735 * @return
736 * @throws Exception
737 */
738 public ActionForward performMonthlyRevenueBudget(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
739 return performMonthlyBudget(true, mapping, form, request, response);
740 }
741
742 /**
743 * Calls performMonthlyBudget for the selected expenditure line
744 *
745 * @param mapping
746 * @param form
747 * @param request
748 * @param response
749 * @return
750 * @throws Exception
751 */
752 public ActionForward performMonthlyExpenditureBudget(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
753 return performMonthlyBudget(false, mapping, form, request, response);
754 }
755
756 /**
757 * Forwards the user to the monthly budget screen. Doing this in edit mode causes the document to be validated, saved and
758 * benefits calculated (if needed).
759 *
760 * @param isRevenue
761 * @param mapping
762 * @param form
763 * @param request
764 * @param response
765 * @return
766 * @throws Exception
767 */
768 public ActionForward performMonthlyBudget(boolean isRevenue, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
769 final String docNumber;
770
771 // this to checks for 2PLG and turns off SS/monthly RI check if found
772 // the final save after removing 2PLG will catch any monthly discrepencies
773 // also need to save object,subobject key we are operating on so refresh can get the latest row version from DB
774
775 // validate, save, etc first then goto the monthly screen or redisplay if errors
776 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
777 BudgetConstructionDocument bcDocument = (BudgetConstructionDocument) budgetConstructionForm.getDocument();
778
779 PendingBudgetConstructionGeneralLedger pbglLine;
780 if (isRevenue) {
781 pbglLine = bcDocument.getPendingBudgetConstructionGeneralLedgerRevenueLines().get(this.getSelectedLine(request));
782 }
783 else {
784 pbglLine = bcDocument.getPendingBudgetConstructionGeneralLedgerExpenditureLines().get(this.getSelectedLine(request));
785 }
786
787 // when we return from the lookup, our next request's method to call is going to be refresh
788 budgetConstructionForm.registerEditableProperty(KNSConstants.DISPATCH_REQUEST_PARAMETER);
789
790 if (budgetConstructionForm.isEditAllowed() && !budgetConstructionForm.isSystemViewOnly()) {
791 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
792
793 // if the doc contains a 2plg line, turn off RI checking to allow cleanup.
794 // The act of attempting to remove a 2plg (delete) forces a complete RI check.
795 // The document is assumed inconsistent as long as a 2plg exists.
796 if (!isRevenue && bcDocument.isContainsTwoPlug()) {
797 if (pbglLine.getLaborObject() != null && pbglLine.getLaborObject().isDetailPositionRequiredIndicator()) {
798 budgetDocumentService.saveDocumentNoWorkFlow(bcDocument, MonthSpreadDeleteType.EXPENDITURE, false);
799 }
800 else {
801 budgetDocumentService.saveDocumentNoWorkFlow(bcDocument, MonthSpreadDeleteType.EXPENDITURE, true);
802 }
803 }
804 else {
805 budgetDocumentService.saveDocumentNoWorkflow(bcDocument);
806
807 }
808 budgetConstructionForm.initializePersistedRequestAmounts();
809 budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
810
811 // repop and refresh refs - esp monthly so jsp can properly display state
812 // budgetConstructionForm.populatePBGLLines();
813
814 }
815
816 // String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() +
817 // request.getContextPath();
818 String basePath = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.APPLICATION_URL_KEY);
819 Properties parameters = new Properties();
820 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, BCConstants.MONTHLY_BUDGET_METHOD);
821 parameters.put(KFSConstants.BACK_LOCATION, basePath + mapping.getPath() + ".do");
822 parameters.put("documentNumber", pbglLine.getDocumentNumber());
823 parameters.put("universityFiscalYear", pbglLine.getUniversityFiscalYear().toString());
824 parameters.put("chartOfAccountsCode", pbglLine.getChartOfAccountsCode());
825 parameters.put("accountNumber", pbglLine.getAccountNumber());
826 parameters.put("subAccountNumber", pbglLine.getSubAccountNumber());
827 parameters.put("financialObjectCode", pbglLine.getFinancialObjectCode());
828 parameters.put("financialSubObjectCode", pbglLine.getFinancialSubObjectCode());
829 parameters.put("financialBalanceTypeCode", pbglLine.getFinancialBalanceTypeCode());
830 parameters.put("financialObjectTypeCode", pbglLine.getFinancialObjectTypeCode());
831 parameters.put(BCPropertyConstants.MAIN_WINDOW, (budgetConstructionForm.isMainWindow() ? "true" : "false"));
832
833 // anchor, if it exists
834 if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
835 parameters.put(BCConstants.RETURN_ANCHOR, ((KualiForm) form).getAnchor());
836 }
837
838 // the form object is retrieved and removed upon return by KualiRequestProcessor.processActionForm()
839 parameters.put(BCConstants.RETURN_FORM_KEY, GlobalVariables.getUserSession().addObject(form, BCConstants.FORMKEY_PREFIX));
840
841 String lookupUrl = UrlFactory.parameterizeUrl(basePath + "/" + BCConstants.MONTHLY_BUDGET_ACTION, parameters);
842 this.setupDocumentExit();
843 return new ActionForward(lookupUrl, true);
844 }
845
846 /**
847 * Forwards the user to the quick salary setting screen. Doing this in edit mode causes the document to be validated, saved and
848 * benefits calculated (if needed).
849 *
850 * @param mapping
851 * @param form
852 * @param request
853 * @param response
854 * @return
855 * @throws Exception
856 */
857 public ActionForward performSalarySetting(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
858 final String docNumber;
859
860 // this to checks for 2PLG and turns off monthly RI check if found
861 // the final save after removing 2PLG will catch any monthly discrepencies
862
863 // validate, save, etc first then goto the SalarySetting screen or redisplay if errors
864 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
865 BudgetConstructionDocument bcDocument = (BudgetConstructionDocument) budgetConstructionForm.getDocument();
866
867 // when we return from the lookup, our next request's method to call is going to be refresh
868 budgetConstructionForm.registerEditableProperty(KNSConstants.DISPATCH_REQUEST_PARAMETER);
869
870 if (budgetConstructionForm.isEditAllowed() && !budgetConstructionForm.isSystemViewOnly()) {
871 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
872
873 // if the doc contains a 2plg line, turn off RI checking to allow cleanup.
874 // The act of attempting to remove a 2plg (delete) forces a complete RI check.
875 // The document is assumed inconsistent as long as a 2plg exists.
876 if (bcDocument.isContainsTwoPlug()) {
877 budgetDocumentService.saveDocumentNoWorkFlow(bcDocument, MonthSpreadDeleteType.EXPENDITURE, false);
878 }
879 else {
880 budgetDocumentService.saveDocumentNoWorkflow(bcDocument);
881 }
882
883 // init persisted property and get the current list of salary setting related rows
884 budgetConstructionForm.initializePersistedRequestAmounts(true);
885
886 budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
887
888 // repop and refresh refs - esp monthly so jsp can properly display state
889 // budgetConstructionForm.populatePBGLLines();
890
891 }
892 PendingBudgetConstructionGeneralLedger pbglLine;
893 pbglLine = bcDocument.getPendingBudgetConstructionGeneralLedgerExpenditureLines().get(this.getSelectedLine(request));
894
895 // String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() +
896 // request.getContextPath();
897 String basePath = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.APPLICATION_URL_KEY);
898 Properties parameters = new Properties();
899 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, BCConstants.QUICK_SALARY_SETTING_METHOD);
900 parameters.put(KFSConstants.BACK_LOCATION, basePath + mapping.getPath() + ".do");
901
902 parameters.put("documentNumber", pbglLine.getDocumentNumber());
903 parameters.put("universityFiscalYear", pbglLine.getUniversityFiscalYear().toString());
904 parameters.put("chartOfAccountsCode", pbglLine.getChartOfAccountsCode());
905 parameters.put("accountNumber", pbglLine.getAccountNumber());
906 parameters.put("subAccountNumber", pbglLine.getSubAccountNumber());
907 parameters.put("financialObjectCode", pbglLine.getFinancialObjectCode());
908 parameters.put("financialSubObjectCode", pbglLine.getFinancialSubObjectCode());
909 parameters.put("financialBalanceTypeCode", pbglLine.getFinancialBalanceTypeCode());
910 parameters.put("financialObjectTypeCode", pbglLine.getFinancialObjectTypeCode());
911 parameters.put(BCPropertyConstants.MAIN_WINDOW, (budgetConstructionForm.isMainWindow() ? "true" : "false"));
912
913 // anchor, if it exists
914 if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
915 parameters.put(BCConstants.RETURN_ANCHOR, ((KualiForm) form).getAnchor());
916 }
917
918 // the form object is retrieved and removed upon return by KualiRequestProcessor.processActionForm()
919 parameters.put(BCConstants.RETURN_FORM_KEY, GlobalVariables.getUserSession().addObject(form, BCConstants.FORMKEY_PREFIX));
920
921 String lookupUrl = UrlFactory.parameterizeUrl(basePath + "/" + BCConstants.QUICK_SALARY_SETTING_ACTION, parameters);
922 this.setupDocumentExit();
923 return new ActionForward(lookupUrl, true);
924 }
925
926 /**
927 * This adds a revenue line to the BC document
928 *
929 * @param mapping
930 * @param form
931 * @param request
932 * @param response
933 * @return
934 * @throws Exception
935 */
936 public ActionForward insertRevenueLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
937 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
938
939 PendingBudgetConstructionGeneralLedger line = budgetConstructionForm.getNewRevenueLine();
940
941 boolean rulePassed = true;
942
943 rulePassed &= SpringContext.getBean(KualiRuleService.class).applyRules(new AddPendingBudgetGeneralLedgerLineEvent(BCConstants.NEW_REVENUE_LINE_PROPERTY_NAME, budgetConstructionForm.getDocument(), line, true));
944
945 if (rulePassed) {
946 // add PBGLLine
947 insertPBGLLine(true, budgetConstructionForm, line);
948
949 // clear the used newRevenueLine
950 budgetConstructionForm.setNewRevenueLine(new PendingBudgetConstructionGeneralLedger());
951 budgetConstructionForm.initNewLine(budgetConstructionForm.getNewRevenueLine(), true);
952 }
953
954 return mapping.findForward(KFSConstants.MAPPING_BASIC);
955 }
956
957 /**
958 * This adds an expenditure line to the BC document
959 *
960 * @param mapping
961 * @param form
962 * @param request
963 * @param response
964 * @return
965 * @throws Exception
966 */
967 public ActionForward insertExpenditureLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
968 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
969
970 PendingBudgetConstructionGeneralLedger line = budgetConstructionForm.getNewExpenditureLine();
971
972 boolean rulePassed = true;
973
974 rulePassed &= SpringContext.getBean(KualiRuleService.class).applyRules(new AddPendingBudgetGeneralLedgerLineEvent(BCConstants.NEW_EXPENDITURE_LINE_PROPERTY_NAME, budgetConstructionForm.getDocument(), line, false));
975
976 if (rulePassed) {
977
978 // add PBGLLine
979 insertPBGLLine(false, budgetConstructionForm, line);
980
981 // clear the used newExpenditureLine
982 budgetConstructionForm.setNewExpenditureLine(new PendingBudgetConstructionGeneralLedger());
983 budgetConstructionForm.initNewLine(budgetConstructionForm.getNewExpenditureLine(), false);
984 }
985
986 return mapping.findForward(KFSConstants.MAPPING_BASIC);
987 }
988
989 /**
990 * This inserts a PBGL revenue or expenditure line
991 *
992 * @param isRevenue
993 * @param budgetConstructionForm
994 * @param line
995 */
996 protected void insertPBGLLine(boolean isRevenue, BudgetConstructionForm budgetConstructionForm, PendingBudgetConstructionGeneralLedger line) {
997
998 BudgetConstructionDocument bcDoc = (BudgetConstructionDocument) budgetConstructionForm.getDocument();
999
1000 // null subobj must be set to dashes
1001 if (StringUtils.isBlank(line.getFinancialSubObjectCode())) {
1002 line.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode());
1003 }
1004
1005 // check the DB for an existing persisted version of the line
1006 // and reinstate that with a message to the user indicating such
1007 boolean isReinstated = false;
1008 Map<String, Object> primaryKey = new HashMap<String, Object>();
1009 primaryKey.put(KFSPropertyConstants.DOCUMENT_NUMBER, line.getDocumentNumber());
1010 primaryKey.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, line.getUniversityFiscalYear());
1011 primaryKey.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, line.getChartOfAccountsCode());
1012 primaryKey.put(KFSPropertyConstants.ACCOUNT_NUMBER, line.getAccountNumber());
1013 primaryKey.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, line.getSubAccountNumber());
1014 primaryKey.put(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE, line.getFinancialBalanceTypeCode());
1015 primaryKey.put(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE, line.getFinancialObjectTypeCode());
1016
1017 primaryKey.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, line.getFinancialObjectCode());
1018 primaryKey.put(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE, line.getFinancialSubObjectCode());
1019
1020 PendingBudgetConstructionGeneralLedger dbLine = (PendingBudgetConstructionGeneralLedger) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(PendingBudgetConstructionGeneralLedger.class, primaryKey);
1021 if (dbLine != null){
1022 line = dbLine;
1023 SpringContext.getBean(BudgetDocumentService.class).populatePBGLLine(line);
1024 isReinstated = true;
1025 }
1026
1027 // add the line in the proper order - assumes already exists check is done in rules
1028 int insertPoint = bcDoc.addPBGLLine(line, isRevenue);
1029
1030 if (isReinstated){
1031 String errorKey;
1032 if (isRevenue){
1033 errorKey = KNSConstants.DOCUMENT_PROPERTY_NAME + "." + BCPropertyConstants.PENDING_BUDGET_CONSTRUCTION_GENERAL_LEDGER_REVENUE_LINES + "[" + insertPoint + "]." + KFSPropertyConstants.ACCOUNT_LINE_ANNUAL_BALANCE_AMOUNT;
1034 }
1035 else {
1036 errorKey = KNSConstants.DOCUMENT_PROPERTY_NAME + "." + BCPropertyConstants.PENDING_BUDGET_CONSTRUCTION_GENERAL_LEDGER_EXPENDITURE_LINES + "[" + insertPoint + "]." + KFSPropertyConstants.ACCOUNT_LINE_ANNUAL_BALANCE_AMOUNT;
1037 }
1038 GlobalVariables.getMessageMap().putError(errorKey, BCKeyConstants.ERROR_BUDGET_LINE_REINSTATED, dbLine.getFinancialObjectCode() + "," + dbLine.getFinancialSubObjectCode());
1039 }
1040
1041 // adjust totals
1042 if (line.getAccountLineAnnualBalanceAmount() != null && line.getAccountLineAnnualBalanceAmount() != KualiInteger.ZERO) {
1043 if (isRevenue) {
1044 bcDoc.setRevenueAccountLineAnnualBalanceAmountTotal(bcDoc.getRevenueAccountLineAnnualBalanceAmountTotal().add(line.getAccountLineAnnualBalanceAmount()));
1045 }
1046 else {
1047 bcDoc.setExpenditureAccountLineAnnualBalanceAmountTotal(bcDoc.getExpenditureAccountLineAnnualBalanceAmountTotal().add(line.getAccountLineAnnualBalanceAmount()));
1048 }
1049 }
1050 if (line.getFinancialBeginningBalanceLineAmount() != null && line.getFinancialBeginningBalanceLineAmount() != KualiInteger.ZERO) {
1051 if (isRevenue) {
1052 bcDoc.setRevenueFinancialBeginningBalanceLineAmountTotal(bcDoc.getRevenueFinancialBeginningBalanceLineAmountTotal().add(line.getFinancialBeginningBalanceLineAmount()));
1053 }
1054 else {
1055 bcDoc.setExpenditureFinancialBeginningBalanceLineAmountTotal(bcDoc.getExpenditureFinancialBeginningBalanceLineAmountTotal().add(line.getFinancialBeginningBalanceLineAmount()));
1056 }
1057 }
1058 }
1059
1060 /**
1061 * Deletes an existing PendingBudgetConstructionGeneralLedger revenue line if rules passed. Any associated monthly budget
1062 * (BudgetConstructionMonthly) is also deleted.
1063 *
1064 * @param mapping
1065 * @param form
1066 * @param request
1067 * @param response
1068 * @return
1069 * @throws Exception
1070 */
1071 public ActionForward deleteRevenueLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1072
1073 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1074 BudgetConstructionDocument tDoc = tForm.getBudgetConstructionDocument();
1075
1076 boolean rulePassed = true;
1077 int deleteIndex = this.getLineToDelete(request);
1078
1079 // check business rule if there is a persisted request amount, otherwise the line can just be removed
1080 PendingBudgetConstructionGeneralLedger revLine = tDoc.getPendingBudgetConstructionGeneralLedgerRevenueLines().get(deleteIndex);
1081 if (revLine.getPersistedAccountLineAnnualBalanceAmount() == null) {
1082 rulePassed = true;
1083 }
1084 else {
1085 // check deletion rules and delete if passed
1086 String errorPath = KFSConstants.DOCUMENT_PROPERTY_NAME + "." + BCPropertyConstants.PENDING_BUDGET_CONSTRUCTION_GENERAL_LEDGER_REVENUE_LINES + "[" + deleteIndex + "]";
1087 rulePassed &= SpringContext.getBean(KualiRuleService.class).applyRules(new DeletePendingBudgetGeneralLedgerLineEvent(errorPath, tDoc, revLine, true));
1088 }
1089
1090 if (rulePassed) {
1091 deletePBGLLine(true, tForm, deleteIndex, revLine);
1092 }
1093
1094 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1095 }
1096
1097 /**
1098 * Deletes an existing PendingBudgetConstructionGeneralLedger expenditure line if rules passed Any associated monthly budget
1099 * (BudgetConstructionMonthly) is also deleted. Check for the special case where the line is a 2PLG line, in which case the
1100 * document is validated and RI checks are forced even if there are no current differences between persisted and request
1101 * amounts.
1102 *
1103 * @param mapping
1104 * @param form
1105 * @param request
1106 * @param response
1107 * @return
1108 * @throws Exception
1109 */
1110 public ActionForward deleteExpenditureLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1111
1112 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1113 BudgetConstructionDocument tDoc = tForm.getBudgetConstructionDocument();
1114
1115 boolean rulePassed = true;
1116 int deleteIndex = this.getLineToDelete(request);
1117
1118 // check business rule if there is a persisted request amount, otherwise the line can just be removed
1119 PendingBudgetConstructionGeneralLedger expLine = tDoc.getPendingBudgetConstructionGeneralLedgerExpenditureLines().get(deleteIndex);
1120 if (expLine.getPersistedAccountLineAnnualBalanceAmount() == null) {
1121 rulePassed = true;
1122 }
1123 else {
1124 // check regular deletion rules and delete if passed
1125 String errorPath = KFSConstants.DOCUMENT_PROPERTY_NAME + "." + BCPropertyConstants.PENDING_BUDGET_CONSTRUCTION_GENERAL_LEDGER_EXPENDITURE_LINES + "[" + deleteIndex + "]";
1126 rulePassed &= SpringContext.getBean(KualiRuleService.class).applyRules(new DeletePendingBudgetGeneralLedgerLineEvent(errorPath, tDoc, expLine, false));
1127 }
1128
1129 if (rulePassed) {
1130
1131 // if the line is a 2PLG line do document validation, which forces RI checks in no current change situation
1132 if (expLine.getFinancialObjectCode().equalsIgnoreCase(KFSConstants.BudgetConstructionConstants.OBJECT_CODE_2PLG)) {
1133 SpringContext.getBean(BudgetDocumentService.class).validateDocument(tDoc);
1134 }
1135 // gets here if line is not 2PLG or doc is valid from 2plg perspective
1136 deletePBGLLine(false, tForm, deleteIndex, expLine);
1137 }
1138
1139 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1140 }
1141
1142 /**
1143 * Deletes an existing PendingBudgetConstructionGeneralLedger revenue or expenditure line along with any associated monthly
1144 * budget (BudgetConstructionMonthly)
1145 *
1146 * @param isRevenue
1147 * @param budgetConstructionForm
1148 * @param deleteIndex
1149 */
1150 protected void deletePBGLLine(boolean isRevenue, BudgetConstructionForm budgetConstructionForm, int deleteIndex, PendingBudgetConstructionGeneralLedger line) {
1151
1152 BudgetConstructionDocument bcDoc = budgetConstructionForm.getBudgetConstructionDocument();
1153
1154 // adjust totals
1155 if (line.getAccountLineAnnualBalanceAmount() != null && line.getAccountLineAnnualBalanceAmount() != KualiInteger.ZERO) {
1156 if (isRevenue) {
1157 bcDoc.setRevenueAccountLineAnnualBalanceAmountTotal(bcDoc.getRevenueAccountLineAnnualBalanceAmountTotal().subtract(line.getAccountLineAnnualBalanceAmount()));
1158 }
1159 else {
1160 bcDoc.setExpenditureAccountLineAnnualBalanceAmountTotal(bcDoc.getExpenditureAccountLineAnnualBalanceAmountTotal().subtract(line.getAccountLineAnnualBalanceAmount()));
1161 }
1162 }
1163 if (line.getFinancialBeginningBalanceLineAmount() != null && line.getFinancialBeginningBalanceLineAmount() != KualiInteger.ZERO) {
1164 if (isRevenue) {
1165 bcDoc.setRevenueFinancialBeginningBalanceLineAmountTotal(bcDoc.getRevenueFinancialBeginningBalanceLineAmountTotal().subtract(line.getFinancialBeginningBalanceLineAmount()));
1166 }
1167 else {
1168 bcDoc.setExpenditureFinancialBeginningBalanceLineAmountTotal(bcDoc.getExpenditureFinancialBeginningBalanceLineAmountTotal().subtract(line.getFinancialBeginningBalanceLineAmount()));
1169 }
1170 }
1171
1172 // remove the line
1173 if (isRevenue) {
1174 bcDoc.getPendingBudgetConstructionGeneralLedgerRevenueLines().remove(deleteIndex);
1175 }
1176 else {
1177 if (line.getFinancialObjectCode().equalsIgnoreCase(KFSConstants.BudgetConstructionConstants.OBJECT_CODE_2PLG)) {
1178 bcDoc.setContainsTwoPlug(true);
1179 }
1180 bcDoc.getPendingBudgetConstructionGeneralLedgerExpenditureLines().remove(deleteIndex);
1181 }
1182
1183 }
1184
1185 /*
1186 * public ActionForward returnFromMonthly(ActionMapping mapping, ActionForm form, HttpServletRequest request,
1187 * HttpServletResponse response) throws Exception { BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm)
1188 * form; String documentNumber = request.getParameter("documentNumber"); BudgetConstructionDocument budgetConstructionDocument =
1189 * (BudgetConstructionDocument) SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(documentNumber);
1190 * budgetConstructionForm.setDocument(budgetConstructionDocument); KualiWorkflowDocument workflowDoc =
1191 * budgetConstructionDocument.getDocumentHeader().getWorkflowDocument();
1192 * budgetConstructionForm.setDocTypeName(workflowDoc.getDocumentType()); // KualiDocumentFormBase.populate() needs this updated
1193 * in the session GlobalVariables.getUserSession().setWorkflowDocument(workflowDoc); return
1194 * mapping.findForward(KFSConstants.MAPPING_BASIC); }
1195 */
1196
1197 /**
1198 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#refresh(org.apache.struts.action.ActionMapping,
1199 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
1200 */
1201 @Override
1202 public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1203 BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) form;
1204 budgetConstructionForm.setDerivedValuesOnForm(request);
1205
1206 // Do specific refresh stuff here based on refreshCaller parameter
1207 // typical refresh callers would be monthlyBudget or salarySetting or lookupable
1208 String refreshCaller = request.getParameter(KFSConstants.REFRESH_CALLER);
1209
1210 if (refreshCaller != null && refreshCaller.equalsIgnoreCase(BCConstants.MONTHLY_BUDGET_REFRESH_CALLER)) {
1211
1212 // monthly process applies any changes to the DB and the form session object
1213 // including any override to the request amount which also changes the request total
1214 // it also sets up calc monthly benefits if the line is involved in benefits
1215 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
1216 budgetDocumentService.calculateBenefitsIfNeeded(budgetConstructionForm.getBudgetConstructionDocument());
1217
1218 }
1219 if (refreshCaller != null && refreshCaller.equalsIgnoreCase(BCConstants.QUICK_SALARY_SETTING_REFRESH_CALLER)) {
1220
1221
1222 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
1223
1224 // if editing - reload expenditure and check for changes to detail salary lines and 2plg request amount
1225 boolean diffFound = false;
1226 if (budgetConstructionForm.isEditAllowed() && !budgetConstructionForm.isSystemViewOnly()) {
1227 BudgetConstructionDocument currentBCDoc = budgetConstructionForm.getBudgetConstructionDocument();
1228
1229 // get the current set of salary setting related rows from DB and compare against preSalarySettingRows
1230
1231 List<PendingBudgetConstructionGeneralLedger> dbSalarySettingRows = budgetDocumentService.getPBGLSalarySettingRows(currentBCDoc);
1232 for (PendingBudgetConstructionGeneralLedger dbSalarySettingRow : dbSalarySettingRows) {
1233 if (budgetConstructionForm.getPreSalarySettingRows().containsKey(dbSalarySettingRow.getFinancialObjectCode() + dbSalarySettingRow.getFinancialSubObjectCode())) {
1234
1235 // update the existing row if a difference is found
1236 KualiInteger dbReqAmount = dbSalarySettingRow.getAccountLineAnnualBalanceAmount();
1237 KualiInteger preReqAmount = budgetConstructionForm.getPreSalarySettingRows().get(dbSalarySettingRow.getFinancialObjectCode() + dbSalarySettingRow.getFinancialSubObjectCode()).getAccountLineAnnualBalanceAmount();
1238 Long dbVersionNumber = dbSalarySettingRow.getVersionNumber();
1239 Long preReqVersionNumber = budgetConstructionForm.getPreSalarySettingRows().get(dbSalarySettingRow.getFinancialObjectCode() + dbSalarySettingRow.getFinancialSubObjectCode()).getVersionNumber();
1240 if ((dbVersionNumber.compareTo(preReqVersionNumber) != 0) || (dbReqAmount.compareTo(preReqAmount) != 0)) {
1241 budgetDocumentService.addOrUpdatePBGLRow(currentBCDoc, dbSalarySettingRow);
1242
1243 // only flag for existing line diff when the request amount changes
1244 // changes in versionNumber implies offsetting updates of some sort
1245 if (dbReqAmount.compareTo(preReqAmount) != 0) {
1246 diffFound = true;
1247 }
1248 }
1249 }
1250 else {
1251
1252 // update the req amount and version or add the new row to the current doc as needed
1253 // insert the new DB row to the set in memory
1254 budgetDocumentService.addOrUpdatePBGLRow(currentBCDoc, dbSalarySettingRow);
1255 diffFound = true;
1256 }
1257 }
1258
1259 if (diffFound) {
1260 this.adjustForSalarySettingChanges(budgetConstructionForm);
1261
1262 }
1263 }
1264
1265 }
1266
1267 if (refreshCaller != null && refreshCaller.equalsIgnoreCase(KFSConstants.KUALI_LOOKUPABLE_IMPL)) {
1268 final List REFRESH_FIELDS = Collections.unmodifiableList(Arrays.asList(new String[] { "financialObject", "financialSubObject" }));
1269 SpringContext.getBean(PersistenceService.class).retrieveReferenceObjects(budgetConstructionForm.getNewRevenueLine(), REFRESH_FIELDS);
1270 SpringContext.getBean(PersistenceService.class).retrieveReferenceObjects(budgetConstructionForm.getNewExpenditureLine(), REFRESH_FIELDS);
1271 }
1272
1273 // balance inquiry anchor is set before doing a balance inquiry
1274 if (budgetConstructionForm.getBalanceInquiryReturnAnchor() != null) {
1275 budgetConstructionForm.setAnchor(budgetConstructionForm.getBalanceInquiryReturnAnchor());
1276 budgetConstructionForm.setBalanceInquiryReturnAnchor(null);
1277 }
1278 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1279 }
1280
1281 /**
1282 * This action changes the value of the hide field in the user interface so that when the page is rendered, the UI knows to show
1283 * all of the descriptions and labels for each of the pbgl line values.
1284 *
1285 * @param mapping
1286 * @param form
1287 * @param request
1288 * @param response
1289 * @return ActionForward
1290 * @throws Exception
1291 */
1292 public ActionForward showDetails(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1293 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1294 tForm.setHideDetails(false);
1295 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1296 }
1297
1298 /**
1299 * This action toggles the value of the hide field in the user interface to "hide" so that when the page is rendered, the UI
1300 * displays values without all of the descriptions and labels for each of the pbgl lines.
1301 *
1302 * @param mapping
1303 * @param form
1304 * @param request
1305 * @param response
1306 * @return ActionForward
1307 * @throws Exception
1308 */
1309 public ActionForward hideDetails(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1310 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1311 tForm.setHideDetails(true);
1312 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1313 }
1314
1315 public ActionForward toggleAdjustmentMeasurement(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1316 BudgetConstructionForm docForm = (BudgetConstructionForm) form;
1317
1318 boolean currentStatus = docForm.isHideAdjustmentMeasurement();
1319 docForm.setHideAdjustmentMeasurement(!currentStatus);
1320
1321 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1322 }
1323
1324 public ActionForward adjustRevenueLinePercent(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1325 BudgetConstructionForm docForm = (BudgetConstructionForm) form;
1326 BudgetConstructionDocument bcDoc = docForm.getBudgetConstructionDocument();
1327 PendingBudgetConstructionGeneralLedger revLine = bcDoc.getPendingBudgetConstructionGeneralLedgerRevenueLines().get(this.getSelectedLine(request));
1328
1329 if (revLine.getAdjustmentAmount() != null) {
1330 this.adjustRequest(revLine);
1331 docForm.populatePBGLLines();
1332 }
1333
1334 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1335 }
1336
1337 public ActionForward adjustExpenditureLinePercent(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1338 BudgetConstructionForm docForm = (BudgetConstructionForm) form;
1339 BudgetConstructionDocument bcDoc = docForm.getBudgetConstructionDocument();
1340 PendingBudgetConstructionGeneralLedger expLine = bcDoc.getPendingBudgetConstructionGeneralLedgerExpenditureLines().get(this.getSelectedLine(request));
1341
1342 if (expLine.getAdjustmentAmount() != null) {
1343 this.adjustRequest(expLine);
1344 docForm.populatePBGLLines();
1345 }
1346
1347 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1348 }
1349
1350 public ActionForward adjustAllRevenueLinesPercent(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1351 BudgetConstructionForm docForm = (BudgetConstructionForm) form;
1352 BudgetConstructionDocument bcDoc = docForm.getBudgetConstructionDocument();
1353 List<PendingBudgetConstructionGeneralLedger> revenueLines = bcDoc.getPendingBudgetConstructionGeneralLedgerRevenueLines();
1354
1355 KualiDecimal adjustmentAmount = docForm.getRevenueAdjustmentAmount();
1356 if (adjustmentAmount != null) {
1357
1358 // not sure we need this check since the tool isn't displayed in view mode
1359 boolean isEditable = docForm.isEditAllowed() && !docForm.isSystemViewOnly();
1360 for (PendingBudgetConstructionGeneralLedger revenueLine : revenueLines) {
1361 if (isEditable) {
1362 revenueLine.setAdjustmentAmount(adjustmentAmount);
1363 this.adjustRequest(revenueLine);
1364 }
1365 }
1366 if (isEditable){
1367 docForm.populatePBGLLines();
1368 }
1369 }
1370
1371 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1372 }
1373
1374 public ActionForward adjustAllExpenditureLinesPercent(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1375 BudgetConstructionForm docForm = (BudgetConstructionForm) form;
1376 BudgetConstructionDocument bcDoc = docForm.getBudgetConstructionDocument();
1377 List<PendingBudgetConstructionGeneralLedger> expenditureLines = bcDoc.getPendingBudgetConstructionGeneralLedgerExpenditureLines();
1378
1379 KualiDecimal adjustmentAmount = docForm.getExpenditureAdjustmentAmount();
1380 if (adjustmentAmount != null) {
1381
1382 // not sure we need this check since the tool isn't displayed in view mode
1383 boolean isEditable = docForm.isEditAllowed() && !docForm.isSystemViewOnly();
1384 // (!benecalcDisabled && !empty item.laborObject && item.laborObject.financialObjectFringeOrSalaryCode == 'F')
1385 for (PendingBudgetConstructionGeneralLedger expenditureLine : expenditureLines) {
1386 boolean isLineEditable = (isEditable && (docForm.isBenefitsCalculationDisabled() || (expenditureLine.getLaborObject() == null) || !expenditureLine.getLaborObject().getFinancialObjectFringeOrSalaryCode().equalsIgnoreCase(BCConstants.LABOR_OBJECT_FRINGE_CODE)));
1387 if (isLineEditable) {
1388 expenditureLine.setAdjustmentAmount(adjustmentAmount);
1389 this.adjustRequest(expenditureLine);
1390 }
1391 }
1392 if (isEditable){
1393 docForm.populatePBGLLines();
1394 }
1395 }
1396
1397 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1398 }
1399
1400 /**
1401 * Handles the document (account) pullup action, resetting the cached editingMode as appropriate for the new level.
1402 *
1403 * @param mapping
1404 * @param form
1405 * @param request
1406 * @param response
1407 * @return
1408 * @throws Exception
1409 */
1410 public ActionForward performAccountPullup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1411 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1412
1413 boolean doAllowPullup = false;
1414 boolean lockNeeded = false;
1415 boolean prePullReadOnlyAccess;
1416
1417 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
1418
1419 // if system view only or view only - reload to get the latest status
1420 // and check that the document is still below the selected POV
1421 if (!tForm.isEditAllowed() || tForm.isSystemViewOnly()) {
1422
1423 prePullReadOnlyAccess = true;
1424
1425 // now reload the document and get latest status info
1426 loadDocument(tForm);
1427 this.initAuthorization(tForm);
1428 if (tForm.getBudgetConstructionDocument().getOrganizationLevelCode() < Integer.parseInt(tForm.getPullupKeyCode())) {
1429 doAllowPullup = true;
1430
1431 // if not system view only mode, we are in document view mode - we'll need a lock before the pullup
1432 // since by definition pullup puts the account at a full_entry level
1433 // and we need exclusive access to perform the pullup
1434 if (!tForm.isSystemViewOnly()) {
1435 lockNeeded = true;
1436 }
1437 }
1438 else {
1439 // document has been moved and is either at the desired level or above
1440 doAllowPullup = false;
1441 lockNeeded = false;
1442
1443 // document has been moved above the desired level - let populate through an authorization exception
1444 if (tForm.getBudgetConstructionDocument().getOrganizationLevelCode() > Integer.parseInt(tForm.getPullupKeyCode())) {
1445 GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_MESSAGES, BCKeyConstants.ERROR_BUDGET_PULLUP_DOCUMENT, "Document has already been moved above the selected level.");
1446 }
1447 }
1448 }
1449 else {
1450 // we are in document full_entry
1451 // assume we already have a lock, allow the pullup
1452 // and we need to ensure the user can finish editing work if after pullup system goes to system view only
1453 prePullReadOnlyAccess = false;
1454 doAllowPullup = true;
1455 }
1456
1457 if (lockNeeded || doAllowPullup) {
1458
1459 // get a fresh header to use for lock and/or pullup
1460 HashMap primaryKey = new HashMap();
1461 primaryKey.put(KFSPropertyConstants.DOCUMENT_NUMBER, tForm.getDocument().getDocumentNumber());
1462 BudgetConstructionHeader budgetConstructionHeader = (BudgetConstructionHeader) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(BudgetConstructionHeader.class, primaryKey);
1463 if (budgetConstructionHeader == null) {
1464 GlobalVariables.getMessageMap().putError(BCConstants.BUDGET_CONSTRUCTION_SYSTEM_INFORMATION_TAB_ERRORS, BCKeyConstants.ERROR_BUDGET_PULLUP_DOCUMENT, "Fatal, Document not found.");
1465 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1466 }
1467
1468 if (lockNeeded) {
1469 // only successful lock allows pullup here
1470 doAllowPullup = false;
1471
1472 LockService lockService = SpringContext.getBean(LockService.class);
1473 BudgetConstructionLockStatus bcLockStatus = lockService.lockAccount(budgetConstructionHeader, GlobalVariables.getUserSession().getPerson().getPrincipalId());
1474 LockStatus lockStatus = bcLockStatus.getLockStatus();
1475 switch (lockStatus) {
1476 case SUCCESS:
1477 doAllowPullup = true;
1478 break;
1479 case BY_OTHER:
1480 String lockerName = SpringContext.getBean(org.kuali.rice.kim.service.PersonService.class).getPerson(bcLockStatus.getAccountLockOwner()).getName();
1481 GlobalVariables.getMessageMap().putError(BCConstants.BUDGET_CONSTRUCTION_SYSTEM_INFORMATION_TAB_ERRORS, BCKeyConstants.ERROR_BUDGET_PULLUP_DOCUMENT, "Locked by " + lockerName);
1482 break;
1483 case FLOCK_FOUND:
1484 GlobalVariables.getMessageMap().putError(BCConstants.BUDGET_CONSTRUCTION_SYSTEM_INFORMATION_TAB_ERRORS, BCKeyConstants.ERROR_BUDGET_PULLUP_DOCUMENT, "Funding lock found.");
1485 break;
1486 default:
1487 GlobalVariables.getMessageMap().putError(BCConstants.BUDGET_CONSTRUCTION_SYSTEM_INFORMATION_TAB_ERRORS, BCKeyConstants.ERROR_BUDGET_PULLUP_DOCUMENT, "Optimistic lock or other failure during lock attempt.");
1488 break;
1489 }
1490 }
1491
1492 // attempt pullup
1493 if (doAllowPullup) {
1494 budgetConstructionHeader.setOrganizationLevelCode(Integer.parseInt(tForm.getPullupKeyCode()));
1495 budgetConstructionHeader.setOrganizationLevelChartOfAccountsCode(tForm.getAccountOrgHierLevels().get(Integer.parseInt(tForm.getPullupKeyCode())).getOrganizationChartOfAccountsCode());
1496 budgetConstructionHeader.setOrganizationLevelOrganizationCode(tForm.getAccountOrgHierLevels().get(Integer.parseInt(tForm.getPullupKeyCode())).getOrganizationCode());
1497 SpringContext.getBean(BusinessObjectService.class).save(budgetConstructionHeader);
1498
1499 // finally refresh the doc with the changed header info
1500 tForm.getBudgetConstructionDocument().setVersionNumber(budgetConstructionHeader.getVersionNumber());
1501 tForm.getBudgetConstructionDocument().setOrganizationLevelCode(budgetConstructionHeader.getOrganizationLevelCode());
1502 tForm.getBudgetConstructionDocument().setOrganizationLevelChartOfAccountsCode(budgetConstructionHeader.getOrganizationLevelChartOfAccountsCode());
1503 tForm.getBudgetConstructionDocument().setOrganizationLevelOrganizationCode(budgetConstructionHeader.getOrganizationLevelOrganizationCode());
1504
1505 // refresh the lock info even though the user may be pulling while in edit mode
1506 tForm.getBudgetConstructionDocument().setBudgetLockUserIdentifier(budgetConstructionHeader.getBudgetLockUserIdentifier());
1507
1508 // refresh organization - so UI shows new level description
1509 tForm.getBudgetConstructionDocument().refreshReferenceObject("organizationLevelOrganization");
1510
1511 this.initAuthorization(tForm);
1512
1513 // if before pullup, system was 'not system view only' goes to 'system view only' after pull
1514 // need to manually remove the system view only editingMode here to allow the user to save work since still
1515 // full_entry
1516 if (tForm.isEditAllowed() && !prePullReadOnlyAccess) {
1517 if (tForm.isSystemViewOnly()) {
1518 tForm.getEditingMode().remove(BCConstants.EditModes.SYSTEM_VIEW_ONLY);
1519 }
1520 }
1521 }
1522 }
1523
1524 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1525 }
1526
1527 /**
1528 * Handles the document (account) pushdown action, resetting the cached editingMode as appropriate for the new level.
1529 *
1530 * @param mapping
1531 * @param form
1532 * @param request
1533 * @param response
1534 * @return
1535 * @throws Exception
1536 */
1537 public ActionForward performAccountPushdown(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1538
1539 boolean doAllowPushdown = false;
1540 boolean unlockNeeded = false;
1541 boolean prePushSystemViewOnly;
1542 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1543 BudgetConstructionDocument bcDocument = tForm.getBudgetConstructionDocument();
1544 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
1545
1546 // This method is called only if user has edit access and there is somewhere to push to.
1547 // If not system view only and the intended push level is view, we need to validate and save
1548 // Otherwise new level is still allowing editing, just push and keep current lock
1549 if (!tForm.isSystemViewOnly()) {
1550 prePushSystemViewOnly = false;
1551
1552 // check editing mode at the intended level
1553 if (!hasEditPermission(bcDocument, tForm.getPushdownKeyCode(), GlobalVariables.getUserSession().getPerson())) {
1554 budgetDocumentService.saveDocumentNoWorkflow(bcDocument);
1555 tForm.initializePersistedRequestAmounts();
1556 budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
1557
1558 // repop and refresh refs - esp monthly so jsp can properly display state
1559 // tForm.populatePBGLLines();
1560
1561 unlockNeeded = true;
1562 }
1563 doAllowPushdown = true;
1564 }
1565 else {
1566 prePushSystemViewOnly = true;
1567
1568 // reload document to get most up-to-date status and recheck that we still have FULL_ENTRY access
1569 // anything else means the document was moved by someone else and we may no longer even have read access
1570 loadDocument(tForm);
1571 this.initAuthorization(tForm);
1572 if (tForm.isEditAllowed()) {
1573 doAllowPushdown = true;
1574 }
1575 else {
1576 // document has moved
1577 GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_MESSAGES, BCKeyConstants.ERROR_BUDGET_PUSHDOWN_DOCUMENT, "Full Access Control Lost.");
1578 }
1579 }
1580
1581 // gets here if editing and pushing to view and doc is valid and persisted
1582 // or we are pushing from edit to edit
1583 // or we are in system view only
1584 if (doAllowPushdown) {
1585
1586 HashMap primaryKey = new HashMap();
1587 primaryKey.put(KFSPropertyConstants.DOCUMENT_NUMBER, tForm.getDocument().getDocumentNumber());
1588
1589 BudgetConstructionHeader budgetConstructionHeader = (BudgetConstructionHeader) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(BudgetConstructionHeader.class, primaryKey);
1590 if (budgetConstructionHeader != null) {
1591 budgetConstructionHeader.setOrganizationLevelCode(Integer.parseInt(tForm.getPushdownKeyCode()));
1592 if (Integer.parseInt(tForm.getPushdownKeyCode()) == 0) {
1593 budgetConstructionHeader.setOrganizationLevelChartOfAccountsCode(null);
1594 budgetConstructionHeader.setOrganizationLevelOrganizationCode(null);
1595 }
1596 else {
1597 budgetConstructionHeader.setOrganizationLevelChartOfAccountsCode(tForm.getAccountOrgHierLevels().get(Integer.parseInt(tForm.getPushdownKeyCode())).getOrganizationChartOfAccountsCode());
1598 budgetConstructionHeader.setOrganizationLevelOrganizationCode(tForm.getAccountOrgHierLevels().get(Integer.parseInt(tForm.getPushdownKeyCode())).getOrganizationCode());
1599 }
1600 }
1601
1602 // unlock if needed (which stores) - otherwise store the new level
1603 if (unlockNeeded) {
1604
1605 LockService lockService = SpringContext.getBean(LockService.class);
1606 lockService.unlockAccount(budgetConstructionHeader);
1607 }
1608 else {
1609 SpringContext.getBean(BusinessObjectService.class).save(budgetConstructionHeader);
1610
1611 }
1612
1613 // finally refresh the doc with the changed header info
1614 tForm.getBudgetConstructionDocument().setVersionNumber(budgetConstructionHeader.getVersionNumber());
1615 tForm.getBudgetConstructionDocument().setOrganizationLevelCode(budgetConstructionHeader.getOrganizationLevelCode());
1616 tForm.getBudgetConstructionDocument().setOrganizationLevelChartOfAccountsCode(budgetConstructionHeader.getOrganizationLevelChartOfAccountsCode());
1617 tForm.getBudgetConstructionDocument().setOrganizationLevelOrganizationCode(budgetConstructionHeader.getOrganizationLevelOrganizationCode());
1618 tForm.getBudgetConstructionDocument().setBudgetLockUserIdentifier(budgetConstructionHeader.getBudgetLockUserIdentifier());
1619
1620 // refresh organization - so UI shows new level description
1621 tForm.getBudgetConstructionDocument().refreshReferenceObject("organizationLevelOrganization");
1622
1623 this.initAuthorization(tForm);
1624
1625 // if before push, system is 'not system view only' goes to 'system view only' after push
1626 // need to manually remove the system view only editingMode here to allow the user to save work if still full_entry
1627 if (tForm.isEditAllowed()) {
1628 if (tForm.isSystemViewOnly() && !prePushSystemViewOnly) {
1629 tForm.getEditingMode().remove(BCConstants.EditModes.SYSTEM_VIEW_ONLY);
1630 }
1631 }
1632
1633 }
1634
1635 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1636 }
1637
1638 /**
1639 * Checks whether the current user would have access for the given budget document for the given organization level code
1640 *
1641 * @param document current bc document
1642 * @param orgLevelCode organization level code for access check
1643 * @param user user to check access for
1644 * @return true if user would have edit permission, false otherwise
1645 */
1646 protected boolean hasEditPermission(BudgetConstructionDocument document, String orgLevelCode, Person user) {
1647 TransactionalDocumentAuthorizer documentAuthorizer = (TransactionalDocumentAuthorizer) SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(document);
1648
1649 AttributeSet roleQualifiers = new AttributeSet();
1650 roleQualifiers.put(BCPropertyConstants.ORGANIZATION_LEVEL_CODE, orgLevelCode);
1651
1652 List<BudgetConstructionAccountOrganizationHierarchy> accountOrganizationHierarchy = (List<BudgetConstructionAccountOrganizationHierarchy>) SpringContext.getBean(BudgetDocumentService.class).retrieveOrBuildAccountOrganizationHierarchy(document.getUniversityFiscalYear(), document.getChartOfAccountsCode(), document.getAccountNumber());
1653 for (BudgetConstructionAccountOrganizationHierarchy accountOrganization : accountOrganizationHierarchy) {
1654 if (accountOrganization.getOrganizationLevelCode().intValue() == Integer.parseInt(orgLevelCode)) {
1655 roleQualifiers.put(BCPropertyConstants.ORGANIZATION_CHART_OF_ACCOUNTS_CODE, accountOrganization.getOrganizationChartOfAccountsCode());
1656 roleQualifiers.put(KfsKimAttributes.ORGANIZATION_CODE, accountOrganization.getOrganizationCode());
1657 }
1658 }
1659
1660 return documentAuthorizer.isAuthorizedByTemplate(document, KNSConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId(), null, roleQualifiers);
1661 }
1662
1663 public ActionForward performReportDump(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1664
1665 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1666 BudgetConstructionDocument bcDocument = tForm.getBudgetConstructionDocument();
1667
1668 // when we return from the lookup, our next request's method to call is going to be refresh
1669 tForm.registerEditableProperty(KNSConstants.DISPATCH_REQUEST_PARAMETER);
1670
1671 if (tForm.isEditAllowed() && !tForm.isSystemViewOnly()) {
1672 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
1673
1674 budgetDocumentService.saveDocumentNoWorkflow(bcDocument);
1675 budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
1676 tForm.initializePersistedRequestAmounts();
1677
1678 // repop and refresh refs - esp monthly so jsp can properly display state
1679 // tForm.populatePBGLLines();
1680 }
1681
1682 // gets here if rules passed and doc detail gets persisted and refreshed
1683 String basePath = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.APPLICATION_URL_KEY);
1684 Properties parameters = new Properties();
1685 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, BCConstants.MONTHLY_BUDGET_METHOD);
1686 parameters.put(KFSConstants.BACK_LOCATION, basePath + mapping.getPath() + ".do");
1687 parameters.put("documentNumber", tForm.getDocument().getDocumentNumber());
1688 parameters.put("universityFiscalYear", tForm.getUniversityFiscalYear().toString());
1689 parameters.put("chartOfAccountsCode", tForm.getChartOfAccountsCode());
1690 parameters.put("accountNumber", tForm.getAccountNumber());
1691 parameters.put("subAccountNumber", tForm.getSubAccountNumber());
1692 parameters.put(BCPropertyConstants.MAIN_WINDOW, (tForm.isMainWindow() ? "true" : "false"));
1693
1694 // anchor, if it exists
1695 if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
1696 parameters.put(BCConstants.RETURN_ANCHOR, ((KualiForm) form).getAnchor());
1697 }
1698
1699 // the form object is retrieved and removed upon return by KualiRequestProcessor.processActionForm()
1700 parameters.put(BCConstants.RETURN_FORM_KEY, GlobalVariables.getUserSession().addObject(form, BCConstants.FORMKEY_PREFIX));
1701
1702 String lookupUrl = UrlFactory.parameterizeUrl(basePath + "/" + BCConstants.REPORT_RUNNER_ACTION, parameters);
1703 this.setupDocumentExit();
1704 return new ActionForward(lookupUrl, true);
1705 }
1706
1707 public ActionForward performPercentChange(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1708
1709 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1710 GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_MESSAGES, KFSKeyConstants.ERROR_UNIMPLEMENTED, "Percent Change");
1711
1712 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1713 }
1714
1715 public ActionForward performRevMonthSpread(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1716 return this.performMonthSpread(mapping, form, request, response, true);
1717 }
1718
1719 public ActionForward performExpMonthSpread(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1720 return this.performMonthSpread(mapping, form, request, response, false);
1721 }
1722
1723 public ActionForward performMonthSpread(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, boolean isRevenue) throws Exception {
1724
1725 // no check for full_entry and system edit mode since this control is not displayed for this case
1726
1727 // need to validate, save and calc benefits first
1728 // this is different than client/server model - need to always keep DB consistent
1729 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1730 BudgetConstructionDocument bcDocument = tForm.getBudgetConstructionDocument();
1731
1732 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
1733
1734 // validate and save without checking monthly RI since the spread will keep things consistent
1735 if (isRevenue) {
1736 budgetDocumentService.saveDocumentNoWorkFlow(bcDocument, MonthSpreadDeleteType.REVENUE, false);
1737 }
1738 else {
1739 budgetDocumentService.saveDocumentNoWorkFlow(bcDocument, MonthSpreadDeleteType.EXPENDITURE, false);
1740 }
1741 tForm.initializePersistedRequestAmounts();
1742 // budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
1743
1744 BudgetConstructionMonthlyBudgetsCreateDeleteService monthlyBudgetService = SpringContext.getBean(BudgetConstructionMonthlyBudgetsCreateDeleteService.class);
1745
1746 if (isRevenue) {
1747 monthlyBudgetService.spreadBudgetConstructionMonthlyBudgetsRevenue(bcDocument.getDocumentNumber(), bcDocument.getUniversityFiscalYear(), bcDocument.getChartOfAccountsCode(), bcDocument.getAccountNumber(), bcDocument.getSubAccountNumber());
1748 }
1749 else {
1750 // service returns true if benefit eligible monthly lines exist
1751 if (monthlyBudgetService.spreadBudgetConstructionMonthlyBudgetsExpenditure(bcDocument.getDocumentNumber(), bcDocument.getUniversityFiscalYear(), bcDocument.getChartOfAccountsCode(), bcDocument.getAccountNumber(), bcDocument.getSubAccountNumber())) {
1752 bcDocument.setMonthlyBenefitsCalcNeeded(true);
1753 // budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
1754 }
1755 }
1756 budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
1757
1758 // repop and refresh refs - esp monthly so jsp can properly display state
1759 tForm.populatePBGLLines();
1760
1761 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1762 }
1763
1764 public ActionForward performRevMonthDelete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1765 return this.performMonthDelete(mapping, form, request, response, true);
1766 }
1767
1768 public ActionForward performExpMonthDelete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1769 return this.performMonthDelete(mapping, form, request, response, false);
1770 }
1771
1772 public ActionForward performMonthDelete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, boolean isRevenue) throws Exception {
1773
1774 // no check for full_entry and system edit mode since this control is not displayed for this case
1775
1776 // need to validate, save and calc benefits first
1777 // this is different than client/server model - need to always keep DB consistent
1778 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1779 BudgetConstructionDocument bcDocument = tForm.getBudgetConstructionDocument();
1780
1781 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
1782
1783 // validate and save without checking monthly RI since the delete will make RI check moot
1784 if (isRevenue) {
1785 budgetDocumentService.saveDocumentNoWorkFlow(bcDocument, MonthSpreadDeleteType.REVENUE, false);
1786 }
1787 else {
1788 budgetDocumentService.saveDocumentNoWorkFlow(bcDocument, MonthSpreadDeleteType.EXPENDITURE, false);
1789 }
1790 tForm.initializePersistedRequestAmounts();
1791 // budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
1792
1793 BudgetConstructionMonthlyBudgetsCreateDeleteService monthlyBudgetService = SpringContext.getBean(BudgetConstructionMonthlyBudgetsCreateDeleteService.class);
1794
1795 if (isRevenue) {
1796 monthlyBudgetService.deleteBudgetConstructionMonthlyBudgetsRevenue(bcDocument.getDocumentNumber(), bcDocument.getUniversityFiscalYear(), bcDocument.getChartOfAccountsCode(), bcDocument.getAccountNumber(), bcDocument.getSubAccountNumber());
1797 }
1798 else {
1799 monthlyBudgetService.deleteBudgetConstructionMonthlyBudgetsExpenditure(bcDocument.getDocumentNumber(), bcDocument.getUniversityFiscalYear(), bcDocument.getChartOfAccountsCode(), bcDocument.getAccountNumber(), bcDocument.getSubAccountNumber());
1800 }
1801 budgetDocumentService.calculateBenefitsIfNeeded(bcDocument);
1802
1803 // repop and refresh refs - esp monthly so jsp can properly display state
1804 tForm.populatePBGLLines();
1805
1806 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1807 }
1808
1809 public ActionForward performCalculateBenefits(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
1810
1811 // no check for full_entry and system edit mode since this control is not displayed for this case
1812 BudgetConstructionForm tForm = (BudgetConstructionForm) form;
1813 BudgetConstructionDocument bcDocument = (BudgetConstructionDocument) tForm.getDocument();
1814
1815 // allow benecalc if account is not salary only and benefits calc not disabled
1816 if (!tForm.isBenefitsCalculationDisabled() && !bcDocument.isSalarySettingOnly()) {
1817 BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
1818
1819 budgetDocumentService.saveDocumentNoWorkflow(bcDocument);
1820 tForm.initializePersistedRequestAmounts();
1821 budgetDocumentService.calculateBenefits(bcDocument);
1822
1823 // repop and refresh refs - esp monthly so jsp can properly display state
1824 // tForm.populatePBGLLines();
1825
1826 }
1827
1828 return mapping.findForward(KFSConstants.MAPPING_BASIC);
1829 }
1830
1831 protected void adjustRequest(PendingBudgetConstructionGeneralLedger pbglLine) {
1832
1833 KualiInteger baseAmount = pbglLine.getFinancialBeginningBalanceLineAmount();
1834 if (baseAmount.isNonZero()) {
1835 KualiDecimal percent = pbglLine.getAdjustmentAmount();
1836 BigDecimal adjustedAmount = baseAmount.multiply(percent).divide(KFSConstants.ONE_HUNDRED);
1837
1838 KualiInteger requestAmount = new KualiInteger(adjustedAmount).add(baseAmount);
1839 pbglLine.setAccountLineAnnualBalanceAmount(requestAmount);
1840 }
1841
1842 }
1843 }