/*
* 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.fp.document.web.struts;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
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.fp.businessobject.ProcurementCardTargetAccountingLine;
import org.kuali.kfs.fp.businessobject.ProcurementCardTransactionDetail;
import org.kuali.kfs.fp.document.ProcurementCardDocument;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSKeyConstants;
import org.kuali.kfs.sys.businessobject.AccountingLine;
import org.kuali.kfs.sys.businessobject.AccountingLineParser;
import org.kuali.kfs.sys.businessobject.TargetAccountingLine;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.document.AccountingDocument;
import org.kuali.kfs.sys.document.validation.event.AddAccountingLineEvent;
import org.kuali.kfs.sys.document.validation.event.DeleteAccountingLineEvent;
import org.kuali.kfs.sys.exception.AccountingLineParserException;
import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase;
import org.kuali.rice.kew.api.exception.WorkflowException;
import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
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.KRADConstants;
/**
* This class handles specific Actions requests for the ProcurementCard.
*/
public class ProcurementCardAction extends CapitalAccountingLinesActionBase {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ProcurementCardAction.class);
@Override
protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
super.loadDocument(kualiDocumentFormBase);
ProcurementCardDocument procureCardDocument = (ProcurementCardDocument)kualiDocumentFormBase.getDocument();
int transactionsCount = procureCardDocument.getTransactionEntries().size();
ProcurementCardForm procurementCardForm = (ProcurementCardForm)kualiDocumentFormBase;
procurementCardForm.buildNewTargetAccountingLines(transactionsCount);
}
/**
* Override to accomodate multiple target lines.
*
* @param transForm
*/
@Override
protected void processAccountingLineOverrides(KualiAccountingDocumentFormBase transForm) {
ProcurementCardForm procurementCardForm = (ProcurementCardForm) transForm;
processAccountingLineOverrides(procurementCardForm.getNewSourceLine());
processAccountingLineOverrides(procurementCardForm.getNewTargetLines());
if (procurementCardForm.hasDocumentId()) {
AccountingDocument financialDocument = (AccountingDocument) procurementCardForm.getDocument();
processAccountingLineOverrides(financialDocument.getSourceAccountingLines());
processAccountingLineOverrides(financialDocument.getTargetAccountingLines());
}
}
/**
* Override to add the new accounting line to the correct transaction
*
* @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#insertTargetLine(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward insertTargetLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
ProcurementCardForm procurementCardForm = (ProcurementCardForm) form;
ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) procurementCardForm.getDocument();
int targetContainerIndex = this.getSelectedContainer(request);
ProcurementCardTargetAccountingLine line = (ProcurementCardTargetAccountingLine)procurementCardForm.getNewTargetLines().get(targetContainerIndex);
ProcurementCardTransactionDetail transactionDetail = (ProcurementCardTransactionDetail) procurementCardDocument.getTransactionEntries().get(targetContainerIndex);
line.setFinancialDocumentTransactionLineNumber(transactionDetail.getFinancialDocumentTransactionLineNumber());
// check any business rules
boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(KFSConstants.NEW_TARGET_ACCT_LINES_PROPERTY_NAME + "[" + Integer.toString(targetContainerIndex) + "]", procurementCardForm.getDocument(), line));
if (rulePassed) {
// add accountingLine
SpringContext.getBean(PersistenceService.class).retrieveNonKeyFields(line);
insertAccountingLine(false, procurementCardForm, line);
ProcurementCardTargetAccountingLine newLine = new ProcurementCardTargetAccountingLine();
newLine.setTransactionContainerIndex(targetContainerIndex);
procurementCardForm.getNewTargetLines().set(targetContainerIndex, newLine);
}
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#performBalanceInquiryForTargetLine(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward performBalanceInquiryForTargetLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
ProcurementCardForm procurementCardForm = (ProcurementCardForm) form;
ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) procurementCardForm.getDocument();
int targetContainerIndex = this.getSelectedContainer(request);
ProcurementCardTransactionDetail ProcurementCardTransactionDetail = (ProcurementCardTransactionDetail) procurementCardDocument.getTransactionEntries().get(targetContainerIndex);
int targetIndex = super.getSelectedLine(request);
TargetAccountingLine targetLine = (ProcurementCardTargetAccountingLine) ProcurementCardTransactionDetail.getTargetAccountingLines().get(targetIndex);
return performBalanceInquiryForAccountingLine(mapping, form, request, targetLine);
}
/**
* Override to resync base accounting lines. New lines on the PCDO document can be inserted anywhere in the list, not necessary
* at the end.
*
* @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#insertAccountingLine(boolean,
* org.kuali.module.financial.web.struts.form.KualiFinancialDocumentFormBase, org.kuali.rice.krad.bo.AccountingLine)
*/
@Override
protected void insertAccountingLine(boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, AccountingLine line) {
AccountingDocument tdoc = financialDocumentForm.getFinancialDocument();
// add it to the document
tdoc.addTargetAccountingLine((TargetAccountingLine) line);
}
/**
* Override to get the correct container of the transaction and then delete the correct accounting line
*
* @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#deleteTargetLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response
*/
@Override
public ActionForward deleteTargetLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
int targetContainerIndex = this.getSelectedContainer(request);
int targetIndex = this.getSelectedLine(request);
KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
String errorPath = KFSConstants.DOCUMENT_PROPERTY_NAME + "." + KFSConstants.EXISTING_TARGET_ACCT_LINE_PROPERTY_NAME + "[" + targetIndex + "]";
boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new DeleteAccountingLineEvent(errorPath, financialDocumentForm.getDocument(), ((AccountingDocument) financialDocumentForm.getDocument()).getTargetAccountingLine(targetIndex), false));
// if the rule evaluation passed, let's delete it
if (rulePassed) {
deleteAccountingLineFromTransactionContainer(financialDocumentForm, targetContainerIndex, targetIndex);
}
else {
String[] errorParams = new String[] { "target", Integer.toString(targetIndex + 1) };
GlobalVariables.getMessageMap().putError(errorPath, KFSKeyConstants.ERROR_ACCOUNTINGLINE_DELETERULE_INVALIDACCOUNT, errorParams);
}
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* Override to remove the accounting line from the correct transaction
*
* @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#deleteAccountingLine(boolean,
* org.kuali.module.financial.web.struts.form.KualiFinancialDocumentFormBase, int)
*/
@Override
protected void deleteAccountingLine(boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, int deleteIndex) {
ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) financialDocumentForm.getDocument();
procurementCardDocument.removeTargetAccountingLine(deleteIndex);
}
/**
* Ensures that ProcurementCardForm.newTargetLines is cleared. Otherwise works like super.reload.
*
* @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#reload(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward reload(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
ProcurementCardForm procurementCardForm = (ProcurementCardForm) form;
procurementCardForm.setNewTargetLines(new ArrayList<ProcurementCardTargetAccountingLine>());
return super.reload(mapping, procurementCardForm, request, response);
}
// get the index of selected transaction entry
protected int getSelectedContainer(HttpServletRequest request) {
int selectedContainer = -1;
String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
if (StringUtils.isNotBlank(parameterName)) {
String lineNumber = StringUtils.substringBetween(parameterName, ".transactionEntries[", "].");
selectedContainer = Integer.parseInt(lineNumber);
}
return selectedContainer;
}
/**
* Removes the target accounting line at the given index from the transaction container transaction entries.
*
* @param financialDocumentForm, targetContainerIndex, targetIndex
*/
protected void deleteAccountingLineFromTransactionContainer(KualiAccountingDocumentFormBase financialDocumentForm, int targetContainerIndex, int targetIndex) {
ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) financialDocumentForm.getDocument();
ProcurementCardTransactionDetail procurementCardTransactionDetail = (ProcurementCardTransactionDetail) procurementCardDocument.getTransactionEntries().get(targetContainerIndex);
procurementCardTransactionDetail.getTargetAccountingLines().remove(targetIndex);
}
/**
*
* @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#uploadTargetLines(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward uploadTargetLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
ProcurementCardForm procurementCardForm = (ProcurementCardForm) form;
ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) procurementCardForm.getDocument();
// get index of transaction line
int tranasactionIndex = getTransactionLineIndex(request);
uploadTargetAccountingLines(form, tranasactionIndex);
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* This method handles retrieving the actual upload file as an input stream into the document.
*
* @param isSource
* @param form
* @throws FileNotFoundException
* @throws IOException
*/
protected void uploadTargetAccountingLines(ActionForm form, int tranasactionIndex) throws FileNotFoundException, IOException {
ProcurementCardForm pcardForm = (ProcurementCardForm) form;
List importedLines = null;
ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) pcardForm.getFinancialDocument();
ProcurementCardTransactionDetail transactionDetail = (ProcurementCardTransactionDetail) procurementCardDocument.getTransactionEntries().get(tranasactionIndex);
AccountingLineParser accountingLineParser = procurementCardDocument.getAccountingLineParser();
// import the lines
String errorPathPrefix = null;
try {
errorPathPrefix = KFSConstants.DOCUMENT_PROPERTY_NAME + "." + KFSConstants.TARGET_ACCOUNTING_LINE_ERRORS;
// get the import file
FormFile targetFile = ((ProcurementCardTransactionDetail) (procurementCardDocument.getTransactionEntries().get(tranasactionIndex))).getTargetFile();
checkUploadFile(targetFile);
importedLines = accountingLineParser.importTargetAccountingLines(targetFile.getFileName(), targetFile.getInputStream(), procurementCardDocument);
}
catch (AccountingLineParserException e) {
GlobalVariables.getMessageMap().putError(errorPathPrefix, e.getErrorKey(), e.getErrorParameters());
}
// add line to list for those lines which were successfully imported
if (importedLines != null) {
for (Iterator i = importedLines.iterator(); i.hasNext();) {
ProcurementCardTargetAccountingLine importedLine = (ProcurementCardTargetAccountingLine) i.next();
importedLine.setFinancialDocumentTransactionLineNumber(transactionDetail.getFinancialDocumentTransactionLineNumber());
super.insertAccountingLine(false, pcardForm, importedLine);
}
}
}
/**
* Parses the method to call attribute to pick off the transaction line number which should have an action performed
* on it.
*
* @param request
* @return
*/
protected int getTransactionLineIndex(HttpServletRequest request) {
int selectedLine = -1;
String parameterName = (String) request.getAttribute(KFSConstants.METHOD_TO_CALL_ATTRIBUTE);
if (StringUtils.isNotBlank(parameterName)) {
String lineNumber = StringUtils.substringBetween(parameterName, "document.transactionEntries[", "]");
selectedLine = Integer.parseInt(lineNumber);
}
return selectedLine;
}
}