context: //
  // DO NOT REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  //
  // @Authors:
  //       timop
  //       Tim Ingham, alanP
  //
  // Copyright 2004-2014 by OM International
  //
  // This file is part of OpenPetra.org.
  //
  // OpenPetra.org is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // OpenPetra.org 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 General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with OpenPetra.org.  If not, see <http://www.gnu.org/licenses/>.
  //
  
  using System;
  using System.Collections.Generic;
  using System.Windows.Forms;
  using System.Data;
  using Ict.Common;
  using Ict.Common.Verification;
  using Ict.Common.Controls;
  using Ict.Petra.Shared.MFinance.AP.Data;
  using Ict.Petra.Client.App.Core;
  using Ict.Petra.Client.App.Core.RemoteObjects;
  using Ict.Petra.Client.CommonForms;
  using Ict.Petra.Client.CommonControls;
  using Ict.Petra.Client.MCommon;
  using Ict.Petra.Client.MFinance.Gui.GL;
  using Ict.Petra.Client.MFinance.Gui.Setup;
  using Ict.Petra.Shared.Interfaces.MFinance;
  using System.Threading;
  
  
  namespace Ict.Petra.Client.MFinance.Gui.AP
  {
      public partial class TUC_OutstandingInvoices
      {
          private bool FKeepUpSearchFinishedCheck = false;
  
          /// <summary>DataTable that holds all Pages of data (also empty ones that are not retrieved yet!)</summary>
          private DataTable FInvoiceTable;
          private TSgrdDataGrid grdDetails;
          private int FPrevRowChangedRow = -1;
          private DataRow FPreviouslySelectedDetailRow = null;
  
          private TFrmAPMain FMainForm = null;
  
          private Boolean FRequireApprovalBeforePosting = false;
  
  
          private void InitializeManualCode()
          {
              // The auto-generated code requires that the grid be named grdDetails (for filter/find), but that doesn't work for another part of the autogenerated code!
              // So we make grdDetails reference grdInvoices here at initialization
              grdDetails = grdInvoices;
  
              grdInvoices.MouseClick += new MouseEventHandler(grdResult_Click);
              grdInvoices.DataPageLoaded += new TDataPageLoadedEventHandler(grdInvoices_DataPageLoaded);
              grdInvoices.Selection.SelectionChanged += new SourceGrid.RangeRegionChangedEventHandler(Selection_SelectionChanged);
          }
  
          void Selection_SelectionChanged(object sender, SourceGrid.RangeRegionChangedEventArgs e)
          {
              FPrevRowChangedRow = grdInvoices.Selection.ActivePosition.Row;
          }
  
          private void RunOnceOnParentActivationManual()
          {
              // Get our AP ledger settings and enable/disable the corresponding search option on the filter panel
              FRequireApprovalBeforePosting = FMainForm.RequireApprovalBeforePosting;
              Control rbtForApproval = FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtForApproval");
              rbtForApproval.Enabled = FRequireApprovalBeforePosting;
          }
  
          //////////////////////////////////////////////////////////////////////////////////////////////////////////
          // These methods are stubs that allow the auto-generated code to compile (we don't have a details panel)
  
          /// <summary>
          /// Method required by IGridBase.
          /// </summary>
          public void SelectRowInGrid(int ARowNumber)
          {
              if (ARowNumber >= grdInvoices.Rows.Count)
              {
                  ARowNumber = grdInvoices.Rows.Count - 1;
              }
  
              if ((ARowNumber < 1) && (grdInvoices.Rows.Count > 1))
              {
                  ARowNumber = 1;
              }
  
              // Note:  We need to be sure to focus column 1 in this case because sometimes column 0 is not visible!!
              grdInvoices.Selection.Focus(new SourceGrid.Position(ARowNumber, 1), true);
              FPrevRowChangedRow = ARowNumber;
          }
  
          /// <summary>
          /// Standard method
          /// </summary>
          public void GetDataFromControls()
          {
          }
  
          /// /////////////////////////////////////////////////////////////////////////////////////////////////////////
  
          public void InitializeGUI(TFrmAPMain AMainForm)
          {
              FMainForm = AMainForm;
  
              TFrmPetraUtils utils = FMainForm.GetPetraUtilsObject();
              utils.SetStatusBarText(grdInvoices, Catalog.GetString("Double-click an invoice to see full details"));
              utils.SetStatusBarText(btnApproveTagged, Catalog.GetString("Click to approve all the tagged items"));
              utils.SetStatusBarText(btnPayTagged, Catalog.GetString("Click to pay or part pay all the tagged items"));
              utils.SetStatusBarText(btnPostTagged, Catalog.GetString("Click to post all the tagged items"));
              utils.SetStatusBarText(btnReverseTagged, Catalog.GetString("Click to reverse the tagged items that have already been posted"));
              utils.SetStatusBarText(btnTagAll, Catalog.GetString("Click to tag all the displayed items"));
              utils.SetStatusBarText(btnUntagAll, Catalog.GetString("Click to un-tag all the displayed items"));
              utils.SetStatusBarText(chkToggleFilter, Catalog.GetString("Click to show/hide the Filter/Find panel"));
          }
  
          /// <summary>
          /// Call this method to load invoices into the user control
          /// </summary>
          public void LoadInvoices()
          {
              if (FKeepUpSearchFinishedCheck)
              {
                  // don't run several searches at the same time
                  return;
              }
  
              if (FInvoiceTable != null)
              {
                  // we have loaded the results already - has anything changed?
                  if (!FMainForm.IsInvoiceDataChanged)
                  {
                      grdInvoices.Focus();
                      return;
                  }
              }
  
              this.Cursor = Cursors.WaitCursor;
  
              DataTable CriteriaTable = new DataTable();
              CriteriaTable.Columns.Add("LedgerNumber", typeof(Int32));
              CriteriaTable.Columns.Add("SupplierId", typeof(string));
              CriteriaTable.Columns.Add("DaysPlus", typeof(decimal));
  
              // From 2014 we load all the data so the only criteria of interest is the ledger number
              DataRow row = CriteriaTable.NewRow();
              row["DaysPlus"] = -1;
              row["SupplierId"] = String.Empty;
              row["LedgerNumber"] = FMainForm.LedgerNumber;
              CriteriaTable.Rows.Add(row);
  
              // Start the asynchronous search operation on the PetraServer
              grdInvoices.DataSource = null;
              FInvoiceTable = null;
              FMainForm.InvoiceFindObject.FindInvoices(CriteriaTable);
  
              // Start thread that checks for the end of the search operation on the PetraServer
              FKeepUpSearchFinishedCheck = true;
              Thread FinishedCheckThread = new Thread(new ThreadStart(SearchFinishedCheckThread));
              FinishedCheckThread.Start();
          }
  
          private void grdInvoices_DataPageLoaded(object Sender, TDataPageLoadEventArgs e)
          {
              // This is where we end up after querying the database and loading the first data into the grid
              // We are back in our main thread here
              this.Cursor = Cursors.Default;
  
              if (e.DataPage == 0)
              {
                  FMainForm.IsInvoiceDataChanged = false;
              }
          }
  
          private delegate void SimpleDelegate();
  
          /// <summary>
          /// Thread for the search operation. Monitor's the Server System.Object's
          /// AsyncExecProgress.ProgressState and invokes UI updates from that.
          ///
          /// </summary>
          /// <returns>void</returns>
          private void SearchFinishedCheckThread()
          {
              TProgressState ThreadStatus;
  
              // Check whether this thread should still execute
              while (FKeepUpSearchFinishedCheck)
              {
                  // Wait and see if anything has changed
                  Thread.Sleep(200);
  
                  try
                  {
                      /* The next line of code calls a function on the PetraServer
                       * > causes a bit of data traffic everytime! */
                      ThreadStatus = FMainForm.InvoiceFindObject.Progress;
                  }
                  catch (NullReferenceException)
                  {
                      // The form is closing on the main thread ...
                      return;         // end this thread
                  }
                  catch (Exception)
                  {
                      throw;
                  }
  
                  if (ThreadStatus.JobFinished)
                  {
                      FKeepUpSearchFinishedCheck = false;
  
                      try
                      {
                          // see also http://stackoverflow.com/questions/6184/how-do-i-make-event-callbacks-into-my-win-forms-thread-safe
                          if (InvokeRequired)
                          {
                              Invoke(new SimpleDelegate(FinishThread));
                          }
                          else
                          {
                              FinishThread();
                          }
                      }
                      catch (ObjectDisposedException)
                      {
                          // Another exception that can be caused when the main screen is closed while running this thread
                          return;
                      }
                  }
                  else if (ThreadStatus.CancelJob)
                  {
                      FKeepUpSearchFinishedCheck = false;
                      return;
                  }
  
                  // Loop again while FKeepUpSearchFinishedCheck is true ...
              }
          }
  
          private void FinishThread()
          {
              DataTable dataTable = null;
  
              // Fetch the first page of data
              try
              {
                  grdInvoices.MinimumPageSize = 200;
                  dataTable = grdInvoices.LoadFirstDataPage(@GetDataPagedResult);
              }
              catch (Exception E)
              {
                  MessageBox.Show(E.ToString());
                  return;
              }
  
              if (dataTable == null)
              {
                  // we lost the supplierFind object - probably means the screen is closing down so quit now
                  return;
              }
  
              InitialiseGrid();
  
              DataView myDataView = grdInvoices.PagedDataTable.DefaultView;
              myDataView.AllowNew = false;
              grdInvoices.DataSource = new DevAge.ComponentModel.BoundDataView(myDataView);
  
              SetInvoiceFilters(null, null);
              string currentFilter = FFilterAndFindObject.CurrentActiveFilter;
              ApplyFilterManual(ref currentFilter);
  
              if (grdInvoices.TotalPages > 0)
              {
                  if (grdInvoices.TotalPages > 1)
                  {
                      // Now we can load the remaining pages ...
                      grdInvoices.LoadAllDataPages();
                  }
  
                  // Highlight first Row
                  SelectRowInGrid(1);
              }
  
              // Size it
              grdInvoices.AutoResizeGrid();
  
              grdInvoices.SetHeaderTooltip(0, Catalog.GetString("Check to Tag"));
              grdInvoices.SetHeaderTooltip(1, Catalog.GetString("AP#"));
              grdInvoices.SetHeaderTooltip(2, Catalog.GetString("Inv#"));
              grdInvoices.SetHeaderTooltip(3, Catalog.GetString("Supplier"));
              grdInvoices.SetHeaderTooltip(4, Catalog.GetString("Amount"));
              grdInvoices.SetHeaderTooltip(5, Catalog.GetString("Outstanding"));
              grdInvoices.SetHeaderTooltip(6, Catalog.GetString("Currency"));
              grdInvoices.SetHeaderTooltip(7, Catalog.GetString("Due Date"));
              grdInvoices.SetHeaderTooltip(8, Catalog.GetString("Status"));
              grdInvoices.SetHeaderTooltip(9, Catalog.GetString("Issued"));
  
              UpdateRecordNumberDisplay();
              UpdateInvoiceBalance();
              UpdateDisplayedBalance();
              RefreshSumTagged(null, null);
          }
  
          /// <summary>
          ///
          /// </summary>
          /// <param name="ANeededPage"></param>
          /// <param name="APageSize"></param>
          /// <param name="ATotalRecords"></param>
          /// <param name="ATotalPages"></param>
          /// <returns></returns>
          private DataTable GetDataPagedResult(Int16 ANeededPage, Int16 APageSize, out Int32 ATotalRecords, out Int16 ATotalPages)
          {
              ATotalRecords = 0;
              ATotalPages = 0;
  
              IAPUIConnectorsFind findObject = FMainForm.InvoiceFindObject;
  
              if (findObject != null)
              {
                  DataTable NewPage = findObject.GetDataPagedResult(ANeededPage, APageSize, out ATotalRecords, out ATotalPages);
  
                  // change CreditNote amounts to negatives
                  foreach (DataRow Row in NewPage.Rows)
                  {
                      if (Row["CreditNoteFlag"].Equals(true))
                      {
                          Row["TotalAmount"] = -(Decimal)Row["TotalAmount"];
                          Row["OutstandingAmount"] = -(Decimal)Row["OutstandingAmount"];
                      }
                  }
  
                  if (FInvoiceTable == null)
                  {
                      FInvoiceTable = NewPage;
                  }
  
                  return NewPage;
              }
  
              return null;
          }
  
          private void InitialiseGrid()
          {
              grdInvoices.Columns.Clear();
  
              string SelectedColumn = "Selected";
  
              if (FInvoiceTable.Columns["Selected"].DataType != typeof(bool))
              {
                  SelectedColumn = "SelectedBool";
                  FInvoiceTable.Columns.Add(new DataColumn(SelectedColumn, typeof(Boolean)));
  
                  foreach (DataRow r in FInvoiceTable.Rows)
                  {
                      r[SelectedColumn] = (Convert.ToInt32(r["Selected"]) == 1);
                  }
  
                  FInvoiceTable.Columns["Selected"].ColumnName = "SelectedOld";
                  FInvoiceTable.Columns["SelectedBool"].ColumnName = "Selected";
              }
  
              grdInvoices.AddCheckBoxColumn("", FInvoiceTable.Columns["Selected"], -1, false);
              grdInvoices.AddTextColumn(Catalog.GetString("AP#"), FInvoiceTable.Columns["ApNumber"]);
              grdInvoices.AddTextColumn(Catalog.GetString("Inv#"), FInvoiceTable.Columns["DocumentCode"]);
              grdInvoices.AddTextColumn(Catalog.GetString("Supplier"), FInvoiceTable.Columns["PartnerShortName"]);
              grdInvoices.AddCurrencyColumn(Catalog.GetString("Amount"), FInvoiceTable.Columns["TotalAmount"]);
              grdInvoices.AddCurrencyColumn(Catalog.GetString("Outstanding"), FInvoiceTable.Columns["OutstandingAmount"]);
              grdInvoices.AddTextColumn(Catalog.GetString("Currency"), FInvoiceTable.Columns["CurrencyCode"]);
              grdInvoices.AddDateColumn(Catalog.GetString("Due Date"), FInvoiceTable.Columns["DateDue"]);
              grdInvoices.AddTextColumn(Catalog.GetString("Status"), FInvoiceTable.Columns["DocumentStatus"]);
              grdInvoices.AddDateColumn(Catalog.GetString("Issued"), FInvoiceTable.Columns["DateIssued"]);
          }
  
          private void SetInvoiceFilters(object sender, EventArgs e)
          {
              if (FInvoiceTable != null)
              {
                  string filter = String.Empty;
                  string filterJoint = " AND ";
                  DateTime dtToday = DateTime.Today;
  
                  TextBox txtSupplierName = (TextBox)FFilterAndFindObject.FilterPanelControls.FindControlByName("txtSupplierName");
  
                  if (txtSupplierName.Text.Trim().Length > 0)
                  {
                      filter += String.Format("(PartnerShortName LIKE '%{0}%')", txtSupplierName.Text.Trim());
                  }
  
                  RadioButton rbtOverdue = (RadioButton)FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtOverdue");
  
                  if (rbtOverdue.Checked)
                  {
                      if (filter.Length > 0)
                      {
                          filter += filterJoint;
                      }
  
                      filter += String.Format("(DateDue < #{0}#)", dtToday.ToString("d", System.Globalization.CultureInfo.InvariantCulture));
                  }
  
                  RadioButton rbtDueToday = (RadioButton)FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtDueToday");
  
                  if (rbtDueToday.Checked)
                  {
                      if (filter.Length > 0)
                      {
                          filter += filterJoint;
                      }
  
                      filter += String.Format("(DateDue = #{0}#)", dtToday.ToString("d", System.Globalization.CultureInfo.InvariantCulture));
                  }
  
                  RadioButton rbtDueThisWeek = (RadioButton)FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtDueThisWeek");
  
                  if (rbtDueThisWeek.Checked)
                  {
                      if (filter.Length > 0)
                      {
                          filter += filterJoint;
                      }
  
                      filter += String.Format("(DateDue >= #{0}#) AND (DateDue <= #{1}#)",
                          dtToday.ToString("d", System.Globalization.CultureInfo.InvariantCulture),
                          dtToday.AddDays(7).ToString("d", System.Globalization.CultureInfo.InvariantCulture));
                  }
  
                  RadioButton rbtDueThisMonth = (RadioButton)FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtDueThisMonth");
  
                  if (rbtDueThisMonth.Checked)
                  {
                      if (filter.Length > 0)
                      {
                          filter += filterJoint;
                      }
  
                      filter += String.Format("(DateDue >= #{0}#) AND (DateDue <= #{1}#)",
                          dtToday.ToString("d", System.Globalization.CultureInfo.InvariantCulture),
                          dtToday.AddDays(30).ToString("d", System.Globalization.CultureInfo.InvariantCulture));
                  }
  
                  RadioButton rbtDueThisQuarter = (RadioButton)FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtDueThisQuarter");
  
                  if (rbtDueThisQuarter.Checked)
                  {
                      if (filter.Length > 0)
                      {
                          filter += filterJoint;
                      }
  
                      filter += String.Format("(DateDue >= #{0}#) AND (DateDue <= #{1}#)",
                          dtToday.ToString("d", System.Globalization.CultureInfo.InvariantCulture),
                          dtToday.AddDays(90).ToString("d", System.Globalization.CultureInfo.InvariantCulture));
                  }
  
                  RadioButton rbtForApproval = (RadioButton)FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtForApproval");
  
                  if (rbtForApproval.Checked)
                  {
                      if (filter.Length > 0)
                      {
                          filter += filterJoint;
                      }
  
                      filter += ("(DocumentStatus='OPEN')");
                  }
  
                  RadioButton rbtForPosting = (RadioButton)FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtForPosting");
  
                  if (rbtForPosting.Checked)
                  {
                      if (filter.Length > 0)
                      {
                          filter += filterJoint;
                      }
  
                      if (FRequireApprovalBeforePosting)
                      {
                          filter += ("(DocumentStatus='APPROVED')");
                      }
                      else
                      {
                          filter += ("(DocumentStatus='OPEN' OR DocumentStatus='APPROVED')");
                      }
                  }
  
                  RadioButton rbtForPaying = (RadioButton)FFilterAndFindObject.FilterPanelControls.FindControlByName("rbtForPaying");
  
                  if (rbtForPaying.Checked)
                  {
                      if (filter.Length > 0)
                      {
                          filter += filterJoint;
                      }
  
                      filter += ("(DocumentStatus='POSTED' OR DocumentStatus='PARTPAID')");
                  }
  
                  FFilterAndFindObject.FilterPanelControls.SetBaseFilter(filter, filter.Length == 0);
              }
          }
  
          private void UpdateDisplayedBalance()
          {
              DevAge.ComponentModel.BoundDataView dv = (DevAge.ComponentModel.BoundDataView)grdInvoices.DataSource;
              txtFilteredBalance.Text = UpdateBalance(dv.DataView).ToString("n2") + " " + FMainForm.LedgerCurrency;
          }
  
          private void UpdateInvoiceBalance()
          {
              DataView dv = new DataView(FInvoiceTable);
  
              txtInvoiceBalance.Text = UpdateBalance(dv).ToString("n2") + " " + FMainForm.LedgerCurrency;
          }
  
          private Decimal UpdateBalance(DataView ADataView)
          {
              Decimal balance = 0.0m;
  
              if (FInvoiceTable != null)
              {
                  foreach (DataRowView rv in ADataView)
                  {
                      DataRow Row = rv.Row;
  
                      if ((Row["CurrencyCode"].ToString() == FMainForm.LedgerCurrency) && (Row["OutstandingAmount"].GetType() == typeof(Decimal)))
                      {
                          balance += (Decimal)Row["OutstandingAmount"];
                      }
                  }
              }
  
              return balance;
          }
  
          // Called from a timer, below, so that the default processing of
          // the grid control completes before I get called.
          private void RefreshSumTagged(Object Sender, EventArgs e)
          {
              // If I was called from a timer, kill that now:
              if (Sender != null)
              {
                  ((System.Windows.Forms.Timer)Sender).Stop();
              }
  
              if (FInvoiceTable == null) // I may be called before the first search.
              {
                  return;
              }
  
              // Add up all the selected Items  ** I can only sum items that are in my currency! **
              String MyCurrency = FMainForm.LedgerCurrency;
  
              Decimal TotalSelected = 0;
              int TaggedItemCount = 0;
  
              foreach (DataRowView rv in FInvoiceTable.DefaultView)
              {
                  DataRow Row = rv.Row;
  
                  if (Row["Selected"].Equals(true))
                  {
                      TaggedItemCount++;
  
                      if (Row["CurrencyCode"].Equals(MyCurrency))
                      {
                          TotalSelected += (Decimal)(Row["TotalAmount"]);
                      }
                  }
              }
  
              txtTaggedBalance.Text = TotalSelected.ToString("n2") + " " + FMainForm.LedgerCurrency;
              txtTaggedCount.Text = TaggedItemCount.ToString();
          }
  
          private void grdResult_Click(object sender, EventArgs e)
          {
              // I want to update the total tagged field,
              // but it needs to be performed AFTER the default processing so I'm using a timer.
              System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
  
              timer.Tick += new EventHandler(RefreshSumTagged);
              timer.Interval = 100;
              timer.Start();
          }
  
          private Int32 GetCurrentlySelectedDocumentId()
          {
              DataRowView[] SelectedGridRow = grdInvoices.SelectedDataRowsAsDataRowView;
              Int32 ApDocumentId = -1;
  
              if (SelectedGridRow.Length >= 1)
              {
                  Object Cell = SelectedGridRow[0]["ApDocumentId"];
  
                  if (Cell.GetType() == typeof(Int32))
                  {
                      ApDocumentId = Convert.ToInt32(Cell);
                  }
              }
  
              return ApDocumentId;
          }
  
          /// <summary>
          /// Open the selected invoice
          /// </summary>
          public void OpenSelectedInvoice(object sender, EventArgs e)
          {
              this.Cursor = Cursors.WaitCursor;
  
              Int32 SelectedInvoice = GetCurrentlySelectedDocumentId();
  
              if (SelectedInvoice > 0)
              {
                  TFrmAPEditDocument frm = new TFrmAPEditDocument(FMainForm);
  
                  if (frm.LoadAApDocument(FMainForm.LedgerNumber, SelectedInvoice))
                  {
                      frm.Show();
                  }
              }
  
              this.Cursor = Cursors.Default;
          }
  
          /// <summary>
          /// Open the selected invoice
          /// </summary>
          public void OpenAllTagged(object sender, EventArgs e)
          {
              if (grdInvoices.PagedDataTable.DefaultView.Count > 0)
              {
                  foreach (DataRowView rv in grdInvoices.PagedDataTable.DefaultView)
                  {
                      if (rv.Row["Selected"].Equals(true))
                      {
                          TFrmAPEditDocument frm = new TFrmAPEditDocument(FMainForm);
  
                          if (frm.LoadAApDocument(FMainForm.LedgerNumber, Convert.ToInt32(rv.Row["ApDocumentId"])))
                          {
                              frm.Show();
                          }
                      }
                  }
              }
              else
              {
                  MessageBox.Show(Catalog.GetString("There are no tagged invoices to be opened."), Catalog.GetString("Open Documents"));
              }
          }
  
          ///// <summary>
          ///// Tag all postable rows
          ///// </summary>
          ///// <param name="sender"></param>
          ///// <param name="e"></param>
          //public void TagAllPostable(object sender, EventArgs e)
          //{
          //    foreach (DataRow Row in grdInvoices.PagedDataTable.Rows)
          //    {
          //        if ("|POSTED|PARTPAID|PAID|".IndexOf("|" + Row["DocumentStatus"].ToString()) < 0)
          //        {
          //            Row["Selected"] = true;
          //        }
          //    }
  
          //    RefreshSumTagged(null, null);
          //}
  
          ///// <summary>
          ///// Tag all payable rows
          ///// </summary>
          ///// <param name="sender"></param>
          ///// <param name="e"></param>
          //public void TagAllPayable(object sender, EventArgs e)
          //{
          //    foreach (DataRow Row in grdInvoices.PagedDataTable.Rows)
          //    {
          //        if ("|POSTED|PARTPAID|".IndexOf("|" + Row["DocumentStatus"].ToString()) >= 0)
          //        {
          //            Row["Selected"] = true;
          //        }
          //    }
  
          //    RefreshSumTagged(null, null);
          //}
  
          /// <summary>
          /// Untag all rows
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          public void UntagAll(object sender, EventArgs e)
          {
              // We do this for all tags in the complete data table
              foreach (DataRow Row in grdInvoices.PagedDataTable.Rows)
              {
                  Row["Selected"] = false;
              }
  
              if (sender != null)
              {
                  RefreshSumTagged(null, null);
              }
          }
  
          /// <summary>
          /// Tag all rows
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          public void TagAll(object sender, EventArgs e)
          {
              // Untag everything
              UntagAll(null, null);
  
              // Now tag all the rows in the current view
              foreach (DataRowView rv in grdInvoices.PagedDataTable.DefaultView)
              {
                  rv.Row["Selected"] = true;
              }
  
              RefreshSumTagged(null, null);
          }
  
          /// <summary>
          /// Approve all tagged rows
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          public void ApproveAllTagged(object sender, EventArgs e)
          {
              string MsgTitle = Catalog.GetString("Document Approval");
  
              // I can only approve invoices that are OPEN.
              // This method is only enabled when the grid shows items for Approval
              List <int>ApproveTheseDocs = new List <int>();
  
              foreach (DataRowView rv in grdInvoices.PagedDataTable.DefaultView)
              {
                  if (rv.Row["Selected"].Equals(true))
                  {
                      if (rv.Row["DocumentStatus"].ToString() == "OPEN")
                      {
                          ApproveTheseDocs.Add(Convert.ToInt32(rv.Row["ApDocumentId"]));
                      }
                      else
                      {
                          MessageBox.Show(Catalog.GetString("Only OPEN documents can be approved."), MsgTitle);
                          return;
                      }
                  }
              }
  
              if (ApproveTheseDocs.Count > 0)
              {
                  string msg = String.Format(Catalog.GetString(
                          "Are you sure that you want to approve the {0} tagged document(s)?"), ApproveTheseDocs.Count);
  
                  if (MessageBox.Show(msg, MsgTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question,
                          MessageBoxDefaultButton.Button2) == DialogResult.No)
                  {
                      return;
                  }
  
                  this.Cursor = Cursors.WaitCursor;
                  TVerificationResultCollection VerificationResult;
  
                  if (TRemote.MFinance.AP.WebConnectors.ApproveAPDocuments(FMainForm.LedgerNumber, ApproveTheseDocs, out VerificationResult))
                  {
                      this.Cursor = Cursors.Default;
                      FMainForm.IsInvoiceDataChanged = true;
  
                      LoadInvoices();
                      MessageBox.Show(Catalog.GetString("The tagged documents have been approved successfully!"), MsgTitle);
                  }
                  else
                  {
                      MessageBox.Show(VerificationResult.BuildVerificationResultString(), MsgTitle);
                  }
  
                  this.Cursor = Cursors.Default;
              }
              else
              {
                  MessageBox.Show(Catalog.GetString("There are no tagged invoices to be approved."), MsgTitle);
              }
          }
  
          /// <summary>
          /// Delete all tagged rows
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          public void DeleteAllTagged(object sender, EventArgs e)
          {
              string MsgTitle = Catalog.GetString("Document Deletion");
  
              // I can only delete invoices that are not posted already.
              // This method is only enabled when the grid shows items for Posting
              List <int>DeleteTheseDocs = new List <int>();
  
              foreach (DataRowView rv in grdInvoices.PagedDataTable.DefaultView)
              {
                  if (rv.Row["Selected"].Equals(true))
                  {
                      if ("|POSTED|PARTPAID|PAID|".IndexOf("|" + rv.Row["DocumentStatus"].ToString()) < 0)
                      {
                          DeleteTheseDocs.Add(Convert.ToInt32(rv.Row["ApDocumentId"]));
                      }
                      else
                      {
                          MessageBox.Show(Catalog.GetString("Cannot delete posted documents. Please reverse the document first."), MsgTitle);
                      }
                  }
              }
  
              if (DeleteTheseDocs.Count > 0)
              {
                  string msg = String.Format(Catalog.GetString(
                          "Are you sure that you want to delete the {0} tagged document(s)?"), DeleteTheseDocs.Count);
  
                  if (MessageBox.Show(msg, MsgTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question,
                          MessageBoxDefaultButton.Button2) == DialogResult.No)
                  {
                      return;
                  }
  
                  this.Cursor = Cursors.WaitCursor;
                  TRemote.MFinance.AP.WebConnectors.DeleteAPDocuments(FMainForm.LedgerNumber, DeleteTheseDocs);
                  this.Cursor = Cursors.Default;
                  FMainForm.IsInvoiceDataChanged = true;
  
                  LoadInvoices();
                  MessageBox.Show(Catalog.GetString("The tagged documents have been deleted successfully!"), MsgTitle);
              }
              else
              {
                  MessageBox.Show(Catalog.GetString("There are no tagged invoices to be deleted."), MsgTitle);
              }
          }
  
          /// <summary>
          /// Post all tagged documents
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          public void PostAllTagged(object sender, EventArgs e)
          {
              string MsgTitle = Catalog.GetString("Document Posting");
  
              AccountsPayableTDS TempDS = LoadTaggedDocuments();
  
              List <int>PostTheseDocs = new List <int>();
              TempDS.AApDocument.DefaultView.Sort = AApDocumentDetailTable.GetApDocumentIdDBName();
  
              string testString = "|POSTED|PARTPAID|PAID|";
  
              if (FRequireApprovalBeforePosting)
              {
                  testString += "OPEN|";
              }
  
              foreach (DataRowView rv in grdInvoices.PagedDataTable.DefaultView)
              {
                  if ((rv.Row["Selected"].Equals(true) && (testString.IndexOf("|" + rv.Row["DocumentStatus"].ToString()) < 0)))
                  {
                      int DocId = Convert.ToInt32(rv.Row["ApDocumentId"]);
  
                      int RowIdx = TempDS.AApDocument.DefaultView.Find(DocId);
  
                      if (RowIdx >= 0)
                      {
                          AApDocumentRow DocumentRow = (AApDocumentRow)TempDS.AApDocument.DefaultView[RowIdx].Row;
  
                          if (TFrmAPEditDocument.ApDocumentCanPost(TempDS, DocumentRow)) // This will produce an message box if there's a problem.
                          {
                              PostTheseDocs.Add(DocId);
                          }
                      }
                  }
              }
  
              if (PostTheseDocs.Count > 0)
              {
                  string msg = String.Format(Catalog.GetString("Are you sure that you want to post the {0} tagged document(s)?"), PostTheseDocs.Count);
  
                  if (MessageBox.Show(msg, MsgTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question,
                          MessageBoxDefaultButton.Button2) == DialogResult.No)
                  {
                      return;
                  }
  
                  if (TFrmAPEditDocument.PostApDocumentList(TempDS, FMainForm.LedgerNumber, PostTheseDocs, FMainForm))
                  {
                      // TODO: print reports on successfully posted batch
                      MessageBox.Show(Catalog.GetString("The tagged documents have been posted successfully!"), MsgTitle);
                      FMainForm.IsInvoiceDataChanged = true;
  
                      LoadInvoices();
  
                      // TODO: show posting register of GL Batch?
                  }
              }
              else
              {
                  MessageBox.Show(Catalog.GetString("There are no tagged documents to be posted."), MsgTitle);
              }
          }
  
          /// <summary>
          /// Reverse all tagged rows
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          public void ReverseAllTagged(object sender, EventArgs e)
          {
  
gt:             string MsgTitle = Catalog.GetString("Document Reversal");