Skip to content

Commit

Permalink
fix: Debitor ids are optional for transfers
Browse files Browse the repository at this point in the history
Also: Actually include the creditor/debitor ids when they are set

Fixes #58
  • Loading branch information
Tobias Lippert authored and kewisch committed Nov 25, 2023
1 parent e6f29bc commit 76d7055
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 3 deletions.
8 changes: 7 additions & 1 deletion lib/sepa.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,9 @@
assert_date(this.requestedExecutionDate, 'requestedExecutionDate');
}

assert_cid(this[pullFrom + 'Id'], pullFrom + 'Id');
if (this[pullFrom + 'Id']) {
assert_cid(this[pullFrom + 'Id'], pullFrom + 'Id');
}

assert_length(this[pullFrom + 'Name'], null, 70, pullFrom + 'Name');
assert_length(this[pullFrom + 'Street'], null, 70, pullFrom + 'Street');
Expand Down Expand Up @@ -411,6 +413,10 @@
var emitter = n(pmtInf, emitterNodeName);

r(emitter, 'Nm', this[pullFrom + 'Name']);
if (this[pullFrom + 'Id']) {
r(emitter, 'Id', this[pullFrom + 'Id']);
}

if (this[pullFrom + 'Street'] && this[pullFrom + 'City'] && this[pullFrom + 'Country']) {
var pstl = n(emitter, 'PstlAdr');
r(pstl, 'Ctry', this[pullFrom + 'Country']);
Expand Down
149 changes: 149 additions & 0 deletions lib/sepa.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
var SEPA = require('./sepa.js');
var xpath = require('xpath');

// The following debtor id is provided by German Bundesbank for testing purposes.
const A_VALID_CREDITOR_ID = 'DE98ZZZ09999999999';

const A_VALID_IBAN = 'DE43500105178994141576';

describe('IBAN tests',
() => {
Expand Down Expand Up @@ -30,3 +36,146 @@ describe('IBAN tests',
expect(SEPA.validateIBAN('DE1Zsantander')).toBe(false);
});
});

describe('xml generation for transfer documents', () => {
const PAIN_FOR_TRANSFERS = 'pain.001.003.03';

function validTransferDocument(overrides = {}) {
const doc = new SEPA.Document(PAIN_FOR_TRANSFERS);
doc.grpHdr.created = new Date();

const info = doc.createPaymentInfo();
info.collectionDate = new Date();
info.debtorIBAN = A_VALID_IBAN;
if (overrides.debtorName !== undefined) {
info.debtorName = overrides.debtorName;
} else {
info.debtorName = 'debtor-name';
}
if (overrides.debtorId !== undefined) {
info.debtorId = overrides.debtorId;
} else {
info.debtorId = A_VALID_CREDITOR_ID;
}
info.requestedExecutionDate = new Date();
doc.addPaymentInfo(info);

const tx = info.createTransaction();
tx.creditorName = 'creditor-name';
tx.creditorIBAN = A_VALID_IBAN;
tx.amount = 1.0;
tx.mandateSignatureDate = new Date();
info.addTransaction(tx);
return doc;
}

test('debtor id is optional for transfer documents', () => {
// GIVEN
const doc = validTransferDocument({debtorId: null});
// WHEN
const dom = doc.toXML();
// THEN
const select = xpath.useNamespaces({
p: `urn:iso:std:iso:20022:tech:xsd:${PAIN_FOR_TRANSFERS}`,
});
const debtorId = select('/p:Document/p:CstmrCdtTrfInitn/p:PmtInf/p:Dbtr/p:Id', dom, true);
expect(debtorId).toBeUndefined();
});

test('debtor name and id are included in transfer documents when they are set', () => {
// GIVEN
const doc = validTransferDocument({debtorId: A_VALID_CREDITOR_ID, debtorName: 'debtor-name'});

// WHEN
const dom = doc.toXML();

// THEN
const select = xpath.useNamespaces({
p: `urn:iso:std:iso:20022:tech:xsd:${PAIN_FOR_TRANSFERS}`,
});

const debtorName = select('/p:Document/p:CstmrCdtTrfInitn/p:PmtInf/p:Dbtr/p:Nm', dom, true);
expect(debtorName).not.toBeUndefined();
expect(debtorName.textContent).toBe('debtor-name');

const debtorId = select('/p:Document/p:CstmrCdtTrfInitn/p:PmtInf/p:Dbtr/p:Id', dom, true);
expect(debtorId).not.toBeUndefined();
expect(debtorId.textContent).toBe(A_VALID_CREDITOR_ID);
});

test('dutch debtor ids are accepted', () => {
// GIVEN
const validDutchCreditorId = 'NL79ZZZ999999990000';
const doc = validTransferDocument({debtorId: validDutchCreditorId});

// WHEN
const dom = doc.toXML();

// THEN
const select = xpath.useNamespaces({
p: `urn:iso:std:iso:20022:tech:xsd:${PAIN_FOR_TRANSFERS}`,
});

const debtorId = select('/p:Document/p:CstmrCdtTrfInitn/p:PmtInf/p:Dbtr/p:Id', dom, true);
expect(debtorId).not.toBeUndefined();
expect(debtorId.textContent).toBe(validDutchCreditorId);
});
});

describe('xml generation for direct debit documents', () => {
const PAIN_FOR_DIRECT_DEBIT = 'pain.008.001.02';
function validDirectDebitDocument(overrides = {}) {
var doc = new SEPA.Document(PAIN_FOR_DIRECT_DEBIT);
doc.grpHdr.created = new Date();

var info = doc.createPaymentInfo();
info.collectionDate = new Date();
info.creditorIBAN = A_VALID_IBAN;
if (overrides.creditorId !== undefined) {
info.creditorId = overrides.creditorId;
} else {
info.creditorId = A_VALID_CREDITOR_ID;
}
doc.addPaymentInfo(info);

var tx = info.createTransaction();
tx.debtorIBAN = A_VALID_IBAN;
tx.mandateSignatureDate = new Date('2014-02-01');
tx.amount = 50.23;
info.addTransaction(tx);
return doc;
}

test('includes creditor id when set', () => {
// GIVEN
const doc = validDirectDebitDocument({creditorId: A_VALID_CREDITOR_ID});

// WHEN
const dom = doc.toXML();

// THEN
const select = xpath.useNamespaces({
p: `urn:iso:std:iso:20022:tech:xsd:${PAIN_FOR_DIRECT_DEBIT}`,
});

const creditorId = select('/p:Document/p:CstmrDrctDbtInitn/p:PmtInf/p:Cdtr/p:Id', dom, true);
expect(creditorId).not.toBeUndefined();
expect(creditorId.textContent).toBe(A_VALID_CREDITOR_ID);
});

test('Works without setting creditor id', () => {
// GIVEN
const doc = validDirectDebitDocument({creditorId: null});

// WHEN
const dom = doc.toXML();

// THEN
const select = xpath.useNamespaces({
p: `urn:iso:std:iso:20022:tech:xsd:${PAIN_FOR_DIRECT_DEBIT}`,
});

const creditorId = select('/p:Document/p:CstmrDrctDbtInitn/p:PmtInf/p:Cdtr/p:Id', dom, true);
expect(creditorId).toBeUndefined();
});
});
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"eslint-plugin-jest": "^27.6.0",
"jest": "^29.7.0",
"pre-commit": "*",
"uglify-js": "^3.3.20"
"uglify-js": "^3.3.20",
"xpath": "^0.0.33"
},
"engines": {
"node": "*"
Expand Down

0 comments on commit 76d7055

Please sign in to comment.