context: //
  // DO NOT REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  //
  // @Authors:
  //       timop, Tim Ingham, ChristianK (refactoring, '3-As')
  //
  // Copyright 2004-2013 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;
  using System.Collections.Generic;
  using System.Data;
  using System.IO;
  using System.Data.Odbc;
  using NUnit.Framework;
  using Ict.Testing.NUnitTools;
  using Ict.Testing.NUnitPetraServer;
  using Ict.Petra.Server.MFinance.GL;
  using Ict.Common;
  using Ict.Common.Data;
  using Ict.Common.DB;
  using Ict.Common.Remoting.Server;
  using Ict.Common.Remoting.Shared;
  using Ict.Common.Verification;
  using Ict.Petra.Server.App.Core;
  using Ict.Petra.Server.MFinance.AP.WebConnectors;
  using Ict.Petra.Shared.MFinance.AP.Data;
  using Ict.Petra.Shared.MFinance.Account.Data;
  using Ict.Petra.Server.MFinance.AP.Data.Access;
  using Ict.Petra.Server.MFinance.Account.Data.Access;
  using Ict.Petra.Server.MFinance.Common;
  using Ict.Petra.Shared.MFinance;
  
  namespace Ict.Testing.Petra.Server.MFinance.AP
  {
      /// <summary>
      /// a couple of tests for AP
      /// </summary>
      [TestFixture]
      public class TestAP
      {
          private const int FLedgerNumber = 43;
  
          /// <summary>
          /// Holds various bits of information about AP.
          /// </summary>
          private struct AAPInfos
          {
              public DateTime PeriodStartDate;
              public DateTime PeriodEndDate;
              public string ForexGainsLossesAccount;
              public string BankAccount;
              public string CurrencyCode;
              public string ApAccountCode;
              public string CostCentreCode;
              public AccountsPayableTDS ApDS;
          }
  
          /// <summary>
          /// TestFixtureSetUp
          /// </summary>
          [TestFixtureSetUp]
          public void Init()
          {
              TPetraServerConnector.Connect();
          }
  
          /// <summary>
          /// TearDown the test
          /// </summary>
          [TestFixtureTearDown]
          public void TearDownTest()
          {
              TPetraServerConnector.Disconnect();
          }
  
          // using the sample supplier from the demo database
          const long SUPPLIER_PARTNER_KEY = 43005002;
          const long SUPPLIER_FOREIGN_PARTNER_KEY = 43005003;
  
          /// <summary>
          /// Posts a document and pays it. (The supplier DOESN'T work with foreign currency.)
          /// </summary>
          [Test]
          public void SimpleDocument_ExpectPostingAndPayingWorking()
          {
              //
              // Arrange
              //
              decimal Amount = 399.0m;
              decimal APAccountBalanceBefore;
              decimal ABankAccountBefore;
              decimal AExpAccountBefore;
              TVerificationResultCollection VerificationResult;
  
              List <int>DocumentIDs;
              int PaymentNumber;
              AAPInfos APInfos;
  
              CommonNUnitFunctions.ResetDatabase();
  
              APInfos = PostSimpleAPDocument(Amount, "Test", "Detail Item", out APAccountBalanceBefore, out ABankAccountBefore,
                  out AExpAccountBefore, out DocumentIDs);
  
              //
              // Act: Pay the AP document
              //
              VerificationResult = PayAPDocument(APInfos.ApDS.AApDocument[0].ApDocumentId, Amount,
                  APInfos.BankAccount, APInfos.CurrencyCode, APInfos.PeriodEndDate, out PaymentNumber);
              CommonNUnitFunctions.EnsureNullOrEmptyVerificationResult(VerificationResult);   // Guard Assert
  
              // Save the current amount on the AP account
              decimal APAccountBalanceAfter = new TGet_GLM_Info(FLedgerNumber,
                  APInfos.ApAccountCode, APInfos.CostCentreCode).YtdActual;
              decimal BankAccountAfter = new TGet_GLM_Info(FLedgerNumber,
                  APInfos.BankAccount, APInfos.CostCentreCode).YtdActual;
  
              //
              // Primary Assert: Paying OK?
              //
              // Check the amount on the AP account
              Assert.AreEqual(0.0m, APAccountBalanceAfter - APAccountBalanceBefore, "after paying the invoice, the AP account should be cleared");
              Assert.AreEqual((-1.0m) * Amount, BankAccountAfter - ABankAccountBefore, "after paying the invoice, the bank account should be credited");
          }
  
          /// <summary>
          /// Posts a document and pays it. The supplier works with foreign currency.
          /// </summary>
          [Test]
          public void ForeignCurrencySupplier_ExpectDocumentPostingAndPayingWorking()
          {
              //
              // Arrange
              //
              int PaymentNumber;
  
              List <int>DocumentIDs;
              decimal APAccountBalanceBefore;
              decimal BankAccountBefore;
              decimal RevalAccountBefore;
  
              CommonNUnitFunctions.ResetDatabase();
  
              // Act and Assert: both encapsulated in the method that gets called!
              PostAndPayForeignSupplierAPDocument("Test", out PaymentNumber, out DocumentIDs,
                  out APAccountBalanceBefore, out BankAccountBefore, out RevalAccountBefore);
          }
  
          /// <summary>
          /// Posts a document and pays it, then reverses it. The supplier works with foreign currency.
          /// </summary>
          [Test]
          public void ForeignCurrencySupplier_ExpectDocumentPostingPayingAndReversingWorking()
          {
              //
              // Arrange
              //
              decimal APAccountBalanceBefore;
              decimal BankAccountBefore;
              decimal RevalAccountBefore;
              TVerificationResultCollection VerificationResult;
              int PaymentNumber;
  
              List <int>DocumentIDs;
              AAPInfos APInfos;
  
              CommonNUnitFunctions.ResetDatabase();
  
              // Post and pay a document with a foreign currency supplier
              APInfos = PostAndPayForeignSupplierAPDocument("Test Reverse", out PaymentNumber, out DocumentIDs,
                  out APAccountBalanceBefore, out BankAccountBefore, out RevalAccountBefore);
  
  
              //
              // Act: Immediately "un-pay" and "un-post" this invoice!
              //
              VerificationResult = ReversePayment(PaymentNumber, APInfos.PeriodEndDate, DocumentIDs, APInfos.ApDS);
              CommonNUnitFunctions.EnsureNullOrEmptyVerificationResult(VerificationResult);   // Guard Assert
  
              // Save the current amount on the AP account
              decimal APAccountBalanceAfter = new TGet_GLM_Info(FLedgerNumber,
                  APInfos.ApAccountCode, APInfos.CostCentreCode).YtdActual;
              decimal BankAccountAfter = new TGet_GLM_Info(FLedgerNumber,
                  APInfos.BankAccount, APInfos.CostCentreCode).YtdForeign;
              decimal RevalAccountAfter = new TGet_GLM_Info(FLedgerNumber,
                  APInfos.ForexGainsLossesAccount, APInfos.CostCentreCode).YtdActual;
  
              //
              // Primary Assert: Reversal OK?
              //
              // Now I can see whether anything is left over by all these
              // various transactions, that should have added up to 0.
              // Check the amount on the AP account
              Assert.AreEqual(APAccountBalanceBefore, APAccountBalanceAfter, "After paying then reversing, the AP account should be as before.");
              Assert.AreEqual(BankAccountBefore, BankAccountAfter, "After paying then reversing, the Bank account should be as before.");
              Assert.AreEqual(
                  Math.Round(RevalAccountAfter, 2),
                  Math.Round(RevalAccountBefore, 2),
                  "After paying then reversing, the Forex Gains/Losses Account account should be as before.");
          }
  
          #region Helper Methods
  
          private AAPInfos APTestsArrangement(Int64 APartnerKey, decimal AAmount, decimal? AExchangeRatePosting,
              string ADocumentCode, string ANarrative)
          {
              AAPInfos APInfos = new AAPInfos();
  
              TVerificationResultCollection VerificationResult = CreateAPDocument(APartnerKey,
                  AAmount,
                  AExchangeRatePosting,
                  ADocumentCode,
                  ANarrative,
                  out APInfos.ApDS);
  
              CommonNUnitFunctions.EnsureNullOrEmptyVerificationResult(VerificationResult);   // Guard Assert
  
              GetLedgerInfo(out APInfos.PeriodStartDate, out APInfos.PeriodEndDate, out APInfos.ForexGainsLossesAccount);
  
              SetupSupplierAndDocumentInfo(APInfos.ApDS,
                  out APInfos.BankAccount,
                  out APInfos.CurrencyCode,
                  out APInfos.ApAccountCode,
                  out APInfos.CostCentreCode);
  
              return APInfos;
          }
  
          private void GetLedgerInfo(out DateTime APeriodStartDate, out DateTime APeriodEndDate,
              out string AForexGainsLossesAccount)
          {
              ALedgerTable LedgerTable = null;
  
              TDBTransaction Transaction = null;
  
              DBAccess.GDBAccessObj.GetNewOrExistingAutoReadTransaction(IsolationLevel.ReadCommitted,
                  TEnforceIsolationLevel.eilMinimum,
                  ref Transaction,
                  delegate
                  {
                      LedgerTable = ALedgerAccess.LoadByPrimaryKey(FLedgerNumber, Transaction);
                  });
  
              AForexGainsLossesAccount = LedgerTable[0].ForexGainsLossesAccount;
  
              TFinancialYear.GetStartAndEndDateOfPeriod(FLedgerNumber, LedgerTable[0].CurrentPeriod, out APeriodStartDate, out APeriodEndDate, null);
          }
  
          private void SetupSupplierAndDocumentInfo(AccountsPayableTDS AMainDS, out string ABankAccount, out string ACurrencyCode,
              out string AApAccountCode, out string ACostCentreCode)
          {
              ABankAccount = AMainDS.AApSupplier[0].DefaultBankAccount;
  
gt:             ACurrencyCode = AMainDS.AApDocument[0].CurrencyCode;