/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.module.purap.document.web.struts;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
import org.kuali.kfs.module.purap.PurapConstants;
import org.kuali.kfs.module.purap.PurapPropertyConstants;
import org.kuali.kfs.module.purap.businessobject.PurApAccountingLine;
import org.kuali.kfs.module.purap.businessobject.PurApAccountingLineParser;
import org.kuali.kfs.module.purap.businessobject.PurApItem;
import org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument;
import org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase;
import org.kuali.kfs.module.purap.document.service.PurapService;
import org.kuali.kfs.module.purap.service.PurapAccountingService;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.businessobject.AccountingLine;
import org.kuali.kfs.sys.businessobject.SourceAccountingLine;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.document.validation.event.AddAccountingLineEvent;
import org.kuali.kfs.sys.exception.AccountingLineParserException;
import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase;
import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase;
import org.kuali.rice.core.api.util.RiceConstants;
import org.kuali.rice.kew.api.WorkflowDocument;
import org.kuali.rice.kew.api.exception.WorkflowException;
import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
import org.kuali.rice.kns.web.struts.form.KualiForm;
import org.kuali.rice.kns.web.struts.form.KualiTransactionalDocumentFormBase;
import org.kuali.rice.krad.document.Document;
import org.kuali.rice.krad.service.DocumentService;
import org.kuali.rice.krad.service.KualiRuleService;
import org.kuali.rice.krad.service.PersistenceService;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.ObjectUtils;
/**
* Struts Action for Purchasing and Accounts Payable documents
*/
public class PurchasingAccountsPayableActionBase extends KualiAccountingDocumentActionBase {
/**
* @see org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase#copy(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward copy(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
ActionForward actionForward = super.copy(mapping, form, request, response);
KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
PurchasingAccountsPayableDocument purapDocument = (PurchasingAccountsPayableDocument) kualiDocumentFormBase.getDocument();
//refresh accounts in each item....
List<PurApItem> items = purapDocument.getItems();
for (PurApItem item : items) {
//set default sequence number.
for (PurApAccountingLine account : item.getSourceAccountingLines()) {
account.setSequenceNumber(0);
}
}
return actionForward;
}
/**
* @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
*/
@Override
protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
super.loadDocument(kualiDocumentFormBase);
PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) kualiDocumentFormBase;
PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) purapForm.getDocument();
// refresh the account summary (note this also updates the account amounts)
purapForm.refreshAccountSummmary();
for (org.kuali.rice.krad.bo.Note note : (java.util.List<org.kuali.rice.krad.bo.Note>) document.getNotes()) {
note.refreshReferenceObject("attachment");
}
// sort the below the line
SpringContext.getBean(PurapService.class).sortBelowTheLine(document);
updateBaseline(document, (PurchasingAccountsPayableFormBase) kualiDocumentFormBase);
}
/**
* Updates the baseline accounts on form and doc.
*
* @param document A descendant of PurchasingAccountsPayableDocument
*/
protected <T extends PurchasingAccountsPayableDocument, V extends KualiAccountingDocumentFormBase> void updateBaseline(T document, V form) {
// clear out the old lines first
for (PurApItem item : document.getItems()) {
// clear out the old lines first
item.getBaselineSourceAccountingLines().clear();
for (PurApAccountingLine sourceAccount : item.getSourceAccountingLines()) {
// JHK: KFSMI-287 - removed deep copy since this object will be thrown away after the page renders, we just need a
// different path to have them stored on the form
// ESPECIALLY since PURAP does not allow lines to be reverted (see calls to setRevertible)
item.getBaselineSourceAccountingLines().add(sourceAccount);
}
}
}
/**
* Invokes a service method to refresh the account summary.
*
* @param mapping An ActionMapping
* @param form An ActionForm
* @param request The HttpServletRequest
* @param response The HttpServletResponse
* @throws Exception
* @return An ActionForward
*/
public ActionForward refreshAccountSummary(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form;
PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) purapForm.getDocument();
SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(document);
purapForm.refreshAccountSummmary();
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#uploadAccountingLines(boolean,org.apache.struts.action.ActionForm)
*/
@Override
protected void uploadAccountingLines(boolean isSource, ActionForm form) throws FileNotFoundException, IOException {
PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form;
PurchasingAccountsPayableDocumentBase purapDocument = (PurchasingAccountsPayableDocumentBase)purapForm.getFinancialDocument();
PurApAccountingLineParser accountingLineParser = (PurApAccountingLineParser)purapDocument.getAccountingLineParser();
List importedLines = null;
String errorPathPrefix = PurapConstants.ACCOUNT_DISTRIBUTION_ERROR_KEY;
//String errorPathPrefix = "accountDistributionnewSourceLine";
// import the lines
try {
FormFile sourceFile = purapForm.getSourceFile();
checkUploadFile(sourceFile);
GlobalVariables.getMessageMap().clearErrorPath();
GlobalVariables.getMessageMap().addToErrorPath(errorPathPrefix);
importedLines = accountingLineParser.importSourceAccountingLines(sourceFile.getFileName(), sourceFile.getInputStream(), purapDocument);
GlobalVariables.getMessageMap().removeFromErrorPath(errorPathPrefix);
}
catch (AccountingLineParserException e) {
GlobalVariables.getMessageMap().putError(errorPathPrefix, e.getErrorKey(), e.getErrorParameters());
}
// add to list those lines successfully imported
if (importedLines != null) {
for (Iterator iter = importedLines.iterator(); iter.hasNext();) {
PurApAccountingLine importedLine = (PurApAccountingLine) iter.next();
//boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPathPrefix, purapForm.getDocument(), (AccountingLine) importedLine));
//if (rulePassed) {
// add accountingLine
SpringContext.getBean(PersistenceService.class).retrieveNonKeyFields(importedLine);
((PurchasingFormBase)purapForm).addAccountDistributionsourceAccountingLine(importedLine);
//}
}
}
}
/**
* @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#insertSourceLine(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward insertSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
// It would be preferable to find a way to genericize the KualiAccountingDocument methods but this will work for now
PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form;
// index of item selected
int itemIndex = getSelectedLine(request);
PurApItem item = null;
// if custom processing of an accounting line is not done then insert a line generically.
if (processCustomInsertAccountingLine(purapForm, request) == false) {
String errorPrefix = null;
PurApAccountingLine line = null;
boolean rulePassed = false;
if (itemIndex >= 0) {
item = (PurApItem) ((PurchasingAccountsPayableDocument) purapForm.getDocument()).getItem((itemIndex));
line = (PurApAccountingLine) ObjectUtils.deepCopy(item.getNewSourceLine());
//SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line);
errorPrefix = KFSPropertyConstants.DOCUMENT + "." + PurapPropertyConstants.ITEM + "[" + Integer.toString(itemIndex) + "]." + KFSConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME;
rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPrefix, purapForm.getDocument(), (AccountingLine) line));
}
else if (itemIndex == -2){
//corrected: itemIndex == -2 is the only case for distribute account
//This is the case when we're inserting an accounting line for distribute account.
line = ((PurchasingFormBase)purapForm).getAccountDistributionnewSourceLine();
//SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line);
errorPrefix = PurapPropertyConstants.ACCOUNT_DISTRIBUTION_NEW_SRC_LINE;
rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPrefix, purapForm.getDocument(), (AccountingLine) line));
}
if (rulePassed) {
// add accountingLine
SpringContext.getBean(PersistenceService.class).retrieveNonKeyFields(line);
if (itemIndex >=0) {
insertAccountingLine(purapForm, item, line);
// clear the temp account
item.resetAccount();
}
else if (itemIndex == -2) {
//this is the case for distribute account
((PurchasingFormBase)purapForm).addAccountDistributionsourceAccountingLine(line);
}
}
}
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* Insert the given Accounting Line in several appropriate places in the given item and given form.
*
* @param financialDocumentForm A form that inherits from PurchasingAccountsPaybleFormBase
* @param item A PurApItem
* @param line A PurApAccountingLine
*/
protected void insertAccountingLine(PurchasingAccountsPayableFormBase financialDocumentForm, PurApItem item, PurApAccountingLine line) {
PurchasingAccountsPayableDocument preq = (PurchasingAccountsPayableDocument) financialDocumentForm.getDocument();
Integer index = item.getSourceAccountingLines().size() + 1;
line.setSequenceNumber(index);
// add it to the item
item.getSourceAccountingLines().add(line);
}
/**
* Allows the custom processing of an accounting line during a call to insert source line. If a custom method for inserting an
* accounting line was performed, then a value of true must be returned.
*
* @param purapForm
* @param request
* @return boolean indicating if validation succeeded
*/
public boolean processCustomInsertAccountingLine(PurchasingAccountsPayableFormBase purapForm, HttpServletRequest request) {
return false;
}
/**
* Insert the given Accounting Line in several appropriate places in the given item and given form.
*
* @param financialDocumentForm A form that inherits from KualiAccountingDocumentFormBase
* @param item A PurApItem
* @param line A PurApAccountingLine
*/
protected void insertAccountingLine(KualiAccountingDocumentFormBase financialDocumentForm, PurApItem item, PurApAccountingLine line) {
// add it to the item
item.getSourceAccountingLines().add(line);
}
/**
* @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#deleteSourceLine(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward deleteSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form;
String[] indexes = getSelectedLineForAccounts(request);
int itemIndex = Integer.parseInt(indexes[0]);
int accountIndex = Integer.parseInt(indexes[1]);
PurApItem item = (PurApItem) ((PurchasingAccountsPayableDocument) purapForm.getDocument()).getItem((itemIndex));
item.getSourceAccountingLines().remove(accountIndex);
// remove the decorator
// financialDocumentForm.getSourceLineDecorators().remove(decorator);
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#getSourceAccountingLine(org.apache.struts.action.ActionForm,
* javax.servlet.http.HttpServletRequest)
*/
@Override
public SourceAccountingLine getSourceAccountingLine(ActionForm form, HttpServletRequest request) {
String[] indexes = getSelectedLineForAccounts(request);
int itemIndex = Integer.parseInt(indexes[0]);
int accountIndex = Integer.parseInt(indexes[1]);
PurchasingAccountsPayableFormBase purchasingAccountsPayableForm = (PurchasingAccountsPayableFormBase) form;
SourceAccountingLine line;
if (itemIndex == -2) {
line = customAccountRetrieval(accountIndex, purchasingAccountsPayableForm);
}
else {
PurApItem item = (PurApItem) ((PurchasingAccountsPayableDocument) purchasingAccountsPayableForm.getDocument()).getItem((itemIndex));
line = (SourceAccountingLine) ObjectUtils.deepCopy(item.getSourceAccountingLines().get(accountIndex));
}
return line;
}
/**
* Perform custom processing on accounting lines. See <code>getSelectedLineForAccounts</code>.
*
* @param accountIndex The index of the account into the request parameter
* @param purchasingAccountsPayableForm A form which inherits from PurchasingAccountsPayableFormBase
* @return A SourceAccountingLine
*/
protected SourceAccountingLine customAccountRetrieval(int accountIndex, PurchasingAccountsPayableFormBase purchasingAccountsPayableForm) {
// default impl returns null
return null;
}
/**
* Will return an array of Strings containing 2 indexes, the first String is the item index and the second String is the account
* index. These are obtained by parsing the method to call parameter from the request, between the word ".line" and "." The
* indexes are separated by a semicolon (:)
*
* @param request The HttpServletRequest
* @return An array of Strings containing pairs of two indices, an item index and a account index
*/
protected String[] getSelectedLineForAccounts(HttpServletRequest request) {
String accountString = new String();
String parameterName = (String) request.getAttribute(KFSConstants.METHOD_TO_CALL_ATTRIBUTE);
if (StringUtils.isNotBlank(parameterName)) {
accountString = StringUtils.substringBetween(parameterName, ".line", ".");
}
String[] result = StringUtils.split(accountString, ":");
return result;
}
/**
* @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#downloadBOAttachment(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward downloadBOAttachment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) ((PurchasingAccountsPayableFormBase) form).getDocument();
for (org.kuali.rice.krad.bo.Note note : (java.util.List<org.kuali.rice.krad.bo.Note>) document.getNotes()) {
note.refreshReferenceObject("attachment");
}
return super.downloadBOAttachment(mapping, form, request, response);
}
@Override
protected void processAccountingLineOverrides(List accountingLines) {
//do nothing purap handles these differently
}
/**
* Perform calculation on item line.
*
* @param mapping An ActionMapping
* @param form An ActionForm
* @param request The HttpServletRequest
* @param response The HttpServletResponse
* @return An ActionForward
*/
public ActionForward calculate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
public ActionForward clearAllTaxes(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
protected void customCalculate(PurchasingAccountsPayableDocument purapDoc) {
// do nothing by default
}
/**
* Toggles all specific tabs to open
*
* @param mapping
* @param form
* @param request
* @param response
* @return
* @throws Exception
*/
public ActionForward showAllAccounts(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
KualiForm kualiForm = (KualiForm) form;
String accountingLineTab = "AccountingLines";
String value = null;
Map<String, String> tabStates = kualiForm.getTabStates();
Map<String, String> newTabStates = new HashMap<String, String>();
for (Entry<String, String> tabEntry: tabStates.entrySet()) {
if(tabEntry.getKey().startsWith(accountingLineTab)){
newTabStates.put(tabEntry.getKey(), "OPEN");
}else{
if (tabEntry.getValue() instanceof String) {
value = tabEntry.getValue();
}
else {
//This is the case where the value is an Array of String,
//so we'll have to get the first element
Object result = tabEntry.getValue();
result.getClass();
value = ((String[])result)[0];
}
newTabStates.put(tabEntry.getKey(), value);
}
}
kualiForm.setTabStates(newTabStates);
return mapping.findForward(RiceConstants.MAPPING_BASIC);
}
/**
* Toggles all specific tabs to closed
*
* @param mapping
* @param form
* @param request
* @param response
* @return
* @throws Exception
*/
public ActionForward hideAllAccounts(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
KualiForm kualiForm = (KualiForm) form;
String accountingLineTab = "AccountingLines";
String value = null;
Map<String, String> tabStates = kualiForm.getTabStates();
Map<String, String> newTabStates = new HashMap<String, String>();
for (Entry<String, String> tabEntry: tabStates.entrySet()) {
if(tabEntry.getKey().startsWith(accountingLineTab)){
newTabStates.put(tabEntry.getKey(), "CLOSE");
}else{
if (tabEntry.getValue() instanceof String) {
value = tabEntry.getValue();
}
else {
//This is the case where the value is an Array of String,
//so we'll have to get the first element
Object result = tabEntry.getValue();
result.getClass();
value = ((String[])result)[0];
}
newTabStates.put(tabEntry.getKey(), value);
}
}
kualiForm.setTabStates(newTabStates);
return mapping.findForward(RiceConstants.MAPPING_BASIC);
}
/**
* Override to verify the document has been saved before the note is inserted. This will assure the correct parent object id is
* associated with the note.
*
* @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#insertBONote(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward insertBONote(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) ((PurchasingAccountsPayableFormBase) form).getDocument();
WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
if (workflowDocument.isInitiated()) {
SpringContext.getBean(DocumentService.class).saveDocument(document);
}
return super.insertBONote(mapping, form, request, response);
}
}