fints
Version:
FinTS client library with psd2 support
213 lines • 7.12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const detectionRegex = /(?:^|\?)(..)(.*?)(?:$|\?)/g;
/**
* Used to sniff whether the 86 section of the MT940 statement list supports the fints structured
* representation.
*
* @param input The string for the 86 section.
*
* @return Whether the string is likely structured.
*/
function is86Structured(input) {
const matches = [];
let lastMatch;
do {
lastMatch = detectionRegex.exec(input);
matches.push(lastMatch);
} while (lastMatch);
const results = matches
.filter(match => match !== null)
.map(match => ({ code: Number(match[1]), value: match[2] }));
if (results.length === 0) {
return false;
}
if (results.some(result => isNaN(result.code))) {
return false;
}
return true;
}
exports.is86Structured = is86Structured;
/**
* Parses a commonly used date format ("DATUM 15.11.2018, 12:00 UHR") into a date
*
* @param content The date string to parse.
*
* @return The parsed date.
*/
function parsePaymentReferenceDate(content) {
const groups = /DATUM\s+(\d+)\.(\d+)\.(\d+),\s+(\d+)\.(\d+)\s+UHR/.exec(content);
if (!groups) {
return;
}
return new Date(Number(groups[3]), Number(groups[2]) - 1, Number(groups[1]), Number(groups[4]), Number(groups[5]));
}
exports.parsePaymentReferenceDate = parsePaymentReferenceDate;
/**
* Parses a commonly format for representing a TAN related to a transaction ("1. TAN 123456").
*
* @param content The string to parse.
*
* @return The parsed TAN number and TAN iteself.
*/
function parsePaymentReferenceTan(content) {
const groups = /(\d+)\.\s*TAN\s+(.*)/.exec(content);
if (!groups) {
return;
}
return {
num: Number(groups[1]),
value: groups[2],
};
}
exports.parsePaymentReferenceTan = parsePaymentReferenceTan;
/**
* If the payment reference follows the SEPA tagging system, parse the information.
* See: https://tinyurl.com/ycdfx5hd
*
* @param references A list of all sections used for payment reference (20 - 29 and 60 - 63).
*
* @return A parsed payment reference with all extracted data.
*/
function assemblePaymentReference(references) {
let lastIdentifiedAttribute;
const result = { raw: "" };
const add = (name, content) => {
lastIdentifiedAttribute = name;
result[name] = content;
};
references
.sort((a, b) => a.code - b.code)
.forEach(({ content }) => {
if (content.startsWith("IBAN+")) {
add("iban", content.substr(5));
}
else if (content.startsWith("BIC+")) {
add("bic", content.substr(5));
}
else if (content.startsWith("EREF+")) {
add("endToEndRef", content.substr(5));
}
else if (content.startsWith("KREF+")) {
add("customerRef", content.substr(5));
}
else if (content.startsWith("MREF+")) {
add("mandateRef", content.substr(5));
}
else if (content.startsWith("CRED+")) {
add("creditorId", content.substr(5));
}
else if (content.startsWith("DEBT+")) {
add("originatorId", content.substr(5));
}
else if (content.startsWith("COAM+")) {
add("interestCompensation", content.substr(5));
}
else if (content.startsWith("OAMT+")) {
add("originalTurnover", content.substr(5));
}
else if (content.startsWith("SVWZ+")) {
add("text", content.substr(5));
}
else if (content.startsWith("ABWA+")) {
add("divergingPrincipal", content.substr(5));
}
else if (content.startsWith("PURP+")) {
add("purpose", content.substr(5));
}
else if (content.startsWith("BREF+")) {
add("back", content.substr(5));
}
else if (content.startsWith("RREF+")) {
add("back", content.substr(5));
}
else if (content.startsWith("DATUM ")) {
result.date = parsePaymentReferenceDate(content);
}
else if (/\d+\.\s*TAN/.test(content)) {
result.tan = parsePaymentReferenceTan(content);
}
else if (lastIdentifiedAttribute) {
result[lastIdentifiedAttribute] += content;
}
result.raw += content;
return result;
});
return result;
}
exports.assemblePaymentReference = assemblePaymentReference;
/**
* Parse as much information as possible from the structured 86 section of a MT940 statement list.
* Use `is86Structured` to sniff whether the payment reference is parsable.
*
* @param input The input string for the 86 section to parse.
*
* @return The parsed structured description.
*/
function parse86Structured(input) {
let iban;
let text;
let bic;
let primaNota;
let currentContent = "";
let inHeader = true;
let sectionCode;
const references = [];
const names = [];
// The header has been parsed fully. Store the section code and begin parsing the content.
const flushHeader = () => {
sectionCode = Number(currentContent);
currentContent = "";
inHeader = false;
};
// A questionmark has been encountered, hence the content of the current section is complete.
// Store the parsed data and continue to read the next header.
const flushSection = () => {
if (sectionCode === 0) {
text = currentContent;
}
else if (sectionCode === 10) {
primaNota = currentContent;
}
else if ((sectionCode >= 20 && sectionCode < 30) || (sectionCode >= 60 && sectionCode <= 63)) {
references.push({ code: sectionCode, content: currentContent });
}
else if (sectionCode === 30) {
bic = currentContent;
}
else if (sectionCode === 31) {
iban = currentContent;
}
else if (sectionCode >= 32 && sectionCode <= 33) {
names.push({ code: sectionCode, content: currentContent });
}
currentContent = "";
sectionCode = undefined;
inHeader = true;
};
// Read the string character by character and split it into sections.
for (let i = 0; i < input.length; ++i) {
const character = input[i];
if (character === "?") {
flushSection();
continue;
}
currentContent += character;
if (inHeader && currentContent.length === 2) {
flushHeader();
continue;
}
}
// After parsing, flush the last section.
flushSection();
// The payment reference could have been using tags.
// Attempt to parse the tags.
const reference = assemblePaymentReference(references);
const name = names
.sort((a, b) => a.code - b.code)
.map(recipient => recipient.content)
.join("");
return { reference, name, iban, text, bic, primaNota };
}
exports.parse86Structured = parse86Structured;
//# sourceMappingURL=mt940-86-structured.js.map