Beispiel #1
0
        private void ProcessDocument(Document document)
        {
            statements = new List <TStatement>();

            AccountStatement2[] stmts = document.BkToCstmrStmt.Stmt;

            foreach (AccountStatement2 accStatement in stmts)
            {
                TStatement stmt = new TStatement();

                stmt.id           = accStatement.Id;
                stmt.elctrncSeqNb = accStatement.ElctrncSeqNb.ToString();

                stmt.accountCode = accStatement.Acct?.Id?.Item?.ToString();
                stmt.bankCode    = accStatement.Acct?.Svcr?.FinInstnId?.BIC;
                stmt.currency    = accStatement.Acct?.Ccy;

                stmt.severalYears = false;
                string nm      = accStatement.Acct?.Ownr?.Nm;
                string ownName = nm ?? "AccountNameFor" + stmt.bankCode + "/" + stmt.accountCode;

                CashBalance3[] balances = accStatement.Bal;
                if (balances != null)
                {
                    foreach (CashBalance3 balance in balances)
                    {
                        // PRCD: PreviouslyClosedBooked
                        if (balance.Tp?.CdOrPrtry?.Item?.ToString() == "PRCD")
                        {
                            stmt.startBalance = balance.Amt.Value;

                            // CreditDebitIndicator: CRDT or DBIT for credit or debit
                            if (balance.CdtDbtInd == CreditDebitCode.DBIT)
                            {
                                stmt.startBalance *= -1.0m;
                            }

                            stmt.startDate = balance.Dt.Item;
                        }
                        // CLBD: ClosingBooked
                        else if (balance.Tp?.CdOrPrtry?.Item?.ToString() == "CLBD")
                        {
                            stmt.endBalance = balance.Amt.Value;

                            // CreditDebitIndicator: CRDT or DBIT for credit or debit
                            if (balance.CdtDbtInd == CreditDebitCode.DBIT)
                            {
                                stmt.endBalance *= -1.0m;
                            }

                            stmt.endDate = balance.Dt.Item;
                        }

                        // ITBD: InterimBooked
                        // CLAV: ClosingAvailable
                        // FWAV: ForwardAvailable
                    }
                }

                //string strDiffBalance = "DiffBalanceFor" + stmt.bankCode + "/" + stmt.accountCode;
                //Decimal DiffBalance = 0.0m;
                //if (Decimal.TryParse(strDiffBalance, out DiffBalance))
                //{
                //    stmt.startBalance += DiffBalance;
                //    stmt.endBalance += DiffBalance;
                //}
                //else
                //{
                //    Log.Write("problem parsing decimal from configuration setting DiffBalanceFor" + stmt.bankCode + "/" + stmt.accountCode);
                //}

                //string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);

                //// if the file has already been split and moved, use the statement date from the file name (if it is on the last of december)
                //if (!filenameWithoutExtension.Contains("_C53_")
                //    && filenameWithoutExtension.EndsWith("1231")
                //    && stmt.date.Month != 12
                //    && stmt.date.Day != 31)
                //{
                //    stmt.date = new DateTime(stmt.date.Year - 1, 12, 31);
                //}

                ReportEntry2[] entries = accStatement.Ntry;
                if (entries != null)
                {
                    foreach (ReportEntry2 entry in entries)
                    {
                        if (entry.Amt.Ccy != stmt.currency)
                        {
                            throw new Exception("transaction currency " + entry.Amt.Ccy + " does not match the bank statement currency");
                        }

                        TTransaction tr = new TTransaction();

                        tr.pending = entry.Sts == EntryStatus2Code.PDNG;

                        if (entry.BookgDt != null)
                        {
                            tr.inputDate = entry.BookgDt.Item;
                        }
                        if (entry.ValDt != null)
                        {
                            tr.valueDate = entry.ValDt.Item;
                            if (tr.valueDate.Year != stmt.startDate.Year)
                            {
                                stmt.severalYears = true;
                            }
                        }

                        // Soll/Haben
                        tr.amount = entry.Amt.Value;
                        bool debit = entry.CdtDbtInd == CreditDebitCode.DBIT;
                        if (debit)
                        {
                            tr.amount *= -1.0m;
                        }

                        tr.storno = entry.RvslInd;

                        EntryDetails1     entryDetails = entry.NtryDtls?.FirstOrDefault();
                        EntryTransaction2 txDetails    = entryDetails?.TxDtls?.FirstOrDefault();

                        // Verwendungszweck
                        if (txDetails?.RmtInf?.Ustrd != null)
                        {
                            tr.description = string.Join(string.Empty, txDetails.RmtInf.Ustrd.Select(s => s?.Trim()));
                        }

                        tr.text = entry.AddtlNtryInf?.Trim();

                        tr.bankCode = debit ?
                                      txDetails?.RltdAgts?.CdtrAgt?.FinInstnId?.BIC :
                                      txDetails?.RltdAgts?.DbtrAgt?.FinInstnId?.BIC;

                        tr.partnerName = debit ?
                                         txDetails?.RltdPties?.Cdtr?.Nm :
                                         txDetails?.RltdPties?.Dbtr?.Nm;

                        tr.accountCode = debit ?
                                         txDetails?.RltdPties?.CdtrAcct?.Id?.Item?.ToString() :
                                         txDetails?.RltdPties?.DbtrAcct?.Id?.Item?.ToString();

                        string CrdtName = txDetails?.RltdPties?.Cdtr?.Nm;
                        string DbtrName = txDetails?.RltdPties?.Dbtr?.Nm;

                        if ((CrdtName != null) && (CrdtName != ownName))
                        {
                            if ((DbtrName != null) && (DbtrName == ownName))
                            {
                                // we are the debitor
                            }
                            else if (ownName != string.Empty)
                            {
                                // sometimes donors write the project or recipient in the field where the organisation is supposed to be
                                Log.Write("CrdtName is not like expected: " + tr.description + " --- " + CrdtName);
                            }
                        }

                        tr.endToEndId = txDetails?.Refs?.EndToEndId;

                        tr.msgId    = txDetails?.Refs?.MsgId;
                        tr.pmtInfId = txDetails?.Refs?.PmtInfId;
                        tr.mndtId   = txDetails?.Refs?.MndtId;
                        tr.id       = txDetails?.Refs?.Prtry?.Ref;

                        tr.customerRef = entry.AcctSvcrRef;

                        if (txDetails?.BkTxCd.Prtry.Cd != null)
                        {
                            // eg NSTO+152+00900. look for SEPA Geschäftsvorfallcodes
                            // see the codes: https://www.hettwer-beratung.de/business-portfolio/zahlungsverkehr/elektr-kontoinformationen-swift-mt-940/
                            string[] GVCCode = txDetails?.BkTxCd?.Prtry?.Cd?.Split(new char[] { '+' });
                            if (GVCCode.Length > 0)
                            {
                                tr.transactionTypeId = GVCCode[0];
                            }
                            if (GVCCode.Length > 1)
                            {
                                tr.typecode = GVCCode[1];
                            }
                        }

                        // for SEPA direct debit batches, there are multiple TxDtls records
                        if (entryDetails?.TxDtls?.Count() > 1)
                        {
                            tr.partnerName = string.Empty;
                            tr.description = string.Format("SEPA Sammel-Basislastschrift mit {0} Lastschriften", entryDetails?.TxDtls?.Count());
                        }

                        stmt.transactions.Add(tr);

                        Log.Write("count : " + stmt.transactions.Count.ToString());
                    }
                }

                statements.Add(stmt);
            }
        }
Beispiel #2
0
        /// <summary>
        /// processing CAMT file
        /// </summary>
        /// <param name="filename"></param>
        public void ProcessFile(string filename)
        {
            Console.WriteLine("Read file " + filename);
            statements = new List <TStatement>();

            CultureInfo backupCulture = Thread.CurrentThread.CurrentCulture;

            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(filename);
                string namespaceName      = "urn:iso:std:iso:20022:tech:xsd:camt.052.001.02";
                XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
                nsmgr.AddNamespace("camt", namespaceName);

                XmlNode nodeDocument = doc.DocumentElement;

                if ((nodeDocument == null) || (nodeDocument.Attributes["xmlns"].Value != namespaceName))
                {
                    throw new Exception("expecting xmlns = '" + namespaceName + "'");
                }

                XmlNodeList stmts = nodeDocument.SelectNodes("camt:BkToCstmrAcctRpt/camt:Rpt", nsmgr);
                Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                foreach (XmlNode nodeStatement in stmts)
                {
                    TStatement stmt = new TStatement();
                    currentStatement = stmt;

                    stmt.id          = nodeStatement.SelectSingleNode("camt:ElctrncSeqNb", nsmgr).InnerText;
                    stmt.accountCode = nodeStatement.SelectSingleNode("camt:Acct/camt:Id/camt:IBAN", nsmgr).InnerText;
                    stmt.bankCode    = nodeStatement.SelectSingleNode("camt:Acct/camt:Svcr/camt:FinInstnId/camt:BIC", nsmgr).InnerText;
                    stmt.currency    = nodeStatement.SelectSingleNode("camt:Acct/camt:Ccy", nsmgr).InnerText;

                    stmt.severalYears = false;
                    XmlNode nm      = nodeStatement.SelectSingleNode("camt:Acct/camt:Ownr/camt:Nm", nsmgr);
                    string  ownName = nm != null ? nm.InnerText :
                                      "AccountNameFor" + stmt.bankCode + "/" + stmt.accountCode;
                    XmlNodeList nodeBalances = nodeStatement.SelectNodes("camt:Bal", nsmgr);

                    foreach (XmlNode nodeBalance in nodeBalances)
                    {
                        // PRCD: PreviouslyClosedBooked
                        if (nodeBalance.SelectSingleNode("camt:Tp/camt:CdOrPrtry/camt:Cd", nsmgr).InnerText == "PRCD")
                        {
                            stmt.startBalance = Decimal.Parse(nodeBalance.SelectSingleNode("camt:Amt", nsmgr).InnerText);

                            // CreditDebitIndicator: CRDT or DBIT for credit or debit
                            if (nodeBalance.SelectSingleNode("camt:CdtDbtInd", nsmgr).InnerText == "DBIT")
                            {
                                stmt.startBalance *= -1.0m;
                            }

                            stmt.date = DateTime.Parse(nodeBalance.SelectSingleNode("camt:Dt", nsmgr).InnerText);
                        }
                        // CLBD: ClosingBooked
                        else if (nodeBalance.SelectSingleNode("camt:Tp/camt:CdOrPrtry/camt:Cd", nsmgr).InnerText == "CLBD")
                        {
                            stmt.endBalance = Decimal.Parse(nodeBalance.SelectSingleNode("camt:Amt", nsmgr).InnerText);

                            // CreditDebitIndicator: CRDT or DBIT for credit or debit
                            if (nodeBalance.SelectSingleNode("camt:CdtDbtInd", nsmgr).InnerText == "DBIT")
                            {
                                stmt.endBalance *= -1.0m;
                            }

                            stmt.date = DateTime.Parse(nodeBalance.SelectSingleNode("camt:Dt", nsmgr).InnerText);
                        }

                        // ITBD: InterimBooked
                        // CLAV: ClosingAvailable
                        // FWAV: ForwardAvailable
                    }

                    string  strDiffBalance = "DiffBalanceFor" + stmt.bankCode + "/" + stmt.accountCode;
                    Decimal DiffBalance    = 0.0m;
                    if (Decimal.TryParse(strDiffBalance, out DiffBalance))
                    {
                        stmt.startBalance += DiffBalance;
                        stmt.endBalance   += DiffBalance;
                    }
                    else
                    {
                        Log.Write("problem parsing decimal from configuration setting DiffBalanceFor" + stmt.bankCode + "/" + stmt.accountCode);
                    }

                    string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);

                    // if the file has already been split and moved, use the statement date from the file name (if it is on the last of december)
                    if (!filenameWithoutExtension.Contains("_C53_") &&
                        filenameWithoutExtension.EndsWith("1231") &&
                        stmt.date.Month != 12 &&
                        stmt.date.Day != 31)
                    {
                        stmt.date = new DateTime(stmt.date.Year - 1, 12, 31);
                    }

                    XmlNodeList nodeEntries = nodeStatement.SelectNodes("camt:Ntry", nsmgr);

                    foreach (XmlNode nodeEntry in nodeEntries)
                    {
                        TTransaction tr = new TTransaction();
                        tr.inputDate = DateTime.Parse(nodeEntry.SelectSingleNode("camt:BookgDt/camt:Dt", nsmgr).InnerText);
                        tr.valueDate = DateTime.Parse(nodeEntry.SelectSingleNode("camt:ValDt/camt:Dt", nsmgr).InnerText);

                        if (tr.valueDate.Year != stmt.date.Year)
                        {
                            // ignore transactions that are in a different year than the statement
                            stmt.severalYears = true;
                            continue;
                        }

                        tr.amount = Decimal.Parse(nodeEntry.SelectSingleNode("camt:Amt", nsmgr).InnerText);

                        if (nodeEntry.SelectSingleNode("camt:Amt", nsmgr).Attributes["Ccy"].Value != stmt.currency)
                        {
                            throw new Exception("transaction currency " + nodeEntry.SelectSingleNode("camt:Amt",
                                                                                                     nsmgr).Attributes["Ccy"].Value + " does not match the bank statement currency");
                        }

                        if (nodeEntry.SelectSingleNode("camt:CdtDbtInd", nsmgr).InnerText == "DBIT")
                        {
                            tr.amount *= -1.0m;
                        }

                        XmlNode desc = nodeEntry.SelectSingleNode("camt:NtryDtls/camt:TxDtls/camt:RmtInf/camt:Ustrd", nsmgr);
                        tr.description = desc != null ? desc.InnerText : String.Empty;
                        XmlNode partnerName = nodeEntry.SelectSingleNode("camt:NtryDtls/camt:TxDtls/camt:RltdPties/camt:Dbtr/camt:Nm", nsmgr);

                        if (partnerName != null)
                        {
                            tr.partnerName = partnerName.InnerText;
                        }

                        XmlNode accountCode = nodeEntry.SelectSingleNode("camt:NtryDtls/camt:TxDtls/camt:RltdPties/camt:DbtrAcct/camt:Id/camt:IBAN",
                                                                         nsmgr);

                        if (accountCode != null)
                        {
                            tr.accountCode = accountCode.InnerText;
                        }

                        XmlNode CrdtName = nodeEntry.SelectSingleNode("camt:NtryDtls/camt:TxDtls/camt:RltdPties/camt:Cdtr/camt:Nm", nsmgr);
                        XmlNode DbtrName = nodeEntry.SelectSingleNode("camt:NtryDtls/camt:TxDtls/camt:RltdPties/camt:Dbtr/camt:Nm", nsmgr);

                        if ((CrdtName != null) && (CrdtName.InnerText != ownName))
                        {
                            if ((DbtrName != null) && (DbtrName.InnerText == ownName))
                            {
                                // we are the debitor
                            }
                            else if (ownName != String.Empty)
                            {
                                // sometimes donors write the project or recipient in the field where the organisation is supposed to be
                                Log.Write("CrdtName is not like expected: " + tr.description + " --- " + CrdtName.InnerText);
                                tr.description += " " + CrdtName.InnerText;
                            }
                        }

                        XmlNode EndToEndId = nodeEntry.SelectSingleNode("camt:NtryDtls/camt:TxDtls/camt:Refs/camt:EndToEndId", nsmgr);

                        if ((EndToEndId != null) &&
                            (EndToEndId.InnerText != "NOTPROVIDED") &&
                            !EndToEndId.InnerText.StartsWith("LS-") &&
                            !EndToEndId.InnerText.StartsWith("ZV") &&
                            !EndToEndId.InnerText.StartsWith("IZV-DISPO"))
                        {
                            // sometimes donors write the project or recipient in unexpected field
                            Log.Write("EndToEndId: " + tr.description + " --- " + EndToEndId.InnerText);
                            tr.description += " " + EndToEndId.InnerText;
                        }

                        // eg NSTO+152+00900. look for SEPA Geschäftsvorfallcodes
                        // 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
                        string[] GVCCode =
                            nodeEntry.SelectSingleNode("camt:NtryDtls/camt:TxDtls/camt:BkTxCd/camt:Prtry/camt:Cd", nsmgr).InnerText.Split(
                                new char[] { '+' });
                        tr.typecode = GVCCode[1];

                        // for SEPA direct debit batches, there are multiple TxDtls records
                        XmlNodeList transactionDetails = nodeEntry.SelectNodes("camt:NtryDtls/camt:TxDtls", nsmgr);

                        if (transactionDetails.Count > 1)
                        {
                            tr.partnerName = String.Empty;
                            tr.description = String.Format("SEPA Sammel-Basislastschrift mit {0} Lastschriften",
                                                           transactionDetails.Count);
                        }

                        stmt.transactions.Add(tr);

                        Log.Write("count : " + stmt.transactions.Count.ToString());
                    }

                    statements.Add(stmt);
                }
            }
            catch (Exception e)
            {
                throw new Exception(
                          "problem with file " + filename + "; " + e.Message + Environment.NewLine + e.StackTrace);
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = backupCulture;
            }
        }