/// create new AP info
        public static AApDocumentRow CreateNewAPInfo(Int64 APartnerKey, ref AccountsPayableTDS AMainDS)
        {
            ALedgerTable LedgerTable = ALedgerAccess.LoadAll(DBAccess.GDBAccessObj.Transaction);

            AMainDS = TAPTransactionWebConnector.CreateAApDocument(((ALedgerRow)LedgerTable.Rows[0]).LedgerNumber, APartnerKey, true);

            // Create a new RecurringGiftBatch
            AApDocumentRow Document = AMainDS.AApDocument[0];

            Document.DocumentCode     = "TEST";
            Document.CreditNoteFlag   = false;
            Document.DateIssued       = DateTime.Today;
            Document.DateEntered      = DateTime.Today;
            Document.TotalAmount      = 0;
            Document.CurrencyCode     = "EUR";
            Document.LastDetailNumber = 0;

            // Create a new RecurringGift record
            AApSupplierRow ApSupplierRow = AMainDS.AApSupplier.NewRowTyped();

            ApSupplierRow.PartnerKey   = APartnerKey;
            ApSupplierRow.CurrencyCode = "EUR";
            AMainDS.AApSupplier.Rows.Add(ApSupplierRow);

            return(Document);
        }
        /// <summary>
        /// This static function is called from several places
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="Adocument"></param>
        /// <returns>true if this document seems OK to post.</returns>
        public static bool ApDocumentCanPost(AccountsPayableTDS Atds, AApDocumentRow Adocument)
        {
            // If the batch will not balance, or required attributes are missing, I'll stop right here..

            if (!BatchBalancesOK(Atds, Adocument))
            {
                return(false);
            }

            if (!AllLinesAccountsOK(Atds, Adocument))
            {
                return(false);
            }

            if (!AllLinesHaveAttributes(Atds, Adocument))
            {
                return(false);
            }

            if (!ExchangeRateIsOk(Atds, Adocument))
            {
                return(false);
            }

            if (!CurrencyIsOkForPosting(Atds, Adocument))
            {
                return(false);
            }

            return(true);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AApDocument"></param>
        /// <returns>true if the document TotalAmount equals the sum of its parts!</returns>
        public static bool BatchBalancesOK(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            decimal DocumentBalance = AApDocument.TotalAmount;

            if (DocumentBalance == 0)
            {
                System.Windows.Forms.MessageBox.Show(
                    String.Format(Catalog.GetString("The document {0} is empty."), AApDocument.DocumentCode),
                    Catalog.GetString("Balance Problem"));
                return(false);
            }

            foreach (AApDocumentDetailRow Row in Atds.AApDocumentDetail.Rows)
            {
                if (Row.ApDocumentId == AApDocument.ApDocumentId) // NOTE: When called from elsewhere, the TDS could contain data for several documents.
                {
                    DocumentBalance -= Row.Amount;
                }
            }

            if (DocumentBalance == 0.0m)
            {
                return(true);
            }
            else
            {
                System.Windows.Forms.MessageBox.Show(
                    String.Format(Catalog.GetString("The document {0} Amount does not equal the sum of the detail lines."), AApDocument.DocumentCode),
                    Catalog.GetString("Balance Problem"));
                return(false);
            }
        }
        /// create new AP info
        public static AApDocumentRow CreateNewAPInfo(Int64 APartnerKey, ref AccountsPayableTDS AMainDS, TDataBase ADataBase = null)
        {
            TDataBase      db          = DBAccess.Connect("CreateNewAPInfo", ADataBase);
            TDBTransaction Transaction = db.BeginTransaction(IsolationLevel.Serializable);

            ALedgerTable LedgerTable = ALedgerAccess.LoadAll(Transaction);

            AMainDS = TAPTransactionWebConnector.CreateAApDocument(((ALedgerRow)LedgerTable.Rows[0]).LedgerNumber, APartnerKey, true, db);

            // Create a new RecurringGiftBatch
            AApDocumentRow Document = AMainDS.AApDocument[0];

            Document.DocumentCode     = "TEST";
            Document.CreditNoteFlag   = false;
            Document.DateIssued       = DateTime.Today;
            Document.DateEntered      = DateTime.Today;
            Document.TotalAmount      = 0;
            Document.CurrencyCode     = "EUR";
            Document.LastDetailNumber = 0;

            // Create a new RecurringGift record
            AApSupplierRow ApSupplierRow = AMainDS.AApSupplier.NewRowTyped();

            ApSupplierRow.PartnerKey   = APartnerKey;
            ApSupplierRow.CurrencyCode = "EUR";
            AMainDS.AApSupplier.Rows.Add(ApSupplierRow);

            Transaction.Commit();

            return(Document);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AApDocument"></param>
        /// <returns></returns>
        public static bool ExchangeRateIsOk(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            if (AApDocument.ExchangeRateToBase == 0)
            {
                System.Windows.Forms.MessageBox.Show(
                    String.Format(Catalog.GetString("No Exchange Rate has been set."), AApDocument.DocumentCode),
                    Catalog.GetString("Post Document"));
                return(false);
            }

            return(true);
        }
        private static bool CurrencyIsOkForPosting(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            if (AApDocument.CurrencyCode != Atds.AApSupplier[0].CurrencyCode)
            {
                System.Windows.Forms.MessageBox.Show(
                    String.Format(Catalog.GetString("Document {0} cannot be posted because the supplier currency has been changed."),
                                  AApDocument.DocumentCode),
                    Catalog.GetString("Post Document"));
                return(false);
            }

            return(true);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AdocumentRow"></param>
        /// <returns></returns>
        public static bool ApDocumentCanPay(AccountsPayableTDS Atds, AApDocumentRow AdocumentRow)
        {
            if (!CurrencyIsOkForPaying(Atds, AdocumentRow))
            {
                return(false);
            }

            if ("|POSTED|PARTPAID|".IndexOf("|" + AdocumentRow.DocumentStatus) < 0)
            {
                return(false);
            }

            return(true);
        }
Beispiel #8
0
        /// <summary>
        /// Post all tagged documents in one GL Batch
        /// Uses static functions from TFrmAPEditDocument
        /// </summary>
        private void PostTaggedDocuments(object sender, EventArgs e)
        {
            List <Int32>       TaggedDocuments = new List <Int32>();
            AccountsPayableTDS TempDS          = new AccountsPayableTDS();

            foreach (DataRowView rv in FPagedDataTable.DefaultView)
            {
                if ((rv.Row["Tagged"].Equals(true)) && (rv.Row["Status"].ToString().Length > 0) && // Invoices have status, Payments don't.
                    ("|POSTED|PARTPAID|PAID".IndexOf("|" + rv.Row["Status"].ToString()) < 0) &&
                    (rv.Row["Currency"].ToString() == txtSupplierCurrency.Text)
                    )
                {
                    Int32 DocumentId = Convert.ToInt32(rv.Row["ApDocumentId"]);
                    TempDS.Merge(TRemote.MFinance.AP.WebConnectors.LoadAApDocument(FLedgerNumber, DocumentId));

                    // I've loaded this record in my DS, but I was not given a handle to it, so I need to find it!
                    TempDS.AApDocument.DefaultView.Sort = "a_ap_document_id_i";
                    Int32          Idx         = TempDS.AApDocument.DefaultView.Find(DocumentId);
                    AApDocumentRow DocumentRow = TempDS.AApDocument[Idx];

                    if (TFrmAPEditDocument.ApDocumentCanPost(TempDS, DocumentRow))
                    {
                        TaggedDocuments.Add(DocumentId);
                    }
                }
            }

            if (TaggedDocuments.Count == 0)
            {
                return;
            }

            if (TFrmAPEditDocument.PostApDocumentList(TempDS, FLedgerNumber, TaggedDocuments, this))
            {
                // TODO: print reports on successfully posted batch
                MessageBox.Show(Catalog.GetString("The AP documents have been posted successfully!"));

                // TODO: show posting register of GL Batch?

                LoadSupplier(FLedgerNumber, FPartnerKey);
            }
        }
Beispiel #9
0
        /// Add all selected invoices to the payment list and show that list so that the user can make the payment
        private void AddTaggedToPayment(object sender, EventArgs e)
        {
            List <Int32>       TaggedDocuments = new List <Int32>();
            AccountsPayableTDS TempDS          = new AccountsPayableTDS();

            foreach (DataRowView rv in FPagedDataTable.DefaultView)
            {
                if (
                    (rv.Row["Tagged"].Equals(true)) &&
                    (rv.Row["Currency"].ToString() == txtSupplierCurrency.Text) &&
                    ("|POSTED|PARTPAID|".IndexOf("|" + rv.Row["Status"].ToString()) >= 0)
                    )
                {
                    Int32 DocumentId = Convert.ToInt32(rv.Row["ApDocumentId"]);
                    TempDS.Merge(TRemote.MFinance.AP.WebConnectors.LoadAApDocument(FLedgerNumber, DocumentId));

                    // I've loaded this record in my DS, but I was not given a handle to it, so I need to find it!
                    TempDS.AApDocument.DefaultView.Sort = AApDocumentTable.GetApDocumentIdDBName();
                    Int32          Idx         = TempDS.AApDocument.DefaultView.Find(DocumentId);
                    AApDocumentRow DocumentRow = TempDS.AApDocument[Idx];

                    if ("|POSTED|PARTPAID|".IndexOf("|" + DocumentRow["a_document_status_c"].ToString()) >= 0)
                    {
                        TaggedDocuments.Add(DocumentId);
                    }
                }
            }

            if (TaggedDocuments.Count == 0)
            {
                return;
            }

            TFrmAPPayment frm = new TFrmAPPayment(this);

            if (frm.AddDocumentsToPayment(TempDS, FLedgerNumber, TaggedDocuments))
            {
                frm.Show();
            }
        }
        /// <summary>
        /// Check that the cost centres referred to are OK with the accounts I'm using. If not a message is displayed.
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AApDocument"></param>
        /// <returns>false if any detail lines have incompatible cost centres.</returns>
        public static bool AllLinesAccountsOK(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            List <String> AccountCodesCostCentres = new List <string>();

            foreach (AApDocumentDetailRow Row in Atds.AApDocumentDetail.Rows)
            {
                if (Row.ApDocumentId == AApDocument.ApDocumentId)  // NOTE: When called from elsewhere, the TDS could contain data for several documents.
                {
                    if ((Row.AccountCode == "") || (Row.CostCentreCode == ""))
                    {
                        MessageBox.Show(
                            String.Format(Catalog.GetString("Account and Cost Centre must be specified in Document {0}."), AApDocument.DocumentCode),
                            Catalog.GetString("Post Document"), MessageBoxButtons.OK, MessageBoxIcon.Stop);
                        return(false);
                    }

                    String AccountCostCentre = Row.AccountCode + "|" + Row.CostCentreCode;

                    if (!AccountCodesCostCentres.Contains(AccountCostCentre))
                    {
                        AccountCodesCostCentres.Add(AccountCostCentre);
                    }
                }
            }

            //
            // The check is done on the server..

            String ReportMsg = TRemote.MFinance.AP.WebConnectors.CheckAccountsAndCostCentres(AApDocument.LedgerNumber, AccountCodesCostCentres);

            if (ReportMsg != "")
            {
                MessageBox.Show(ReportMsg, Catalog.GetString("Invalid Account"), MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Check the required analysis attributes for the detail lines in this invoice
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AApDocument"></param>
        /// <returns>false if any lines don't have the analysis attributes they require</returns>
        public static bool AllLinesHaveAttributes(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            foreach (AApDocumentDetailRow Row in Atds.AApDocumentDetail.Rows)
            {
                if (Row.ApDocumentId == AApDocument.ApDocumentId)  // NOTE: When called from elsewhere, the TDS could contain data for several documents.
                {
                    bool AllPresent = true;

                    if (DetailLineAttributesRequired(ref AllPresent, Atds, Row))
                    {
                        if (!AllPresent)
                        {
                            System.Windows.Forms.MessageBox.Show(
                                String.Format(Catalog.GetString("Analysis Attributes are required for account {0} in Document {1}."),
                                              Row.AccountCode, AApDocument.DocumentCode),
                                Catalog.GetString("Analysis Attributes"));
                            return(false);
                        }
                    }
                }
            }

            return(true);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AApDocument"></param>
        /// <returns></returns>
        public static bool ExchangeRateIsOk(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            if (AApDocument.ExchangeRateToBase == 0)
            {
                System.Windows.Forms.MessageBox.Show(
                    String.Format(Catalog.GetString("No Exchange Rate has been set."), AApDocument.DocumentCode),
                    Catalog.GetString("Post Document"));
                return false;
            }

            return true;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AdocumentRow"></param>
        /// <returns></returns>
        public static bool ApDocumentCanPay(AccountsPayableTDS Atds, AApDocumentRow AdocumentRow)
        {
            if (!CurrencyIsOkForPaying(Atds, AdocumentRow))
            {
                return false;
            }

            if ("|POSTED|PARTPAID|".IndexOf("|" + AdocumentRow.DocumentStatus) < 0)
            {
                return false;
            }

            return true;
        }
        private static bool CurrencyIsOkForPaying(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            if (AApDocument.CurrencyCode != Atds.AApSupplier[0].CurrencyCode)
            {
                System.Windows.Forms.MessageBox.Show(
                    String.Format(Catalog.GetString("Document {0} cannot be paid because the supplier's currency has been changed to {1}."),
                        AApDocument.DocumentCode, Atds.AApSupplier[0].CurrencyCode),
                    Catalog.GetString("Pay Document"));
                return false;
            }

            return true;
        }
        /// <summary>
        /// A payment made to a supplier needs to be reversed.
        /// It's done by creating and posting a set of matching "negatives" -
        /// In the simplest case this is a single credit note matching an invoice
        /// but it could be more complex. These negative documents are payed using
        /// a standard call to PostAPPayments.
        ///
        /// After the reversal, I'll also create and post new copies of all
        /// the invoices / credit notes that made up the original payment.
        /// </summary>
        /// <param name="ALedgerNumber"></param>
        /// <param name="APaymentNumber"></param>
        public void ReversePayment(Int32 ALedgerNumber, Int32 APaymentNumber)
        {
            AccountsPayableTDS TempDS = TRemote.MFinance.AP.WebConnectors.LoadAPPayment(ALedgerNumber, APaymentNumber);

            if (TempDS.AApPayment.Rows.Count == 0) // Invalid Payment number?
            {
                MessageBox.Show(Catalog.GetString("The referenced payment Connot be loaded."), Catalog.GetString("Error"));
                return;
            }

            TempDS.AApDocument.DefaultView.Sort = AApDocumentTable.GetApDocumentIdDBName();

            //
            // First I'll check that the amounts add up:
            //
            Decimal PaidDocumentsTotal = 0.0m;

            foreach (AApDocumentPaymentRow PaymentRow in TempDS.AApDocumentPayment.Rows)
            {
                Int32          DocIdx      = TempDS.AApDocument.DefaultView.Find(PaymentRow.ApDocumentId);
                AApDocumentRow DocumentRow = TempDS.AApDocument[DocIdx];

                if (DocumentRow.CreditNoteFlag)
                {
                    PaidDocumentsTotal -= DocumentRow.TotalAmount;
                }
                else
                {
                    PaidDocumentsTotal += DocumentRow.TotalAmount;
                }
            }

            //
            // If this is a partial payment, I can't deal with that here...
            //
            if (PaidDocumentsTotal != TempDS.AApPayment[0].Amount)
            {
                String ErrorMsg =
                    String.Format(Catalog.GetString(
                                      "This Payment cannot be reversed automatically because the total amount of the referenced documents ({0:n2} {1}) differs from the amount in the payment ({2:n2} {3})."),
                                  PaidDocumentsTotal, TempDS.AApSupplier[0].CurrencyCode, TempDS.AApPayment[0].Amount, TempDS.AApSupplier[0].CurrencyCode);
                MessageBox.Show(ErrorMsg, Catalog.GetString("Reverse Payment"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // Find out if this payment was already reversed,
            // because if it was, perhaps the user doesn't really want to
            // reverse it again?
            this.Cursor = Cursors.WaitCursor;

            if (TRemote.MFinance.AP.WebConnectors.WasThisPaymentReversed(ALedgerNumber, APaymentNumber))
            {
                this.Cursor = Cursors.Default;
                MessageBox.Show(Catalog.GetString("Cannot reverse Payment - there is already a matching reverse transaction."),
                                Catalog.GetString("Reverse Payment"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            this.Cursor = Cursors.Default;

            //
            // Ask the user to confirm reversal of this payment
            //
            String PaymentMsg = Catalog.GetString("Do you want to reverse this payment?");

            PaymentMsg += ("\r\n" + String.Format("Payment made {0} to {1}\r\n\r\nRelated invoices:",
                                                  TDate.DateTimeToLongDateString2(TempDS.AApPayment[0].PaymentDate.Value), TempDS.PPartner[0].PartnerShortName));

            foreach (AApDocumentPaymentRow PaymentRow in TempDS.AApDocumentPayment.Rows)
            {
                Int32          DocIdx      = TempDS.AApDocument.DefaultView.Find(PaymentRow.ApDocumentId);
                AApDocumentRow DocumentRow = TempDS.AApDocument[DocIdx];
                PaymentMsg += ("\r\n" + String.Format("     {2} ({3})  {0:n2} {1}",
                                                      DocumentRow.TotalAmount, TempDS.AApSupplier[0].CurrencyCode, DocumentRow.DocumentCode, DocumentRow.Reference));
            }

            PaymentMsg += ("\r\n\r\n" + String.Format("Total payment {0:n2} {1}", TempDS.AApPayment[0].Amount, TempDS.AApSupplier[0].CurrencyCode));
            DialogResult YesNo = MessageBox.Show(PaymentMsg, Catalog.GetString("Reverse Payment"), MessageBoxButtons.YesNo);

            if (YesNo == DialogResult.No)
            {
                return;
            }

            TDlgGLEnterDateEffective dateEffectiveDialog = new TDlgGLEnterDateEffective(
                ALedgerNumber,
                Catalog.GetString("Select posting date"),
                Catalog.GetString("The date effective for the reversal") + ":");

            if (dateEffectiveDialog.ShowDialog() != DialogResult.OK)
            {
                MessageBox.Show(Catalog.GetString("Reversal was cancelled."), Catalog.GetString("Reverse Payment"),
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            DateTime PostingDate = dateEffectiveDialog.SelectedDate;
            TVerificationResultCollection Verifications;

            this.Cursor = Cursors.WaitCursor;

            if (TRemote.MFinance.AP.WebConnectors.ReversePayment(ALedgerNumber, APaymentNumber, PostingDate, out Verifications))
            {
                this.Cursor = Cursors.Default;
                // TODO: print reports on successfully posted batch
                MessageBox.Show(Catalog.GetString("The AP payment has been reversed."), Catalog.GetString("Reverse Payment"));
                TFormsMessage broadcastMessage = new TFormsMessage(TFormsMessageClassEnum.mcAPTransactionChanged);
                broadcastMessage.SetMessageDataAPTransaction(String.Empty);
                TFormsList.GFormsList.BroadcastFormMessage(broadcastMessage);
            }
            else
            {
                this.Cursor = Cursors.Default;
                string ErrorMessages = String.Empty;

                foreach (TVerificationResult verif in Verifications)
                {
                    ErrorMessages += "[" + verif.ResultContext + "] " +
                                     verif.ResultTextCaption + ": " +
                                     verif.ResultText + Environment.NewLine;
                }

                System.Windows.Forms.MessageBox.Show(ErrorMessages, Catalog.GetString("Reverse Payment Failed"));
            }
        }
        /// <summary>
        /// Check the required analysis attributes for the detail lines in this invoice
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AApDocument"></param>
        /// <returns>false if any lines don't have the analysis attributes they require</returns>
        public static bool AllLinesHaveAttributes(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            foreach (AApDocumentDetailRow Row in Atds.AApDocumentDetail.Rows)
            {
                if (Row.ApDocumentId == AApDocument.ApDocumentId)  // NOTE: When called from elsewhere, the TDS could contain data for several documents.
                {
                    bool AllPresent = true;

                    if (DetailLineAttributesRequired(ref AllPresent, Atds, Row))
                    {
                        if (!AllPresent)
                        {
                            System.Windows.Forms.MessageBox.Show(
                                String.Format(Catalog.GetString("Analysis Attributes are required for account {0} in Document {1}."),
                                    Row.AccountCode, AApDocument.DocumentCode),
                                Catalog.GetString("Analysis Attributes"));
                            return false;
                        }
                    }
                }
            }

            return true;
        }
        /// <summary>
        /// Check that the cost centres referred to are OK with the accounts I'm using. If not a message is displayed.
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AApDocument"></param>
        /// <returns>false if any detail lines have incompatible cost centres.</returns>
        public static bool AllLinesAccountsOK(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            List <String>AccountCodesCostCentres = new List <string>();

            foreach (AApDocumentDetailRow Row in Atds.AApDocumentDetail.Rows)
            {
                if (Row.ApDocumentId == AApDocument.ApDocumentId)  // NOTE: When called from elsewhere, the TDS could contain data for several documents.
                {
                    if ((Row.AccountCode == "") || (Row.CostCentreCode == ""))
                    {
                        MessageBox.Show(
                            String.Format(Catalog.GetString("Account and Cost Centre must be specified in Document {0}."), AApDocument.DocumentCode),
                            Catalog.GetString("Post Document"), MessageBoxButtons.OK, MessageBoxIcon.Stop);
                        return false;
                    }

                    String AccountCostCentre = Row.AccountCode + "|" + Row.CostCentreCode;

                    if (!AccountCodesCostCentres.Contains(AccountCostCentre))
                    {
                        AccountCodesCostCentres.Add(AccountCostCentre);
                    }
                }
            }

            //
            // The check is done on the server..

            String ReportMsg = TRemote.MFinance.AP.WebConnectors.CheckAccountsAndCostCentres(AApDocument.LedgerNumber, AccountCodesCostCentres);

            if (ReportMsg != "")
            {
                MessageBox.Show(ReportMsg, Catalog.GetString("Invalid Account"), MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return false;
            }

            return true;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="AApDocument"></param>
        /// <returns>true if the document TotalAmount equals the sum of its parts!</returns>
        public static bool BatchBalancesOK(AccountsPayableTDS Atds, AApDocumentRow AApDocument)
        {
            decimal DocumentBalance = AApDocument.TotalAmount;

            if (DocumentBalance == 0)
            {
                System.Windows.Forms.MessageBox.Show(
                    String.Format(Catalog.GetString("The document {0} is empty."), AApDocument.DocumentCode),
                    Catalog.GetString("Balance Problem"));
                return false;
            }

            foreach (AApDocumentDetailRow Row in Atds.AApDocumentDetail.Rows)
            {
                if (Row.ApDocumentId == AApDocument.ApDocumentId) // NOTE: When called from elsewhere, the TDS could contain data for several documents.
                {
                    DocumentBalance -= Row.Amount;
                }
            }

            if (DocumentBalance == 0.0m)
            {
                return true;
            }
            else
            {
                System.Windows.Forms.MessageBox.Show(
                    String.Format(Catalog.GetString("The document {0} Amount does not equal the sum of the detail lines."), AApDocument.DocumentCode),
                    Catalog.GetString("Balance Problem"));
                return false;
            }
        }
        /// <summary>
        /// generate the invoices from a text file that was generated with Benerator
        /// </summary>
        /// <param name="AInputBeneratorFile"></param>
        /// <param name="AYear">eg. 2013</param>
        /// <param name="ASmallNumber">boolean to keep the size of the demo database down</param>
        public static void GenerateInvoices(string AInputBeneratorFile, int AYear, bool ASmallNumber)
        {
            MaxInvoicesPerYear = (ASmallNumber ? 25 : 200);

            XmlDocument doc = TCsv2Xml.ParseCSVFile2Xml(AInputBeneratorFile, ",");

            XmlNode RecordNode = doc.FirstChild.NextSibling.FirstChild;

            AccountsPayableTDS MainDS = new AccountsPayableTDS();

            // get a list of potential suppliers
            string sqlGetSupplierPartnerKeys =
                "SELECT PUB_a_ap_supplier.p_partner_key_n, PUB_a_ap_supplier.a_currency_code_c " +
                "FROM PUB_p_organisation, PUB_a_ap_supplier WHERE PUB_a_ap_supplier.p_partner_key_n = PUB_p_organisation.p_partner_key_n";
            DataTable SupplierKeys = DBAccess.GDBAccessObj.SelectDT(sqlGetSupplierPartnerKeys, "keys", null);

            // get a list of potential expense account codes
            string sqlGetExpenseAccountCodes = "SELECT a_account_code_c FROM PUB_a_account WHERE a_ledger_number_i = " +
                                               FLedgerNumber.ToString() +
                                               " AND a_account_type_c = 'Expense' AND a_account_active_flag_l = true AND a_posting_status_l = true";
            DataTable AccountCodes = DBAccess.GDBAccessObj.SelectDT(sqlGetExpenseAccountCodes, "codes", null);

            while (RecordNode != null)
            {
                int            supplierID   = Convert.ToInt32(TXMLParser.GetAttribute(RecordNode, "Supplier")) % SupplierKeys.Rows.Count;
                Int64          SupplierKey  = Convert.ToInt64(SupplierKeys.Rows[supplierID].ItemArray[0]);
                String         CurrencyCode = Convert.ToString(SupplierKeys.Rows[supplierID].ItemArray[1]);
                AApDocumentRow invoiceRow   = MainDS.AApDocument.NewRowTyped(true);

                invoiceRow.LedgerNumber     = FLedgerNumber;
                invoiceRow.ApDocumentId     = (Int32)TSequenceWebConnector.GetNextSequence(TSequenceNames.seq_ap_document);
                invoiceRow.ApNumber         = invoiceRow.ApDocumentId;
                invoiceRow.DocumentCode     = invoiceRow.ApDocumentId.ToString();
                invoiceRow.PartnerKey       = SupplierKey;
                invoiceRow.Reference        = "something";
                invoiceRow.DateIssued       = Convert.ToDateTime(TXMLParser.GetAttribute(RecordNode, "DateIssued"));
                invoiceRow.DateIssued       = new DateTime(AYear, invoiceRow.DateIssued.Month, invoiceRow.DateIssued.Day);
                invoiceRow.DateEntered      = invoiceRow.DateIssued;
                invoiceRow.TotalAmount      = Convert.ToDecimal(TXMLParser.GetAttribute(RecordNode, "Amount")) / 100.0m;
                invoiceRow.CurrencyCode     = CurrencyCode;
                invoiceRow.ApAccount        = "9100";
                invoiceRow.DocumentStatus   = MFinanceConstants.AP_DOCUMENT_APPROVED;
                invoiceRow.LastDetailNumber = 1;

                // TODO reasonable exchange rate for non base currency. need to check currency of supplier
                invoiceRow.ExchangeRateToBase = 1.0m;

                MainDS.AApDocument.Rows.Add(invoiceRow);

                AApDocumentDetailRow detailRow = MainDS.AApDocumentDetail.NewRowTyped(true);
                detailRow.ApDocumentId   = invoiceRow.ApDocumentId;
                detailRow.DetailNumber   = 1;
                detailRow.LedgerNumber   = invoiceRow.LedgerNumber;
                detailRow.CostCentreCode = (FLedgerNumber * 100).ToString("0000");
                int accountID = Convert.ToInt32(TXMLParser.GetAttribute(RecordNode, "ExpenseAccount")) % AccountCodes.Rows.Count;
                detailRow.AccountCode = AccountCodes.Rows[accountID].ItemArray[0].ToString();
                detailRow.Amount      = invoiceRow.TotalAmount;

                MainDS.AApDocumentDetail.Rows.Add(detailRow);

                if (MainDS.AApDocument.Rows.Count > MaxInvoicesPerYear)
                {
                    break;
                }

                RecordNode = RecordNode.NextSibling;
            }

            AccountsPayableTDSAccess.SubmitChanges(MainDS);
        }
        /// <summary>
        /// Post all tagged documents
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void PostAllTagged(object sender, EventArgs e)
        {
            // This will throw an exception if insufficient permissions
            TSecurityChecks.CheckUserModulePermissions("FINANCE-2", "PostAllTagged [raised by Client Proxy for ModuleAccessManager]");

            string MsgTitle = Catalog.GetString("Document Posting");

            AccountsPayableTDS TempDS = LoadTaggedDocuments();

            List <int> PostTheseDocs = new List <int>();

            TempDS.AApDocument.DefaultView.Sort = AApDocumentDetailTable.GetApDocumentIdDBName();

            string testString = "|CANCELLED|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>
        /// This static function is called from several places
        /// </summary>
        /// <param name="Atds"></param>
        /// <param name="Adocument"></param>
        /// <returns>true if this document seems OK to post.</returns>
        public static bool ApDocumentCanPost(AccountsPayableTDS Atds, AApDocumentRow Adocument)
        {
            // If the batch will not balance, or required attributes are missing, I'll stop right here..

            if (!BatchBalancesOK(Atds, Adocument))
            {
                return false;
            }

            if (!AllLinesAccountsOK(Atds, Adocument))
            {
                return false;
            }

            if (!AllLinesHaveAttributes(Atds, Adocument))
            {
                return false;
            }

            if (!ExchangeRateIsOk(Atds, Adocument))
            {
                return false;
            }

            if (!CurrencyIsOkForPosting(Atds, Adocument))
            {
                return false;
            }

            return true;
        }