/*
/// This class writes DTAUS files for german banks, direct debit orders
/// see http://www.infodrom.org/projects/dtaus/dtaus.html for description of file format;
/// the data comes from special request objects
* DTA Specifiation: see http://www.ebics-zka.de/dokument/pdf/Anlage%203-Spezifikation%20der%20Datenformate%20-%20Version%202.3%20Endfassung%20vom%2005.11.2008.pdf
* DTA File checker (online): https://www.xpecto.de/index.php?id=148,7
* Author: Timotheus Pokorra (http://tpokorra.blogspot.com/2008/09/dtaus-with-c.html)
* Date: 22/09/2008
* Feel free to use this code in any way you like
* Florian Harbich: The extended code you have here is licensed as "Creative Commons NC-BY-SA"
* Please contact me at florian.harbich (at) die-rooter.de if you want to use this code
* in commercial projects.
* This file is licensed under Creative Commons Namensnennung-Keine kommerzielle Nutzung-Weitergabe unter gleichen Bedingungen 3.0 Deutschland license.
*
* Changelog:
* May 2009: Timotheus Pokorra: fixed a bug with long references, make more extensions possible
* Nov 2009: Florian Harbich (http://www.die-rooter.de/ITworks/archives/26-Writing-DTAUS-files-with-C-DTA-Dateien-mit-C-erzeugen.html):
* - changed input data type to special request object classes
* - fixed writing of dataset C extensions for all 13 allowed extra reference lines
* - fixed writing of decimal places of amount and amount checksum (according to DTAUS documentation)
* - fixed empty DM-Amount-Field: must be 0 instead of blank.
* - added selection of transaction type: Direct debit or bank transfer
* - added sample code
* Jun 2010: Florian Harbich
* - fixed extension block writing when no additional reference lines are specified
* - fixed DTAUS Log reference Line writing
* - CreateHumanReadableDTA method added for log file creation.
*/
using System;
using System.Linq;
using System.Collections.Specialized;
using System.Text;
using System.Collections.Generic;
namespace Ict.Plugin.EP.Germany
{
///
/// States the type of Transaction for a BankTransactionRequest.
///
public enum DTAUSTransactionType
{
///
/// Unknown type, this will fail when calling WriteDTAUSFile...
///
Unknown,
///
/// Direct debit request, the executive account will receive the money from the target accounts (Lastschrift-Einzug).
///
DirectDebit,
///
/// regular bank transfer, the executive account will transfer the money to the target accounts (Überweisung).
///
BankTransfer
}
///
/// Container for bank transaction requests. This object can be used together with the DTAUSWriter class in order to
/// create a DTAUS file for bank transactions.
///
/// Florian Harbich
/// 21.11.2009 16:11
/// $Revision: 201 $
/// $Id: DTAUSWriter.cs 201 2010-05-30 13:17:35Z flo $
public class BankTransactionRequest
{
public DTAUSTransactionType TransactionType { get; set; }
///
/// List of all concrete direct debit transactions for this request.
///
public List Transactions { get; private set; }
///
/// Gets or sets the creation date of this request structure.
///
public DateTime CreationDate { get; set; }
///
/// Gets or sets the requested execution date of the direct debit transactions.
/// For use with DTAUS files, this date must not be less than the creation date and not more than 15 days after the creation date.
/// Can be null to indicate immediate execution.
///
public DateTime? ExecutionDate { get; set; }
///
/// Gets or sets the bank number (BLZ) from which the transaction originates.
///
public int ExecutiveBankNumber { get; set; }
///
/// Gets or sets the bank account number from which thetransaction originates.
///
public long ExecutiveBankAccountNumber { get; set; }
///
/// Gets or sets the bank account holder from which the direct debit originates.
///
public string ExecutiveBankAccountHolder { get; set; }
///
/// Initializes a new instance of the class.
///
public BankTransactionRequest()
{
this.Transactions = new List();
this.TransactionType = DTAUSTransactionType.Unknown;
}
}
///
/// Container for bank transactions. This object can be used in BankTransactionRequest objects
/// together with the DTAUSWriter class in order to
/// create a DTAUS file for bank transactions.
///
/// Florian Harbich
/// 21.11.2009 16:15
/// $Revision: 201 $
/// $Id: DTAUSWriter.cs 201 2010-05-30 13:17:35Z flo $
public class BankTransactionItem
{
///
/// List of Reference lines (Verwendungszweck) for this transaction.
/// At least one line but not more than 14 are needed for use with DTAUS files.
///
public List ReferenceLines { get; private set; }
///
/// Gets or sets the bank number (BLZ) of the recipient account.
///
public int TargetBankNumber { get; set; }
///
/// Gets or sets the bank account number of the recipient account.
///
public long TargetBankAccountNumber { get; set; }
///
/// Gets or sets the bank account holder of the account stated in TargetBankAccountNumber
/// (the recipient account).
///
public string TargetBankAccountHolder { get; set; }
///
/// Gets or sets the amount of money that is requested from the TargetBankAccount in Euro-Cents.
/// For DTAUS files, this value must not be 0 or negative.
///
public int AmountCents { get; set; }
///
/// Initializes a new instance of the class.
///
public BankTransactionItem()
{
this.ReferenceLines = new List();
}
}
///
/// This class writes DTAUS files for german banks, direct debit orders
/// see http://www.infodrom.org/projects/dtaus/dtaus.html for description of file format;
/// the data comes from an xml file
///
public static class DTAUSWriter
{
///
/// States the alignment for length ensured strings.
///
private enum Alignment
{
///
/// The string is left-aligned, missing characters are added to the right.
///
AlignLeft,
///
/// The string is right-aligned, missing characters are added to the left.
///
AlignRight
};
///
/// The Encoding used for DTAUS files.
///
public static Encoding DTAUSFileEncoding = Encoding.ASCII;
///
/// Creates a complete DTAUS data string for the given request object.
///
/// The request to create the DTAUS dataset from. must not be null.
/// the complete DTAUS dataset for the given request as an ascii byte[].
/// When any data in the request is invalid (bad string length etc.),
/// an InvalidOperationException is created. See its message for detailed information.
/// The request object must contain at least one transaction,
/// else an ArgumentOutOfRangeException is thrown.
/// The TransactionType of the request is not supported.
public static byte[] WriteDTAUSFile(BankTransactionRequest request)
{
StringBuilder result = new StringBuilder();
if (request.Transactions.Count < 1)
{
throw new ArgumentOutOfRangeException("request", "the Direct debit request must contain at least one transaction object.");
}
WriteHeader(result, request);
foreach (BankTransactionItem transaction in request.Transactions)
{
WriteTransactionBody(result, transaction, request);
}
WriteFooter(result, request);
return DTAUSFileEncoding.GetBytes(result.ToString());
}
///
/// Creates a human readable protocol for the passed DTA request.
///
/// The request to transform into a human readable representation.
/// Stringbuilder with the human readable DTA log text
public static StringBuilder CreateHumanReadableDTA(BankTransactionRequest request)
{
StringBuilder humanReadableDTA = new StringBuilder();
humanReadableDTA.AppendLine("ANFANG DTA-Erstellung");
humanReadableDTA.AppendLine();
humanReadableDTA.AppendFormat("Erstellzeit: {0:G}", request.CreationDate);
humanReadableDTA.AppendLine();
humanReadableDTA.Append("Ausführung: ");
if (request.ExecutionDate.HasValue)
{
humanReadableDTA.AppendFormat("{0:G}", request.ExecutionDate);
}
else
{
humanReadableDTA.Append("sofort");
}
humanReadableDTA.AppendLine();
humanReadableDTA.AppendFormat("Absender-Kontoinhaber: {0}", request.ExecutiveBankAccountHolder);
humanReadableDTA.AppendLine();
humanReadableDTA.AppendFormat("Absender-Kontonummer: {0,10}", request.ExecutiveBankAccountNumber);
humanReadableDTA.AppendLine();
humanReadableDTA.AppendFormat("Absender-BLZ: {0,8}", request.ExecutiveBankNumber);
humanReadableDTA.AppendLine();
humanReadableDTA.Append("Transaktionsart: ");
if (request.TransactionType == DTAUSTransactionType.BankTransfer)
{
humanReadableDTA.Append("Überweisung");
}
else if (request.TransactionType == DTAUSTransactionType.DirectDebit)
{
humanReadableDTA.Append("Lastschrift-Einzug");
}
else
{
humanReadableDTA.AppendFormat("{0}", request.TransactionType);
}
humanReadableDTA.AppendLine();
foreach (BankTransactionItem transaction in request.Transactions)
{
humanReadableDTA.AppendLine();
humanReadableDTA.AppendFormat(" Empfänger-Kontoinhaber: {0}", transaction.TargetBankAccountHolder);
humanReadableDTA.AppendLine();
humanReadableDTA.AppendFormat(" Empfänger-Kontonummer: {0,10}", transaction.TargetBankAccountNumber);
humanReadableDTA.AppendLine();
humanReadableDTA.AppendFormat(" Empfänger-BLZ: {0,8}", transaction.TargetBankNumber);
humanReadableDTA.AppendLine();
humanReadableDTA.AppendFormat(" Betrag: {0:0.00} EUR", (double)transaction.AmountCents / 100);
humanReadableDTA.AppendLine();
foreach (string reference in transaction.ReferenceLines)
{
humanReadableDTA.AppendFormat(" Verwendungszweck: {0}", reference);
humanReadableDTA.AppendLine();
}
}
humanReadableDTA.AppendLine();
humanReadableDTA.AppendLine("ENDE DTA-Erstellung");
return humanReadableDTA;
}
#region internal helpers
///
/// Checks if the length of the input string is exactly the required length.
///
/// The input string to check.
/// The required length of the input string.
/// An error message to be created when the length does not match.
/// When the input string length does not math the required length,
/// an InvalidOperationException is created. See its message for detailed information.
private static void CheckLength(string input, int requiredlength, string msg)
{
if (input.Length != requiredlength)
{
throw new InvalidOperationException("wrong length: " + msg);
}
}
///
/// Formats the given input string such that
/// * it uses only uppercase letters
/// * it is not null and has no blanks at the beginning or end
/// * it contains only valid characters for DTAUS files.
///
/// The input to format, may be null.
/// the formatted input as described in the summary. never null, may be empty.
public static string FormatName(string input)
{
string allowedchars = " 0123456789.,&-/+*$%ABCDEFGHIJKLMNOPQRSTUVWXYZ";
input = (input ?? String.Empty).Trim().ToUpper().
Replace("Ü", "UE").
Replace("Ä", "AE").
Replace("Ö", "OE").
Replace("ß", "SS");
for (int count = 0; count < input.Length; count++)
{
if (allowedchars.IndexOf(input[count]) < 0)
{
input = input.Substring(0, count) + ' ' + input.Substring(count + 1);
}
}
return input;
}
///
/// Returns a string whose length is exactly requredlength characters.
///
/// The input string to pad up to the required length.
/// The length of the string to be returned.
/// The fieldname (only used in error message when the input string is too long).
/// The character used to pad the input string to the required length.
/// The Alignment of the padded string.
/// A string containing the input string with length requiredlength. missing characters from
/// input are padded using the fill character such that the input string is aligned acccording to the alignwhere parameter.
///The input length is longer than the requiredlength parameter.
private static string EnsureLength(string input, int requiredlength, string fieldname, char fill, Alignment alignwhere)
{
string padded;
if (input.Length > requiredlength)
{
throw new InvalidOperationException("Problem with length of " + fieldname + " " +
input + "; should only be " + requiredlength.ToString());
}
else if (input.Length < requiredlength)
{
if (alignwhere == Alignment.AlignRight)
{
padded = input.PadLeft(requiredlength, fill);
}
else
{
padded = input.PadRight(requiredlength, fill);
}
}
else
{
padded = input;
}
return padded;
}
#endregion
///
/// Writes the DTAUS dataset A (DTAUS Header)
///
/// The StringBuilder to write the header to.
/// The Direct debit request object for which the header is created.
///The execution date of the request is before the creation date or more than 15 days after the creation date.
/// The TransactionType is not supported.
private static void WriteHeader(StringBuilder result, BankTransactionRequest request)
{
DateTime creationDate = request.CreationDate.Date;
DateTime? dateEffective = request.ExecutionDate;
#region sanity checks
if (String.IsNullOrEmpty(request.ExecutiveBankAccountHolder))
{
throw new InvalidOperationException("No executive account holder is given for this transaction.");
}
if (request.ExecutiveBankAccountNumber <= 0)
{
throw new InvalidOperationException("The executive bank account number must not be 0 or negative!.");
}
if (request.ExecutiveBankNumber < 10000000 || request.ExecutiveBankNumber >= 90000000)
{
throw new InvalidOperationException("The executive bank number is invalid.");
}
if (dateEffective.HasValue)
{
double daysBetween = (dateEffective.Value.Date - creationDate).TotalDays;
if (daysBetween < 0.0 || daysBetween > 15.0)
{
throw new InvalidOperationException("Date of execution must not be before today and no more than 15 days from today!");
}
}
#endregion
/* DTAUS Dataset A Structure (see http://www.infodrom.org/projects/dtaus/dtaus.html)
1 0 4 Zeichen Länge des Datensatzes, immer 128 Bytes, also immer "0128"
2 4 1 Zeichen Datensatz-Typ, immer 'A'
3 5 2 Zeichen Art der Transaktionen
"LB" für Lastschriften Bankseitig
"LK" für Lastschriften Kundenseitig
"GB" für Gutschriften Bankseitig
"GK" für Gutschriften Kundenseitig
4 7 8 Zeichen Bankleitzahl des Auftraggebers
5 15 8 Zeichen CST, "00000000", nur belegt, wenn Diskettenabsender Kreditinstitut
6 23 27 Zeichen Name des Auftraggebers
7 50 6 Zeichen aktuelles Datum im Format DDMMJJ
8 56 4 Zeichen CST, " " (Blanks)
9 60 10 Zeichen Kontonummer des Auftraggebers
10 70 10 Zeichen Optionale Referenznummer (numerisch, leer = 10*'0')
11a 80 15 Zeichen Reserviert, 15 Blanks
11b 95 8 Zeichen Optionales Ausführungsdatum im Format DDMMJJJJ. Nicht jünger als Erstellungsdatum (A7), jedoch höchstens 15 Kalendertage später. Sonst Blanks.
11c 103 24 Zeichen Reserviert, 24 Blanks
12 127 1 Zeichen Währungskennzeichen
" " = DM
"1" = Euro
Insgesamt 128 Zeichen
*/
result.Append("0128");
result.Append("A");
if (request.TransactionType == DTAUSTransactionType.DirectDebit)
{
result.Append("LK");
}
else if (request.TransactionType == DTAUSTransactionType.BankTransfer)
{
result.Append("GK");
}
else
{
throw new NotSupportedException("The Transaction type " + request.TransactionType + " is not yet supported.");
}
result.Append(EnsureLength(request.ExecutiveBankNumber.ToString(), 8, "ExecutiveBankSortcode", '0', Alignment.AlignLeft));
result.Append(new String('0', 8));
result.Append(EnsureLength(FormatName(request.ExecutiveBankAccountHolder), 27, "ExecutiveName", ' ', Alignment.AlignLeft));
result.AppendFormat("{0:ddMMyy}", creationDate);
result.Append(new String(' ', 4));
result.Append(EnsureLength(request.ExecutiveBankAccountNumber.ToString(), 10, "ExecutiveAccountNumber", '0', Alignment.AlignRight));
result.Append(new String('0', 10));
result.Append(new String(' ', 15));
if (dateEffective.HasValue)
{
result.AppendFormat("{0:ddMMyyyy}", dateEffective.Value);
}
else
{
result.Append(new String(' ', 8));
}
result.Append(new String(' ', 24));
result.Append("1");
}
///
/// Writes a DTAUS dataset C block (Body) for the given direct debit request and transaction object.
///
/// The StringBuilder to write the transaction to.
/// The transaction to be written
/// The request object that contains the direct debit recipient information.
/// When any data in the request is invalid (bad string length etc.),
/// an InvalidOperationException is created. See its message for detailed information.
/// The TransactionType is not supported.
private static void WriteTransactionBody(StringBuilder result, BankTransactionItem transaction, BankTransactionRequest request)
{
List extraReferences = new List(transaction.ReferenceLines);
#region sanity checks
if (String.IsNullOrEmpty(transaction.TargetBankAccountHolder))
{
throw new InvalidOperationException("No target account holder is given for this transaction.");
}
if (transaction.TargetBankAccountNumber <= 0)
{
throw new InvalidOperationException("target account number must not be 0 or negative!.");
}
if (transaction.TargetBankNumber < 10000000 || transaction.TargetBankNumber >= 90000000)
{
throw new InvalidOperationException("target bank number is invalid.");
}
if (extraReferences.Count < 1)
{
throw new InvalidOperationException("No Reference text is given for this transaction.");
}
if (transaction.AmountCents <= 0)
{
throw new InvalidOperationException("The amount for each transaction must be greater than 0");
}
if (extraReferences.Count > 14)
{
throw new InvalidOperationException("at most 14 reference lines can be given for each transaction.");
}
#endregion
string primaryReferenceLine = extraReferences[0];
extraReferences.RemoveAt(0);
/* Aufbau Datensatz C
Nr. Start Länge Beschreibung
1 0 4 Zeichen Länge des Datensatzes, 187 + x * 29 (x..Anzahl Erweiterungsteile)
2 4 1 Zeichen Datensatz-Typ, immer 'C'
3 5 8 Zeichen Bankleitzahl des Auftraggebers (optional, ggf. '0' auffüllen)
4 13 8 Zeichen Bankleitzahl des Kunden
5 21 10 Zeichen Kontonummer des Kunden
6 31 13 Zeichen Verschiedenes
1. Zeichen: "0"
2. - 12. Zeichen: interne Kundennummer oder Nullen
13. Zeichen: "0"
Die interne Nummer wird vom erstbeauftragten Institut zum endbegünstigten Institut weitergeleitet. Die Weitergabe der internenen Nummer an den Überweisungsempfänger ist der Zahlstelle freigestellt.
7 44 5 Zeichen Art der Transaktion (7a: 2 Zeichen, 7b: 3 Zeichen)
"04000" Lastschrift des Abbuchungsauftragsverfahren
"05000" Lastschrift des Einzugsermächtigungsverfahren
"05005" Lastschrift aus Verfügung im elektronischen Cash-System
"05006" Wie 05005 mit ausländischen Karten
"05015" Lastschrift aus Verfügung im elec. Cash-System - POZ
"51000" Überweisungs-Gutschrift
"53000" Überweisung Lohn/Gehalt/Rente
"54XXJ" Vermögenswirksame Leistung (VL) mit Sparzulage
"56000" Überweisung öffentlicher Kassen
Die im Textschlüssel mit XX bezeichnete Stelle ist 00 oder der Prozentsatz der Sparzulage.
Die im Textschlüssel mit J bezeichnete Stelle wird bei Übernahme in eine Zahlung automatisch mit der jeweils aktuellen Jahresendziffer (z.B. 7, wenn 97) ersetzt.
8 49 1 Zeichen Reserviert, " " (Blank)
9 50 11 Zeichen Betrag (9 Vorkomma, 2 Nachkommastellen ohne Trennzeichen)
10 61 8 Zeichen Bankleitzahl des Auftraggebers
11 69 10 Zeichen Kontonummer des Auftraggebers
12 79 11 Zeichen Betrag in Euro (9 Vorkomma, 2 Nachkommastellen ohne Trennzeichen), nur belegt, wenn Euro als Währung angegeben wurde (A12, C17a), sonst Nullen
13 90 3 Zeichen Reserviert, 3 Blanks
14a 93 27 Zeichen Name des Kunden
14b 120 8 Zeichen Reserviert, 8 Blanks
Insgesamt 128 Zeichen
15 128 27 Zeichen Name des Auftraggebers
16 155 27 Zeichen Verwendungszweck
17a 182 1 Zeichen Währungskennzeichen
" " = DM
"1" = Euro
17b 183 2 Zeichen Reserviert, 2 Blanks
18 185 2 Zeichen Anzahl der Erweiterungsdatensätze, "00" bis "15"
19 187 2 Zeichen Typ (1. Erweiterungsdatensatz)
"01" Name des Kunden
"02" Verwendungszweck
"03" Name des Auftraggebers
20 189 27 Zeichen Beschreibung gemäß Typ
21 216 2 Zeichen wie C19, oder Blanks (2. Erweiterungsdatensatz)
22 218 27 Zeichen wie C20, oder Blanks
23 245 11 Zeichen 11 Blanks
Insgesamt 256 Zeichen
*/
result.AppendFormat("{0:0000}", 187 + (extraReferences.Count * 29));
result.Append("C");
result.Append(new String('0', 8));
result.Append(EnsureLength(transaction.TargetBankNumber.ToString(), 8, "PartnerBankSortcode", '0', Alignment.AlignRight));
result.Append(EnsureLength(transaction.TargetBankAccountNumber.ToString(), 10, "PartnerBankAccountNumber", '0', Alignment.AlignRight));
result.Append("0");
result.Append(new String('0', 11));
result.Append("0");
if (request.TransactionType == DTAUSTransactionType.DirectDebit)
{
result.Append("05000"); // Einzugsermaechtigung
}
else if (request.TransactionType == DTAUSTransactionType.BankTransfer)
{
result.Append("51000"); // Überweisungs-Gutschrift
}
else
{
throw new NotSupportedException("The Transaction type " + request.TransactionType + " is not yet supported.");
}
result.Append(" ");
result.Append(new String('0', 11)); // With Euro-Transactions, the Amount is in Field C12, not here.
result.Append(EnsureLength(request.ExecutiveBankNumber.ToString(), 8, "ExecutiveBankSortcode", '0', Alignment.AlignRight));
result.Append(EnsureLength(request.ExecutiveBankAccountNumber.ToString(), 10, "ExecutiveBankAccountNumber", '0', Alignment.AlignRight));
string amountFormatted = Convert.ToDouble(transaction.AmountCents).ToString(new String('0', 11));
CheckLength(amountFormatted, 11, "The Amount of this transaction is too big to be used in a DTA file.");
result.Append(amountFormatted);
result.Append(new String(' ', 3));
result.Append(EnsureLength(FormatName(transaction.TargetBankAccountHolder), 27, "PartnerName", ' ', Alignment.AlignLeft));
result.Append(new String(' ', 8));
result.Append(EnsureLength(FormatName(request.ExecutiveBankAccountHolder), 27, "ExecutiveName", ' ', Alignment.AlignLeft));
result.Append(EnsureLength(FormatName(primaryReferenceLine), 27, "PartnerKeyReference", ' ', Alignment.AlignLeft));
result.Append("1");
result.Append(new string(' ', 2));
WriteAllReferenceExtensions(result, extraReferences);
}
///
/// Writes all extra reference lines as extension blocks to the given StringBuilder.
///
/// The Stringbuilder to write to.
/// The list of reference lines to be written. must not be more than 13.
/// When more than 13 reference lines are given,
/// an InvalidOperationException is created.
private static void WriteAllReferenceExtensions(StringBuilder result, List references)
{
if (references.Count > 13)
{
throw new InvalidOperationException("A Transaction can have at most 13 additional reference lines.");
}
//First add the yet missing extension count (Field C18).
result.AppendFormat("{0:00}", references.Count);
//The first two extensions will complete the 128 characters of the dataset C base block: 2*(2+27) + 11 chars
for (int i = 0; i < 2; i++)
{
string reference = null;
if (i < references.Count)
{
reference = references[i];
}
WriteReferenceExtension(result, reference);
}
result.Append(new String(' ', 11));
if (references.Count > 2)
{
//The remaining extensions (#<=13) must be written in blocks of 4 extensions with a total of 128 chars.
//4*(2+27) + 12
//the last extension block can have only one extension (because the total is 15), but must still be
//128 chars wide, so the remainder is simply filled with empty blocks.
//Because the references list is checked to have less than 14 items, the maximum block count is always ensured.
for (int block = 0; block < 5; block++)
{
//first block of four starts with the third extension (index 2) and so on
int offset = (4*block) + 2;
if (offset < references.Count)
{
//4 extensions will form a 128 chars block and always have to be written together.
//if not enough extensions are available, fill the remaining block with blanks.
for (int i = 0; i < 4 ; i++)
{
int currentIndex = offset + i;
string reference = null;
if (currentIndex < references.Count)
{
reference = references[currentIndex];
}
WriteReferenceExtension(result, reference);
}
result.Append(new String(' ', 12));
}
else
{
//no more extensions, so do not start a new 128 chars block and terminate extension writing.
break;
}
}
}
}
///
/// Creates the datafields for a reference extension of a dataset C extension block.
/// when the input string is null or empty, an empty extension is written.
///
/// The Stringbuilder where the extension is written to.
/// The reference line to be written.
///The length of the (DTA formatted) reference line is longer than the allowed field size.
private static void WriteReferenceExtension(StringBuilder result, string referenceLine)
{
//XXX: change signature to DTAExtensionData{ExtensionType type, string contents} and be able to write the extra executive and target name fields, too
//A check would be needed to ensure that at most 1 type 00 and type 01 extension is defined and
//the BankTransactionRequest/BankTransactionItem classes must be extended to Support the property "ExtraAccountHolderText"
if (!String.IsNullOrEmpty(referenceLine))
{
result.Append("02"); //C19: 02 = Verwendungszweck
result.Append(EnsureLength(FormatName(referenceLine), 27, "Extension", ' ', Alignment.AlignLeft));
}
else
{
result.Append(new string(' ', 2 + 27));
}
}
///
/// Writes the footer (DTAUS dataset E) of the given direct debit request.
///
/// The StringBuilder to write to.
/// The request of which the footer is generated.
/// When any checksum field lengths exceed the allowed field length,
/// an InvalidOperationException is created. See its message for detailed information.
private static void WriteFooter(StringBuilder result, BankTransactionRequest request)
{
/* DTAUS Datensatz E (Footer)
1 0 4 Zeichen Länge des Datensatzes, immer 128 Bytes, also immer "0128"
2 4 1 Zeichen Datensatz-Typ, immer 'E'
3 5 5 Zeichen " " (Blanks)
4 10 7 Zeichen Anzahl der Datensätze vom Typ C
5 17 13 Zeichen Kontrollsumme Beträge in DM (11 Vorkommastellen und 2 Nachkommastellen ohne Trennzeichen)
6 30 17 Zeichen Kontrollsumme Kontonummern
7 47 17 Zeichen Kontrollsumme Bankleitzahlen
8 64 13 Zeichen Kontrollsumme Beträge in Euro (11 Vorkommastellen und 2 Nachkommastellen ohne Trennzeichen), nur belegt, wenn Euro als Währung angegeben wurde (A12, C17a)
9 77 51 Zeichen 51 Blanks
Insgesamt 128 Zeichen
*/
string bankAccountNumberSumFormatted = request.Transactions.Sum(item => item.TargetBankAccountNumber).ToString(new String('0', 17));
CheckLength(bankAccountNumberSumFormatted, 17, "The bank account number sum of this request is too big to be used in a DTA file. Try using less transactions.");
string bankNumberSumFormatted = request.Transactions.Sum(item => (long)item.TargetBankNumber).ToString(new String('0', 17));
CheckLength(bankNumberSumFormatted, 17, "The bank number sum of this transaction is too big to be used in a DTA file. Try using less transactions.");
string amountSumFormatted = request.Transactions.Sum(item => item.AmountCents).ToString(new String('0', 13));
CheckLength(amountSumFormatted, 13, "The total Amount of all transactions in this request is too big to be used in a DTA file. try using less transactions.");
string transactionCountFormatted = request.Transactions.Count.ToString(new String('0', 7));
CheckLength(transactionCountFormatted, 7, "The total transaction count is too big to be used in a single DTA file. try using less transactions.");
result.Append("0128");
result.Append("E");
result.Append(new String(' ', 5));
result.Append(transactionCountFormatted);
result.Append(new String('0', 13));
result.Append(bankAccountNumberSumFormatted);
result.Append(bankNumberSumFormatted);
result.Append(amountSumFormatted);
result.Append(new String(' ', 51));
}
#region Sample usage
///
/// Sample usage method that donates the given amount to the class extending developer Florian Harbich.
///
/// The account holder (you).
/// The account number (your bank account number).
/// The bank number (your bank number (BLZ)).
/// The amount you would like to donate, in cents.
/// byte[] containing the DTAUS file to donate some money to me.
public static byte[] DonateToDeveloper(string accountHolder, long accountNumber, int bankNumber, int amountCents)
{
BankTransactionRequest request = new BankTransactionRequest()
{
CreationDate = DateTime.Now,
ExecutionDate = null,
ExecutiveBankAccountHolder = accountHolder,
ExecutiveBankAccountNumber = accountNumber,
ExecutiveBankNumber = bankNumber,
TransactionType = DTAUSTransactionType.BankTransfer
};
BankTransactionItem transaction = new BankTransactionItem()
{
AmountCents = amountCents,
TargetBankAccountHolder = "Florian Harbich",
TargetBankAccountNumber = 834915,
TargetBankNumber = 60450050,
};
transaction.ReferenceLines.Add("Donation for DTAUS");
transaction.ReferenceLines.Add("writing library");
transaction.ReferenceLines.Add("in csharp");
transaction.ReferenceLines.Add("from " + accountHolder);
request.Transactions.Add(transaction);
return DTAUSWriter.WriteDTAUSFile(request);
}
#endregion
}
}