@lucianpacurar/iso20022.js 0.2.10 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7153,10 +7153,12 @@ const exportAccountIdentification = (accountId) => {
7153
7153
  const obj = {
7154
7154
  Othr: {
7155
7155
  Id: accountId.id,
7156
- }
7156
+ },
7157
7157
  };
7158
7158
  if (accountId.schemeName) {
7159
- obj.Othr.SchmeNm = { Cd: accountId.schemeName }; // TODO: Add support for Prtry scheme name
7159
+ obj.Othr.SchmeNm = {
7160
+ Cd: accountId.schemeName,
7161
+ }; // TODO: Add support for Prtry scheme name
7160
7162
  }
7161
7163
  if (accountId.issuer) {
7162
7164
  obj.Othr.Issr = accountId.issuer;
@@ -7195,7 +7197,9 @@ const parseAmountToMinorUnits = (rawAmount, currency = 'USD') => {
7195
7197
  precision: getCurrencyPrecision(currency),
7196
7198
  });
7197
7199
  // Also make sure Javascript number parsing error do not happen.
7198
- return new Decimal(rawAmount).mul(10 ** currencyObject.getPrecision()).toNumber();
7200
+ return new Decimal(rawAmount)
7201
+ .mul(10 ** currencyObject.getPrecision())
7202
+ .toNumber();
7199
7203
  };
7200
7204
  const exportAmountToString = (amount, currency = 'USD') => {
7201
7205
  const currencyObject = Dinero({
@@ -7245,10 +7249,16 @@ const parseAdditionalInformation = (additionalInformation) => {
7245
7249
  const parseMessageHeader = (rawHeader) => {
7246
7250
  return {
7247
7251
  id: rawHeader.MsgId,
7248
- creationDateTime: rawHeader.CreDtTm ? parseDate(rawHeader.CreDtTm) : undefined,
7252
+ creationDateTime: rawHeader.CreDtTm
7253
+ ? parseDate(rawHeader.CreDtTm)
7254
+ : undefined,
7249
7255
  queryName: rawHeader.QueryNm,
7250
- requestType: rawHeader.ReqTp?.PmtCtrl || rawHeader.ReqTp?.Enqry || rawHeader.ReqTp?.Prtry,
7251
- originalMessageHeader: rawHeader.OrgnlBizQry ? parseMessageHeader(rawHeader.OrgnlBizQry) : undefined,
7256
+ requestType: rawHeader.ReqTp?.PmtCtrl ||
7257
+ rawHeader.ReqTp?.Enqry ||
7258
+ rawHeader.ReqTp?.Prtry,
7259
+ originalMessageHeader: rawHeader.OrgnlBizQry
7260
+ ? parseMessageHeader(rawHeader.OrgnlBizQry)
7261
+ : undefined,
7252
7262
  };
7253
7263
  };
7254
7264
  const exportMessageHeader = (header) => {
@@ -7433,7 +7443,7 @@ class SWIFTCreditPaymentInitiation extends PaymentInitiation {
7433
7443
  * @param {SWIFTCreditPaymentInitiationConfig} config - The configuration object.
7434
7444
  */
7435
7445
  constructor(config) {
7436
- super({ type: "swift" });
7446
+ super({ type: 'swift' });
7437
7447
  this.initiatingParty = config.initiatingParty;
7438
7448
  this.paymentInstructions = config.paymentInstructions;
7439
7449
  this.messageId =
@@ -7506,9 +7516,10 @@ class SWIFTCreditPaymentInitiation extends PaymentInitiation {
7506
7516
  const parser = new fxp.XMLParser({ ignoreAttributes: false });
7507
7517
  const xml = parser.parse(rawXml);
7508
7518
  if (!xml.Document) {
7509
- throw new InvalidXmlError("Invalid XML format");
7519
+ throw new InvalidXmlError('Invalid XML format');
7510
7520
  }
7511
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
7521
+ const namespace = (xml.Document['@_xmlns'] ||
7522
+ xml.Document['@_Xmlns']);
7512
7523
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001')) {
7513
7524
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
7514
7525
  }
@@ -7521,8 +7532,8 @@ class SWIFTCreditPaymentInitiation extends PaymentInitiation {
7521
7532
  id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id?.OrgId?.Othr?.Id,
7522
7533
  account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct),
7523
7534
  agent: {
7524
- bic: xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt?.FinInstnId?.BIC
7525
- }
7535
+ bic: xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt?.FinInstnId?.BIC,
7536
+ },
7526
7537
  };
7527
7538
  const rawInstructions = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf)
7528
7539
  ? xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf
@@ -7534,34 +7545,38 @@ class SWIFTCreditPaymentInitiation extends PaymentInitiation {
7534
7545
  const creditor = {
7535
7546
  name: inst.Cdtr.Nm,
7536
7547
  agent: {
7537
- bic: inst.CdtrAgt?.FinInstnId?.BIC
7548
+ bic: inst.CdtrAgt?.FinInstnId?.BIC,
7538
7549
  },
7539
- account: (inst.CdtrAcct?.Id?.IBAN || inst.CdtrAcct?.Id?.Othr?.Id) ? parseAccount(inst.CdtrAcct) : undefined,
7550
+ account: inst.CdtrAcct?.Id?.IBAN || inst.CdtrAcct?.Id?.Othr?.Id
7551
+ ? parseAccount(inst.CdtrAcct)
7552
+ : undefined,
7540
7553
  address: {
7541
7554
  streetName: inst.Cdtr.PstlAdr.StrtNm,
7542
7555
  buildingNumber: inst.Cdtr.PstlAdr.BldgNb,
7543
7556
  postalCode: inst.Cdtr.PstlAdr.PstCd,
7544
7557
  townName: inst.Cdtr.PstlAdr.TwnNm,
7545
7558
  countrySubDivision: inst.Cdtr.PstlAdr.CtrySubDvsn,
7546
- country: inst.Cdtr.PstlAdr.Ctry
7547
- }
7559
+ country: inst.Cdtr.PstlAdr.Ctry,
7560
+ },
7548
7561
  };
7549
7562
  // Return instruction with validated data
7550
7563
  return {
7551
7564
  type: 'swift',
7552
7565
  direction: 'credit',
7553
7566
  ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
7554
- ...(inst.PmtId.EndToEndId && { endToEndId: inst.PmtId.EndToEndId.toString() }),
7567
+ ...(inst.PmtId.EndToEndId && {
7568
+ endToEndId: inst.PmtId.EndToEndId.toString(),
7569
+ }),
7555
7570
  amount,
7556
7571
  currency,
7557
- creditor
7572
+ creditor,
7558
7573
  };
7559
7574
  });
7560
7575
  return new SWIFTCreditPaymentInitiation({
7561
7576
  messageId,
7562
7577
  creationDate,
7563
7578
  initiatingParty: baseInitiatingParty,
7564
- paymentInstructions: paymentInstructions
7579
+ paymentInstructions: paymentInstructions,
7565
7580
  });
7566
7581
  }
7567
7582
  serialize() {
@@ -7569,7 +7584,7 @@ class SWIFTCreditPaymentInitiation extends PaymentInitiation {
7569
7584
  const xml = {
7570
7585
  '?xml': {
7571
7586
  '@version': '1.0',
7572
- '@encoding': 'UTF-8'
7587
+ '@encoding': 'UTF-8',
7573
7588
  },
7574
7589
  Document: {
7575
7590
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
@@ -7647,7 +7662,7 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7647
7662
  * @param {SEPACreditPaymentInitiationConfig} config - The configuration object for the SEPA credit transfer.
7648
7663
  */
7649
7664
  constructor(config) {
7650
- super({ type: "sepa" });
7665
+ super({ type: 'sepa' });
7651
7666
  this.initiatingParty = config.initiatingParty;
7652
7667
  this.paymentInstructions = config.paymentInstructions;
7653
7668
  this.messageId = config.messageId || v4().replace(/-/g, '');
@@ -7669,9 +7684,11 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7669
7684
  sumPaymentInstructions(instructions) {
7670
7685
  this.validateAllInstructionsHaveSameCurrency();
7671
7686
  const instructionDineros = instructions.map(instruction => Dinero({ amount: instruction.amount, currency: instruction.currency }));
7672
- return instructionDineros.reduce((acc, next) => {
7687
+ return instructionDineros
7688
+ .reduce((acc, next) => {
7673
7689
  return acc.add(next);
7674
- }, Dinero({ amount: 0, currency: instructions[0].currency })).toFormat('0.00');
7690
+ }, Dinero({ amount: 0, currency: instructions[0].currency }))
7691
+ .toFormat('0.00');
7675
7692
  }
7676
7693
  /**
7677
7694
  * Validates the payment initiation data according to SEPA requirements.
@@ -7689,8 +7706,10 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7689
7706
  // Validates that all payment instructions have the same currency
7690
7707
  // TODO: Remove this when we figure out how to run sumPaymentInstructions safely
7691
7708
  validateAllInstructionsHaveSameCurrency() {
7692
- if (!this.paymentInstructions.every((i) => { return i.currency === this.paymentInstructions[0].currency; })) {
7693
- throw new Error("In order to calculate the payment instructions sum, all payment instruction currencies must be the same.");
7709
+ if (!this.paymentInstructions.every(i => {
7710
+ return i.currency === this.paymentInstructions[0].currency;
7711
+ })) {
7712
+ throw new Error('In order to calculate the payment instructions sum, all payment instruction currencies must be the same.');
7694
7713
  }
7695
7714
  }
7696
7715
  /**
@@ -7701,7 +7720,10 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7701
7720
  creditTransfer(instruction) {
7702
7721
  const paymentInstructionId = sanitize(instruction.id || v4(), 35);
7703
7722
  const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
7704
- const dinero = Dinero({ amount: instruction.amount, currency: instruction.currency });
7723
+ const dinero = Dinero({
7724
+ amount: instruction.amount,
7725
+ currency: instruction.currency,
7726
+ });
7705
7727
  return {
7706
7728
  PmtId: {
7707
7729
  InstrId: paymentInstructionId,
@@ -7713,15 +7735,19 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7713
7735
  '@Ccy': instruction.currency,
7714
7736
  },
7715
7737
  },
7716
- ...(instruction.creditor.agent && { CdtrAgt: this.agent(instruction.creditor.agent) }),
7738
+ ...(instruction.creditor.agent && {
7739
+ CdtrAgt: this.agent(instruction.creditor.agent),
7740
+ }),
7717
7741
  Cdtr: this.party(instruction.creditor),
7718
7742
  CdtrAcct: {
7719
7743
  Id: { IBAN: instruction.creditor.account.iban },
7720
7744
  Ccy: instruction.currency,
7721
7745
  },
7722
- RmtInf: instruction.remittanceInformation ? {
7723
- Ustrd: instruction.remittanceInformation,
7724
- } : undefined,
7746
+ RmtInf: instruction.remittanceInformation
7747
+ ? {
7748
+ Ustrd: instruction.remittanceInformation,
7749
+ }
7750
+ : undefined,
7725
7751
  };
7726
7752
  }
7727
7753
  /**
@@ -7733,7 +7759,7 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7733
7759
  const xml = {
7734
7760
  '?xml': {
7735
7761
  '@version': '1.0',
7736
- '@encoding': 'UTF-8'
7762
+ '@encoding': 'UTF-8',
7737
7763
  },
7738
7764
  Document: {
7739
7765
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
@@ -7765,7 +7791,7 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7765
7791
  PmtTpInf: {
7766
7792
  SvcLvl: { Cd: 'SEPA' },
7767
7793
  ...(this.categoryPurpose && {
7768
- CtgyPurp: { Cd: this.categoryPurpose }
7794
+ CtgyPurp: { Cd: this.categoryPurpose },
7769
7795
  }),
7770
7796
  },
7771
7797
  ReqdExctnDt: this.creationDate.toISOString().split('T').at(0),
@@ -7775,8 +7801,8 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7775
7801
  ChrgBr: 'SLEV',
7776
7802
  // payments[]
7777
7803
  CdtTrfTxInf: this.paymentInstructions.map(p => this.creditTransfer(p)),
7778
- }
7779
- }
7804
+ },
7805
+ },
7780
7806
  },
7781
7807
  };
7782
7808
  return builder.build(xml);
@@ -7785,9 +7811,10 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7785
7811
  const parser = new fxp.XMLParser({ ignoreAttributes: false });
7786
7812
  const xml = parser.parse(rawXml);
7787
7813
  if (!xml.Document) {
7788
- throw new InvalidXmlError("Invalid XML format");
7814
+ throw new InvalidXmlError('Invalid XML format');
7789
7815
  }
7790
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
7816
+ const namespace = (xml.Document['@_xmlns'] ||
7817
+ xml.Document['@_Xmlns']);
7791
7818
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
7792
7819
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
7793
7820
  }
@@ -7798,19 +7825,27 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7798
7825
  }
7799
7826
  // Assuming we have one PmtInf / one Debtor, we can hack together this information from InitgPty / Dbtr
7800
7827
  const initiatingParty = {
7801
- name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm || xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
7802
- id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId.Othr.Id,
7828
+ name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm ||
7829
+ xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
7830
+ id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId.Othr
7831
+ .Id,
7803
7832
  agent: parseAgent(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt),
7804
- account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct)
7833
+ account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct),
7805
7834
  };
7806
- const rawInstructions = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf) ? xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf : [xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf];
7835
+ const rawInstructions = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf)
7836
+ ? xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf
7837
+ : [xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf];
7807
7838
  const paymentInstructions = rawInstructions.map((inst) => {
7808
7839
  const currency = inst.Amt.InstdAmt['@_Ccy'];
7809
7840
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
7810
7841
  const rawPostalAddress = inst.Cdtr.PstlAdr;
7811
7842
  return {
7812
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
7813
- ...(inst.PmtId.EndToEndId && { endToEndId: inst.PmtId.EndToEndId.toString() }),
7843
+ ...(inst.PmtId.InstrId && {
7844
+ id: inst.PmtId.InstrId.toString(),
7845
+ }),
7846
+ ...(inst.PmtId.EndToEndId && {
7847
+ endToEndId: inst.PmtId.EndToEndId.toString(),
7848
+ }),
7814
7849
  type: 'sepa',
7815
7850
  direction: 'credit',
7816
7851
  amount: amount,
@@ -7819,25 +7854,46 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
7819
7854
  name: inst.Cdtr?.Nm,
7820
7855
  agent: parseAgent(inst.CdtrAgt),
7821
7856
  account: parseAccount(inst.CdtrAcct),
7822
- ...((rawPostalAddress && (rawPostalAddress.StreetName || rawPostalAddress.BldgNb || rawPostalAddress.PstlCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
7823
- address: {
7824
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
7825
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
7826
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
7827
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
7828
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
7829
- ...(rawPostalAddress.Ctry && { country: rawPostalAddress.Ctry }),
7857
+ ...(rawPostalAddress &&
7858
+ (rawPostalAddress.StreetName ||
7859
+ rawPostalAddress.BldgNb ||
7860
+ rawPostalAddress.PstlCd ||
7861
+ rawPostalAddress.TwnNm ||
7862
+ rawPostalAddress.Ctry)
7863
+ ? {
7864
+ address: {
7865
+ ...(rawPostalAddress.StrtNm && {
7866
+ streetName: rawPostalAddress.StrtNm.toString(),
7867
+ }),
7868
+ ...(rawPostalAddress.BldgNb && {
7869
+ buildingNumber: rawPostalAddress.BldgNb.toString(),
7870
+ }),
7871
+ ...(rawPostalAddress.TwnNm && {
7872
+ townName: rawPostalAddress.TwnNm.toString(),
7873
+ }),
7874
+ ...(rawPostalAddress.CtrySubDvsn && {
7875
+ countrySubDivision: rawPostalAddress.CtrySubDvsn.toString(),
7876
+ }),
7877
+ ...(rawPostalAddress.PstCd && {
7878
+ postalCode: rawPostalAddress.PstCd.toString(),
7879
+ }),
7880
+ ...(rawPostalAddress.Ctry && {
7881
+ country: rawPostalAddress.Ctry,
7882
+ }),
7883
+ },
7830
7884
  }
7831
- } : {}),
7885
+ : {}),
7832
7886
  },
7833
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
7887
+ ...(inst.RmtInf?.Ustrd && {
7888
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
7889
+ }),
7834
7890
  };
7835
7891
  });
7836
7892
  return new SEPACreditPaymentInitiation({
7837
7893
  messageId: messageId,
7838
7894
  creationDate: creationDate,
7839
7895
  initiatingParty: initiatingParty,
7840
- paymentInstructions: paymentInstructions
7896
+ paymentInstructions: paymentInstructions,
7841
7897
  });
7842
7898
  }
7843
7899
  }
@@ -7880,7 +7936,7 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
7880
7936
  * @param {SEPAMultiCreditPaymentInitiationConfig} config - The configuration object for the SEPA multi credit transfer.
7881
7937
  */
7882
7938
  constructor(config) {
7883
- super({ type: "sepa" });
7939
+ super({ type: 'sepa' });
7884
7940
  this.initiatingParty = config.initiatingParty;
7885
7941
  this.paymentInstructions = config.paymentInstructions;
7886
7942
  this.messageId = config.messageId || v4().replace(/-/g, '');
@@ -7943,8 +7999,10 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
7943
7999
  * @throws {Error} If payment instructions have different currencies.
7944
8000
  */
7945
8001
  validateGroupInstructionsHaveSameCurrency(payments) {
7946
- if (!payments.every((i) => { return i.currency === payments[0].currency; })) {
7947
- throw new Error("In order to calculate the payment instructions sum, all payment instruction currencies within a group must be the same.");
8002
+ if (!payments.every(i => {
8003
+ return i.currency === payments[0].currency;
8004
+ })) {
8005
+ throw new Error('In order to calculate the payment instructions sum, all payment instruction currencies within a group must be the same.');
7948
8006
  }
7949
8007
  }
7950
8008
  /**
@@ -7955,7 +8013,10 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
7955
8013
  creditTransfer(instruction) {
7956
8014
  const paymentInstructionId = sanitize(instruction.id || v4(), 35);
7957
8015
  const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
7958
- const dinero = Dinero({ amount: instruction.amount, currency: instruction.currency });
8016
+ const dinero = Dinero({
8017
+ amount: instruction.amount,
8018
+ currency: instruction.currency,
8019
+ });
7959
8020
  return {
7960
8021
  PmtId: {
7961
8022
  InstrId: paymentInstructionId,
@@ -7967,15 +8028,19 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
7967
8028
  '@Ccy': instruction.currency,
7968
8029
  },
7969
8030
  },
7970
- ...(instruction.creditor.agent && { CdtrAgt: this.agent(instruction.creditor.agent) }),
8031
+ ...(instruction.creditor.agent && {
8032
+ CdtrAgt: this.agent(instruction.creditor.agent),
8033
+ }),
7971
8034
  Cdtr: this.party(instruction.creditor),
7972
8035
  CdtrAcct: {
7973
8036
  Id: { IBAN: instruction.creditor.account.iban },
7974
8037
  Ccy: instruction.currency,
7975
8038
  },
7976
- RmtInf: instruction.remittanceInformation ? {
7977
- Ustrd: instruction.remittanceInformation,
7978
- } : undefined,
8039
+ RmtInf: instruction.remittanceInformation
8040
+ ? {
8041
+ Ustrd: instruction.remittanceInformation,
8042
+ }
8043
+ : undefined,
7979
8044
  };
7980
8045
  }
7981
8046
  /**
@@ -7987,7 +8052,10 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
7987
8052
  // Generate one PmtInf entry per individual payment
7988
8053
  const paymentInfoEntries = this.paymentInstructions.flatMap((group, groupIndex) => {
7989
8054
  return group.payments.map((payment, paymentIndex) => {
7990
- const dinero = Dinero({ amount: payment.amount, currency: payment.currency });
8055
+ const dinero = Dinero({
8056
+ amount: payment.amount,
8057
+ currency: payment.currency,
8058
+ });
7991
8059
  const pmtInfId = sanitize(`${this.paymentInformationIdBase}-${groupIndex + 1}-${paymentIndex + 1}`, 35);
7992
8060
  const requestedExecutionDate = payment.requestedPaymentExecutionDate || new Date();
7993
8061
  return {
@@ -7998,7 +8066,7 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
7998
8066
  PmtTpInf: {
7999
8067
  SvcLvl: { Cd: 'SEPA' },
8000
8068
  ...(group.categoryPurpose && {
8001
- CtgyPurp: { Cd: group.categoryPurpose }
8069
+ CtgyPurp: { Cd: group.categoryPurpose },
8002
8070
  }),
8003
8071
  },
8004
8072
  ReqdExctnDt: requestedExecutionDate.toISOString().split('T')[0],
@@ -8013,11 +8081,12 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8013
8081
  const xml = {
8014
8082
  '?xml': {
8015
8083
  '@version': '1.0',
8016
- '@encoding': 'UTF-8'
8084
+ '@encoding': 'UTF-8',
8017
8085
  },
8018
8086
  Document: {
8019
8087
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
8020
8088
  '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
8089
+ '@xsi:schemaLocation': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03 pain.001.001.03.xsd',
8021
8090
  CstmrCdtTrfInitn: {
8022
8091
  GrpHdr: {
8023
8092
  MsgId: this.messageId,
@@ -8038,7 +8107,7 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8038
8107
  },
8039
8108
  },
8040
8109
  PmtInf: paymentInfoEntries,
8041
- }
8110
+ },
8042
8111
  },
8043
8112
  };
8044
8113
  return builder.build(xml);
@@ -8056,10 +8125,11 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8056
8125
  const xml = parser.parse(rawXml);
8057
8126
  // Validate XML structure
8058
8127
  if (!xml.Document) {
8059
- throw new InvalidXmlError("Invalid XML format");
8128
+ throw new InvalidXmlError('Invalid XML format');
8060
8129
  }
8061
8130
  // Validate namespace
8062
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8131
+ const namespace = (xml.Document['@_xmlns'] ||
8132
+ xml.Document['@_Xmlns']);
8063
8133
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8064
8134
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8065
8135
  }
@@ -8069,7 +8139,8 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8069
8139
  // Extract top-level initiating party from GrpHdr
8070
8140
  const topLevelInitiatingParty = {
8071
8141
  name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm,
8072
- id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id?.OrgId?.Othr?.Id,
8142
+ id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id?.OrgId?.Othr
8143
+ ?.Id,
8073
8144
  };
8074
8145
  // Normalize PmtInf to array (handle both single object and array cases)
8075
8146
  const rawPmtInf = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf)
@@ -8087,7 +8158,9 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8087
8158
  // Extract optional category purpose
8088
8159
  const categoryPurpose = pmtInf.PmtTpInf?.CtgyPurp?.Cd;
8089
8160
  // Extract requested execution date
8090
- const requestedExecutionDate = pmtInf.ReqdExctnDt ? new Date(pmtInf.ReqdExctnDt) : undefined;
8161
+ const requestedExecutionDate = pmtInf.ReqdExctnDt
8162
+ ? new Date(pmtInf.ReqdExctnDt)
8163
+ : undefined;
8091
8164
  // Normalize CdtTrfTxInf to array
8092
8165
  const rawInstructions = Array.isArray(pmtInf.CdtTrfTxInf)
8093
8166
  ? pmtInf.CdtTrfTxInf
@@ -8098,29 +8171,56 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8098
8171
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8099
8172
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8100
8173
  return {
8101
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8102
- ...(inst.PmtId.EndToEndId && { endToEndId: inst.PmtId.EndToEndId.toString() }),
8174
+ ...(inst.PmtId.InstrId && {
8175
+ id: inst.PmtId.InstrId.toString(),
8176
+ }),
8177
+ ...(inst.PmtId.EndToEndId && {
8178
+ endToEndId: inst.PmtId.EndToEndId.toString(),
8179
+ }),
8103
8180
  type: 'sepa',
8104
8181
  direction: 'credit',
8105
8182
  amount: amount,
8106
8183
  currency: currency,
8107
- ...(requestedExecutionDate && { requestedPaymentExecutionDate: requestedExecutionDate }),
8184
+ ...(requestedExecutionDate && {
8185
+ requestedPaymentExecutionDate: requestedExecutionDate,
8186
+ }),
8108
8187
  creditor: {
8109
8188
  name: inst.Cdtr?.Nm,
8110
8189
  agent: parseAgent(inst.CdtrAgt),
8111
8190
  account: parseAccount(inst.CdtrAcct),
8112
- ...((rawPostalAddress && (rawPostalAddress.StrtNm || rawPostalAddress.BldgNb || rawPostalAddress.PstCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8113
- address: {
8114
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8115
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8116
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8117
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8118
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8119
- ...(rawPostalAddress.Ctry && { country: rawPostalAddress.Ctry }),
8191
+ ...(rawPostalAddress &&
8192
+ (rawPostalAddress.StrtNm ||
8193
+ rawPostalAddress.BldgNb ||
8194
+ rawPostalAddress.PstCd ||
8195
+ rawPostalAddress.TwnNm ||
8196
+ rawPostalAddress.Ctry)
8197
+ ? {
8198
+ address: {
8199
+ ...(rawPostalAddress.StrtNm && {
8200
+ streetName: rawPostalAddress.StrtNm.toString(),
8201
+ }),
8202
+ ...(rawPostalAddress.BldgNb && {
8203
+ buildingNumber: rawPostalAddress.BldgNb.toString(),
8204
+ }),
8205
+ ...(rawPostalAddress.TwnNm && {
8206
+ townName: rawPostalAddress.TwnNm.toString(),
8207
+ }),
8208
+ ...(rawPostalAddress.CtrySubDvsn && {
8209
+ countrySubDivision: rawPostalAddress.CtrySubDvsn.toString(),
8210
+ }),
8211
+ ...(rawPostalAddress.PstCd && {
8212
+ postalCode: rawPostalAddress.PstCd.toString(),
8213
+ }),
8214
+ ...(rawPostalAddress.Ctry && {
8215
+ country: rawPostalAddress.Ctry,
8216
+ }),
8217
+ },
8120
8218
  }
8121
- } : {}),
8219
+ : {}),
8122
8220
  },
8123
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8221
+ ...(inst.RmtInf?.Ustrd && {
8222
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8223
+ }),
8124
8224
  };
8125
8225
  });
8126
8226
  return {
@@ -8168,7 +8268,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8168
8268
  paymentInformationId;
8169
8269
  formattedPaymentSum;
8170
8270
  constructor(config) {
8171
- super({ type: "rtp" });
8271
+ super({ type: 'rtp' });
8172
8272
  this.initiatingParty = config.initiatingParty;
8173
8273
  this.paymentInstructions = config.paymentInstructions;
8174
8274
  this.messageId = config.messageId || v4().replace(/-/g, '');
@@ -8186,9 +8286,11 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8186
8286
  */
8187
8287
  sumPaymentInstructions(instructions) {
8188
8288
  const instructionDineros = instructions.map(instruction => Dinero({ amount: instruction.amount, currency: instruction.currency }));
8189
- return instructionDineros.reduce((acc, next) => {
8289
+ return instructionDineros
8290
+ .reduce((acc, next) => {
8190
8291
  return acc.add(next);
8191
- }, Dinero({ amount: 0, currency: instructions[0].currency })).toFormat('0.00');
8292
+ }, Dinero({ amount: 0, currency: instructions[0].currency }))
8293
+ .toFormat('0.00');
8192
8294
  }
8193
8295
  /**
8194
8296
  * Validates the payment initiation data according to SEPA requirements.
@@ -8210,7 +8312,10 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8210
8312
  creditTransfer(instruction) {
8211
8313
  const paymentInstructionId = sanitize(instruction.id || v4(), 35);
8212
8314
  const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
8213
- const dinero = Dinero({ amount: instruction.amount, currency: instruction.currency });
8315
+ const dinero = Dinero({
8316
+ amount: instruction.amount,
8317
+ currency: instruction.currency,
8318
+ });
8214
8319
  return {
8215
8320
  PmtId: {
8216
8321
  InstrId: paymentInstructionId,
@@ -8231,9 +8336,11 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8231
8336
  },
8232
8337
  },
8233
8338
  },
8234
- RmtInf: instruction.remittanceInformation ? {
8235
- Ustrd: instruction.remittanceInformation,
8236
- } : undefined,
8339
+ RmtInf: instruction.remittanceInformation
8340
+ ? {
8341
+ Ustrd: instruction.remittanceInformation,
8342
+ }
8343
+ : undefined,
8237
8344
  };
8238
8345
  }
8239
8346
  /**
@@ -8245,7 +8352,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8245
8352
  const xml = {
8246
8353
  '?xml': {
8247
8354
  '@version': '1.0',
8248
- '@encoding': 'UTF-8'
8355
+ '@encoding': 'UTF-8',
8249
8356
  },
8250
8357
  Document: {
8251
8358
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
@@ -8274,7 +8381,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8274
8381
  CtrlSum: this.formattedPaymentSum,
8275
8382
  PmtTpInf: {
8276
8383
  SvcLvl: { Cd: 'URNS' },
8277
- LclInstrm: { Prtry: "RTP" },
8384
+ LclInstrm: { Prtry: 'RTP' },
8278
8385
  },
8279
8386
  ReqdExctnDt: this.creationDate.toISOString().split('T').at(0),
8280
8387
  Dbtr: this.party(this.initiatingParty),
@@ -8283,8 +8390,8 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8283
8390
  ChrgBr: 'SLEV',
8284
8391
  // payments[]
8285
8392
  CdtTrfTxInf: this.paymentInstructions.map(p => this.creditTransfer(p)),
8286
- }
8287
- }
8393
+ },
8394
+ },
8288
8395
  },
8289
8396
  };
8290
8397
  return builder.build(xml);
@@ -8293,9 +8400,10 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8293
8400
  const parser = new fxp.XMLParser({ ignoreAttributes: false });
8294
8401
  const xml = parser.parse(rawXml);
8295
8402
  if (!xml.Document) {
8296
- throw new InvalidXmlError("Invalid XML format");
8403
+ throw new InvalidXmlError('Invalid XML format');
8297
8404
  }
8298
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8405
+ const namespace = (xml.Document['@_xmlns'] ||
8406
+ xml.Document['@_Xmlns']);
8299
8407
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8300
8408
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8301
8409
  }
@@ -8306,19 +8414,27 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8306
8414
  }
8307
8415
  // Assuming we have one PmtInf / one Debtor, we can hack together this information from InitgPty / Dbtr
8308
8416
  const initiatingParty = {
8309
- name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm || xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
8310
- id: (xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId?.Othr?.Id) || (xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId?.BICOrBEI),
8417
+ name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm ||
8418
+ xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
8419
+ id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId?.Othr?.Id ||
8420
+ xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId?.BICOrBEI,
8311
8421
  agent: parseAgent(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt),
8312
- account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct)
8422
+ account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct),
8313
8423
  };
8314
- const rawInstructions = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf) ? xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf : [xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf];
8424
+ const rawInstructions = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf)
8425
+ ? xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf
8426
+ : [xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf];
8315
8427
  const paymentInstructions = rawInstructions.map((inst) => {
8316
8428
  const currency = inst.Amt.InstdAmt['@_Ccy'];
8317
8429
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8318
8430
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8319
8431
  return {
8320
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8321
- ...(inst.PmtId.EndToEndId && { endToEndId: inst.PmtId.EndToEndId.toString() }),
8432
+ ...(inst.PmtId.InstrId && {
8433
+ id: inst.PmtId.InstrId.toString(),
8434
+ }),
8435
+ ...(inst.PmtId.EndToEndId && {
8436
+ endToEndId: inst.PmtId.EndToEndId.toString(),
8437
+ }),
8322
8438
  type: 'sepa',
8323
8439
  direction: 'credit',
8324
8440
  amount: amount,
@@ -8327,25 +8443,46 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8327
8443
  name: inst.Cdtr?.Nm,
8328
8444
  agent: parseAgent(inst.CdtrAgt),
8329
8445
  account: parseAccount(inst.CdtrAcct),
8330
- ...((rawPostalAddress && (rawPostalAddress.StreetName || rawPostalAddress.BldgNb || rawPostalAddress.PstlCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8331
- address: {
8332
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8333
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8334
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8335
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8336
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8337
- ...(rawPostalAddress.Ctry && { country: rawPostalAddress.Ctry }),
8446
+ ...(rawPostalAddress &&
8447
+ (rawPostalAddress.StreetName ||
8448
+ rawPostalAddress.BldgNb ||
8449
+ rawPostalAddress.PstlCd ||
8450
+ rawPostalAddress.TwnNm ||
8451
+ rawPostalAddress.Ctry)
8452
+ ? {
8453
+ address: {
8454
+ ...(rawPostalAddress.StrtNm && {
8455
+ streetName: rawPostalAddress.StrtNm.toString(),
8456
+ }),
8457
+ ...(rawPostalAddress.BldgNb && {
8458
+ buildingNumber: rawPostalAddress.BldgNb.toString(),
8459
+ }),
8460
+ ...(rawPostalAddress.TwnNm && {
8461
+ townName: rawPostalAddress.TwnNm.toString(),
8462
+ }),
8463
+ ...(rawPostalAddress.CtrySubDvsn && {
8464
+ countrySubDivision: rawPostalAddress.CtrySubDvsn.toString(),
8465
+ }),
8466
+ ...(rawPostalAddress.PstCd && {
8467
+ postalCode: rawPostalAddress.PstCd.toString(),
8468
+ }),
8469
+ ...(rawPostalAddress.Ctry && {
8470
+ country: rawPostalAddress.Ctry,
8471
+ }),
8472
+ },
8338
8473
  }
8339
- } : {}),
8474
+ : {}),
8340
8475
  },
8341
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8476
+ ...(inst.RmtInf?.Ustrd && {
8477
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8478
+ }),
8342
8479
  };
8343
8480
  });
8344
8481
  return new RTPCreditPaymentInitiation({
8345
8482
  messageId: messageId,
8346
8483
  creationDate: creationDate,
8347
8484
  initiatingParty: initiatingParty,
8348
- paymentInstructions: paymentInstructions
8485
+ paymentInstructions: paymentInstructions,
8349
8486
  });
8350
8487
  }
8351
8488
  }
@@ -8380,14 +8517,14 @@ const ACHLocalInstrumentCode = {
8380
8517
  RepresentedCheck: 'RCK',
8381
8518
  };
8382
8519
  const ACHLocalInstrumentCodeDescriptionMap = {
8383
- 'CCD': 'Corporate Credit or Debit',
8384
- 'PPD': 'Prearranged Payment and Deposit',
8385
- 'WEB': 'Internet-Initiated Entry',
8386
- 'TEL': 'Telephone-Initiated Entry',
8387
- 'POP': 'Point-of-Purchase Entry',
8388
- 'ARC': 'Accounts Receivable Entry',
8389
- 'BOC': 'Back Office Conversion',
8390
- 'RCK': 'Represented Check Entry',
8520
+ CCD: 'Corporate Credit or Debit',
8521
+ PPD: 'Prearranged Payment and Deposit',
8522
+ WEB: 'Internet-Initiated Entry',
8523
+ TEL: 'Telephone-Initiated Entry',
8524
+ POP: 'Point-of-Purchase Entry',
8525
+ ARC: 'Accounts Receivable Entry',
8526
+ BOC: 'Back Office Conversion',
8527
+ RCK: 'Represented Check Entry',
8391
8528
  };
8392
8529
 
8393
8530
  /**
@@ -8446,13 +8583,14 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8446
8583
  instructionPriority;
8447
8584
  formattedPaymentSum;
8448
8585
  constructor(config) {
8449
- super({ type: "ach" });
8586
+ super({ type: 'ach' });
8450
8587
  this.initiatingParty = config.initiatingParty;
8451
8588
  this.paymentInstructions = config.paymentInstructions;
8452
8589
  this.messageId = config.messageId || v4().replace(/-/g, '');
8453
8590
  this.creationDate = config.creationDate || new Date();
8454
8591
  this.paymentInformationId = sanitize(v4(), 35);
8455
- this.localInstrument = config.localInstrument || ACHLocalInstrumentCode.CorporateCreditDebit;
8592
+ this.localInstrument =
8593
+ config.localInstrument || ACHLocalInstrumentCode.CorporateCreditDebit;
8456
8594
  this.serviceLevel = 'NURG'; // Normal Urgency
8457
8595
  this.instructionPriority = 'NORM'; // Normal Priority
8458
8596
  this.formattedPaymentSum = this.sumPaymentInstructions(this.paymentInstructions);
@@ -8467,9 +8605,11 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8467
8605
  */
8468
8606
  sumPaymentInstructions(instructions) {
8469
8607
  const instructionDineros = instructions.map(instruction => Dinero({ amount: instruction.amount, currency: instruction.currency }));
8470
- return instructionDineros.reduce((acc, next) => {
8608
+ return instructionDineros
8609
+ .reduce((acc, next) => {
8471
8610
  return acc.add(next);
8472
- }, Dinero({ amount: 0, currency: instructions[0].currency })).toFormat('0.00');
8611
+ }, Dinero({ amount: 0, currency: instructions[0].currency }))
8612
+ .toFormat('0.00');
8473
8613
  }
8474
8614
  /**
8475
8615
  * Validates the payment initiation data according to ACH requirements.
@@ -8497,7 +8637,10 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8497
8637
  creditTransfer(instruction) {
8498
8638
  const paymentInstructionId = sanitize(instruction.id || v4(), 35);
8499
8639
  const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
8500
- const dinero = Dinero({ amount: instruction.amount, currency: instruction.currency });
8640
+ const dinero = Dinero({
8641
+ amount: instruction.amount,
8642
+ currency: instruction.currency,
8643
+ });
8501
8644
  return {
8502
8645
  PmtId: {
8503
8646
  InstrId: paymentInstructionId,
@@ -8522,9 +8665,11 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8522
8665
  },
8523
8666
  Ccy: instruction.currency,
8524
8667
  },
8525
- RmtInf: instruction.remittanceInformation ? {
8526
- Ustrd: instruction.remittanceInformation,
8527
- } : undefined,
8668
+ RmtInf: instruction.remittanceInformation
8669
+ ? {
8670
+ Ustrd: instruction.remittanceInformation,
8671
+ }
8672
+ : undefined,
8528
8673
  };
8529
8674
  }
8530
8675
  /**
@@ -8536,7 +8681,7 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8536
8681
  const xml = {
8537
8682
  '?xml': {
8538
8683
  '@version': '1.0',
8539
- '@encoding': 'UTF-8'
8684
+ '@encoding': 'UTF-8',
8540
8685
  },
8541
8686
  Document: {
8542
8687
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
@@ -8574,8 +8719,8 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8574
8719
  ChrgBr: 'SHAR',
8575
8720
  // payments[]
8576
8721
  CdtTrfTxInf: this.paymentInstructions.map(p => this.creditTransfer(p)),
8577
- }
8578
- }
8722
+ },
8723
+ },
8579
8724
  },
8580
8725
  };
8581
8726
  return builder.build(xml);
@@ -8589,12 +8734,17 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8589
8734
  * @throws {Error} If multiple payment information blocks are found.
8590
8735
  */
8591
8736
  static fromXML(rawXml) {
8592
- const parser = new fxp.XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_', textNodeName: '#text' });
8737
+ const parser = new fxp.XMLParser({
8738
+ ignoreAttributes: false,
8739
+ attributeNamePrefix: '@_',
8740
+ textNodeName: '#text',
8741
+ });
8593
8742
  const xml = parser.parse(rawXml);
8594
8743
  if (!xml.Document) {
8595
- throw new InvalidXmlError("Invalid XML format");
8744
+ throw new InvalidXmlError('Invalid XML format');
8596
8745
  }
8597
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8746
+ const namespace = (xml.Document['@_xmlns'] ||
8747
+ xml.Document['@_Xmlns']);
8598
8748
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8599
8749
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8600
8750
  }
@@ -8607,19 +8757,27 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8607
8757
  xml.Document.CstmrCdtTrfInitn.PmtInf.PmtTpInf;
8608
8758
  // Assuming we have one PmtInf / one Debtor, we can hack together this information from InitgPty / Dbtr
8609
8759
  const initiatingParty = {
8610
- name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm || xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
8611
- id: (xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId?.BICOrBEI) || (xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId?.Othr?.Id),
8760
+ name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm ||
8761
+ xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
8762
+ id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId?.BICOrBEI ||
8763
+ xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id.OrgId?.Othr?.Id,
8612
8764
  agent: parseAgent(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt),
8613
- account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct)
8765
+ account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct),
8614
8766
  };
8615
- const rawInstructions = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf) ? xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf : [xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf];
8767
+ const rawInstructions = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf)
8768
+ ? xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf
8769
+ : [xml.Document.CstmrCdtTrfInitn.PmtInf.CdtTrfTxInf];
8616
8770
  const paymentInstructions = rawInstructions.map((inst) => {
8617
8771
  const currency = inst.Amt.InstdAmt['@_Ccy'];
8618
8772
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8619
8773
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8620
8774
  return {
8621
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8622
- ...(inst.PmtId.EndToEndId && { endToEndId: inst.PmtId.EndToEndId.toString() }),
8775
+ ...(inst.PmtId.InstrId && {
8776
+ id: inst.PmtId.InstrId.toString(),
8777
+ }),
8778
+ ...(inst.PmtId.EndToEndId && {
8779
+ endToEndId: inst.PmtId.EndToEndId.toString(),
8780
+ }),
8623
8781
  type: 'ach',
8624
8782
  direction: 'credit',
8625
8783
  amount: amount,
@@ -8628,41 +8786,458 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8628
8786
  name: inst.Cdtr?.Nm,
8629
8787
  agent: parseAgent(inst.CdtrAgt),
8630
8788
  account: parseAccount(inst.CdtrAcct),
8631
- ...((rawPostalAddress && (rawPostalAddress.StrtNm || rawPostalAddress.BldgNb || rawPostalAddress.PstCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8632
- address: {
8633
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8634
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8635
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8636
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8637
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8638
- ...(rawPostalAddress.Ctry && { country: rawPostalAddress.Ctry }),
8789
+ ...(rawPostalAddress &&
8790
+ (rawPostalAddress.StrtNm ||
8791
+ rawPostalAddress.BldgNb ||
8792
+ rawPostalAddress.PstCd ||
8793
+ rawPostalAddress.TwnNm ||
8794
+ rawPostalAddress.Ctry)
8795
+ ? {
8796
+ address: {
8797
+ ...(rawPostalAddress.StrtNm && {
8798
+ streetName: rawPostalAddress.StrtNm.toString(),
8799
+ }),
8800
+ ...(rawPostalAddress.BldgNb && {
8801
+ buildingNumber: rawPostalAddress.BldgNb.toString(),
8802
+ }),
8803
+ ...(rawPostalAddress.TwnNm && {
8804
+ townName: rawPostalAddress.TwnNm.toString(),
8805
+ }),
8806
+ ...(rawPostalAddress.CtrySubDvsn && {
8807
+ countrySubDivision: rawPostalAddress.CtrySubDvsn.toString(),
8808
+ }),
8809
+ ...(rawPostalAddress.PstCd && {
8810
+ postalCode: rawPostalAddress.PstCd.toString(),
8811
+ }),
8812
+ ...(rawPostalAddress.Ctry && {
8813
+ country: rawPostalAddress.Ctry,
8814
+ }),
8815
+ },
8639
8816
  }
8640
- } : {}),
8817
+ : {}),
8641
8818
  },
8642
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8819
+ ...(inst.RmtInf?.Ustrd && {
8820
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8821
+ }),
8643
8822
  };
8644
8823
  });
8645
8824
  return new ACHCreditPaymentInitiation({
8646
8825
  messageId: messageId,
8647
8826
  creationDate: creationDate,
8648
8827
  initiatingParty: initiatingParty,
8649
- paymentInstructions: paymentInstructions
8828
+ paymentInstructions: paymentInstructions,
8829
+ });
8830
+ }
8831
+ }
8832
+
8833
+ /**
8834
+ * Represents a SEPA Direct Debit Payment Initiation.
8835
+ * This class handles the creation and serialization of SEPA direct debit messages
8836
+ * with multiple payment information blocks (multiple creditors) according to the ISO20022 pain.008 standard.
8837
+ * @class
8838
+ * @extends PaymentInitiation
8839
+ * @param {SEPADirectDebitPaymentInitiationConfig} config - The configuration for the SEPA Direct Debit Payment Initiation message.
8840
+ * @example
8841
+ * ```typescript
8842
+ * // Creating a SEPA direct debit message
8843
+ * const payment = new SEPADirectDebitPaymentInitiation({
8844
+ * initiatingParty: { name: 'Company Ltd', id: '12345' },
8845
+ * paymentInstructions: [
8846
+ * {
8847
+ * creditor: creditor1,
8848
+ * creditorSchemeId: 'DE96ZZZ00000345986',
8849
+ * requestedCollectionDate: new Date('2025-11-22'),
8850
+ * sequenceType: 'RCUR',
8851
+ * payments: [debit1, debit2]
8852
+ * }
8853
+ * ]
8854
+ * });
8855
+ * ```
8856
+ */
8857
+ class SEPADirectDebitPaymentInitiation extends PaymentInitiation {
8858
+ initiatingParty;
8859
+ messageId;
8860
+ creationDate;
8861
+ paymentInstructions;
8862
+ paymentInformationIdBase;
8863
+ formattedPaymentSum;
8864
+ totalTransactionCount;
8865
+ /**
8866
+ * Creates an instance of SEPADirectDebitPaymentInitiation.
8867
+ * @param {SEPADirectDebitPaymentInitiationConfig} config - The configuration object for the SEPA direct debit.
8868
+ */
8869
+ constructor(config) {
8870
+ super({ type: 'sepa' });
8871
+ this.initiatingParty = config.initiatingParty;
8872
+ this.paymentInstructions = config.paymentInstructions;
8873
+ this.messageId = config.messageId || v4().replace(/-/g, '');
8874
+ this.creationDate = config.creationDate || new Date();
8875
+ this.paymentInformationIdBase = sanitize(v4(), 35);
8876
+ this.totalTransactionCount = this.countAllTransactions();
8877
+ this.formattedPaymentSum = this.sumAllPayments();
8878
+ this.validate();
8879
+ }
8880
+ /**
8881
+ * Counts the total number of transactions across all payment instruction groups.
8882
+ * @private
8883
+ * @returns {number} The total count of all transactions.
8884
+ */
8885
+ countAllTransactions() {
8886
+ return this.paymentInstructions.reduce((total, group) => {
8887
+ return total + group.payments.length;
8888
+ }, 0);
8889
+ }
8890
+ /**
8891
+ * Calculates the sum of all payment instructions across all groups.
8892
+ * @private
8893
+ * @returns {string} The total sum formatted as a string with 2 decimal places.
8894
+ */
8895
+ sumAllPayments() {
8896
+ let totalAmount = 0;
8897
+ let currency = null;
8898
+ for (const group of this.paymentInstructions) {
8899
+ for (const payment of group.payments) {
8900
+ if (currency === null) {
8901
+ currency = payment.currency;
8902
+ }
8903
+ totalAmount += payment.amount;
8904
+ }
8905
+ }
8906
+ if (currency === null) {
8907
+ throw new Error('No payments found');
8908
+ }
8909
+ return Dinero({ amount: totalAmount, currency }).toFormat('0.00');
8910
+ }
8911
+ /**
8912
+ * Validates the payment initiation data according to SEPA requirements.
8913
+ * @private
8914
+ * @throws {Error} If messageId exceeds 35 characters.
8915
+ * @throws {Error} If any group's payment instructions have different currencies.
8916
+ */
8917
+ validate() {
8918
+ if (this.messageId.length > 35) {
8919
+ throw new Error('messageId must not exceed 35 characters');
8920
+ }
8921
+ // Validate each group has same currency within its payments
8922
+ for (const group of this.paymentInstructions) {
8923
+ this.validateGroupInstructionsHaveSameCurrency(group.payments);
8924
+ }
8925
+ }
8926
+ /**
8927
+ * Validates that all payment instructions in a group have the same currency (EUR).
8928
+ * @private
8929
+ * @param {AtLeastOne<SEPADirectDebitPaymentInstruction>} payments - Array of payment instructions.
8930
+ * @throws {Error} If payment instructions have different currencies.
8931
+ */
8932
+ validateGroupInstructionsHaveSameCurrency(payments) {
8933
+ if (!payments.every(i => {
8934
+ return i.currency === payments[0].currency;
8935
+ })) {
8936
+ throw new Error('In order to calculate the payment instructions sum, all payment instruction currencies within a group must be the same.');
8937
+ }
8938
+ }
8939
+ /**
8940
+ * Generates payment information for a single SEPA direct debit transfer instruction.
8941
+ * @param {SEPADirectDebitPaymentInstruction} instruction - The payment instruction.
8942
+ * @returns {Object} The payment information object formatted according to SEPA direct debit specifications.
8943
+ */
8944
+ directDebitTransfer(instruction) {
8945
+ const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
8946
+ const dinero = Dinero({
8947
+ amount: instruction.amount,
8948
+ currency: instruction.currency,
8949
+ });
8950
+ return {
8951
+ PmtId: {
8952
+ EndToEndId: endToEndId,
8953
+ },
8954
+ InstdAmt: {
8955
+ '#': dinero.toFormat('0.00'),
8956
+ '@Ccy': instruction.currency,
8957
+ },
8958
+ DrctDbtTx: {
8959
+ MndtRltdInf: {
8960
+ MndtId: instruction.mandate.mandateId,
8961
+ DtOfSgntr: instruction.mandate.dateOfSignature
8962
+ .toISOString()
8963
+ .split('T')[0],
8964
+ AmdmntInd: instruction.mandate.amendmentIndicator,
8965
+ ...(instruction.mandate.amendmentIndicator &&
8966
+ instruction.mandate.amendmentInformation && {
8967
+ AmdmntInfDtls: {
8968
+ ...(instruction.mandate.amendmentInformation
8969
+ .originalMandateId && {
8970
+ OrgnlMndtId: instruction.mandate.amendmentInformation.originalMandateId,
8971
+ }),
8972
+ ...(instruction.mandate.amendmentInformation
8973
+ .originalCreditorSchemeId && {
8974
+ OrgnlCdtrSchmeId: {
8975
+ ...(instruction.mandate.amendmentInformation
8976
+ .originalCreditorSchemeId.name && {
8977
+ Nm: instruction.mandate.amendmentInformation
8978
+ .originalCreditorSchemeId.name,
8979
+ }),
8980
+ ...(instruction.mandate.amendmentInformation
8981
+ .originalCreditorSchemeId.id && {
8982
+ Id: {
8983
+ PrvtId: {
8984
+ Othr: {
8985
+ Id: instruction.mandate.amendmentInformation
8986
+ .originalCreditorSchemeId.id,
8987
+ SchmeNm: { Prtry: 'SEPA' },
8988
+ },
8989
+ },
8990
+ },
8991
+ }),
8992
+ },
8993
+ }),
8994
+ },
8995
+ }),
8996
+ },
8997
+ },
8998
+ DbtrAgt: this.agent(instruction.debtor.agent),
8999
+ Dbtr: this.party(instruction.debtor),
9000
+ DbtrAcct: this.account(instruction.debtor.account),
9001
+ ...(instruction.remittanceInformation && {
9002
+ RmtInf: {
9003
+ Ustrd: instruction.remittanceInformation,
9004
+ },
9005
+ }),
9006
+ };
9007
+ }
9008
+ /**
9009
+ * Serializes the SEPA direct debit initiation to an XML string.
9010
+ * @returns {string} The XML representation of the SEPA direct debit initiation.
9011
+ */
9012
+ serialize() {
9013
+ const builder = PaymentInitiation.getBuilder();
9014
+ // Generate one PmtInf entry per creditor group
9015
+ const paymentInfoEntries = this.paymentInstructions.map((group, groupIndex) => {
9016
+ const pmtInfId = sanitize(`${this.paymentInformationIdBase}-${groupIndex + 1}`, 35);
9017
+ const localInstrument = group.localInstrument || 'CORE';
9018
+ const batchBooking = group.batchBooking !== undefined ? group.batchBooking : false;
9019
+ // Calculate sum for this group
9020
+ let groupSum = 0;
9021
+ for (const payment of group.payments) {
9022
+ groupSum += payment.amount;
9023
+ }
9024
+ const groupCtrlSum = Dinero({
9025
+ amount: groupSum,
9026
+ currency: 'EUR',
9027
+ }).toFormat('0.00');
9028
+ return {
9029
+ PmtInfId: pmtInfId,
9030
+ PmtMtd: 'DD',
9031
+ BtchBookg: batchBooking,
9032
+ NbOfTxs: group.payments.length.toString(),
9033
+ CtrlSum: groupCtrlSum,
9034
+ PmtTpInf: {
9035
+ SvcLvl: { Cd: 'SEPA' },
9036
+ LclInstrm: { Cd: localInstrument },
9037
+ SeqTp: group.sequenceType,
9038
+ ...(group.categoryPurpose && {
9039
+ CtgyPurp: { Cd: group.categoryPurpose },
9040
+ }),
9041
+ },
9042
+ ReqdColltnDt: group.requestedCollectionDate
9043
+ .toISOString()
9044
+ .split('T')[0],
9045
+ Cdtr: this.party(group.creditor),
9046
+ CdtrAcct: this.account(group.creditor.account),
9047
+ CdtrAgt: this.agent(group.creditor.agent),
9048
+ ChrgBr: 'SLEV',
9049
+ CdtrSchmeId: {
9050
+ Id: {
9051
+ PrvtId: {
9052
+ Othr: {
9053
+ Id: group.creditorSchemeId,
9054
+ SchmeNm: { Prtry: 'SEPA' },
9055
+ },
9056
+ },
9057
+ },
9058
+ },
9059
+ DrctDbtTxInf: group.payments.map(payment => this.directDebitTransfer(payment)),
9060
+ };
9061
+ });
9062
+ const xml = {
9063
+ '?xml': {
9064
+ '@version': '1.0',
9065
+ '@encoding': 'UTF-8',
9066
+ },
9067
+ Document: {
9068
+ '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.008.001.02',
9069
+ '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
9070
+ '@xsi:schemaLocation': 'urn:iso:std:iso:20022:tech:xsd:pain.008.001.02 pain.008.001.02.xsd',
9071
+ CstmrDrctDbtInitn: {
9072
+ GrpHdr: {
9073
+ MsgId: this.messageId,
9074
+ CreDtTm: this.creationDate.toISOString(),
9075
+ NbOfTxs: this.totalTransactionCount.toString(),
9076
+ CtrlSum: this.formattedPaymentSum,
9077
+ InitgPty: {
9078
+ Nm: this.initiatingParty.name,
9079
+ ...(this.initiatingParty.id && {
9080
+ Id: {
9081
+ OrgId: {
9082
+ Othr: {
9083
+ Id: this.initiatingParty.id,
9084
+ },
9085
+ },
9086
+ },
9087
+ }),
9088
+ },
9089
+ },
9090
+ PmtInf: paymentInfoEntries,
9091
+ },
9092
+ },
9093
+ };
9094
+ return builder.build(xml);
9095
+ }
9096
+ /**
9097
+ * Parses an XML string and creates a SEPADirectDebitPaymentInitiation instance.
9098
+ * Supports multiple PmtInf blocks in the XML document.
9099
+ * @param {string} rawXml - The XML string to parse.
9100
+ * @returns {SEPADirectDebitPaymentInitiation} A new instance created from the XML data.
9101
+ * @throws {InvalidXmlError} If the XML format is invalid.
9102
+ * @throws {InvalidXmlNamespaceError} If the namespace is not pain.008.
9103
+ */
9104
+ static fromXML(rawXml) {
9105
+ const parser = new fxp.XMLParser({ ignoreAttributes: false });
9106
+ const xml = parser.parse(rawXml);
9107
+ // Validate XML structure
9108
+ if (!xml.Document) {
9109
+ throw new InvalidXmlError('Invalid XML format');
9110
+ }
9111
+ // Validate namespace
9112
+ const namespace = (xml.Document['@_xmlns'] ||
9113
+ xml.Document['@_Xmlns']);
9114
+ if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.008')) {
9115
+ throw new InvalidXmlNamespaceError('Invalid PAIN.008 namespace');
9116
+ }
9117
+ // Extract GrpHdr data
9118
+ const messageId = xml.Document.CstmrDrctDbtInitn.GrpHdr.MsgId;
9119
+ const creationDate = new Date(xml.Document.CstmrDrctDbtInitn.GrpHdr.CreDtTm);
9120
+ // Extract top-level initiating party from GrpHdr
9121
+ const topLevelInitiatingParty = {
9122
+ name: xml.Document.CstmrDrctDbtInitn.GrpHdr.InitgPty.Nm,
9123
+ id: xml.Document.CstmrDrctDbtInitn.GrpHdr.InitgPty.Id?.OrgId?.Othr
9124
+ ?.Id,
9125
+ };
9126
+ // Normalize PmtInf to array (handle both single object and array cases)
9127
+ const rawPmtInf = Array.isArray(xml.Document.CstmrDrctDbtInitn.PmtInf)
9128
+ ? xml.Document.CstmrDrctDbtInitn.PmtInf
9129
+ : [xml.Document.CstmrDrctDbtInitn.PmtInf];
9130
+ // Map each PmtInf to SEPADirectDebitPaymentInstructionGroup
9131
+ const paymentInstructions = rawPmtInf.map((pmtInf) => {
9132
+ // Extract creditor info as the group's collecting party
9133
+ const groupCreditor = {
9134
+ name: pmtInf.Cdtr.Nm,
9135
+ id: pmtInf.Cdtr.Id?.OrgId?.Othr?.Id,
9136
+ agent: parseAgent(pmtInf.CdtrAgt),
9137
+ account: parseAccount(pmtInf.CdtrAcct),
9138
+ };
9139
+ // Extract creditor scheme ID
9140
+ const creditorSchemeId = pmtInf.CdtrSchmeId?.Id?.PrvtId?.Othr?.Id || '';
9141
+ // Extract optional category purpose
9142
+ const categoryPurpose = pmtInf.PmtTpInf?.CtgyPurp?.Cd;
9143
+ // Extract local instrument (CORE or B2B)
9144
+ const localInstrument = pmtInf.PmtTpInf?.LclInstrm?.Cd || 'CORE';
9145
+ // Extract sequence type from PmtInf level
9146
+ const sequenceType = pmtInf.PmtTpInf?.SeqTp || 'RCUR';
9147
+ // Extract requested collection date
9148
+ const requestedCollectionDate = new Date(pmtInf.ReqdColltnDt);
9149
+ // Extract batch booking
9150
+ const batchBooking = pmtInf.BtchBookg === 'true' || pmtInf.BtchBookg === true;
9151
+ // Normalize DrctDbtTxInf to array
9152
+ const rawInstructions = Array.isArray(pmtInf.DrctDbtTxInf)
9153
+ ? pmtInf.DrctDbtTxInf
9154
+ : [pmtInf.DrctDbtTxInf];
9155
+ // Parse each DrctDbtTxInf to SEPADirectDebitPaymentInstruction
9156
+ const payments = rawInstructions.map((inst) => {
9157
+ const currency = inst.InstdAmt['@_Ccy'];
9158
+ const amount = parseAmountToMinorUnits(Number(inst.InstdAmt['#text']), currency);
9159
+ // Parse mandate information
9160
+ const mandateInfo = inst.DrctDbtTx?.MndtRltdInf;
9161
+ const mandate = {
9162
+ mandateId: mandateInfo?.MndtId,
9163
+ dateOfSignature: new Date(mandateInfo?.DtOfSgntr),
9164
+ amendmentIndicator: mandateInfo?.AmdmntInd === 'true' ||
9165
+ mandateInfo?.AmdmntInd === true,
9166
+ ...(mandateInfo?.AmdmntInd &&
9167
+ mandateInfo?.AmdmntInfDtls && {
9168
+ amendmentInformation: {
9169
+ ...(mandateInfo.AmdmntInfDtls.OrgnlMndtId && {
9170
+ originalMandateId: mandateInfo.AmdmntInfDtls
9171
+ .OrgnlMndtId,
9172
+ }),
9173
+ ...(mandateInfo.AmdmntInfDtls.OrgnlCdtrSchmeId && {
9174
+ originalCreditorSchemeId: {
9175
+ ...(mandateInfo.AmdmntInfDtls.OrgnlCdtrSchmeId.Nm && {
9176
+ name: mandateInfo.AmdmntInfDtls.OrgnlCdtrSchmeId
9177
+ .Nm,
9178
+ }),
9179
+ ...(mandateInfo.AmdmntInfDtls.OrgnlCdtrSchmeId.Id?.PrvtId
9180
+ ?.Othr?.Id && {
9181
+ id: mandateInfo.AmdmntInfDtls.OrgnlCdtrSchmeId.Id.PrvtId
9182
+ .Othr.Id,
9183
+ }),
9184
+ },
9185
+ }),
9186
+ },
9187
+ }),
9188
+ };
9189
+ return {
9190
+ ...(inst.PmtId.EndToEndId && {
9191
+ endToEndId: inst.PmtId.EndToEndId.toString(),
9192
+ }),
9193
+ type: 'sepa',
9194
+ direction: 'debit',
9195
+ amount: amount,
9196
+ currency: currency,
9197
+ debtor: {
9198
+ name: inst.Dbtr?.Nm,
9199
+ agent: parseAgent(inst.DbtrAgt),
9200
+ account: parseAccount(inst.DbtrAcct),
9201
+ },
9202
+ mandate: mandate,
9203
+ ...(inst.RmtInf?.Ustrd && {
9204
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
9205
+ }),
9206
+ };
9207
+ });
9208
+ return {
9209
+ creditor: groupCreditor,
9210
+ creditorSchemeId: creditorSchemeId,
9211
+ payments: payments,
9212
+ requestedCollectionDate: requestedCollectionDate,
9213
+ sequenceType: sequenceType,
9214
+ localInstrument: localInstrument,
9215
+ ...(categoryPurpose && { categoryPurpose }),
9216
+ batchBooking: batchBooking,
9217
+ };
9218
+ });
9219
+ // Return new instance
9220
+ return new SEPADirectDebitPaymentInitiation({
9221
+ messageId: messageId,
9222
+ creationDate: creationDate,
9223
+ initiatingParty: topLevelInitiatingParty,
9224
+ paymentInstructions: paymentInstructions,
8650
9225
  });
8651
9226
  }
8652
9227
  }
8653
9228
 
8654
9229
  const ISO20022Messages = {
8655
- CAMT_003: "CAMT.003",
8656
- CAMT_004: "CAMT.004",
8657
- CAMT_005: "CAMT.005",
8658
- CAMT_006: "CAMT.006",
8659
- CAMT_053: "CAMT.053",
8660
- PAIN_001: "PAIN.001",
8661
- PAIN_002: "PAIN.002",
9230
+ CAMT_003: 'CAMT.003',
9231
+ CAMT_004: 'CAMT.004',
9232
+ CAMT_005: 'CAMT.005',
9233
+ CAMT_006: 'CAMT.006',
9234
+ CAMT_053: 'CAMT.053',
9235
+ PAIN_001: 'PAIN.001',
9236
+ PAIN_002: 'PAIN.002',
8662
9237
  };
8663
9238
  const ISO20022Implementations = new Map();
8664
9239
  function registerISO20022Implementation(cl) {
8665
- cl.supportedMessages().forEach((msg) => {
9240
+ cl.supportedMessages().forEach(msg => {
8666
9241
  ISO20022Implementations.set(msg, cl);
8667
9242
  });
8668
9243
  }
@@ -8718,12 +9293,12 @@ class CashManagementGetAccount {
8718
9293
  static fromDocumentOject(doc) {
8719
9294
  const rawHeader = doc.Document?.GetAcct?.MsgHdr;
8720
9295
  if (!rawHeader) {
8721
- throw new InvalidStructureError("Invalid CAMT.003 document: missing MsgHdr");
9296
+ throw new InvalidStructureError('Invalid CAMT.003 document: missing MsgHdr');
8722
9297
  }
8723
9298
  const header = parseMessageHeader(rawHeader);
8724
9299
  const newCrit = doc.Document?.GetAcct?.AcctQryDef?.AcctCrit?.NewCrit;
8725
9300
  if (!newCrit) {
8726
- throw new InvalidStructureError("Invalid CAMT.003 document: missing GetAcct.AcctQryDef.AcctCrit.NewCrit");
9301
+ throw new InvalidStructureError('Invalid CAMT.003 document: missing GetAcct.AcctQryDef.AcctCrit.NewCrit');
8727
9302
  }
8728
9303
  const name = newCrit.NewQryNm;
8729
9304
  let searchCriteria = [];
@@ -8733,16 +9308,19 @@ class CashManagementGetAccount {
8733
9308
  }
8734
9309
  rawCriterias = rawCriterias.filter((c) => !!c);
8735
9310
  if (rawCriterias.length === 0) {
8736
- throw new InvalidStructureError("Invalid CAMT.003 document: missing search criteria");
9311
+ throw new InvalidStructureError('Invalid CAMT.003 document: missing search criteria');
8737
9312
  }
8738
9313
  for (const rawCriterium of rawCriterias) {
8739
9314
  const crit = {};
8740
9315
  // search on Ids, only one criterium supported for now
8741
9316
  if (rawCriterium.AcctId) {
8742
- if (Array.isArray(rawCriterium.AcctId) && rawCriterium.AcctId.length > 1) {
8743
- throw new InvalidStructureError("Invalid CAMT.003 document: multiple AcctId criterium not supported");
9317
+ if (Array.isArray(rawCriterium.AcctId) &&
9318
+ rawCriterium.AcctId.length > 1) {
9319
+ throw new InvalidStructureError('Invalid CAMT.003 document: multiple AcctId criterium not supported');
8744
9320
  }
8745
- const acctId = Array.isArray(rawCriterium.AcctId) ? rawCriterium.AcctId[0] : rawCriterium.AcctId;
9321
+ const acctId = Array.isArray(rawCriterium.AcctId)
9322
+ ? rawCriterium.AcctId[0]
9323
+ : rawCriterium.AcctId;
8746
9324
  if (acctId.CTTxt) {
8747
9325
  crit.accountRegExp = `.*${acctId.CTTxt}.*`; // contains
8748
9326
  }
@@ -8756,19 +9334,23 @@ class CashManagementGetAccount {
8756
9334
  // search on currency
8757
9335
  if (rawCriterium.Ccy) {
8758
9336
  if (Array.isArray(rawCriterium.Ccy) && rawCriterium.Ccy.length > 1) {
8759
- throw new InvalidStructureError("Invalid CAMT.003 document: multiple Ccy criterium not supported");
9337
+ throw new InvalidStructureError('Invalid CAMT.003 document: multiple Ccy criterium not supported');
8760
9338
  }
8761
- const ccy = Array.isArray(rawCriterium.Ccy) ? rawCriterium.Ccy[0] : rawCriterium.Ccy;
9339
+ const ccy = Array.isArray(rawCriterium.Ccy)
9340
+ ? rawCriterium.Ccy[0]
9341
+ : rawCriterium.Ccy;
8762
9342
  crit.currencyEqualTo = ccy;
8763
9343
  }
8764
9344
  // search on balance as of date
8765
9345
  if (rawCriterium.Bal) {
8766
9346
  if (Array.isArray(rawCriterium.Bal) && rawCriterium.Bal.length > 1) {
8767
- throw new InvalidStructureError("Invalid CAMT.003 document: multiple Bal criterium not supported");
9347
+ throw new InvalidStructureError('Invalid CAMT.003 document: multiple Bal criterium not supported');
8768
9348
  }
8769
- const bal = Array.isArray(rawCriterium.Bal) ? rawCriterium.Bal[0] : rawCriterium.Bal;
9349
+ const bal = Array.isArray(rawCriterium.Bal)
9350
+ ? rawCriterium.Bal[0]
9351
+ : rawCriterium.Bal;
8770
9352
  if (bal?.ValDt && Array.isArray(bal.ValDt) && bal.ValDt.length > 1) {
8771
- throw new InvalidStructureError("Invalid CAMT.003 document: multiple ValDt criterium not supported");
9353
+ throw new InvalidStructureError('Invalid CAMT.003 document: multiple ValDt criterium not supported');
8772
9354
  }
8773
9355
  const valDt = Array.isArray(bal?.ValDt) ? bal.ValDt[0] : bal?.ValDt;
8774
9356
  if (valDt?.Dt?.EQDt) {
@@ -8789,9 +9371,10 @@ class CashManagementGetAccount {
8789
9371
  const parser = XML.getParser();
8790
9372
  const doc = parser.parse(xml);
8791
9373
  if (!doc.Document) {
8792
- throw new Error("Invalid XML format");
9374
+ throw new Error('Invalid XML format');
8793
9375
  }
8794
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
9376
+ const namespace = (doc.Document['@_xmlns'] ||
9377
+ doc.Document['@_Xmlns']);
8795
9378
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.003.001.')) {
8796
9379
  throw new InvalidXmlNamespaceError('Invalid CAMT.003 namespace');
8797
9380
  }
@@ -8800,7 +9383,7 @@ class CashManagementGetAccount {
8800
9383
  static fromJSON(json) {
8801
9384
  const obj = JSON.parse(json);
8802
9385
  if (!obj.Document) {
8803
- throw new Error("Invalid JSON format");
9386
+ throw new Error('Invalid JSON format');
8804
9387
  }
8805
9388
  return CashManagementGetAccount.fromDocumentOject(obj);
8806
9389
  }
@@ -8820,39 +9403,55 @@ class CashManagementGetAccount {
8820
9403
  AcctCrit: {
8821
9404
  NewCrit: {
8822
9405
  NewQryNm: this._data.newCriteria?.name,
8823
- SchCrit: this._data.newCriteria?.searchCriteria.map((c) => {
9406
+ SchCrit: this._data.newCriteria?.searchCriteria.map(c => {
8824
9407
  const obj = {};
8825
9408
  if (c.accountRegExp) {
8826
- if (c.accountRegExp.startsWith('.*') && c.accountRegExp.endsWith('.*')) {
8827
- obj.AcctId = { CTTxt: c.accountRegExp.replace(/^\.\*/, '').replace(/\.\*$/, '') }; // contains
9409
+ if (c.accountRegExp.startsWith('.*') &&
9410
+ c.accountRegExp.endsWith('.*')) {
9411
+ obj.AcctId = {
9412
+ CTTxt: c.accountRegExp
9413
+ .replace(/^\.\*/, '')
9414
+ .replace(/\.\*$/, ''),
9415
+ }; // contains
8828
9416
  }
8829
- else if (c.accountRegExp.startsWith('^((?!') && c.accountRegExp.endsWith(').)*$')) {
8830
- obj.AcctId = { NCTTxt: c.accountRegExp.replace(/^\^\(\(\!\(/, '').replace(/\)\.\)\*\$$/, '') }; // does not contain
9417
+ else if (c.accountRegExp.startsWith('^((?!') &&
9418
+ c.accountRegExp.endsWith(').)*$')) {
9419
+ obj.AcctId = {
9420
+ NCTTxt: c.accountRegExp
9421
+ .replace(/^\^\(\(\!\(/, '')
9422
+ .replace(/\)\.\)\*\$$/, ''),
9423
+ }; // does not contain
8831
9424
  }
8832
9425
  }
8833
9426
  else if (c.accountEqualTo) {
8834
9427
  obj.AcctId = {
8835
- EQ: exportAccountIdentification(c.accountEqualTo)
9428
+ EQ: exportAccountIdentification(c.accountEqualTo),
8836
9429
  };
8837
9430
  }
8838
9431
  if (c.currencyEqualTo) {
8839
9432
  obj.Ccy = [c.currencyEqualTo];
8840
9433
  }
8841
9434
  if (c.balanceAsOfDateEqualTo) {
8842
- obj.Bal = [{
8843
- ValDt: [{
9435
+ obj.Bal = [
9436
+ {
9437
+ ValDt: [
9438
+ {
8844
9439
  Dt: {
8845
- EQDt: c.balanceAsOfDateEqualTo.toISOString().slice(0, 10)
8846
- }
8847
- }]
8848
- }];
9440
+ EQDt: c.balanceAsOfDateEqualTo
9441
+ .toISOString()
9442
+ .slice(0, 10),
9443
+ },
9444
+ },
9445
+ ],
9446
+ },
9447
+ ];
8849
9448
  }
8850
9449
  return obj;
8851
9450
  }),
8852
- }
8853
- }
8854
- }
8855
- }
9451
+ },
9452
+ },
9453
+ },
9454
+ },
8856
9455
  };
8857
9456
  return { Document };
8858
9457
  }
@@ -8952,10 +9551,10 @@ const exportStatement = (stmt) => {
8952
9551
  },
8953
9552
  Acct: {
8954
9553
  ...exportAccount(stmt.account),
8955
- Svcr: exportAgent(stmt.agent)
9554
+ Svcr: exportAgent(stmt.agent),
8956
9555
  },
8957
- Bal: stmt.balances.map((bal) => exportBalance(bal)),
8958
- Ntry: stmt.entries.map((entry) => exportEntry(entry)),
9556
+ Bal: stmt.balances.map(bal => exportBalance(bal)),
9557
+ Ntry: stmt.entries.map(entry => exportEntry(entry)),
8959
9558
  };
8960
9559
  return obj;
8961
9560
  };
@@ -9079,7 +9678,9 @@ const exportEntry = (entry) => {
9079
9678
  BkTxCd: exportBankTransactionCode(entry.bankTransactionCode, entry.proprietaryCode),
9080
9679
  AddtlNtryInf: entry.additionalInformation,
9081
9680
  AcctSvcrRef: entry.accountServicerReferenceId,
9082
- NtryDtls: entry.transactions.map((tx) => ({ TxDtls: exportTransactionDetails(tx) }))
9681
+ NtryDtls: entry.transactions.map(tx => ({
9682
+ TxDtls: exportTransactionDetails(tx),
9683
+ })),
9083
9684
  };
9084
9685
  return obj;
9085
9686
  };
@@ -9172,7 +9773,9 @@ const exportTransactionDetails = (tx) => {
9172
9773
  Dbtr: {
9173
9774
  Nm: tx.debtor.name,
9174
9775
  },
9175
- DbtrAcct: tx.debtor.account ? exportAccount(tx.debtor.account) : undefined,
9776
+ DbtrAcct: tx.debtor.account
9777
+ ? exportAccount(tx.debtor.account)
9778
+ : undefined,
9176
9779
  };
9177
9780
  obj.RltdAgts = {
9178
9781
  DbtrAgt: tx.debtor.agent ? exportAgent(tx.debtor.agent) : undefined,
@@ -9184,7 +9787,9 @@ const exportTransactionDetails = (tx) => {
9184
9787
  Cdtr: {
9185
9788
  Nm: tx.creditor.name,
9186
9789
  },
9187
- CdtrAcct: tx.creditor.account ? exportAccount(tx.creditor.account) : undefined,
9790
+ CdtrAcct: tx.creditor.account
9791
+ ? exportAccount(tx.creditor.account)
9792
+ : undefined,
9188
9793
  };
9189
9794
  obj.RltdAgts = {
9190
9795
  CdtrAgt: tx.creditor.agent ? exportAgent(tx.creditor.agent) : undefined,
@@ -9229,7 +9834,7 @@ const exportBankTransactionCode = (bankTransactionCode, proprietaryCode) => {
9229
9834
  return obj;
9230
9835
  };
9231
9836
  const parseBusinessError = (bizErr) => {
9232
- const code = bizErr.Err?.Cd || bizErr.Err?.Prtry || "UKNW";
9837
+ const code = bizErr.Err?.Cd || bizErr.Err?.Prtry || 'UKNW';
9233
9838
  const description = bizErr.Desc;
9234
9839
  return {
9235
9840
  code,
@@ -9260,7 +9865,7 @@ class CashManagementReturnAccount {
9260
9865
  static fromDocumentOject(doc) {
9261
9866
  const rawHeader = doc.Document?.RtrAcct?.MsgHdr;
9262
9867
  if (!rawHeader) {
9263
- throw new InvalidStructureError("Invalid CAMT.004 document: missing MsgHdr");
9868
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing MsgHdr');
9264
9869
  }
9265
9870
  const header = parseMessageHeader(rawHeader);
9266
9871
  // interpret the report
@@ -9275,7 +9880,7 @@ class CashManagementReturnAccount {
9275
9880
  if (r.AcctOrErr?.Acct) {
9276
9881
  // report
9277
9882
  if (!r.AcctOrErr.Acct.Ccy) {
9278
- throw new InvalidStructureError("Invalid CAMT.004 document: missing Ccy in Acct");
9883
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing Ccy in Acct');
9279
9884
  }
9280
9885
  let rawMulBal = r.AcctOrErr.Acct.MulBal;
9281
9886
  if (!Array.isArray(rawMulBal))
@@ -9288,7 +9893,7 @@ class CashManagementReturnAccount {
9288
9893
  balances: rawMulBal.map((bal) => parseBalanceReport(r.AcctOrErr.Acct.Ccy, bal)),
9289
9894
  };
9290
9895
  if (report.balances.length === 0) {
9291
- throw new InvalidStructureError("Invalid CAMT.004 document: missing MulBal in Acct");
9896
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing MulBal in Acct');
9292
9897
  }
9293
9898
  }
9294
9899
  else if (r.AcctOrErr?.BizErr) {
@@ -9296,7 +9901,7 @@ class CashManagementReturnAccount {
9296
9901
  error = parseBusinessError(r.AcctOrErr.BizErr);
9297
9902
  }
9298
9903
  else {
9299
- throw new InvalidStructureError("Invalid CAMT.004 document: missing AcctOrErr");
9904
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing AcctOrErr');
9300
9905
  }
9301
9906
  return { accountId, report, error };
9302
9907
  });
@@ -9309,9 +9914,10 @@ class CashManagementReturnAccount {
9309
9914
  const parser = XML.getParser();
9310
9915
  const doc = parser.parse(xml);
9311
9916
  if (!doc.Document) {
9312
- throw new Error("Invalid XML format");
9917
+ throw new Error('Invalid XML format');
9313
9918
  }
9314
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
9919
+ const namespace = (doc.Document['@_xmlns'] ||
9920
+ doc.Document['@_Xmlns']);
9315
9921
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.004.001.')) {
9316
9922
  throw new InvalidXmlNamespaceError('Invalid CAMT.004 namespace');
9317
9923
  }
@@ -9320,7 +9926,7 @@ class CashManagementReturnAccount {
9320
9926
  static fromJSON(json) {
9321
9927
  const obj = JSON.parse(json);
9322
9928
  if (!obj.Document) {
9323
- throw new Error("Invalid JSON format");
9929
+ throw new Error('Invalid JSON format');
9324
9930
  }
9325
9931
  return CashManagementReturnAccount.fromDocumentOject(obj);
9326
9932
  }
@@ -9337,7 +9943,7 @@ class CashManagementReturnAccount {
9337
9943
  RtrAcct: {
9338
9944
  MsgHdr: exportMessageHeader(this._data.header),
9339
9945
  RptOrErr: {
9340
- AcctRpt: this._data.reports.map((report) => {
9946
+ AcctRpt: this._data.reports.map(report => {
9341
9947
  const obj = {
9342
9948
  AcctId: exportAccountIdentification(report.accountId),
9343
9949
  AcctOrErr: {}, // filled below
@@ -9347,16 +9953,16 @@ class CashManagementReturnAccount {
9347
9953
  Ccy: report.report.currency,
9348
9954
  Nm: report.report.name,
9349
9955
  Tp: { Cd: report.report.type }, // TODO add Prtry handling
9350
- MulBal: report.report.balances.map((bal) => exportBalanceReport(report.report.currency, bal)),
9956
+ MulBal: report.report.balances.map(bal => exportBalanceReport(report.report.currency, bal)),
9351
9957
  };
9352
9958
  }
9353
9959
  else if (report.error) {
9354
9960
  obj.AcctOrErr.BizErr = exportBusinessError(report.error);
9355
9961
  }
9356
9962
  return obj;
9357
- })
9358
- }
9359
- }
9963
+ }),
9964
+ },
9965
+ },
9360
9966
  };
9361
9967
  return { Document };
9362
9968
  }
@@ -9377,12 +9983,12 @@ class CashManagementGetTransaction {
9377
9983
  static fromDocumentOject(doc) {
9378
9984
  const rawHeader = doc.Document?.GetTx?.MsgHdr;
9379
9985
  if (!rawHeader) {
9380
- throw new InvalidStructureError("Invalid CAMT.005 document: missing MsgHdr");
9986
+ throw new InvalidStructureError('Invalid CAMT.005 document: missing MsgHdr');
9381
9987
  }
9382
9988
  const header = parseMessageHeader(rawHeader);
9383
9989
  const newCrit = doc.Document?.GetTx?.TxQryDef?.TxCrit?.NewCrit;
9384
9990
  if (!newCrit) {
9385
- throw new InvalidStructureError("Invalid CAMT.005 document: missing GetTx.TxQryDef.TxCrit.NewCrit");
9991
+ throw new InvalidStructureError('Invalid CAMT.005 document: missing GetTx.TxQryDef.TxCrit.NewCrit');
9386
9992
  }
9387
9993
  const name = newCrit.NewQryNm;
9388
9994
  let searchCriteria = [];
@@ -9392,35 +9998,42 @@ class CashManagementGetTransaction {
9392
9998
  }
9393
9999
  rawCriterias = rawCriterias.filter((c) => !!c);
9394
10000
  if (rawCriterias.length === 0) {
9395
- throw new InvalidStructureError("Invalid CAMT.005 document: missing search criteria");
10001
+ throw new InvalidStructureError('Invalid CAMT.005 document: missing search criteria');
9396
10002
  }
9397
10003
  for (const rawCriterium of rawCriterias) {
9398
10004
  // search on Ids
9399
10005
  if (rawCriterium.PmtSch.MsgId) {
9400
10006
  searchCriteria.push({
9401
- type: "PmtSch.MsgId",
9402
- msgIdsEqualTo: Array.isArray(rawCriterium.PmtSch.MsgId) ? rawCriterium.PmtSch.MsgId : [rawCriterium.PmtSch.MsgId],
10007
+ type: 'PmtSch.MsgId',
10008
+ msgIdsEqualTo: Array.isArray(rawCriterium.PmtSch.MsgId)
10009
+ ? rawCriterium.PmtSch.MsgId
10010
+ : [rawCriterium.PmtSch.MsgId],
9403
10011
  });
9404
10012
  }
9405
10013
  // seach on date
9406
10014
  if (rawCriterium.PmtSch.ReqdExctnDt) {
9407
- if (Array.isArray(rawCriterium.PmtSch.ReqdExctnDt) && rawCriterium.PmtSch.ReqdExctnDt.length > 1) {
9408
- throw new InvalidStructureError("Invalid CAMT.005 document: multiple ReqdExctnDt criterium not supported");
10015
+ if (Array.isArray(rawCriterium.PmtSch.ReqdExctnDt) &&
10016
+ rawCriterium.PmtSch.ReqdExctnDt.length > 1) {
10017
+ throw new InvalidStructureError('Invalid CAMT.005 document: multiple ReqdExctnDt criterium not supported');
9409
10018
  }
9410
- const criterium = Array.isArray(rawCriterium.PmtSch.ReqdExctnDt) ? rawCriterium.PmtSch.ReqdExctnDt[0] : rawCriterium.PmtSch.ReqdExctnDt;
10019
+ const criterium = Array.isArray(rawCriterium.PmtSch.ReqdExctnDt)
10020
+ ? rawCriterium.PmtSch.ReqdExctnDt[0]
10021
+ : rawCriterium.PmtSch.ReqdExctnDt;
9411
10022
  if (criterium?.DtSch?.EQDt) {
9412
10023
  searchCriteria.push({
9413
- type: "PmtSch.ReqdExctnDt",
10024
+ type: 'PmtSch.ReqdExctnDt',
9414
10025
  dateEqualTo: parseDate(criterium.DtSch.EQDt),
9415
10026
  });
9416
10027
  }
9417
10028
  }
9418
- let pmtIds = Array.isArray(rawCriterium.PmtSch.PmtId) ? rawCriterium.PmtSch.PmtId : [rawCriterium.PmtSch.PmtId];
9419
- pmtIds = pmtIds.filter((p) => !!p && p.LngBizId?.EndToEndId);
10029
+ let pmtIds = Array.isArray(rawCriterium.PmtSch.PmtId)
10030
+ ? rawCriterium.PmtSch.PmtId
10031
+ : [rawCriterium.PmtSch.PmtId];
10032
+ pmtIds = pmtIds.filter(p => !!p && p.LngBizId?.EndToEndId);
9420
10033
  if (pmtIds.length > 0) {
9421
10034
  searchCriteria.push({
9422
- type: "PmtSch.PmtId.LngBizId.EndToEndId",
9423
- endToEndIdEqualTo: pmtIds.map((id) => id.LngBizId.EndToEndId),
10035
+ type: 'PmtSch.PmtId.LngBizId.EndToEndId',
10036
+ endToEndIdEqualTo: pmtIds.map(id => id.LngBizId.EndToEndId),
9424
10037
  });
9425
10038
  }
9426
10039
  }
@@ -9436,9 +10049,10 @@ class CashManagementGetTransaction {
9436
10049
  const parser = XML.getParser();
9437
10050
  const doc = parser.parse(xml);
9438
10051
  if (!doc.Document) {
9439
- throw new Error("Invalid XML format");
10052
+ throw new Error('Invalid XML format');
9440
10053
  }
9441
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
10054
+ const namespace = (doc.Document['@_xmlns'] ||
10055
+ doc.Document['@_Xmlns']);
9442
10056
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.005.001.')) {
9443
10057
  throw new InvalidXmlNamespaceError('Invalid CAMT.005 namespace');
9444
10058
  }
@@ -9447,7 +10061,7 @@ class CashManagementGetTransaction {
9447
10061
  static fromJSON(json) {
9448
10062
  const obj = JSON.parse(json);
9449
10063
  if (!obj.Document) {
9450
- throw new Error("Invalid JSON format");
10064
+ throw new Error('Invalid JSON format');
9451
10065
  }
9452
10066
  return CashManagementGetTransaction.fromDocumentOject(obj);
9453
10067
  }
@@ -9467,37 +10081,38 @@ class CashManagementGetTransaction {
9467
10081
  TxCrit: {
9468
10082
  NewCrit: {
9469
10083
  NewQryNm: this._data.newCriteria?.name,
9470
- SchCrit: this._data.newCriteria?.searchCriteria.map((c) => {
10084
+ SchCrit: this._data.newCriteria?.searchCriteria.map(c => {
9471
10085
  const obj = {};
9472
- if (c.type === "PmtSch.MsgId" && c.msgIdsEqualTo) {
10086
+ if (c.type === 'PmtSch.MsgId' && c.msgIdsEqualTo) {
9473
10087
  obj.PmtSch = {
9474
- MsgId: c.msgIdsEqualTo
10088
+ MsgId: c.msgIdsEqualTo,
9475
10089
  };
9476
10090
  }
9477
- if (c.type === "PmtSch.ReqdExctnDt" && c.dateEqualTo) {
10091
+ if (c.type === 'PmtSch.ReqdExctnDt' && c.dateEqualTo) {
9478
10092
  obj.PmtSch = {
9479
10093
  ReqdExctnDt: {
9480
10094
  DtSch: {
9481
10095
  EQDt: c.dateEqualTo.toISOString().slice(0, 10),
9482
- }
9483
- }
10096
+ },
10097
+ },
9484
10098
  };
9485
10099
  }
9486
- if (c.type === "PmtSch.PmtId.LngBizId.EndToEndId" && c.endToEndIdEqualTo) {
10100
+ if (c.type === 'PmtSch.PmtId.LngBizId.EndToEndId' &&
10101
+ c.endToEndIdEqualTo) {
9487
10102
  obj.PmtSch = {
9488
- PmtId: c.endToEndIdEqualTo.map((id) => ({
10103
+ PmtId: c.endToEndIdEqualTo.map(id => ({
9489
10104
  LngBizId: {
9490
10105
  EndToEndId: id,
9491
- }
9492
- }))
10106
+ },
10107
+ })),
9493
10108
  };
9494
10109
  }
9495
10110
  return obj;
9496
10111
  }),
9497
- }
9498
- }
9499
- }
9500
- }
10112
+ },
10113
+ },
10114
+ },
10115
+ },
9501
10116
  };
9502
10117
  return { Document };
9503
10118
  }
@@ -9518,7 +10133,7 @@ class CashManagementReturnTransaction {
9518
10133
  static fromDocumentOject(doc) {
9519
10134
  const rawHeader = doc.Document?.RtrTx?.MsgHdr;
9520
10135
  if (!rawHeader) {
9521
- throw new InvalidStructureError("Invalid CAMT.006 document: missing MsgHdr");
10136
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing MsgHdr');
9522
10137
  }
9523
10138
  const header = parseMessageHeader(rawHeader);
9524
10139
  // interpret the report
@@ -9527,7 +10142,8 @@ class CashManagementReturnTransaction {
9527
10142
  rawReports = [rawReports];
9528
10143
  rawReports = rawReports.filter((r) => !!r); // remove null/undefined
9529
10144
  const reports = rawReports.map((r) => {
9530
- const rawAmount = r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Amt || r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Amount; // some implementations use Amount instead of Amt
10145
+ const rawAmount = r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Amt ||
10146
+ r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Amount; // some implementations use Amount instead of Amt
9531
10147
  const paymentId = {
9532
10148
  currency: r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Ccy,
9533
10149
  amount: parseAmountToMinorUnits(rawAmount, r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Ccy),
@@ -9537,20 +10153,24 @@ class CashManagementReturnTransaction {
9537
10153
  };
9538
10154
  // check required fields
9539
10155
  if (!paymentId.currency) {
9540
- throw new InvalidStructureError("Invalid CAMT.006 document: missing Ccy in PmtId.LngBizId.IntrBkSttlmAmt");
10156
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing Ccy in PmtId.LngBizId.IntrBkSttlmAmt');
9541
10157
  }
9542
- if (paymentId.amount === undefined || paymentId.amount === null || isNaN(paymentId.amount)) {
9543
- throw new InvalidStructureError("Invalid CAMT.006 document: missing or invalid Amt in PmtId.LngBizId.IntrBkSttlmAmt");
10158
+ if (paymentId.amount === undefined ||
10159
+ paymentId.amount === null ||
10160
+ isNaN(paymentId.amount)) {
10161
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing or invalid Amt in PmtId.LngBizId.IntrBkSttlmAmt');
9544
10162
  }
9545
10163
  if (!paymentId.endToEndId) {
9546
- throw new InvalidStructureError("Invalid CAMT.006 document: missing EndToEndId in PmtId.LngBizId");
10164
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing EndToEndId in PmtId.LngBizId');
9547
10165
  }
9548
10166
  let report = undefined;
9549
10167
  let error = undefined;
9550
10168
  if (r.TxOrErr?.Tx) {
9551
10169
  // report
9552
10170
  const msgId = r.TxOrErr.Tx.Pmt?.MsgId;
9553
- const reqExecutionDate = r.TxOrErr.Tx.Pmt?.ReqdExctnDt?.Dt ? parseDate(r.TxOrErr.Tx.Pmt.ReqdExctnDt) : undefined;
10171
+ const reqExecutionDate = r.TxOrErr.Tx.Pmt?.ReqdExctnDt?.Dt
10172
+ ? parseDate(r.TxOrErr.Tx.Pmt.ReqdExctnDt)
10173
+ : undefined;
9554
10174
  const status = ((sts) => {
9555
10175
  if (!sts)
9556
10176
  return undefined;
@@ -9558,9 +10178,13 @@ class CashManagementReturnTransaction {
9558
10178
  return undefined;
9559
10179
  if (Array.isArray(sts))
9560
10180
  sts = sts[0]; // take the first one only
9561
- let code = sts.Cd?.Pdg || sts.Cd?.Fnl || sts.Cd?.RTGS || sts.Cd?.Sttlm || sts.Cd?.Prtly;
10181
+ let code = sts.Cd?.Pdg ||
10182
+ sts.Cd?.Fnl ||
10183
+ sts.Cd?.RTGS ||
10184
+ sts.Cd?.Sttlm ||
10185
+ sts.Cd?.Prtly;
9562
10186
  if (code)
9563
- code = Object.keys(sts.Cd)[0] + ":" + code; // prefix with the type of code
10187
+ code = Object.keys(sts.Cd)[0] + ':' + code; // prefix with the type of code
9564
10188
  else
9565
10189
  return undefined;
9566
10190
  const reason = sts.Rsn?.Prtry;
@@ -9575,7 +10199,7 @@ class CashManagementReturnTransaction {
9575
10199
  }
9576
10200
  function parseAgent(agent) {
9577
10201
  if (!agent)
9578
- return { bic: "" };
10202
+ return { bic: '' };
9579
10203
  return { bic: agent?.FinInstnId?.BICFI };
9580
10204
  }
9581
10205
  report = {
@@ -9589,10 +10213,10 @@ class CashManagementReturnTransaction {
9589
10213
  };
9590
10214
  // check the debtor and creditor required fields
9591
10215
  if (!report.debtor.id) {
9592
- throw new InvalidStructureError("Invalid CAMT.006 document: missing Id in TxOrErr.Tx.Dbtr.Pty");
10216
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing Id in TxOrErr.Tx.Dbtr.Pty');
9593
10217
  }
9594
10218
  if (!report.creditor.id) {
9595
- throw new InvalidStructureError("Invalid CAMT.006 document: missing Id in TxOrErr.Tx.Cdtr.Pty");
10219
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing Id in TxOrErr.Tx.Cdtr.Pty');
9596
10220
  }
9597
10221
  }
9598
10222
  else if (r.TxOrErr?.BizErr) {
@@ -9600,7 +10224,7 @@ class CashManagementReturnTransaction {
9600
10224
  error = parseBusinessError(r.TxOrErr.BizErr);
9601
10225
  }
9602
10226
  else {
9603
- throw new InvalidStructureError("Invalid CAMT.006 document: missing TxOrErr");
10227
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing TxOrErr');
9604
10228
  }
9605
10229
  return { paymentId, report, error };
9606
10230
  });
@@ -9613,9 +10237,10 @@ class CashManagementReturnTransaction {
9613
10237
  const parser = XML.getParser();
9614
10238
  const doc = parser.parse(xml);
9615
10239
  if (!doc.Document) {
9616
- throw new Error("Invalid XML format");
10240
+ throw new Error('Invalid XML format');
9617
10241
  }
9618
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
10242
+ const namespace = (doc.Document['@_xmlns'] ||
10243
+ doc.Document['@_Xmlns']);
9619
10244
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.004.001.')) {
9620
10245
  throw new InvalidXmlNamespaceError('Invalid CAMT.004 namespace');
9621
10246
  }
@@ -9624,7 +10249,7 @@ class CashManagementReturnTransaction {
9624
10249
  static fromJSON(json) {
9625
10250
  const obj = JSON.parse(json);
9626
10251
  if (!obj.Document) {
9627
- throw new Error("Invalid JSON format");
10252
+ throw new Error('Invalid JSON format');
9628
10253
  }
9629
10254
  return CashManagementReturnTransaction.fromDocumentOject(obj);
9630
10255
  }
@@ -9642,7 +10267,7 @@ class CashManagementReturnTransaction {
9642
10267
  MsgHdr: exportMessageHeader(this._data.header),
9643
10268
  RptOrErr: {
9644
10269
  BizRpt: {
9645
- TxRpt: this._data.reports.map((report) => {
10270
+ TxRpt: this._data.reports.map(report => {
9646
10271
  const obj = {
9647
10272
  PmtId: {
9648
10273
  LngBizId: {
@@ -9654,7 +10279,7 @@ class CashManagementReturnTransaction {
9654
10279
  UETR: report.paymentId.uetr,
9655
10280
  TxId: report.paymentId.transactionId,
9656
10281
  EndToEndId: report.paymentId.endToEndId,
9657
- }
10282
+ },
9658
10283
  },
9659
10284
  TxOrErr: {}, // filled below
9660
10285
  };
@@ -9673,38 +10298,46 @@ class CashManagementReturnTransaction {
9673
10298
  function exportAgent(a) {
9674
10299
  if (!a)
9675
10300
  return undefined;
9676
- if ("bic" in a && a.bic)
10301
+ if ('bic' in a && a.bic)
9677
10302
  return { FinInstnId: { BICFI: a.bic } };
9678
- if ("abaRoutingNumber" in a && a.abaRoutingNumber)
10303
+ if ('abaRoutingNumber' in a && a.abaRoutingNumber)
9679
10304
  return { FinInstId: { Othr: { Id: a.abaRoutingNumber } } };
9680
10305
  return undefined;
9681
10306
  }
9682
- const [codeType, code] = report.report.status ? report.report.status.code.split(":") : [undefined, undefined];
10307
+ const [codeType, code] = report.report.status
10308
+ ? report.report.status.code.split(':')
10309
+ : [undefined, undefined];
9683
10310
  obj.TxOrErr.Tx = {
9684
10311
  Pmt: {
9685
10312
  MsgId: report.report.msgId,
9686
- ReqdExctnDt: { Dt: report.report.reqExecutionDate?.toISOString()?.slice(0, 10) },
10313
+ ReqdExctnDt: {
10314
+ Dt: report.report.reqExecutionDate
10315
+ ?.toISOString()
10316
+ ?.slice(0, 10),
10317
+ },
9687
10318
  Sts: {
9688
10319
  Cd: codeType ? { [codeType]: code } : undefined,
9689
- Rsn: report.report.status?.reason ? { Prtry: report.report.status.reason } : undefined,
10320
+ Rsn: report.report.status?.reason
10321
+ ? { Prtry: report.report.status.reason }
10322
+ : undefined,
9690
10323
  },
9691
10324
  Pties: {
9692
10325
  Dbtr: exportParty(report.report.debtor),
9693
10326
  DbtrAgt: exportAgent(report.report.debtorAgent),
9694
10327
  Cdtr: exportParty(report.report.creditor),
9695
10328
  CdtrAgt: exportAgent(report.report.creditorAgent),
9696
- }
9697
- }
10329
+ },
10330
+ },
9698
10331
  };
9699
10332
  }
9700
10333
  else if (report.error) {
9701
10334
  obj.TxOrErr.BizErr = exportBusinessError(report.error);
9702
10335
  }
9703
10336
  return obj;
9704
- })
9705
- }
9706
- }
9707
- }
10337
+ }),
10338
+ },
10339
+ },
10340
+ },
9708
10341
  };
9709
10342
  return { Document };
9710
10343
  }
@@ -9744,17 +10377,17 @@ const BalanceTypeCode = {
9744
10377
  * Description mapping of BalanceTypeCode values to their names.
9745
10378
  */
9746
10379
  const BalanceTypeCodeDescriptionMap = {
9747
- 'CLAV': 'Closing Available',
9748
- 'CLBD': 'Closing Booked',
9749
- 'FWAV': 'Forward Available',
9750
- 'INFO': 'Information',
9751
- 'ITAV': 'Interim Available',
9752
- 'ITBD': 'Interim Booked',
9753
- 'OPAV': 'Opening Available',
9754
- 'OPBD': 'Opening Booked',
9755
- 'PRCD': 'Previously Closed Booked',
9756
- 'XPCD': 'Expected',
9757
- 'ABRR': 'Additional Balance Reserve Requirement'
10380
+ CLAV: 'Closing Available',
10381
+ CLBD: 'Closing Booked',
10382
+ FWAV: 'Forward Available',
10383
+ INFO: 'Information',
10384
+ ITAV: 'Interim Available',
10385
+ ITBD: 'Interim Booked',
10386
+ OPAV: 'Opening Available',
10387
+ OPBD: 'Opening Booked',
10388
+ PRCD: 'Previously Closed Booked',
10389
+ XPCD: 'Expected',
10390
+ ABRR: 'Additional Balance Reserve Requirement',
9758
10391
  };
9759
10392
 
9760
10393
  /**
@@ -9977,6 +10610,64 @@ class ISO20022 {
9977
10610
  creationDate: config.creationDate,
9978
10611
  });
9979
10612
  }
10613
+ /**
10614
+ * Creates a SEPA Direct Debit Payment Initiation message.
10615
+ * @param {SEPADirectDebitPaymentInitiationConfig} config - Configuration containing payment instruction groups and optional parameters.
10616
+ * @example
10617
+ * const payment = iso20022.createSEPADirectDebitPaymentInitiation({
10618
+ * paymentInstructions: [
10619
+ * {
10620
+ * creditor: {
10621
+ * name: 'Landlord Company Ltd',
10622
+ * account: {
10623
+ * iban: 'DE54120300001030860744',
10624
+ * },
10625
+ * agent: {
10626
+ * bic: 'BYLADEM1001',
10627
+ * },
10628
+ * },
10629
+ * creditorSchemeId: 'DE96ZZZ00000345986',
10630
+ * requestedCollectionDate: new Date('2025-11-22'),
10631
+ * sequenceType: 'RCUR',
10632
+ * payments: [
10633
+ * {
10634
+ * type: 'sepa',
10635
+ * direction: 'debit',
10636
+ * amount: 31700, // €317.00 Euros
10637
+ * currency: 'EUR',
10638
+ * debtor: {
10639
+ * name: 'John Doe',
10640
+ * account: {
10641
+ * iban: 'DE20120300001088243355',
10642
+ * },
10643
+ * agent: {
10644
+ * bic: 'BYLADEM1001',
10645
+ * },
10646
+ * },
10647
+ * mandate: {
10648
+ * mandateId: 'MR-12345-001',
10649
+ * dateOfSignature: new Date('2024-01-15'),
10650
+ * amendmentIndicator: false,
10651
+ * },
10652
+ * remittanceInformation: 'Rent payment November 2024',
10653
+ * },
10654
+ * ],
10655
+ * localInstrument: 'CORE', // Optional
10656
+ * },
10657
+ * ],
10658
+ * messageId: 'DD-MSG-001', // Optional
10659
+ * creationDate: new Date('2025-03-01'), // Optional
10660
+ * });
10661
+ * @returns {SEPADirectDebitPaymentInitiation} A new SEPA Direct Debit Payment Initiation object.
10662
+ */
10663
+ createSEPADirectDebitPaymentInitiation(config) {
10664
+ return new SEPADirectDebitPaymentInitiation({
10665
+ initiatingParty: this.initiatingParty,
10666
+ paymentInstructions: config.paymentInstructions,
10667
+ messageId: config.messageId,
10668
+ creationDate: config.creationDate,
10669
+ });
10670
+ }
9980
10671
  /** Create a message CAMT or other */
9981
10672
  createMessage(type, config) {
9982
10673
  const implementation = getISO20022Implementation(type);
@@ -10265,9 +10956,10 @@ class CashManagementEndOfDayReport {
10265
10956
  const parser = XML.getParser();
10266
10957
  const xml = parser.parse(rawXml);
10267
10958
  if (!xml.Document) {
10268
- throw new InvalidXmlError("Invalid XML format");
10959
+ throw new InvalidXmlError('Invalid XML format');
10269
10960
  }
10270
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
10961
+ const namespace = (xml.Document['@_xmlns'] ||
10962
+ xml.Document['@_Xmlns']);
10271
10963
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.053.001.')) {
10272
10964
  throw new InvalidXmlNamespaceError('Invalid CAMT.053 namespace');
10273
10965
  }
@@ -10282,7 +10974,7 @@ class CashManagementEndOfDayReport {
10282
10974
  static fromJSON(json) {
10283
10975
  const obj = JSON.parse(json);
10284
10976
  if (!obj.Document) {
10285
- throw new InvalidXmlError("Invalid JSON format");
10977
+ throw new InvalidXmlError('Invalid JSON format');
10286
10978
  }
10287
10979
  return CashManagementEndOfDayReport.fromDocumentObject(obj);
10288
10980
  }
@@ -10292,10 +10984,12 @@ class CashManagementEndOfDayReport {
10292
10984
  GrpHdr: {
10293
10985
  MsgId: this._messageId,
10294
10986
  CreDtTm: this._creationDate.toISOString(),
10295
- MsgRcpt: this._recipient ? exportRecipient(this._recipient) : undefined,
10987
+ MsgRcpt: this._recipient
10988
+ ? exportRecipient(this._recipient)
10989
+ : undefined,
10296
10990
  },
10297
- Stmt: this._statements.map((stmt) => exportStatement(stmt)),
10298
- }
10991
+ Stmt: this._statements.map(stmt => exportStatement(stmt)),
10992
+ },
10299
10993
  };
10300
10994
  return { Document };
10301
10995
  }
@@ -10374,5 +11068,6 @@ exports.PaymentStatusCode = PaymentStatusCode;
10374
11068
  exports.PaymentStatusReport = PaymentStatusReport;
10375
11069
  exports.RTPCreditPaymentInitiation = RTPCreditPaymentInitiation;
10376
11070
  exports.SEPACreditPaymentInitiation = SEPACreditPaymentInitiation;
11071
+ exports.SEPADirectDebitPaymentInitiation = SEPADirectDebitPaymentInitiation;
10377
11072
  exports.SEPAMultiCreditPaymentInitiation = SEPAMultiCreditPaymentInitiation;
10378
11073
  exports.SWIFTCreditPaymentInitiation = SWIFTCreditPaymentInitiation;