@Override
  public ActionForward approve(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;

    // KFSPTS-1735
    ActionForward forward = super.approve(mapping, form, request, response);

    if (GlobalVariables.getMessageMap().hasNoErrors()) {
      // KFSPTS-1735
      SpringContext.getBean(CUFinancialSystemDocumentService.class)
          .checkAccountingLinesForChanges((AccountingDocument) tmpForm.getFinancialDocument());
      // KFSPTS-1735
    }

    // need to check on sales tax for all the accounting lines
    checkSalesTaxRequiredAllLines(
        tmpForm, tmpForm.getFinancialDocument().getSourceAccountingLines());
    checkSalesTaxRequiredAllLines(
        tmpForm, tmpForm.getFinancialDocument().getTargetAccountingLines());

    return forward;
  }
  /**
   * Adds the given accountingLine to the appropriate form-related data structures.
   *
   * @param isSource
   * @param financialDocumentForm
   * @param line
   */
  protected void insertAccountingLine(
      boolean isSource,
      KualiAccountingDocumentFormBase financialDocumentForm,
      AccountingLine line) {
    AccountingDocument tdoc = financialDocumentForm.getFinancialDocument();
    if (isSource) {
      // add it to the document
      tdoc.addSourceAccountingLine((SourceAccountingLine) line);

      // add PK fields to sales tax if needed
      if (line.isSalesTaxRequired()) {
        populateSalesTax(line);
      }

      // Update the doc total
      if (tdoc instanceof AmountTotaling)
        ((FinancialSystemDocumentHeader) financialDocumentForm.getDocument().getDocumentHeader())
            .setFinancialDocumentTotalAmount(((AmountTotaling) tdoc).getTotalDollarAmount());
    } else {
      // add it to the document
      tdoc.addTargetAccountingLine((TargetAccountingLine) line);

      // add PK fields to sales tax if needed
      if (line.isSalesTaxRequired()) {
        populateSalesTax(line);
      }
    }
  }
  /**
   * Adds check for accountingLine updates, generates and dispatches any events caused by such
   * updates
   *
   * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping,
   *     org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse)
   */
  @Override
  public ActionForward execute(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase transForm = (KualiAccountingDocumentFormBase) form;

    // handle changes to accountingLines
    if (transForm.hasDocumentId()) {
      AccountingDocument financialDocument = (AccountingDocument) transForm.getDocument();

      processAccountingLines(financialDocument, transForm, KFSConstants.SOURCE);
      processAccountingLines(financialDocument, transForm, KFSConstants.TARGET);
    }

    // This is after a potential handleUpdate(), to display automatically cleared overrides
    // following a route or save.
    processAccountingLineOverrides(transForm);

    // proceed as usual
    ActionForward result = super.execute(mapping, form, request, response);
    return result;
  }
 /**
  * This method is triggered when the user toggles the show/hide button to "hide" thus making the
  * UI render without any of the accounting line labels/descriptions showing up underneath the
  * values in the UI.
  *
  * @param mapping
  * @param form
  * @param request
  * @param response
  * @return ActionForward
  * @throws Exception
  */
 public ActionForward hideDetails(
     ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response)
     throws Exception {
   KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;
   tmpForm.setHideDetails(true);
   return mapping.findForward(KFSConstants.MAPPING_BASIC);
 }
  /** @param transForm */
  protected void processAccountingLineOverrides(KualiAccountingDocumentFormBase transForm) {
    processAccountingLineOverrides(transForm.getNewSourceLine());
    processAccountingLineOverrides(transForm.getNewTargetLine());
    if (transForm.hasDocumentId()) {
      AccountingDocument financialDocument = (AccountingDocument) transForm.getDocument();

      processAccountingLineOverrides(
          financialDocument, financialDocument.getSourceAccountingLines());
      processAccountingLineOverrides(
          financialDocument, financialDocument.getTargetAccountingLines());
    }
  }
  /**
   * All document-load operations get routed through here
   *
   * @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);

    KualiAccountingDocumentFormBase tform = (KualiAccountingDocumentFormBase) kualiDocumentFormBase;

    // clear out the new accounting line holders
    tform.setNewSourceLine(null);
    tform.setNewTargetLine(null);

    processAccountingLineOverrides(tform);
  }
  /**
   * Deletes the source or target accountingLine with the given index from the given form. Assumes
   * that the rule- and form- validation have already occurred.
   *
   * @param isSource
   * @param financialDocumentForm
   * @param deleteIndex
   */
  protected void deleteAccountingLine(
      boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, int deleteIndex) {
    if (isSource) {
      // remove from document
      financialDocumentForm.getFinancialDocument().getSourceAccountingLines().remove(deleteIndex);

    } else {
      // remove from document
      financialDocumentForm.getFinancialDocument().getTargetAccountingLines().remove(deleteIndex);
    }
    // update the doc total
    AccountingDocument tdoc = (AccountingDocument) financialDocumentForm.getDocument();
    if (tdoc instanceof AmountTotaling) {
      ((FinancialSystemDocumentHeader) financialDocumentForm.getDocument().getDocumentHeader())
          .setFinancialDocumentTotalAmount(((AmountTotaling) tdoc).getTotalDollarAmount());
    }
  }
  /**
   * This method refreshes the sales tax fields on a refresh or tab toggle so that all the
   * information that was there before is still there after a state change
   *
   * @param form
   */
  protected void refreshSalesTaxInfo(ActionForm form) {
    KualiAccountingDocumentFormBase accountingForm = (KualiAccountingDocumentFormBase) form;
    AccountingDocument document = (AccountingDocument) accountingForm.getDocument();
    List sourceLines = document.getSourceAccountingLines();
    List targetLines = document.getTargetAccountingLines();
    handleSalesTaxRequiredAllLines(accountingForm, sourceLines);
    handleSalesTaxRequiredAllLines(accountingForm, targetLines);

    AccountingLine newTargetLine = accountingForm.getNewTargetLine();
    AccountingLine newSourceLine = accountingForm.getNewSourceLine();
    if (newTargetLine != null) {
      handleSalesTaxRequired(document, newTargetLine, false, true, 0);
    }
    if (newSourceLine != null) {
      handleSalesTaxRequired(document, newSourceLine, true, true, 0);
    }
  }
  @Override
  public ActionForward blanketApprove(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;

    checkSalesTaxRequiredAllLines(
        tmpForm, tmpForm.getFinancialDocument().getSourceAccountingLines());
    checkSalesTaxRequiredAllLines(
        tmpForm, tmpForm.getFinancialDocument().getTargetAccountingLines());

    ActionForward forward = super.blanketApprove(mapping, form, request, response);

    return forward;
  }
  /**
   * This method will add a TargetAccountingLine to a FinancialDocument. This assumes that the user
   * presses the add button for a specific accounting line on the document and that the document is
   * represented by a FinancialDocumentFormBase. It first validates the line for data integrity and
   * then checks appropriate business rules.
   *
   * @param mapping
   * @param form
   * @param request
   * @param response
   * @return ActionForward
   * @throws Exception
   */
  public ActionForward insertTargetLine(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
    TargetAccountingLine line = financialDocumentForm.getNewTargetLine();

    // populate chartOfAccountsCode from account number if accounts cant cross chart and Javascript
    // is turned off
    // SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line);

    boolean rulePassed = true;
    // before we check the regular rules we need to check the sales tax rules
    // TODO: Refactor rules so we no longer have to call this before a copy of the
    // accountingLine
    rulePassed &=
        checkSalesTax(
            (AccountingDocument) financialDocumentForm.getDocument(), line, false, true, 0);

    // check any business rules
    rulePassed &=
        SpringContext.getBean(KualiRuleService.class)
            .applyRules(
                new AddAccountingLineEvent(
                    KFSConstants.NEW_TARGET_ACCT_LINE_PROPERTY_NAME,
                    financialDocumentForm.getDocument(),
                    line));

    // if the rule evaluation passed, let's add it
    if (rulePassed) {
      // add accountingLine
      SpringContext.getBean(PersistenceService.class).refreshAllNonUpdatingReferences(line);
      insertAccountingLine(false, financialDocumentForm, line);

      // clear the used newTargetLine
      financialDocumentForm.setNewTargetLine(null);
    }

    return mapping.findForward(KFSConstants.MAPPING_BASIC);
  }
  /**
   * This method determines whether we are uploading source or target lines, and then calls
   * uploadAccountingLines directly on the document object. 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 uploadAccountingLines(boolean isSource, ActionForm form)
      throws FileNotFoundException, IOException {
    KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;

    List importedLines = null;

    AccountingDocument financialDocument = tmpForm.getFinancialDocument();
    AccountingLineParser accountingLineParser = financialDocument.getAccountingLineParser();

    // import the lines
    String errorPathPrefix = null;
    try {
      if (isSource) {
        errorPathPrefix =
            KFSConstants.DOCUMENT_PROPERTY_NAME + "." + KFSConstants.SOURCE_ACCOUNTING_LINE_ERRORS;
        FormFile sourceFile = tmpForm.getSourceFile();
        checkUploadFile(sourceFile);
        importedLines =
            accountingLineParser.importSourceAccountingLines(
                sourceFile.getFileName(), sourceFile.getInputStream(), financialDocument);
      } else {
        errorPathPrefix =
            KFSConstants.DOCUMENT_PROPERTY_NAME + "." + KFSConstants.TARGET_ACCOUNTING_LINE_ERRORS;
        FormFile targetFile = tmpForm.getTargetFile();
        checkUploadFile(targetFile);
        importedLines =
            accountingLineParser.importTargetAccountingLines(
                targetFile.getFileName(), targetFile.getInputStream(), financialDocument);
      }
    } 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(); ) {
        AccountingLine importedLine = (AccountingLine) i.next();
        insertAccountingLine(isSource, tmpForm, importedLine);
      }
    }
  }
  @Override
  public ActionForward save(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;

    // KFSPTS-1735
    boolean passed =
        SpringContext.getBean(KualiRuleService.class)
            .applyRules(new SaveDocumentEvent(tmpForm.getFinancialDocument()));
    if (tmpForm.getFinancialDocument().getDocumentHeader().getWorkflowDocument().isEnroute()
        && passed) {
      SpringContext.getBean(CUFinancialSystemDocumentService.class)
          .checkAccountingLinesForChanges((AccountingDocument) tmpForm.getFinancialDocument());
    }
    // KFSPTS-1735

    ActionForward forward = super.save(mapping, form, request, response);

    // need to check on sales tax for all the accounting lines
    checkSalesTaxRequiredAllLines(
        tmpForm, tmpForm.getFinancialDocument().getSourceAccountingLines());
    checkSalesTaxRequiredAllLines(
        tmpForm, tmpForm.getFinancialDocument().getTargetAccountingLines());
    return forward;
  }
  /**
   * This method will remove a SourceAccountingLine from a FinancialDocument. This assumes that the
   * user presses the delete button for a specific accounting line on the document and that the
   * document is represented by a FinancialDocumentFormBase.
   *
   * @param mapping
   * @param form
   * @param request
   * @param response
   * @return ActionForward
   * @throws Exception
   */
  public ActionForward deleteSourceLine(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;

    int deleteIndex = getLineToDelete(request);
    String errorPath =
        KFSConstants.DOCUMENT_PROPERTY_NAME
            + "."
            + KFSConstants.EXISTING_SOURCE_ACCT_LINE_PROPERTY_NAME
            + "["
            + deleteIndex
            + "]";
    boolean rulePassed =
        SpringContext.getBean(KualiRuleService.class)
            .applyRules(
                new DeleteAccountingLineEvent(
                    errorPath,
                    financialDocumentForm.getDocument(),
                    ((AccountingDocument) financialDocumentForm.getDocument())
                        .getSourceAccountingLine(deleteIndex),
                    false));

    // if the rule evaluation passed, let's delete it
    if (rulePassed) {
      deleteAccountingLine(true, financialDocumentForm, deleteIndex);
    } else {
      String[] errorParams = new String[] {"source", Integer.toString(deleteIndex + 1)};
      GlobalVariables.getMessageMap()
          .putError(
              errorPath,
              KFSKeyConstants.ERROR_ACCOUNTINGLINE_DELETERULE_INVALIDACCOUNT,
              errorParams);
    }

    return mapping.findForward(KFSConstants.MAPPING_BASIC);
  }
  /**
   * This action executes an insert of a SourceAccountingLine into a document only after validating
   * the accounting line and checking any appropriate business rules.
   *
   * @param mapping
   * @param form
   * @param request
   * @param response
   * @return ActionForward
   * @throws Exception
   */
  public ActionForward insertSourceLine(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
    SourceAccountingLine line = financialDocumentForm.getNewSourceLine();

    // populate chartOfAccountsCode from account number if accounts cant cross chart and Javascript
    // is turned off
    // SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line);

    boolean rulePassed = true;
    // DV acct line amount got error during form populate; should not insert this line.
    // KFSUPGRADE-847
    MessageMap msgMap = GlobalVariables.getMessageMap();
    if (msgMap.hasErrors()
        && msgMap.getErrorMessages().keySet().contains("newSourceLine.amount")
        && financialDocumentForm.getDocument() instanceof DisbursementVoucherDocument) {
      rulePassed = false;
    }
    // before we check the regular rules we need to check the sales tax rules
    // TODO: Refactor rules so we no longer have to call this before a copy of the
    // accountingLine
    rulePassed &=
        checkSalesTax(
            (AccountingDocument) financialDocumentForm.getDocument(), line, true, true, 0);
    // check any business rules
    rulePassed &=
        SpringContext.getBean(KualiRuleService.class)
            .applyRules(
                new AddAccountingLineEvent(
                    KFSConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME,
                    financialDocumentForm.getDocument(),
                    line));

    if (rulePassed) {
      // add accountingLine
      SpringContext.getBean(PersistenceService.class).refreshAllNonUpdatingReferences(line);
      insertAccountingLine(true, financialDocumentForm, line);

      // clear the used newTargetLine
      financialDocumentForm.setNewSourceLine(null);
    }

    return mapping.findForward(KFSConstants.MAPPING_BASIC);
  }
  /**
   * This method handles preparing all of the accounting line data so that it can be pushed up to
   * the balance inquiries for populating the search criteria of each.
   *
   * @param mapping
   * @param form
   * @param request
   * @param line
   * @return ActionForward
   */
  protected ActionForward performBalanceInquiryForAccountingLine(
      ActionMapping mapping, ActionForm form, HttpServletRequest request, AccountingLine line) {
    // build out base path for return location
    String basePath =
        request.getScheme()
            + "://"
            + request.getServerName()
            + ":"
            + request.getServerPort()
            + request.getContextPath();

    // build out the actual form key that will be used to retrieve the form on refresh
    String callerDocFormKey = GlobalVariables.getUserSession().addObjectWithGeneratedKey(form);

    // now add required parameters
    Properties parameters = new Properties();
    parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
    // need this next param b/c the lookup's return back will overwrite
    // the original doc form key
    parameters.put(KFSConstants.BALANCE_INQUIRY_REPORT_MENU_CALLER_DOC_FORM_KEY, callerDocFormKey);
    parameters.put(KFSConstants.DOC_FORM_KEY, callerDocFormKey);
    parameters.put(KFSConstants.BACK_LOCATION, basePath + mapping.getPath() + ".do");

    if (line.getPostingYear() != null) {
      parameters.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, line.getPostingYear().toString());
    }
    if (StringUtils.isNotBlank(line.getReferenceOriginCode())) {
      parameters.put("referenceOriginCode", line.getReferenceOriginCode());
    }
    if (StringUtils.isNotBlank(line.getReferenceNumber())) {
      parameters.put("referenceNumber", line.getReferenceNumber());
    }
    if (StringUtils.isNotBlank(line.getReferenceTypeCode())) {
      parameters.put("referenceTypeCode", line.getReferenceTypeCode());
    }
    if (StringUtils.isNotBlank(line.getDebitCreditCode())) {
      parameters.put("debitCreditCode", line.getDebitCreditCode());
    }
    if (StringUtils.isNotBlank(line.getChartOfAccountsCode())) {
      parameters.put("chartOfAccountsCode", line.getChartOfAccountsCode());
    }
    if (StringUtils.isNotBlank(line.getAccountNumber())) {
      parameters.put("accountNumber", line.getAccountNumber());
    }
    if (StringUtils.isNotBlank(line.getFinancialObjectCode())) {
      parameters.put("financialObjectCode", line.getFinancialObjectCode());
    }
    if (StringUtils.isNotBlank(line.getSubAccountNumber())) {
      parameters.put("subAccountNumber", line.getSubAccountNumber());
    }
    if (StringUtils.isNotBlank(line.getFinancialSubObjectCode())) {
      parameters.put("financialSubObjectCode", line.getFinancialSubObjectCode());
    }
    if (StringUtils.isNotBlank(line.getProjectCode())) {
      parameters.put("projectCode", line.getProjectCode());
    }
    if (StringUtils.isNotBlank(getObjectTypeCodeFromLine(line))) {
      if (!StringUtils.isBlank(line.getObjectTypeCode())) {
        parameters.put("objectTypeCode", line.getObjectTypeCode());
      } else {
        line.refreshReferenceObject("objectCode");
        parameters.put("objectTypeCode", line.getObjectCode().getFinancialObjectTypeCode());
      }
    }

    String lookupUrl =
        UrlFactory.parameterizeUrl(
            basePath + "/" + KFSConstants.BALANCE_INQUIRY_REPORT_MENU_ACTION, parameters);

    // register that we're going to come back w/ to this form w/ a refresh methodToCall
    ((KualiAccountingDocumentFormBase) form)
        .registerEditableProperty(KRADConstants.DISPATCH_REQUEST_PARAMETER);

    return new ActionForward(lookupUrl, true);
  }