コード例 #1
0
        public static bool TrainBankStatement(Int32 ALedgerNumber, DateTime ADateOfStatement, string ABankAccountCode)
        {
            // get the statement keys
            TDBTransaction ReadTransaction = DBAccess.GDBAccessObj.BeginTransaction(IsolationLevel.ReadCommitted);

            AEpStatementTable Statements = new AEpStatementTable();
            AEpStatementRow   row        = Statements.NewRowTyped(false);

            row.LedgerNumber    = ALedgerNumber;
            row.Date            = ADateOfStatement;
            row.BankAccountCode = ABankAccountCode;

            Statements = AEpStatementAccess.LoadUsingTemplate(row, ReadTransaction);

            DBAccess.GDBAccessObj.RollbackTransaction();

            if (Statements.Rows.Count == 0)
            {
                return(false);
            }

            // search for already posted gift batches, and do the matching for these imported statements
            TBankImportMatching.Train(Statements);

            return(true);
        }
        private void PopulateStatementGrid(object sender, EventArgs e)
        {
            if (RunningPopulateStatementGrid)
            {
                return;
            }

            // somehow, the datetimepicker throws an event, when we are reading the Date property
            RunningPopulateStatementGrid = true;

            DateTime dateStatementsFrom = DateTime.MinValue;

            if (dtpShowStatementsFrom.Date.HasValue)
            {
                dateStatementsFrom = dtpShowStatementsFrom.Date.Value;
            }

            // update the grid with the bank statements
            AEpStatementTable stmts = FPluginRemote.WebConnectors.GetImportedBankStatements(FLedgerNumber, dateStatementsFrom);

            grdSelectStatement.Columns.Clear();
            grdSelectStatement.AddTextColumn(Catalog.GetString("Bank statement"), stmts.ColumnFilename);
            grdSelectStatement.AddDateColumn(Catalog.GetString("Date"), stmts.ColumnDate);

            stmts.DefaultView.AllowNew    = false;
            stmts.DefaultView.Sort        = AEpStatementTable.GetDateDBName() + " desc";
            grdSelectStatement.DataSource = new DevAge.ComponentModel.BoundDataView(stmts.DefaultView);

            grdSelectStatement.AutoSizeCells();

            RunningPopulateStatementGrid = false;
        }
コード例 #3
0
ファイル: Matching.cs プロジェクト: TheBigBear/openpetra
        /// <summary>
        /// train with imported bank statements and existing gift batches
        /// </summary>
        public static void Train(AEpStatementTable AStatements)
        {
            int stmtCounter = 0;

            // go through all statements in the dataset, and find gift matches for those days
            foreach (AEpStatementRow stmt in AStatements.Rows)
            {
                TLogging.LogAtLevel(1,
                                    "Training Statement " + stmt.StatementKey.ToString() + " " + stmt.Date.ToShortDateString() + " " + stmt.Filename);

                stmtCounter++;

                if (TProgressTracker.GetCurrentState(DomainManager.GClientID.ToString()).CancelJob == true)
                {
                    TProgressTracker.FinishJob(DomainManager.GClientID.ToString());
                    return;
                }

                // first stage: collect historic matches from database:
                // go through each transaction of the statement,
                // and see if you can find a donation on that date with the same amount from the same bank account
                // store this as a match

                TLogging.LogAtLevel(1, "loading data ...");
                BankImportTDS MainDS = LoadData(stmt.LedgerNumber, stmt.StatementKey);

                // Get all gifts at given date
                TLogging.LogAtLevel(1, "get gifts by date ...");
                List <int> GiftBatchNumbers;
                GetGiftsByDate(stmt.LedgerNumber, MainDS, stmt.Date, stmt.BankAccountCode, out GiftBatchNumbers);

                int SelectedGiftBatch = -1;

                if (GiftBatchNumbers.Count > 0)
                {
                    TLogging.LogAtLevel(1, "Found gift batches: " + GiftBatchNumbers.Count.ToString());

                    foreach (int i in GiftBatchNumbers)
                    {
                        TLogging.LogAtLevel(1, "   " + i.ToString());
                    }

                    SelectedGiftBatch = FindGiftBatch(MainDS, stmt);
                    TLogging.LogAtLevel(1, " selected gift batch:   " + SelectedGiftBatch.ToString());
                }

                if (SelectedGiftBatch == -1)
                {
                    // cannot find the posted gift batch without any doubt
                    continue;
                }

                CreateMatches(MainDS, stmt, SelectedGiftBatch, true);
            }
        }
コード例 #4
0
        public static AEpStatementTable GetImportedBankStatements(Int32 ALedgerNumber, DateTime AStartDate)
        {
            TDBTransaction ReadTransaction = DBAccess.GDBAccessObj.BeginTransaction(IsolationLevel.ReadCommitted);

            AEpStatementTable localTable = new AEpStatementTable();
            AEpStatementRow   row        = localTable.NewRowTyped(false);

            row.LedgerNumber = ALedgerNumber;
            row.Date         = AStartDate;

            StringCollection operators = new StringCollection();

            operators.Add("=");
            operators.Add(">=");

            localTable = AEpStatementAccess.LoadUsingTemplate(row, operators, null, ReadTransaction);

            DBAccess.GDBAccessObj.RollbackTransaction();

            return(localTable);
        }
コード例 #5
0
        public static Int32 CreateGLBatch(BankImportTDS AMainDS,
                                          Int32 ALedgerNumber,
                                          Int32 AStatementKey,
                                          Int32 AGLBatchNumber,
                                          out TVerificationResultCollection AVerificationResult)
        {
            AMainDS.AEpTransaction.DefaultView.RowFilter =
                String.Format("{0}={1}",
                              AEpTransactionTable.GetStatementKeyDBName(),
                              AStatementKey);
            AMainDS.AEpStatement.DefaultView.RowFilter =
                String.Format("{0}={1}",
                              AEpStatementTable.GetStatementKeyDBName(),
                              AStatementKey);
            AEpStatementRow stmt = (AEpStatementRow)AMainDS.AEpStatement.DefaultView[0].Row;

            AVerificationResult = null;

            Int32          DateEffectivePeriodNumber, DateEffectiveYearNumber;
            TDBTransaction Transaction = DBAccess.GDBAccessObj.BeginTransaction(IsolationLevel.ReadCommitted);

            if (!TFinancialYear.IsValidPostingPeriod(ALedgerNumber, stmt.Date, out DateEffectivePeriodNumber, out DateEffectiveYearNumber,
                                                     Transaction))
            {
                string msg = String.Format(Catalog.GetString("Cannot create a GL batch for date {0} since it is not in an open period of the ledger."),
                                           stmt.Date.ToShortDateString());
                TLogging.Log(msg);
                AVerificationResult = new TVerificationResultCollection();
                AVerificationResult.Add(new TVerificationResult(Catalog.GetString("Creating GL Batch"), msg, TResultSeverity.Resv_Critical));

                DBAccess.GDBAccessObj.RollbackTransaction();
                return(-1);
            }

            Int32 BatchYear, BatchPeriod;

            // if DateEffective is outside the range of open periods, use the most fitting date
            DateTime DateEffective = stmt.Date;

            TFinancialYear.GetLedgerDatePostingPeriod(ALedgerNumber, ref DateEffective, out BatchYear, out BatchPeriod, Transaction, true);

            ALedgerTable LedgerTable = ALedgerAccess.LoadByPrimaryKey(ALedgerNumber, Transaction);

            DBAccess.GDBAccessObj.RollbackTransaction();

            GLBatchTDS GLDS = TGLTransactionWebConnector.CreateABatch(ALedgerNumber);

            ABatchRow glbatchRow = GLDS.ABatch[0];

            glbatchRow.BatchPeriod      = BatchPeriod;
            glbatchRow.DateEffective    = DateEffective;
            glbatchRow.BatchDescription = String.Format(Catalog.GetString("bank import for date {0}"), stmt.Date.ToShortDateString());

            decimal HashTotal   = 0.0M;
            decimal DebitTotal  = 0.0M;
            decimal CreditTotal = 0.0M;

            // TODO: support several journals
            // TODO: support several currencies, support other currencies than the base currency
            AJournalRow gljournalRow = GLDS.AJournal.NewRowTyped();

            gljournalRow.LedgerNumber        = glbatchRow.LedgerNumber;
            gljournalRow.BatchNumber         = glbatchRow.BatchNumber;
            gljournalRow.JournalNumber       = glbatchRow.LastJournal + 1;
            gljournalRow.TransactionCurrency = LedgerTable[0].BaseCurrency;
            glbatchRow.LastJournal++;
            gljournalRow.JournalPeriod       = glbatchRow.BatchPeriod;
            gljournalRow.DateEffective       = glbatchRow.DateEffective;
            gljournalRow.JournalDescription  = glbatchRow.BatchDescription;
            gljournalRow.SubSystemCode       = CommonAccountingSubSystemsEnum.GL.ToString();
            gljournalRow.TransactionTypeCode = CommonAccountingTransactionTypesEnum.STD.ToString();
            gljournalRow.ExchangeRateToBase  = 1.0m;
            GLDS.AJournal.Rows.Add(gljournalRow);

            foreach (DataRowView dv in AMainDS.AEpTransaction.DefaultView)
            {
                AEpTransactionRow transactionRow = (AEpTransactionRow)dv.Row;

                DataView v = AMainDS.AEpMatch.DefaultView;
                v.RowFilter = AEpMatchTable.GetActionDBName() + " = '" + MFinanceConstants.BANK_STMT_STATUS_MATCHED_GL + "' and " +
                              AEpMatchTable.GetMatchTextDBName() + " = '" + transactionRow.MatchText + "'";

                if (v.Count > 0)
                {
                    AEpMatchRow     match = (AEpMatchRow)v[0].Row;
                    ATransactionRow trans = GLDS.ATransaction.NewRowTyped();
                    trans.LedgerNumber      = glbatchRow.LedgerNumber;
                    trans.BatchNumber       = glbatchRow.BatchNumber;
                    trans.JournalNumber     = gljournalRow.JournalNumber;
                    trans.TransactionNumber = gljournalRow.LastTransactionNumber + 1;
                    trans.AccountCode       = match.AccountCode;
                    trans.CostCentreCode    = match.CostCentreCode;
                    trans.Reference         = match.Reference;
                    trans.Narrative         = match.Narrative;
                    trans.TransactionDate   = transactionRow.DateEffective;

                    if (transactionRow.TransactionAmount < 0)
                    {
                        trans.AmountInBaseCurrency = -1 * transactionRow.TransactionAmount;
                        trans.TransactionAmount    = -1 * transactionRow.TransactionAmount;
                        trans.DebitCreditIndicator = true;
                        DebitTotal += trans.AmountInBaseCurrency;
                    }
                    else
                    {
                        trans.AmountInBaseCurrency = transactionRow.TransactionAmount;
                        trans.TransactionAmount    = transactionRow.TransactionAmount;
                        trans.DebitCreditIndicator = false;
                        CreditTotal += trans.AmountInBaseCurrency;
                    }

                    GLDS.ATransaction.Rows.Add(trans);
                    gljournalRow.LastTransactionNumber++;

                    // add one transaction for the bank as well
                    trans = GLDS.ATransaction.NewRowTyped();
                    trans.LedgerNumber      = glbatchRow.LedgerNumber;
                    trans.BatchNumber       = glbatchRow.BatchNumber;
                    trans.JournalNumber     = gljournalRow.JournalNumber;
                    trans.TransactionNumber = gljournalRow.LastTransactionNumber + 1;
                    trans.AccountCode       = stmt.BankAccountCode;
                    trans.CostCentreCode    = TLedgerInfo.GetStandardCostCentre(ALedgerNumber);
                    trans.Reference         = match.Reference;
                    trans.Narrative         = match.Narrative;
                    trans.TransactionDate   = transactionRow.DateEffective;

                    if (transactionRow.TransactionAmount < 0)
                    {
                        trans.AmountInBaseCurrency = -1 * transactionRow.TransactionAmount;
                        trans.TransactionAmount    = -1 * transactionRow.TransactionAmount;
                        trans.DebitCreditIndicator = false;
                        CreditTotal += trans.AmountInBaseCurrency;
                    }
                    else
                    {
                        trans.AmountInBaseCurrency = transactionRow.TransactionAmount;
                        trans.TransactionAmount    = transactionRow.TransactionAmount;
                        trans.DebitCreditIndicator = true;
                        DebitTotal += trans.AmountInBaseCurrency;
                    }

                    GLDS.ATransaction.Rows.Add(trans);
                    gljournalRow.LastTransactionNumber++;
                }
            }

            gljournalRow.JournalDebitTotal  = DebitTotal;
            gljournalRow.JournalCreditTotal = CreditTotal;
            glbatchRow.BatchDebitTotal      = DebitTotal;
            glbatchRow.BatchCreditTotal     = CreditTotal;
            glbatchRow.BatchControlTotal    = HashTotal;

            TVerificationResultCollection VerificationResult;

            TSubmitChangesResult result = TGLTransactionWebConnector.SaveGLBatchTDS(ref GLDS,
                                                                                    out VerificationResult);

            if (result == TSubmitChangesResult.scrOK)
            {
                return(glbatchRow.BatchNumber);
            }

            TLogging.Log("Problems storing GL Batch");
            return(-1);
        }
コード例 #6
0
        public static Int32 CreateGiftBatch(
            Int32 ALedgerNumber,
            Int32 AStatementKey,
            Int32 AGiftBatchNumber,
            out TVerificationResultCollection AVerificationResult)
        {
            BankImportTDS MainDS = GetBankStatementTransactionsAndMatches(AStatementKey, ALedgerNumber);

            string MyClientID = DomainManager.GClientID.ToString();

            TProgressTracker.InitProgressTracker(MyClientID,
                                                 Catalog.GetString("Creating gift batch"),
                                                 MainDS.AEpTransaction.DefaultView.Count + 10);

            AVerificationResult = new TVerificationResultCollection();

            MainDS.AEpTransaction.DefaultView.RowFilter =
                String.Format("{0}={1}",
                              AEpTransactionTable.GetStatementKeyDBName(),
                              AStatementKey);
            MainDS.AEpStatement.DefaultView.RowFilter =
                String.Format("{0}={1}",
                              AEpStatementTable.GetStatementKeyDBName(),
                              AStatementKey);
            AEpStatementRow stmt = (AEpStatementRow)MainDS.AEpStatement.DefaultView[0].Row;

            // TODO: optional: use the preselected gift batch, AGiftBatchNumber

            Int32          DateEffectivePeriodNumber, DateEffectiveYearNumber;
            DateTime       BatchDateEffective = stmt.Date;
            TDBTransaction Transaction        = DBAccess.GDBAccessObj.BeginTransaction(IsolationLevel.ReadCommitted);

            if (!TFinancialYear.GetLedgerDatePostingPeriod(ALedgerNumber, ref BatchDateEffective, out DateEffectiveYearNumber,
                                                           out DateEffectivePeriodNumber,
                                                           Transaction, true))
            {
                // just use the latest possible date
                string msg =
                    String.Format(Catalog.GetString("Date {0} is not in an open period of the ledger, using date {1} instead for the gift batch."),
                                  stmt.Date.ToShortDateString(),
                                  BatchDateEffective.ToShortDateString());
                AVerificationResult.Add(new TVerificationResult(Catalog.GetString("Creating Gift Batch"), msg, TResultSeverity.Resv_Info));
            }

            ACostCentreAccess.LoadViaALedger(MainDS, ALedgerNumber, Transaction);
            AMotivationDetailAccess.LoadViaALedger(MainDS, ALedgerNumber, Transaction);

            MainDS.AEpMatch.DefaultView.Sort =
                AEpMatchTable.GetActionDBName() + ", " +
                AEpMatchTable.GetMatchTextDBName();

            if (MainDS.AEpTransaction.DefaultView.Count == 0)
            {
                AVerificationResult.Add(new TVerificationResult(
                                            Catalog.GetString("Creating Gift Batch"),
                                            String.Format(Catalog.GetString("There are no transactions for statement #{0}."), AStatementKey),
                                            TResultSeverity.Resv_Info));
                return(-1);
            }

            foreach (DataRowView dv in MainDS.AEpTransaction.DefaultView)
            {
                AEpTransactionRow transactionRow = (AEpTransactionRow)dv.Row;

                DataRowView[] matches = MainDS.AEpMatch.DefaultView.FindRows(new object[] {
                    MFinanceConstants.BANK_STMT_STATUS_MATCHED_GIFT,
                    transactionRow.MatchText
                });

                if (matches.Length > 0)
                {
                    AEpMatchRow match = (AEpMatchRow)matches[0].Row;

                    if (match.IsDonorKeyNull() || (match.DonorKey == 0))
                    {
                        string msg =
                            String.Format(Catalog.GetString("Cannot create a gift for transaction {0} since there is no valid donor."),
                                          transactionRow.Description);
                        AVerificationResult.Add(new TVerificationResult(Catalog.GetString("Creating Gift Batch"), msg, TResultSeverity.Resv_Critical));
                        DBAccess.GDBAccessObj.RollbackTransaction();
                        return(-1);
                    }
                }
            }

            string MatchedGiftReference = stmt.Filename;

            if (!stmt.IsBankAccountKeyNull())
            {
                string sqlGetBankSortCode =
                    "SELECT bank.p_branch_code_c " +
                    "FROM PUB_p_banking_details details, PUB_p_bank bank " +
                    "WHERE details.p_banking_details_key_i = ?" +
                    "AND details.p_bank_key_n = bank.p_partner_key_n";
                OdbcParameter param = new OdbcParameter("detailkey", OdbcType.Int);
                param.Value = stmt.BankAccountKey;

                PBankTable bankTable = new PBankTable();
                DBAccess.GDBAccessObj.SelectDT(bankTable, sqlGetBankSortCode, Transaction, new OdbcParameter[] { param }, 0, 0);

                MatchedGiftReference = bankTable[0].BranchCode + " " + stmt.Date.Day.ToString();
            }

            DBAccess.GDBAccessObj.RollbackTransaction();

            GiftBatchTDS GiftDS = TGiftTransactionWebConnector.CreateAGiftBatch(
                ALedgerNumber,
                BatchDateEffective,
                String.Format(Catalog.GetString("bank import for date {0}"), stmt.Date.ToShortDateString()));

            AGiftBatchRow giftbatchRow = GiftDS.AGiftBatch[0];

            giftbatchRow.BankAccountCode = stmt.BankAccountCode;

            decimal HashTotal = 0.0M;

            MainDS.AEpTransaction.DefaultView.Sort =
                AEpTransactionTable.GetNumberOnPaperStatementDBName();

            MainDS.AEpMatch.DefaultView.RowFilter = String.Empty;
            MainDS.AEpMatch.DefaultView.Sort      =
                AEpMatchTable.GetActionDBName() + ", " +
                AEpMatchTable.GetMatchTextDBName();

            int counter = 5;

            foreach (DataRowView dv in MainDS.AEpTransaction.DefaultView)
            {
                TProgressTracker.SetCurrentState(MyClientID,
                                                 Catalog.GetString("Preparing the gifts"),
                                                 counter++);

                AEpTransactionRow transactionRow = (AEpTransactionRow)dv.Row;

                DataRowView[] matches = MainDS.AEpMatch.DefaultView.FindRows(new object[] {
                    MFinanceConstants.BANK_STMT_STATUS_MATCHED_GIFT,
                    transactionRow.MatchText
                });

                if (matches.Length > 0)
                {
                    AEpMatchRow match = (AEpMatchRow)matches[0].Row;

                    AGiftRow gift = GiftDS.AGift.NewRowTyped();
                    gift.LedgerNumber          = giftbatchRow.LedgerNumber;
                    gift.BatchNumber           = giftbatchRow.BatchNumber;
                    gift.GiftTransactionNumber = giftbatchRow.LastGiftNumber + 1;
                    gift.DonorKey    = match.DonorKey;
                    gift.DateEntered = transactionRow.DateEffective;
                    gift.Reference   = MatchedGiftReference;
                    GiftDS.AGift.Rows.Add(gift);
                    giftbatchRow.LastGiftNumber++;

                    foreach (DataRowView r in matches)
                    {
                        match = (AEpMatchRow)r.Row;

                        AGiftDetailRow detail = GiftDS.AGiftDetail.NewRowTyped();
                        detail.LedgerNumber          = gift.LedgerNumber;
                        detail.BatchNumber           = gift.BatchNumber;
                        detail.GiftTransactionNumber = gift.GiftTransactionNumber;
                        detail.DetailNumber          = gift.LastDetailNumber + 1;
                        gift.LastDetailNumber++;

                        detail.GiftTransactionAmount = match.GiftTransactionAmount;
                        detail.GiftAmount            = match.GiftTransactionAmount;
                        HashTotal += match.GiftTransactionAmount;
                        detail.MotivationGroupCode  = match.MotivationGroupCode;
                        detail.MotivationDetailCode = match.MotivationDetailCode;

                        // do not use the description in comment one, because that could show up on the gift receipt???
                        // detail.GiftCommentOne = transactionRow.Description;

                        detail.CommentOneType        = MFinanceConstants.GIFT_COMMENT_TYPE_BOTH;
                        detail.CostCentreCode        = match.CostCentreCode;
                        detail.RecipientKey          = match.RecipientKey;
                        detail.RecipientLedgerNumber = match.RecipientLedgerNumber;

                        AMotivationDetailRow motivation = (AMotivationDetailRow)MainDS.AMotivationDetail.Rows.Find(
                            new object[] { ALedgerNumber, detail.MotivationGroupCode, detail.MotivationDetailCode });

                        if (motivation == null)
                        {
                            AVerificationResult.Add(new TVerificationResult(
                                                        String.Format(Catalog.GetString("creating gift for match {0}"), transactionRow.Description),
                                                        String.Format(Catalog.GetString("Cannot find motivation group '{0}' and motivation detail '{1}'"),
                                                                      detail.MotivationGroupCode, detail.MotivationDetailCode),
                                                        TResultSeverity.Resv_Critical));
                        }

                        if (detail.CostCentreCode.Length == 0)
                        {
                            // try to retrieve the current costcentre for this recipient
                            if (detail.RecipientKey != 0)
                            {
                                detail.RecipientLedgerNumber = TGiftTransactionWebConnector.GetRecipientFundNumber(detail.RecipientKey);

                                detail.CostCentreCode = TGiftTransactionWebConnector.IdentifyPartnerCostCentre(detail.LedgerNumber,
                                                                                                               detail.RecipientLedgerNumber);
                            }
                            else
                            {
                                if (motivation != null)
                                {
                                    detail.CostCentreCode = motivation.CostCentreCode;
                                }
                            }
                        }

                        // check for active cost centre
                        ACostCentreRow costcentre = (ACostCentreRow)MainDS.ACostCentre.Rows.Find(new object[] { ALedgerNumber, detail.CostCentreCode });

                        if ((costcentre == null) || !costcentre.CostCentreActiveFlag)
                        {
                            AVerificationResult.Add(new TVerificationResult(
                                                        String.Format(Catalog.GetString("creating gift for match {0}"), transactionRow.Description),
                                                        Catalog.GetString("Invalid or inactive cost centre"),
                                                        TResultSeverity.Resv_Critical));
                        }

                        GiftDS.AGiftDetail.Rows.Add(detail);
                    }
                }
            }

            TProgressTracker.SetCurrentState(MyClientID,
                                             Catalog.GetString("Submit to database"),
                                             counter++);

            if (AVerificationResult.HasCriticalErrors)
            {
                return(-1);
            }

            giftbatchRow.HashTotal  = HashTotal;
            giftbatchRow.BatchTotal = HashTotal;

            // do not overwrite the parameter, because there might be the hint for a different gift batch date
            TVerificationResultCollection VerificationResultSubmitChanges;

            TSubmitChangesResult result = TGiftTransactionWebConnector.SaveGiftBatchTDS(ref GiftDS,
                                                                                        out VerificationResultSubmitChanges);

            TProgressTracker.FinishJob(MyClientID);

            if (result == TSubmitChangesResult.scrOK)
            {
                return(giftbatchRow.BatchNumber);
            }

            return(-1);
        }
コード例 #7
0
        /// <summary>
        /// this can be used from the unit tests
        /// </summary>
        public static BankImportTDS ImportBankStatementHelper(Int32 ALedgerNumber,
                                                              string ABankAccountCode,
                                                              string ASeparator,
                                                              string ADateFormat,
                                                              string ANumberFormat,
                                                              string ACurrencyCode,
                                                              string AColumnsUsage,
                                                              string AStartAfterLine,
                                                              string ABankStatementFilename,
                                                              string AStatementData)
        {
            Int32  FirstTransactionRow = 0;
            string DateFormat          = (ADateFormat == "MDY" ? "M/d/yyyy" : "d.M.yyyy");
            string ThousandsSeparator  = (ANumberFormat == "American" ? "," : ".");
            string DecimalSeparator    = (ANumberFormat == "American" ? "." : ",");

            List <String> StatementData = new List <string>();

            string [] stmtarray = AStatementData.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string line in stmtarray)
            {
                StatementData.Add(line);
            }

            // skip headers
            Int32 lineCounter = FirstTransactionRow;

            // TODO: support splitting a file by month?
            // at the moment this only works for files that are already split by month
            // TODO: check if this statement has already been imported, by the stmt.Filename; delete old statement
            BankImportTDS   MainDS = new BankImportTDS();
            AEpStatementRow stmt   = MainDS.AEpStatement.NewRowTyped();

            stmt.StatementKey = -1;

            // TODO: BankAccountKey should be NOT NULL. for the moment not time to implement
            // stmt.BankAccountKey = Convert.ToInt64(TXMLParser.GetAttribute(RootNode, "BankAccountKey"));
            stmt.Filename = Path.GetFileName(ABankStatementFilename.Replace('\\', Path.DirectorySeparatorChar));

            // depending on the path of BankStatementFilename you could determine between several bank accounts
            // search all config parameters starting with "BankNameFor",
            // and see if the rest of the parameter name is part of the filename or path
            StringCollection BankNameForParameters = TAppSettingsManager.GetKeys("BankNameFor");

            foreach (string BankNameForParameter in BankNameForParameters)
            {
                if (stmt.Filename.ToLower().Contains(BankNameForParameter.Substring("BankNameFor".Length).ToLower()))
                {
                    stmt.Filename = TAppSettingsManager.GetValue(BankNameForParameter);
                }
            }

            if (stmt.Filename.Length > AEpStatementTable.GetFilenameLength())
            {
                // use the last number of characters of the path and filename
                stmt.Filename = ABankStatementFilename.Substring(ABankStatementFilename.Length - AEpStatementTable.GetFilenameLength());
            }

            stmt.LedgerNumber    = ALedgerNumber;
            stmt.CurrencyCode    = ACurrencyCode;
            stmt.BankAccountCode = ABankAccountCode;
            MainDS.AEpStatement.Rows.Add(stmt);

            // TODO would need to allow the user to change the order&meaning of columns
            string[] ColumnsUsage = AColumnsUsage.Split(new char[] { ',' });
            Dictionary <DateTime, List <AEpTransactionRow> > TransactionsPerMonth = new Dictionary <DateTime, List <AEpTransactionRow> >();

            bool startParsing = (AStartAfterLine == String.Empty);

            for (; lineCounter < StatementData.Count; lineCounter++)
            {
                string line = StatementData[lineCounter];

                if (AStartAfterLine == line)
                {
                    startParsing = true;
                    continue;
                }

                if (!startParsing)
                {
                    continue;
                }

                AEpTransactionRow row = MainDS.AEpTransaction.NewRowTyped();
                row.StatementKey = stmt.StatementKey;

                foreach (string UseAs in ColumnsUsage)
                {
                    if (line == String.Empty)
                    {
                        // this line is too short, does not have enough columns.
                        // ignore this row.
                        row = null;
                        continue;
                    }

                    string Value = StringHelper.GetNextCSV(ref line, StatementData, ref lineCounter, ASeparator);

                    if (UseAs.ToLower() == "dateeffective")
                    {
                        if (Value.Length == "dd.mm.yy".Length)
                        {
                            DateFormat = DateFormat.Replace("yyyy", "yy");
                        }

                        try
                        {
                            row.DateEffective = XmlConvert.ToDateTime(Value, DateFormat);
                        }
                        catch (Exception)
                        {
                            TLogging.Log("Problem with date effective: " + Value + " (Format: " + DateFormat + ")");
                        }
                    }
                    else if (UseAs.ToLower() == "accountname")
                    {
                        if (row.AccountName.Length > 0)
                        {
                            row.AccountName += " ";
                        }

                        row.AccountName += Value;
                    }
                    else if (UseAs.ToLower() == "description")
                    {
                        // remove everything after DTA; it is not relevant and confused matching
                        if (Value.IndexOf(" DTA ") > 0)
                        {
                            Value = Value.Substring(0, Value.IndexOf(" DTA "));
                        }

                        if (row.Description.Length > 0)
                        {
                            row.Description += " ";
                        }

                        row.Description += Value;
                    }
                    else if (UseAs.ToLower() == "amount")
                    {
                        if (Value.Contains(" "))
                        {
                            // cut off currency code; should have been defined in the data description file, for the whole batch
                            Value = Value.Substring(0, Value.IndexOf(" ") - 1);
                        }

                        Value = Value.Replace(ThousandsSeparator, "");
                        Value = Value.Replace(DecimalSeparator, ".");

                        row.TransactionAmount = Convert.ToDecimal(Value, System.Globalization.CultureInfo.InvariantCulture);
                    }
                    else if (UseAs.ToLower() == "directdebiths")
                    {
                        if (Value == "S")
                        {
                            row.TransactionAmount *= -1;
                        }
                    }
                    else if (UseAs.ToLower() == "currency")
                    {
                        if (stmt.CurrencyCode == string.Empty)
                        {
                            stmt.CurrencyCode = Value.ToUpper();
                        }
                        else if (stmt.CurrencyCode != Value.ToUpper())
                        {
                            throw new Exception("cannot mix several currencies in the same bank statement file");
                        }
                    }
                }

                if (row == null)
                {
                    // ignore this line
                    continue;
                }

                // all transactions with positive amount can be donations
                if (row.TransactionAmount > 0)
                {
                    row.TransactionTypeCode = MFinanceConstants.BANK_STMT_POTENTIAL_GIFT;
                }

                DateTime month = new DateTime(row.DateEffective.Year, row.DateEffective.Month, 1);
                if (!TransactionsPerMonth.ContainsKey(month))
                {
                    TransactionsPerMonth.Add(month, new List <AEpTransactionRow>());
                }
                TransactionsPerMonth[month].Add(row);
            }

            if (TransactionsPerMonth.Keys.Count == 0)
            {
                // cannot find any transactions
                return(MainDS);
            }

            // now find the month that should be imported
            DateTime MonthToBeImported = DateTime.MinValue;

            foreach (DateTime month in TransactionsPerMonth.Keys)
            {
                if (MonthToBeImported == DateTime.MinValue)
                {
                    MonthToBeImported = month;
                }
                else
                {
                    if (TransactionsPerMonth[month].Count > TransactionsPerMonth[MonthToBeImported].Count)
                    {
                        MonthToBeImported = month;
                    }
                }
            }

            DateTime latestDate = DateTime.MinValue;
            Int32    rowCount   = 0;

            foreach (AEpTransactionRow row in TransactionsPerMonth[MonthToBeImported])
            {
                rowCount++;

                row.Order = rowCount;
                row.NumberOnPaperStatement = row.Order;

                MainDS.AEpTransaction.Rows.Add(row);
                if (row.DateEffective > latestDate)
                {
                    latestDate = row.DateEffective;
                }
            }

            stmt.Date = latestDate;

            return(MainDS);
        }
コード例 #8
0
        /// <summary>
        /// import one MT940 file, split into multiple statements per year
        /// </summary>
        static public bool ImportFromFile(
            Int32 ALedgerNumber,
            string ABankAccountCode,
            string AFileName,
            string AFileContent,
            bool AParsePreviousYear,
            out Int32 AStatementKey,
            out TVerificationResultCollection AVerificationResult)
        {
            AVerificationResult = new TVerificationResultCollection();
            TSwiftParser parser = new TSwiftParser();

            parser.ProcessFileContent(AFileContent);

            BankImportTDS MainDS           = new BankImportTDS();
            Int32         statementCounter = MainDS.AEpStatement.Rows.Count;

            foreach (TStatement stmt in parser.statements)
            {
                Int32 transactionCounter = 0;

                foreach (TTransaction tr in stmt.transactions)
                {
                    BankImportTDSAEpTransactionRow row = MainDS.AEpTransaction.NewRowTyped();

                    row.StatementKey = (statementCounter + 1) * -1;
                    row.Order        = transactionCounter;
                    row.DetailKey    = -1;
                    row.AccountName  = tr.partnerName;

                    if ((tr.accountCode != null) && Regex.IsMatch(tr.accountCode, "^[A-Z]"))
                    {
                        // this is an iban
                        row.Iban              = tr.accountCode;
                        row.Bic               = tr.bankCode;
                        row.BranchCode        = tr.accountCode.Substring(4, 8).TrimStart(new char[] { '0' });
                        row.BankAccountNumber = tr.accountCode.Substring(12).TrimStart(new char[] { '0' });
                    }
                    else if (tr.accountCode != null)
                    {
                        row.BankAccountNumber = tr.accountCode.TrimStart(new char[] { '0' });
                        row.BranchCode        = tr.bankCode == null ? string.Empty : tr.bankCode.TrimStart(new char[] { '0' });
                        row.Iban = string.Empty;
                        row.Bic  = string.Empty;
                    }

                    row.DateEffective       = tr.valueDate;
                    row.TransactionAmount   = tr.amount;
                    row.Description         = tr.description;
                    row.TransactionTypeCode = tr.typecode;

                    // see the codes: http://www.hettwer-beratung.de/sepa-spezialwissen/sepa-technische-anforderungen/sepa-gesch%C3%A4ftsvorfallcodes-gvc-mt-940/
                    if ((row.TransactionTypeCode == "052") ||
                        (row.TransactionTypeCode == "051") ||
                        (row.TransactionTypeCode == "053") ||
                        (row.TransactionTypeCode == "067") ||
                        (row.TransactionTypeCode == "068") ||
                        (row.TransactionTypeCode == "069") ||
                        (row.TransactionTypeCode == "119") || /* Einzelbuchung Spende (Purpose: CHAR) */
                        (row.TransactionTypeCode == "152") || /* SEPA Credit Transfer Einzelbuchung Dauerauftrag */
                        (row.TransactionTypeCode == "166") || /* SEPA Credit Transfer */
                        (row.TransactionTypeCode == "169")    /* SEPA Credit Transfer Donation */
                        )
                    {
                        row.TransactionTypeCode += MFinanceConstants.BANK_STMT_POTENTIAL_GIFT;
                    }

                    MainDS.AEpTransaction.Rows.Add(row);

                    transactionCounter++;
                }

                AEpStatementRow epstmt = MainDS.AEpStatement.NewRowTyped();
                epstmt.StatementKey    = (statementCounter + 1) * -1;
                epstmt.LedgerNumber    = ALedgerNumber;
                epstmt.Date            = stmt.date;
                epstmt.CurrencyCode    = stmt.currency;
                epstmt.Filename        = AFileName;
                epstmt.BankAccountCode = ABankAccountCode;
                epstmt.IdFromBank      = stmt.id;

                if (AFileName.Length > AEpStatementTable.GetFilenameLength())
                {
                    epstmt.Filename =
                        TAppSettingsManager.GetValue("BankNameFor" + stmt.bankCode + "/" + stmt.accountCode,
                                                     stmt.bankCode + "/" + stmt.accountCode, true);
                }

                epstmt.StartBalance = stmt.startBalance;
                epstmt.EndBalance   = stmt.endBalance;

                MainDS.AEpStatement.Rows.Add(epstmt);

                // sort by amount, and by accountname; this is the order of the paper statements and attachments
                MainDS.AEpTransaction.DefaultView.Sort = BankImportTDSAEpTransactionTable.GetTransactionAmountDBName() + "," +
                                                         BankImportTDSAEpTransactionTable.GetOrderDBName();
                MainDS.AEpTransaction.DefaultView.RowFilter = BankImportTDSAEpTransactionTable.GetStatementKeyDBName() + "=" +
                                                              epstmt.StatementKey.ToString();

                // starting with the most negative amount, which should be the last in the order on the statement
                Int32 countOrderOnStatement = MainDS.AEpTransaction.DefaultView.Count;
                bool  countingNegative      = true;

                foreach (DataRowView rv in MainDS.AEpTransaction.DefaultView)
                {
                    BankImportTDSAEpTransactionRow row = (BankImportTDSAEpTransactionRow)rv.Row;

                    if ((row.TransactionAmount > 0) && countingNegative)
                    {
                        countingNegative      = false;
                        countOrderOnStatement = 1;
                    }

                    if (countingNegative)
                    {
                        row.NumberOnPaperStatement = countOrderOnStatement;
                        countOrderOnStatement--;
                    }
                    else
                    {
                        row.NumberOnPaperStatement = countOrderOnStatement;
                        countOrderOnStatement++;
                    }
                }

                statementCounter++;
            }

            if (TBankStatementImport.StoreNewBankStatement(
                    MainDS,
                    out AStatementKey) == TSubmitChangesResult.scrOK)
            {
                return(true);
            }

            return(false);
        }
コード例 #9
0
        public static bool TrainBankStatement(Int32 ALedgerNumber, DateTime ADateOfStatement, string ABankAccountCode)
        {
            // get the statement keys
            TDBTransaction ReadTransaction = DBAccess.GDBAccessObj.BeginTransaction(IsolationLevel.ReadCommitted);

            AEpStatementTable Statements = new AEpStatementTable();
            AEpStatementRow row = Statements.NewRowTyped(false);

            row.LedgerNumber = ALedgerNumber;
            row.Date = ADateOfStatement;
            row.BankAccountCode = ABankAccountCode;

            Statements = AEpStatementAccess.LoadUsingTemplate(row, ReadTransaction);

            DBAccess.GDBAccessObj.RollbackTransaction();

            if (Statements.Rows.Count == 0)
            {
                return false;
            }

            // search for already posted gift batches, and do the matching for these imported statements
            TBankImportMatching.Train(Statements);

            return true;
        }
コード例 #10
0
        public static AEpStatementTable GetImportedBankStatements(Int32 ALedgerNumber, DateTime AStartDate)
        {
            TDBTransaction ReadTransaction = DBAccess.GDBAccessObj.BeginTransaction(IsolationLevel.ReadCommitted);

            AEpStatementTable localTable = new AEpStatementTable();
            AEpStatementRow row = localTable.NewRowTyped(false);

            row.LedgerNumber = ALedgerNumber;
            row.Date = AStartDate;

            StringCollection operators = new StringCollection();
            operators.Add("=");
            operators.Add(">=");

            localTable = AEpStatementAccess.LoadUsingTemplate(row, operators, null, ReadTransaction);

            DBAccess.GDBAccessObj.RollbackTransaction();

            return localTable;
        }
コード例 #11
0
        /// <summary>
        /// import one CAMT file, split into multiple statements per year
        /// </summary>
        static public bool ImportFromFile(
            Int32 ALedgerNumber,
            string ABankAccountCode,
            string AFileName,
            string AFileContent,
            bool AParsePreviousYear,
            out Int32 AStatementKey,
            out TVerificationResultCollection AVerificationResult)
        {
            TCAMTParser parser = new TCAMTParser();

            AStatementKey = -1;

            parser.ProcessFileContent(AFileContent, AParsePreviousYear, out AVerificationResult);

            if (AVerificationResult.HasCriticalErrors)
            {
                return(false);
            }

            BankImportTDS MainDS           = new BankImportTDS();
            Int32         statementCounter = MainDS.AEpStatement.Rows.Count;

            foreach (TStatement stmt in parser.statements)
            {
                if (stmt.severalYears && !AParsePreviousYear)
                {
                    // parse the transactions of the previous year separately
                    ImportFromFile(ALedgerNumber, ABankAccountCode, AFileName, AFileContent,
                                   true,
                                   out AStatementKey, out AVerificationResult);

                    if (AVerificationResult.HasCriticalErrors)
                    {
                        return(false);
                    }
                }

                Int32 transactionCounter = 0;

                foreach (TTransaction tr in stmt.transactions)
                {
                    BankImportTDSAEpTransactionRow row = MainDS.AEpTransaction.NewRowTyped();

                    row.StatementKey = (statementCounter + 1) * -1;
                    row.Order        = transactionCounter;
                    row.DetailKey    = -1;
                    row.AccountName  = tr.partnerName;

                    if ((tr.accountCode != null) && Regex.IsMatch(tr.accountCode, "^[A-Z]"))
                    {
                        // this is an iban
                        row.Iban              = tr.accountCode;
                        row.Bic               = tr.bankCode;
                        row.BranchCode        = tr.accountCode.Substring(4, 8).TrimStart(new char[] { '0' });
                        row.BankAccountNumber = tr.accountCode.Substring(12).TrimStart(new char[] { '0' });
                    }
                    else if (tr.accountCode != null)
                    {
                        row.BankAccountNumber = tr.accountCode.TrimStart(new char[] { '0' });
                        row.BranchCode        = tr.bankCode == null ? string.Empty : tr.bankCode.TrimStart(new char[] { '0' });
                        row.Iban = string.Empty;
                        row.Bic  = string.Empty;
                    }

                    row.DateEffective       = tr.valueDate;
                    row.TransactionAmount   = tr.amount;
                    row.Description         = tr.description;
                    row.TransactionTypeCode = tr.typecode;

                    // see the codes: https://www.wgzbank.de/export/sites/wgzbank/de/wgzbank/downloads/produkte_leistungen/firmenkunden/zv_aktuelles/Uebersicht-GVC-und-Buchungstexte-WGZ-BANK_V062015.pdf
                    if ((row.TransactionTypeCode == "052") ||
                        (row.TransactionTypeCode == "051") ||
                        (row.TransactionTypeCode == "053") ||
                        (row.TransactionTypeCode == "067") ||
                        (row.TransactionTypeCode == "068") ||
                        (row.TransactionTypeCode == "069") ||
                        (row.TransactionTypeCode == "119") || /* Einzelbuchung Spende (Purpose: CHAR) */
                        (row.TransactionTypeCode == "152") || /* SEPA Credit Transfer Einzelbuchung Dauerauftrag */
                        (row.TransactionTypeCode == "166") || /* SEPA Credit Transfer */
                        (row.TransactionTypeCode == "169")    /* SEPA Credit Transfer Donation */
                        )
                    {
                        // only incoming money is a potential gift
                        if (row.TransactionAmount > 0)
                        {
                            row.TransactionTypeCode += MFinanceConstants.BANK_STMT_POTENTIAL_GIFT;
                        }
                    }

                    MainDS.AEpTransaction.Rows.Add(row);

                    transactionCounter++;
                }

                AEpStatementRow epstmt = MainDS.AEpStatement.NewRowTyped();
                epstmt.LedgerNumber    = ALedgerNumber;
                epstmt.StatementKey    = (statementCounter + 1) * -1;
                epstmt.Date            = stmt.date;
                epstmt.CurrencyCode    = stmt.currency;
                epstmt.BankAccountCode = ABankAccountCode;
                epstmt.IdFromBank      = stmt.id;

                if (AFileName.Length > AEpStatementTable.GetFilenameLength())
                {
                    epstmt.Filename =
                        stmt.bankCode + "/" + stmt.accountCode;
                }
                else
                {
                    epstmt.Filename = AFileName;
                }

                epstmt.StartBalance = stmt.startBalance;
                epstmt.EndBalance   = stmt.endBalance;

                MainDS.AEpStatement.Rows.Add(epstmt);

                // sort by amount, and by accountname; this is the order of the paper statements and attachments
                MainDS.AEpTransaction.DefaultView.Sort = BankImportTDSAEpTransactionTable.GetTransactionAmountDBName() + "," +
                                                         BankImportTDSAEpTransactionTable.GetOrderDBName();
                MainDS.AEpTransaction.DefaultView.RowFilter = BankImportTDSAEpTransactionTable.GetStatementKeyDBName() + "=" +
                                                              epstmt.StatementKey.ToString();

                // starting with the most negative amount, which should be the last in the order on the statement
                Int32 countOrderOnStatement = MainDS.AEpTransaction.DefaultView.Count;
                bool  countingNegative      = true;

                foreach (DataRowView rv in MainDS.AEpTransaction.DefaultView)
                {
                    BankImportTDSAEpTransactionRow row = (BankImportTDSAEpTransactionRow)rv.Row;

                    if ((row.TransactionAmount > 0) && countingNegative)
                    {
                        countingNegative      = false;
                        countOrderOnStatement = 1;
                    }

                    if (countingNegative)
                    {
                        row.NumberOnPaperStatement = countOrderOnStatement;
                        countOrderOnStatement--;
                    }
                    else
                    {
                        row.NumberOnPaperStatement = countOrderOnStatement;
                        countOrderOnStatement++;
                    }
                }

                statementCounter++;
            }

            if (TBankStatementImport.StoreNewBankStatement(
                    MainDS,
                    out AStatementKey) == TSubmitChangesResult.scrOK)
            {
                return(true);
            }

            return(false);
        }
コード例 #12
0
        /// <summary>
        /// train with imported bank statements and existing gift batches
        /// </summary>
        public static void Train(AEpStatementTable AStatements)
        {
            int stmtCounter = 0;

            // go through all statements in the dataset, and find gift matches for those days
            foreach (AEpStatementRow stmt in AStatements.Rows)
            {
                TLogging.LogAtLevel(1,
                    "Training Statement " + stmt.StatementKey.ToString() + " " + stmt.Date.ToShortDateString() + " " + stmt.Filename);

                stmtCounter++;

                if (TProgressTracker.GetCurrentState(DomainManager.GClientID.ToString()).CancelJob == true)
                {
                    TProgressTracker.FinishJob(DomainManager.GClientID.ToString());
                    return;
                }

                // first stage: collect historic matches from database:
                // go through each transaction of the statement,
                // and see if you can find a donation on that date with the same amount from the same bank account
                // store this as a match

                TLogging.LogAtLevel(1, "loading data ...");
                BankImportTDS MainDS = LoadData(stmt.LedgerNumber, stmt.StatementKey);

                // Get all gifts at given date
                TLogging.LogAtLevel(1, "get gifts by date ...");
                List <int>GiftBatchNumbers;
                GetGiftsByDate(stmt.LedgerNumber, MainDS, stmt.Date, stmt.BankAccountCode, out GiftBatchNumbers);

                int SelectedGiftBatch = -1;

                if (GiftBatchNumbers.Count > 0)
                {
                    TLogging.LogAtLevel(1, "Found gift batches: " + GiftBatchNumbers.Count.ToString());

                    foreach (int i in GiftBatchNumbers)
                    {
                        TLogging.LogAtLevel(1, "   " + i.ToString());
                    }

                    SelectedGiftBatch = FindGiftBatch(MainDS, stmt);
                    TLogging.LogAtLevel(1, " selected gift batch:   " + SelectedGiftBatch.ToString());
                }

                if (SelectedGiftBatch == -1)
                {
                    // cannot find the posted gift batch without any doubt
                    continue;
                }

                CreateMatches(MainDS, stmt, SelectedGiftBatch, true);
            }
        }