@lucianpacurar/iso20022.js 0.2.11 → 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,7 +8081,7 @@ 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',
@@ -8039,7 +8107,7 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8039
8107
  },
8040
8108
  },
8041
8109
  PmtInf: paymentInfoEntries,
8042
- }
8110
+ },
8043
8111
  },
8044
8112
  };
8045
8113
  return builder.build(xml);
@@ -8057,10 +8125,11 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8057
8125
  const xml = parser.parse(rawXml);
8058
8126
  // Validate XML structure
8059
8127
  if (!xml.Document) {
8060
- throw new InvalidXmlError("Invalid XML format");
8128
+ throw new InvalidXmlError('Invalid XML format');
8061
8129
  }
8062
8130
  // Validate namespace
8063
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8131
+ const namespace = (xml.Document['@_xmlns'] ||
8132
+ xml.Document['@_Xmlns']);
8064
8133
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8065
8134
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8066
8135
  }
@@ -8070,7 +8139,8 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8070
8139
  // Extract top-level initiating party from GrpHdr
8071
8140
  const topLevelInitiatingParty = {
8072
8141
  name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm,
8073
- id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id?.OrgId?.Othr?.Id,
8142
+ id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id?.OrgId?.Othr
8143
+ ?.Id,
8074
8144
  };
8075
8145
  // Normalize PmtInf to array (handle both single object and array cases)
8076
8146
  const rawPmtInf = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf)
@@ -8088,7 +8158,9 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8088
8158
  // Extract optional category purpose
8089
8159
  const categoryPurpose = pmtInf.PmtTpInf?.CtgyPurp?.Cd;
8090
8160
  // Extract requested execution date
8091
- const requestedExecutionDate = pmtInf.ReqdExctnDt ? new Date(pmtInf.ReqdExctnDt) : undefined;
8161
+ const requestedExecutionDate = pmtInf.ReqdExctnDt
8162
+ ? new Date(pmtInf.ReqdExctnDt)
8163
+ : undefined;
8092
8164
  // Normalize CdtTrfTxInf to array
8093
8165
  const rawInstructions = Array.isArray(pmtInf.CdtTrfTxInf)
8094
8166
  ? pmtInf.CdtTrfTxInf
@@ -8099,29 +8171,56 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8099
8171
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8100
8172
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8101
8173
  return {
8102
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8103
- ...(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
+ }),
8104
8180
  type: 'sepa',
8105
8181
  direction: 'credit',
8106
8182
  amount: amount,
8107
8183
  currency: currency,
8108
- ...(requestedExecutionDate && { requestedPaymentExecutionDate: requestedExecutionDate }),
8184
+ ...(requestedExecutionDate && {
8185
+ requestedPaymentExecutionDate: requestedExecutionDate,
8186
+ }),
8109
8187
  creditor: {
8110
8188
  name: inst.Cdtr?.Nm,
8111
8189
  agent: parseAgent(inst.CdtrAgt),
8112
8190
  account: parseAccount(inst.CdtrAcct),
8113
- ...((rawPostalAddress && (rawPostalAddress.StrtNm || rawPostalAddress.BldgNb || rawPostalAddress.PstCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8114
- address: {
8115
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8116
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8117
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8118
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8119
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8120
- ...(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
+ },
8121
8218
  }
8122
- } : {}),
8219
+ : {}),
8123
8220
  },
8124
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8221
+ ...(inst.RmtInf?.Ustrd && {
8222
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8223
+ }),
8125
8224
  };
8126
8225
  });
8127
8226
  return {
@@ -8169,7 +8268,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8169
8268
  paymentInformationId;
8170
8269
  formattedPaymentSum;
8171
8270
  constructor(config) {
8172
- super({ type: "rtp" });
8271
+ super({ type: 'rtp' });
8173
8272
  this.initiatingParty = config.initiatingParty;
8174
8273
  this.paymentInstructions = config.paymentInstructions;
8175
8274
  this.messageId = config.messageId || v4().replace(/-/g, '');
@@ -8187,9 +8286,11 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8187
8286
  */
8188
8287
  sumPaymentInstructions(instructions) {
8189
8288
  const instructionDineros = instructions.map(instruction => Dinero({ amount: instruction.amount, currency: instruction.currency }));
8190
- return instructionDineros.reduce((acc, next) => {
8289
+ return instructionDineros
8290
+ .reduce((acc, next) => {
8191
8291
  return acc.add(next);
8192
- }, Dinero({ amount: 0, currency: instructions[0].currency })).toFormat('0.00');
8292
+ }, Dinero({ amount: 0, currency: instructions[0].currency }))
8293
+ .toFormat('0.00');
8193
8294
  }
8194
8295
  /**
8195
8296
  * Validates the payment initiation data according to SEPA requirements.
@@ -8211,7 +8312,10 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8211
8312
  creditTransfer(instruction) {
8212
8313
  const paymentInstructionId = sanitize(instruction.id || v4(), 35);
8213
8314
  const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
8214
- const dinero = Dinero({ amount: instruction.amount, currency: instruction.currency });
8315
+ const dinero = Dinero({
8316
+ amount: instruction.amount,
8317
+ currency: instruction.currency,
8318
+ });
8215
8319
  return {
8216
8320
  PmtId: {
8217
8321
  InstrId: paymentInstructionId,
@@ -8232,9 +8336,11 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8232
8336
  },
8233
8337
  },
8234
8338
  },
8235
- RmtInf: instruction.remittanceInformation ? {
8236
- Ustrd: instruction.remittanceInformation,
8237
- } : undefined,
8339
+ RmtInf: instruction.remittanceInformation
8340
+ ? {
8341
+ Ustrd: instruction.remittanceInformation,
8342
+ }
8343
+ : undefined,
8238
8344
  };
8239
8345
  }
8240
8346
  /**
@@ -8246,7 +8352,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8246
8352
  const xml = {
8247
8353
  '?xml': {
8248
8354
  '@version': '1.0',
8249
- '@encoding': 'UTF-8'
8355
+ '@encoding': 'UTF-8',
8250
8356
  },
8251
8357
  Document: {
8252
8358
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
@@ -8275,7 +8381,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8275
8381
  CtrlSum: this.formattedPaymentSum,
8276
8382
  PmtTpInf: {
8277
8383
  SvcLvl: { Cd: 'URNS' },
8278
- LclInstrm: { Prtry: "RTP" },
8384
+ LclInstrm: { Prtry: 'RTP' },
8279
8385
  },
8280
8386
  ReqdExctnDt: this.creationDate.toISOString().split('T').at(0),
8281
8387
  Dbtr: this.party(this.initiatingParty),
@@ -8284,8 +8390,8 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8284
8390
  ChrgBr: 'SLEV',
8285
8391
  // payments[]
8286
8392
  CdtTrfTxInf: this.paymentInstructions.map(p => this.creditTransfer(p)),
8287
- }
8288
- }
8393
+ },
8394
+ },
8289
8395
  },
8290
8396
  };
8291
8397
  return builder.build(xml);
@@ -8294,9 +8400,10 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8294
8400
  const parser = new fxp.XMLParser({ ignoreAttributes: false });
8295
8401
  const xml = parser.parse(rawXml);
8296
8402
  if (!xml.Document) {
8297
- throw new InvalidXmlError("Invalid XML format");
8403
+ throw new InvalidXmlError('Invalid XML format');
8298
8404
  }
8299
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8405
+ const namespace = (xml.Document['@_xmlns'] ||
8406
+ xml.Document['@_Xmlns']);
8300
8407
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8301
8408
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8302
8409
  }
@@ -8307,19 +8414,27 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8307
8414
  }
8308
8415
  // Assuming we have one PmtInf / one Debtor, we can hack together this information from InitgPty / Dbtr
8309
8416
  const initiatingParty = {
8310
- name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm || xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
8311
- 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,
8312
8421
  agent: parseAgent(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt),
8313
- account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct)
8422
+ account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct),
8314
8423
  };
8315
- 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];
8316
8427
  const paymentInstructions = rawInstructions.map((inst) => {
8317
8428
  const currency = inst.Amt.InstdAmt['@_Ccy'];
8318
8429
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8319
8430
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8320
8431
  return {
8321
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8322
- ...(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
+ }),
8323
8438
  type: 'sepa',
8324
8439
  direction: 'credit',
8325
8440
  amount: amount,
@@ -8328,25 +8443,46 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8328
8443
  name: inst.Cdtr?.Nm,
8329
8444
  agent: parseAgent(inst.CdtrAgt),
8330
8445
  account: parseAccount(inst.CdtrAcct),
8331
- ...((rawPostalAddress && (rawPostalAddress.StreetName || rawPostalAddress.BldgNb || rawPostalAddress.PstlCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8332
- address: {
8333
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8334
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8335
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8336
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8337
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8338
- ...(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
+ },
8339
8473
  }
8340
- } : {}),
8474
+ : {}),
8341
8475
  },
8342
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8476
+ ...(inst.RmtInf?.Ustrd && {
8477
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8478
+ }),
8343
8479
  };
8344
8480
  });
8345
8481
  return new RTPCreditPaymentInitiation({
8346
8482
  messageId: messageId,
8347
8483
  creationDate: creationDate,
8348
8484
  initiatingParty: initiatingParty,
8349
- paymentInstructions: paymentInstructions
8485
+ paymentInstructions: paymentInstructions,
8350
8486
  });
8351
8487
  }
8352
8488
  }
@@ -8381,14 +8517,14 @@ const ACHLocalInstrumentCode = {
8381
8517
  RepresentedCheck: 'RCK',
8382
8518
  };
8383
8519
  const ACHLocalInstrumentCodeDescriptionMap = {
8384
- 'CCD': 'Corporate Credit or Debit',
8385
- 'PPD': 'Prearranged Payment and Deposit',
8386
- 'WEB': 'Internet-Initiated Entry',
8387
- 'TEL': 'Telephone-Initiated Entry',
8388
- 'POP': 'Point-of-Purchase Entry',
8389
- 'ARC': 'Accounts Receivable Entry',
8390
- 'BOC': 'Back Office Conversion',
8391
- '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',
8392
8528
  };
8393
8529
 
8394
8530
  /**
@@ -8447,13 +8583,14 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8447
8583
  instructionPriority;
8448
8584
  formattedPaymentSum;
8449
8585
  constructor(config) {
8450
- super({ type: "ach" });
8586
+ super({ type: 'ach' });
8451
8587
  this.initiatingParty = config.initiatingParty;
8452
8588
  this.paymentInstructions = config.paymentInstructions;
8453
8589
  this.messageId = config.messageId || v4().replace(/-/g, '');
8454
8590
  this.creationDate = config.creationDate || new Date();
8455
8591
  this.paymentInformationId = sanitize(v4(), 35);
8456
- this.localInstrument = config.localInstrument || ACHLocalInstrumentCode.CorporateCreditDebit;
8592
+ this.localInstrument =
8593
+ config.localInstrument || ACHLocalInstrumentCode.CorporateCreditDebit;
8457
8594
  this.serviceLevel = 'NURG'; // Normal Urgency
8458
8595
  this.instructionPriority = 'NORM'; // Normal Priority
8459
8596
  this.formattedPaymentSum = this.sumPaymentInstructions(this.paymentInstructions);
@@ -8468,9 +8605,11 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8468
8605
  */
8469
8606
  sumPaymentInstructions(instructions) {
8470
8607
  const instructionDineros = instructions.map(instruction => Dinero({ amount: instruction.amount, currency: instruction.currency }));
8471
- return instructionDineros.reduce((acc, next) => {
8608
+ return instructionDineros
8609
+ .reduce((acc, next) => {
8472
8610
  return acc.add(next);
8473
- }, Dinero({ amount: 0, currency: instructions[0].currency })).toFormat('0.00');
8611
+ }, Dinero({ amount: 0, currency: instructions[0].currency }))
8612
+ .toFormat('0.00');
8474
8613
  }
8475
8614
  /**
8476
8615
  * Validates the payment initiation data according to ACH requirements.
@@ -8498,7 +8637,10 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8498
8637
  creditTransfer(instruction) {
8499
8638
  const paymentInstructionId = sanitize(instruction.id || v4(), 35);
8500
8639
  const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
8501
- const dinero = Dinero({ amount: instruction.amount, currency: instruction.currency });
8640
+ const dinero = Dinero({
8641
+ amount: instruction.amount,
8642
+ currency: instruction.currency,
8643
+ });
8502
8644
  return {
8503
8645
  PmtId: {
8504
8646
  InstrId: paymentInstructionId,
@@ -8523,9 +8665,11 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8523
8665
  },
8524
8666
  Ccy: instruction.currency,
8525
8667
  },
8526
- RmtInf: instruction.remittanceInformation ? {
8527
- Ustrd: instruction.remittanceInformation,
8528
- } : undefined,
8668
+ RmtInf: instruction.remittanceInformation
8669
+ ? {
8670
+ Ustrd: instruction.remittanceInformation,
8671
+ }
8672
+ : undefined,
8529
8673
  };
8530
8674
  }
8531
8675
  /**
@@ -8537,7 +8681,7 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8537
8681
  const xml = {
8538
8682
  '?xml': {
8539
8683
  '@version': '1.0',
8540
- '@encoding': 'UTF-8'
8684
+ '@encoding': 'UTF-8',
8541
8685
  },
8542
8686
  Document: {
8543
8687
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
@@ -8575,8 +8719,8 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8575
8719
  ChrgBr: 'SHAR',
8576
8720
  // payments[]
8577
8721
  CdtTrfTxInf: this.paymentInstructions.map(p => this.creditTransfer(p)),
8578
- }
8579
- }
8722
+ },
8723
+ },
8580
8724
  },
8581
8725
  };
8582
8726
  return builder.build(xml);
@@ -8590,12 +8734,17 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8590
8734
  * @throws {Error} If multiple payment information blocks are found.
8591
8735
  */
8592
8736
  static fromXML(rawXml) {
8593
- 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
+ });
8594
8742
  const xml = parser.parse(rawXml);
8595
8743
  if (!xml.Document) {
8596
- throw new InvalidXmlError("Invalid XML format");
8744
+ throw new InvalidXmlError('Invalid XML format');
8597
8745
  }
8598
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8746
+ const namespace = (xml.Document['@_xmlns'] ||
8747
+ xml.Document['@_Xmlns']);
8599
8748
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8600
8749
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8601
8750
  }
@@ -8608,19 +8757,27 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8608
8757
  xml.Document.CstmrCdtTrfInitn.PmtInf.PmtTpInf;
8609
8758
  // Assuming we have one PmtInf / one Debtor, we can hack together this information from InitgPty / Dbtr
8610
8759
  const initiatingParty = {
8611
- name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm || xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
8612
- 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,
8613
8764
  agent: parseAgent(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt),
8614
- account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct)
8765
+ account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct),
8615
8766
  };
8616
- 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];
8617
8770
  const paymentInstructions = rawInstructions.map((inst) => {
8618
8771
  const currency = inst.Amt.InstdAmt['@_Ccy'];
8619
8772
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8620
8773
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8621
8774
  return {
8622
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8623
- ...(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
+ }),
8624
8781
  type: 'ach',
8625
8782
  direction: 'credit',
8626
8783
  amount: amount,
@@ -8629,41 +8786,458 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8629
8786
  name: inst.Cdtr?.Nm,
8630
8787
  agent: parseAgent(inst.CdtrAgt),
8631
8788
  account: parseAccount(inst.CdtrAcct),
8632
- ...((rawPostalAddress && (rawPostalAddress.StrtNm || rawPostalAddress.BldgNb || rawPostalAddress.PstCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8633
- address: {
8634
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8635
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8636
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8637
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8638
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8639
- ...(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
+ },
8640
8816
  }
8641
- } : {}),
8817
+ : {}),
8642
8818
  },
8643
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8819
+ ...(inst.RmtInf?.Ustrd && {
8820
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8821
+ }),
8644
8822
  };
8645
8823
  });
8646
8824
  return new ACHCreditPaymentInitiation({
8647
8825
  messageId: messageId,
8648
8826
  creationDate: creationDate,
8649
8827
  initiatingParty: initiatingParty,
8650
- 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,
8651
9225
  });
8652
9226
  }
8653
9227
  }
8654
9228
 
8655
9229
  const ISO20022Messages = {
8656
- CAMT_003: "CAMT.003",
8657
- CAMT_004: "CAMT.004",
8658
- CAMT_005: "CAMT.005",
8659
- CAMT_006: "CAMT.006",
8660
- CAMT_053: "CAMT.053",
8661
- PAIN_001: "PAIN.001",
8662
- 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',
8663
9237
  };
8664
9238
  const ISO20022Implementations = new Map();
8665
9239
  function registerISO20022Implementation(cl) {
8666
- cl.supportedMessages().forEach((msg) => {
9240
+ cl.supportedMessages().forEach(msg => {
8667
9241
  ISO20022Implementations.set(msg, cl);
8668
9242
  });
8669
9243
  }
@@ -8719,12 +9293,12 @@ class CashManagementGetAccount {
8719
9293
  static fromDocumentOject(doc) {
8720
9294
  const rawHeader = doc.Document?.GetAcct?.MsgHdr;
8721
9295
  if (!rawHeader) {
8722
- throw new InvalidStructureError("Invalid CAMT.003 document: missing MsgHdr");
9296
+ throw new InvalidStructureError('Invalid CAMT.003 document: missing MsgHdr');
8723
9297
  }
8724
9298
  const header = parseMessageHeader(rawHeader);
8725
9299
  const newCrit = doc.Document?.GetAcct?.AcctQryDef?.AcctCrit?.NewCrit;
8726
9300
  if (!newCrit) {
8727
- 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');
8728
9302
  }
8729
9303
  const name = newCrit.NewQryNm;
8730
9304
  let searchCriteria = [];
@@ -8734,16 +9308,19 @@ class CashManagementGetAccount {
8734
9308
  }
8735
9309
  rawCriterias = rawCriterias.filter((c) => !!c);
8736
9310
  if (rawCriterias.length === 0) {
8737
- throw new InvalidStructureError("Invalid CAMT.003 document: missing search criteria");
9311
+ throw new InvalidStructureError('Invalid CAMT.003 document: missing search criteria');
8738
9312
  }
8739
9313
  for (const rawCriterium of rawCriterias) {
8740
9314
  const crit = {};
8741
9315
  // search on Ids, only one criterium supported for now
8742
9316
  if (rawCriterium.AcctId) {
8743
- if (Array.isArray(rawCriterium.AcctId) && rawCriterium.AcctId.length > 1) {
8744
- 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');
8745
9320
  }
8746
- 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;
8747
9324
  if (acctId.CTTxt) {
8748
9325
  crit.accountRegExp = `.*${acctId.CTTxt}.*`; // contains
8749
9326
  }
@@ -8757,19 +9334,23 @@ class CashManagementGetAccount {
8757
9334
  // search on currency
8758
9335
  if (rawCriterium.Ccy) {
8759
9336
  if (Array.isArray(rawCriterium.Ccy) && rawCriterium.Ccy.length > 1) {
8760
- 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');
8761
9338
  }
8762
- 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;
8763
9342
  crit.currencyEqualTo = ccy;
8764
9343
  }
8765
9344
  // search on balance as of date
8766
9345
  if (rawCriterium.Bal) {
8767
9346
  if (Array.isArray(rawCriterium.Bal) && rawCriterium.Bal.length > 1) {
8768
- 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');
8769
9348
  }
8770
- 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;
8771
9352
  if (bal?.ValDt && Array.isArray(bal.ValDt) && bal.ValDt.length > 1) {
8772
- 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');
8773
9354
  }
8774
9355
  const valDt = Array.isArray(bal?.ValDt) ? bal.ValDt[0] : bal?.ValDt;
8775
9356
  if (valDt?.Dt?.EQDt) {
@@ -8790,9 +9371,10 @@ class CashManagementGetAccount {
8790
9371
  const parser = XML.getParser();
8791
9372
  const doc = parser.parse(xml);
8792
9373
  if (!doc.Document) {
8793
- throw new Error("Invalid XML format");
9374
+ throw new Error('Invalid XML format');
8794
9375
  }
8795
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
9376
+ const namespace = (doc.Document['@_xmlns'] ||
9377
+ doc.Document['@_Xmlns']);
8796
9378
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.003.001.')) {
8797
9379
  throw new InvalidXmlNamespaceError('Invalid CAMT.003 namespace');
8798
9380
  }
@@ -8801,7 +9383,7 @@ class CashManagementGetAccount {
8801
9383
  static fromJSON(json) {
8802
9384
  const obj = JSON.parse(json);
8803
9385
  if (!obj.Document) {
8804
- throw new Error("Invalid JSON format");
9386
+ throw new Error('Invalid JSON format');
8805
9387
  }
8806
9388
  return CashManagementGetAccount.fromDocumentOject(obj);
8807
9389
  }
@@ -8821,39 +9403,55 @@ class CashManagementGetAccount {
8821
9403
  AcctCrit: {
8822
9404
  NewCrit: {
8823
9405
  NewQryNm: this._data.newCriteria?.name,
8824
- SchCrit: this._data.newCriteria?.searchCriteria.map((c) => {
9406
+ SchCrit: this._data.newCriteria?.searchCriteria.map(c => {
8825
9407
  const obj = {};
8826
9408
  if (c.accountRegExp) {
8827
- if (c.accountRegExp.startsWith('.*') && c.accountRegExp.endsWith('.*')) {
8828
- 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
8829
9416
  }
8830
- else if (c.accountRegExp.startsWith('^((?!') && c.accountRegExp.endsWith(').)*$')) {
8831
- 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
8832
9424
  }
8833
9425
  }
8834
9426
  else if (c.accountEqualTo) {
8835
9427
  obj.AcctId = {
8836
- EQ: exportAccountIdentification(c.accountEqualTo)
9428
+ EQ: exportAccountIdentification(c.accountEqualTo),
8837
9429
  };
8838
9430
  }
8839
9431
  if (c.currencyEqualTo) {
8840
9432
  obj.Ccy = [c.currencyEqualTo];
8841
9433
  }
8842
9434
  if (c.balanceAsOfDateEqualTo) {
8843
- obj.Bal = [{
8844
- ValDt: [{
9435
+ obj.Bal = [
9436
+ {
9437
+ ValDt: [
9438
+ {
8845
9439
  Dt: {
8846
- EQDt: c.balanceAsOfDateEqualTo.toISOString().slice(0, 10)
8847
- }
8848
- }]
8849
- }];
9440
+ EQDt: c.balanceAsOfDateEqualTo
9441
+ .toISOString()
9442
+ .slice(0, 10),
9443
+ },
9444
+ },
9445
+ ],
9446
+ },
9447
+ ];
8850
9448
  }
8851
9449
  return obj;
8852
9450
  }),
8853
- }
8854
- }
8855
- }
8856
- }
9451
+ },
9452
+ },
9453
+ },
9454
+ },
8857
9455
  };
8858
9456
  return { Document };
8859
9457
  }
@@ -8953,10 +9551,10 @@ const exportStatement = (stmt) => {
8953
9551
  },
8954
9552
  Acct: {
8955
9553
  ...exportAccount(stmt.account),
8956
- Svcr: exportAgent(stmt.agent)
9554
+ Svcr: exportAgent(stmt.agent),
8957
9555
  },
8958
- Bal: stmt.balances.map((bal) => exportBalance(bal)),
8959
- Ntry: stmt.entries.map((entry) => exportEntry(entry)),
9556
+ Bal: stmt.balances.map(bal => exportBalance(bal)),
9557
+ Ntry: stmt.entries.map(entry => exportEntry(entry)),
8960
9558
  };
8961
9559
  return obj;
8962
9560
  };
@@ -9080,7 +9678,9 @@ const exportEntry = (entry) => {
9080
9678
  BkTxCd: exportBankTransactionCode(entry.bankTransactionCode, entry.proprietaryCode),
9081
9679
  AddtlNtryInf: entry.additionalInformation,
9082
9680
  AcctSvcrRef: entry.accountServicerReferenceId,
9083
- NtryDtls: entry.transactions.map((tx) => ({ TxDtls: exportTransactionDetails(tx) }))
9681
+ NtryDtls: entry.transactions.map(tx => ({
9682
+ TxDtls: exportTransactionDetails(tx),
9683
+ })),
9084
9684
  };
9085
9685
  return obj;
9086
9686
  };
@@ -9173,7 +9773,9 @@ const exportTransactionDetails = (tx) => {
9173
9773
  Dbtr: {
9174
9774
  Nm: tx.debtor.name,
9175
9775
  },
9176
- DbtrAcct: tx.debtor.account ? exportAccount(tx.debtor.account) : undefined,
9776
+ DbtrAcct: tx.debtor.account
9777
+ ? exportAccount(tx.debtor.account)
9778
+ : undefined,
9177
9779
  };
9178
9780
  obj.RltdAgts = {
9179
9781
  DbtrAgt: tx.debtor.agent ? exportAgent(tx.debtor.agent) : undefined,
@@ -9185,7 +9787,9 @@ const exportTransactionDetails = (tx) => {
9185
9787
  Cdtr: {
9186
9788
  Nm: tx.creditor.name,
9187
9789
  },
9188
- CdtrAcct: tx.creditor.account ? exportAccount(tx.creditor.account) : undefined,
9790
+ CdtrAcct: tx.creditor.account
9791
+ ? exportAccount(tx.creditor.account)
9792
+ : undefined,
9189
9793
  };
9190
9794
  obj.RltdAgts = {
9191
9795
  CdtrAgt: tx.creditor.agent ? exportAgent(tx.creditor.agent) : undefined,
@@ -9230,7 +9834,7 @@ const exportBankTransactionCode = (bankTransactionCode, proprietaryCode) => {
9230
9834
  return obj;
9231
9835
  };
9232
9836
  const parseBusinessError = (bizErr) => {
9233
- const code = bizErr.Err?.Cd || bizErr.Err?.Prtry || "UKNW";
9837
+ const code = bizErr.Err?.Cd || bizErr.Err?.Prtry || 'UKNW';
9234
9838
  const description = bizErr.Desc;
9235
9839
  return {
9236
9840
  code,
@@ -9261,7 +9865,7 @@ class CashManagementReturnAccount {
9261
9865
  static fromDocumentOject(doc) {
9262
9866
  const rawHeader = doc.Document?.RtrAcct?.MsgHdr;
9263
9867
  if (!rawHeader) {
9264
- throw new InvalidStructureError("Invalid CAMT.004 document: missing MsgHdr");
9868
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing MsgHdr');
9265
9869
  }
9266
9870
  const header = parseMessageHeader(rawHeader);
9267
9871
  // interpret the report
@@ -9276,7 +9880,7 @@ class CashManagementReturnAccount {
9276
9880
  if (r.AcctOrErr?.Acct) {
9277
9881
  // report
9278
9882
  if (!r.AcctOrErr.Acct.Ccy) {
9279
- throw new InvalidStructureError("Invalid CAMT.004 document: missing Ccy in Acct");
9883
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing Ccy in Acct');
9280
9884
  }
9281
9885
  let rawMulBal = r.AcctOrErr.Acct.MulBal;
9282
9886
  if (!Array.isArray(rawMulBal))
@@ -9289,7 +9893,7 @@ class CashManagementReturnAccount {
9289
9893
  balances: rawMulBal.map((bal) => parseBalanceReport(r.AcctOrErr.Acct.Ccy, bal)),
9290
9894
  };
9291
9895
  if (report.balances.length === 0) {
9292
- throw new InvalidStructureError("Invalid CAMT.004 document: missing MulBal in Acct");
9896
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing MulBal in Acct');
9293
9897
  }
9294
9898
  }
9295
9899
  else if (r.AcctOrErr?.BizErr) {
@@ -9297,7 +9901,7 @@ class CashManagementReturnAccount {
9297
9901
  error = parseBusinessError(r.AcctOrErr.BizErr);
9298
9902
  }
9299
9903
  else {
9300
- throw new InvalidStructureError("Invalid CAMT.004 document: missing AcctOrErr");
9904
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing AcctOrErr');
9301
9905
  }
9302
9906
  return { accountId, report, error };
9303
9907
  });
@@ -9310,9 +9914,10 @@ class CashManagementReturnAccount {
9310
9914
  const parser = XML.getParser();
9311
9915
  const doc = parser.parse(xml);
9312
9916
  if (!doc.Document) {
9313
- throw new Error("Invalid XML format");
9917
+ throw new Error('Invalid XML format');
9314
9918
  }
9315
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
9919
+ const namespace = (doc.Document['@_xmlns'] ||
9920
+ doc.Document['@_Xmlns']);
9316
9921
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.004.001.')) {
9317
9922
  throw new InvalidXmlNamespaceError('Invalid CAMT.004 namespace');
9318
9923
  }
@@ -9321,7 +9926,7 @@ class CashManagementReturnAccount {
9321
9926
  static fromJSON(json) {
9322
9927
  const obj = JSON.parse(json);
9323
9928
  if (!obj.Document) {
9324
- throw new Error("Invalid JSON format");
9929
+ throw new Error('Invalid JSON format');
9325
9930
  }
9326
9931
  return CashManagementReturnAccount.fromDocumentOject(obj);
9327
9932
  }
@@ -9338,7 +9943,7 @@ class CashManagementReturnAccount {
9338
9943
  RtrAcct: {
9339
9944
  MsgHdr: exportMessageHeader(this._data.header),
9340
9945
  RptOrErr: {
9341
- AcctRpt: this._data.reports.map((report) => {
9946
+ AcctRpt: this._data.reports.map(report => {
9342
9947
  const obj = {
9343
9948
  AcctId: exportAccountIdentification(report.accountId),
9344
9949
  AcctOrErr: {}, // filled below
@@ -9348,16 +9953,16 @@ class CashManagementReturnAccount {
9348
9953
  Ccy: report.report.currency,
9349
9954
  Nm: report.report.name,
9350
9955
  Tp: { Cd: report.report.type }, // TODO add Prtry handling
9351
- MulBal: report.report.balances.map((bal) => exportBalanceReport(report.report.currency, bal)),
9956
+ MulBal: report.report.balances.map(bal => exportBalanceReport(report.report.currency, bal)),
9352
9957
  };
9353
9958
  }
9354
9959
  else if (report.error) {
9355
9960
  obj.AcctOrErr.BizErr = exportBusinessError(report.error);
9356
9961
  }
9357
9962
  return obj;
9358
- })
9359
- }
9360
- }
9963
+ }),
9964
+ },
9965
+ },
9361
9966
  };
9362
9967
  return { Document };
9363
9968
  }
@@ -9378,12 +9983,12 @@ class CashManagementGetTransaction {
9378
9983
  static fromDocumentOject(doc) {
9379
9984
  const rawHeader = doc.Document?.GetTx?.MsgHdr;
9380
9985
  if (!rawHeader) {
9381
- throw new InvalidStructureError("Invalid CAMT.005 document: missing MsgHdr");
9986
+ throw new InvalidStructureError('Invalid CAMT.005 document: missing MsgHdr');
9382
9987
  }
9383
9988
  const header = parseMessageHeader(rawHeader);
9384
9989
  const newCrit = doc.Document?.GetTx?.TxQryDef?.TxCrit?.NewCrit;
9385
9990
  if (!newCrit) {
9386
- 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');
9387
9992
  }
9388
9993
  const name = newCrit.NewQryNm;
9389
9994
  let searchCriteria = [];
@@ -9393,35 +9998,42 @@ class CashManagementGetTransaction {
9393
9998
  }
9394
9999
  rawCriterias = rawCriterias.filter((c) => !!c);
9395
10000
  if (rawCriterias.length === 0) {
9396
- throw new InvalidStructureError("Invalid CAMT.005 document: missing search criteria");
10001
+ throw new InvalidStructureError('Invalid CAMT.005 document: missing search criteria');
9397
10002
  }
9398
10003
  for (const rawCriterium of rawCriterias) {
9399
10004
  // search on Ids
9400
10005
  if (rawCriterium.PmtSch.MsgId) {
9401
10006
  searchCriteria.push({
9402
- type: "PmtSch.MsgId",
9403
- 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],
9404
10011
  });
9405
10012
  }
9406
10013
  // seach on date
9407
10014
  if (rawCriterium.PmtSch.ReqdExctnDt) {
9408
- if (Array.isArray(rawCriterium.PmtSch.ReqdExctnDt) && rawCriterium.PmtSch.ReqdExctnDt.length > 1) {
9409
- 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');
9410
10018
  }
9411
- 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;
9412
10022
  if (criterium?.DtSch?.EQDt) {
9413
10023
  searchCriteria.push({
9414
- type: "PmtSch.ReqdExctnDt",
10024
+ type: 'PmtSch.ReqdExctnDt',
9415
10025
  dateEqualTo: parseDate(criterium.DtSch.EQDt),
9416
10026
  });
9417
10027
  }
9418
10028
  }
9419
- let pmtIds = Array.isArray(rawCriterium.PmtSch.PmtId) ? rawCriterium.PmtSch.PmtId : [rawCriterium.PmtSch.PmtId];
9420
- 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);
9421
10033
  if (pmtIds.length > 0) {
9422
10034
  searchCriteria.push({
9423
- type: "PmtSch.PmtId.LngBizId.EndToEndId",
9424
- endToEndIdEqualTo: pmtIds.map((id) => id.LngBizId.EndToEndId),
10035
+ type: 'PmtSch.PmtId.LngBizId.EndToEndId',
10036
+ endToEndIdEqualTo: pmtIds.map(id => id.LngBizId.EndToEndId),
9425
10037
  });
9426
10038
  }
9427
10039
  }
@@ -9437,9 +10049,10 @@ class CashManagementGetTransaction {
9437
10049
  const parser = XML.getParser();
9438
10050
  const doc = parser.parse(xml);
9439
10051
  if (!doc.Document) {
9440
- throw new Error("Invalid XML format");
10052
+ throw new Error('Invalid XML format');
9441
10053
  }
9442
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
10054
+ const namespace = (doc.Document['@_xmlns'] ||
10055
+ doc.Document['@_Xmlns']);
9443
10056
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.005.001.')) {
9444
10057
  throw new InvalidXmlNamespaceError('Invalid CAMT.005 namespace');
9445
10058
  }
@@ -9448,7 +10061,7 @@ class CashManagementGetTransaction {
9448
10061
  static fromJSON(json) {
9449
10062
  const obj = JSON.parse(json);
9450
10063
  if (!obj.Document) {
9451
- throw new Error("Invalid JSON format");
10064
+ throw new Error('Invalid JSON format');
9452
10065
  }
9453
10066
  return CashManagementGetTransaction.fromDocumentOject(obj);
9454
10067
  }
@@ -9468,37 +10081,38 @@ class CashManagementGetTransaction {
9468
10081
  TxCrit: {
9469
10082
  NewCrit: {
9470
10083
  NewQryNm: this._data.newCriteria?.name,
9471
- SchCrit: this._data.newCriteria?.searchCriteria.map((c) => {
10084
+ SchCrit: this._data.newCriteria?.searchCriteria.map(c => {
9472
10085
  const obj = {};
9473
- if (c.type === "PmtSch.MsgId" && c.msgIdsEqualTo) {
10086
+ if (c.type === 'PmtSch.MsgId' && c.msgIdsEqualTo) {
9474
10087
  obj.PmtSch = {
9475
- MsgId: c.msgIdsEqualTo
10088
+ MsgId: c.msgIdsEqualTo,
9476
10089
  };
9477
10090
  }
9478
- if (c.type === "PmtSch.ReqdExctnDt" && c.dateEqualTo) {
10091
+ if (c.type === 'PmtSch.ReqdExctnDt' && c.dateEqualTo) {
9479
10092
  obj.PmtSch = {
9480
10093
  ReqdExctnDt: {
9481
10094
  DtSch: {
9482
10095
  EQDt: c.dateEqualTo.toISOString().slice(0, 10),
9483
- }
9484
- }
10096
+ },
10097
+ },
9485
10098
  };
9486
10099
  }
9487
- if (c.type === "PmtSch.PmtId.LngBizId.EndToEndId" && c.endToEndIdEqualTo) {
10100
+ if (c.type === 'PmtSch.PmtId.LngBizId.EndToEndId' &&
10101
+ c.endToEndIdEqualTo) {
9488
10102
  obj.PmtSch = {
9489
- PmtId: c.endToEndIdEqualTo.map((id) => ({
10103
+ PmtId: c.endToEndIdEqualTo.map(id => ({
9490
10104
  LngBizId: {
9491
10105
  EndToEndId: id,
9492
- }
9493
- }))
10106
+ },
10107
+ })),
9494
10108
  };
9495
10109
  }
9496
10110
  return obj;
9497
10111
  }),
9498
- }
9499
- }
9500
- }
9501
- }
10112
+ },
10113
+ },
10114
+ },
10115
+ },
9502
10116
  };
9503
10117
  return { Document };
9504
10118
  }
@@ -9519,7 +10133,7 @@ class CashManagementReturnTransaction {
9519
10133
  static fromDocumentOject(doc) {
9520
10134
  const rawHeader = doc.Document?.RtrTx?.MsgHdr;
9521
10135
  if (!rawHeader) {
9522
- throw new InvalidStructureError("Invalid CAMT.006 document: missing MsgHdr");
10136
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing MsgHdr');
9523
10137
  }
9524
10138
  const header = parseMessageHeader(rawHeader);
9525
10139
  // interpret the report
@@ -9528,7 +10142,8 @@ class CashManagementReturnTransaction {
9528
10142
  rawReports = [rawReports];
9529
10143
  rawReports = rawReports.filter((r) => !!r); // remove null/undefined
9530
10144
  const reports = rawReports.map((r) => {
9531
- 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
9532
10147
  const paymentId = {
9533
10148
  currency: r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Ccy,
9534
10149
  amount: parseAmountToMinorUnits(rawAmount, r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Ccy),
@@ -9538,20 +10153,24 @@ class CashManagementReturnTransaction {
9538
10153
  };
9539
10154
  // check required fields
9540
10155
  if (!paymentId.currency) {
9541
- 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');
9542
10157
  }
9543
- if (paymentId.amount === undefined || paymentId.amount === null || isNaN(paymentId.amount)) {
9544
- 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');
9545
10162
  }
9546
10163
  if (!paymentId.endToEndId) {
9547
- 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');
9548
10165
  }
9549
10166
  let report = undefined;
9550
10167
  let error = undefined;
9551
10168
  if (r.TxOrErr?.Tx) {
9552
10169
  // report
9553
10170
  const msgId = r.TxOrErr.Tx.Pmt?.MsgId;
9554
- 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;
9555
10174
  const status = ((sts) => {
9556
10175
  if (!sts)
9557
10176
  return undefined;
@@ -9559,9 +10178,13 @@ class CashManagementReturnTransaction {
9559
10178
  return undefined;
9560
10179
  if (Array.isArray(sts))
9561
10180
  sts = sts[0]; // take the first one only
9562
- 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;
9563
10186
  if (code)
9564
- 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
9565
10188
  else
9566
10189
  return undefined;
9567
10190
  const reason = sts.Rsn?.Prtry;
@@ -9576,7 +10199,7 @@ class CashManagementReturnTransaction {
9576
10199
  }
9577
10200
  function parseAgent(agent) {
9578
10201
  if (!agent)
9579
- return { bic: "" };
10202
+ return { bic: '' };
9580
10203
  return { bic: agent?.FinInstnId?.BICFI };
9581
10204
  }
9582
10205
  report = {
@@ -9590,10 +10213,10 @@ class CashManagementReturnTransaction {
9590
10213
  };
9591
10214
  // check the debtor and creditor required fields
9592
10215
  if (!report.debtor.id) {
9593
- 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');
9594
10217
  }
9595
10218
  if (!report.creditor.id) {
9596
- 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');
9597
10220
  }
9598
10221
  }
9599
10222
  else if (r.TxOrErr?.BizErr) {
@@ -9601,7 +10224,7 @@ class CashManagementReturnTransaction {
9601
10224
  error = parseBusinessError(r.TxOrErr.BizErr);
9602
10225
  }
9603
10226
  else {
9604
- throw new InvalidStructureError("Invalid CAMT.006 document: missing TxOrErr");
10227
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing TxOrErr');
9605
10228
  }
9606
10229
  return { paymentId, report, error };
9607
10230
  });
@@ -9614,9 +10237,10 @@ class CashManagementReturnTransaction {
9614
10237
  const parser = XML.getParser();
9615
10238
  const doc = parser.parse(xml);
9616
10239
  if (!doc.Document) {
9617
- throw new Error("Invalid XML format");
10240
+ throw new Error('Invalid XML format');
9618
10241
  }
9619
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
10242
+ const namespace = (doc.Document['@_xmlns'] ||
10243
+ doc.Document['@_Xmlns']);
9620
10244
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.004.001.')) {
9621
10245
  throw new InvalidXmlNamespaceError('Invalid CAMT.004 namespace');
9622
10246
  }
@@ -9625,7 +10249,7 @@ class CashManagementReturnTransaction {
9625
10249
  static fromJSON(json) {
9626
10250
  const obj = JSON.parse(json);
9627
10251
  if (!obj.Document) {
9628
- throw new Error("Invalid JSON format");
10252
+ throw new Error('Invalid JSON format');
9629
10253
  }
9630
10254
  return CashManagementReturnTransaction.fromDocumentOject(obj);
9631
10255
  }
@@ -9643,7 +10267,7 @@ class CashManagementReturnTransaction {
9643
10267
  MsgHdr: exportMessageHeader(this._data.header),
9644
10268
  RptOrErr: {
9645
10269
  BizRpt: {
9646
- TxRpt: this._data.reports.map((report) => {
10270
+ TxRpt: this._data.reports.map(report => {
9647
10271
  const obj = {
9648
10272
  PmtId: {
9649
10273
  LngBizId: {
@@ -9655,7 +10279,7 @@ class CashManagementReturnTransaction {
9655
10279
  UETR: report.paymentId.uetr,
9656
10280
  TxId: report.paymentId.transactionId,
9657
10281
  EndToEndId: report.paymentId.endToEndId,
9658
- }
10282
+ },
9659
10283
  },
9660
10284
  TxOrErr: {}, // filled below
9661
10285
  };
@@ -9674,38 +10298,46 @@ class CashManagementReturnTransaction {
9674
10298
  function exportAgent(a) {
9675
10299
  if (!a)
9676
10300
  return undefined;
9677
- if ("bic" in a && a.bic)
10301
+ if ('bic' in a && a.bic)
9678
10302
  return { FinInstnId: { BICFI: a.bic } };
9679
- if ("abaRoutingNumber" in a && a.abaRoutingNumber)
10303
+ if ('abaRoutingNumber' in a && a.abaRoutingNumber)
9680
10304
  return { FinInstId: { Othr: { Id: a.abaRoutingNumber } } };
9681
10305
  return undefined;
9682
10306
  }
9683
- 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];
9684
10310
  obj.TxOrErr.Tx = {
9685
10311
  Pmt: {
9686
10312
  MsgId: report.report.msgId,
9687
- ReqdExctnDt: { Dt: report.report.reqExecutionDate?.toISOString()?.slice(0, 10) },
10313
+ ReqdExctnDt: {
10314
+ Dt: report.report.reqExecutionDate
10315
+ ?.toISOString()
10316
+ ?.slice(0, 10),
10317
+ },
9688
10318
  Sts: {
9689
10319
  Cd: codeType ? { [codeType]: code } : undefined,
9690
- 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,
9691
10323
  },
9692
10324
  Pties: {
9693
10325
  Dbtr: exportParty(report.report.debtor),
9694
10326
  DbtrAgt: exportAgent(report.report.debtorAgent),
9695
10327
  Cdtr: exportParty(report.report.creditor),
9696
10328
  CdtrAgt: exportAgent(report.report.creditorAgent),
9697
- }
9698
- }
10329
+ },
10330
+ },
9699
10331
  };
9700
10332
  }
9701
10333
  else if (report.error) {
9702
10334
  obj.TxOrErr.BizErr = exportBusinessError(report.error);
9703
10335
  }
9704
10336
  return obj;
9705
- })
9706
- }
9707
- }
9708
- }
10337
+ }),
10338
+ },
10339
+ },
10340
+ },
9709
10341
  };
9710
10342
  return { Document };
9711
10343
  }
@@ -9745,17 +10377,17 @@ const BalanceTypeCode = {
9745
10377
  * Description mapping of BalanceTypeCode values to their names.
9746
10378
  */
9747
10379
  const BalanceTypeCodeDescriptionMap = {
9748
- 'CLAV': 'Closing Available',
9749
- 'CLBD': 'Closing Booked',
9750
- 'FWAV': 'Forward Available',
9751
- 'INFO': 'Information',
9752
- 'ITAV': 'Interim Available',
9753
- 'ITBD': 'Interim Booked',
9754
- 'OPAV': 'Opening Available',
9755
- 'OPBD': 'Opening Booked',
9756
- 'PRCD': 'Previously Closed Booked',
9757
- 'XPCD': 'Expected',
9758
- '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',
9759
10391
  };
9760
10392
 
9761
10393
  /**
@@ -9978,6 +10610,64 @@ class ISO20022 {
9978
10610
  creationDate: config.creationDate,
9979
10611
  });
9980
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
+ }
9981
10671
  /** Create a message CAMT or other */
9982
10672
  createMessage(type, config) {
9983
10673
  const implementation = getISO20022Implementation(type);
@@ -10266,9 +10956,10 @@ class CashManagementEndOfDayReport {
10266
10956
  const parser = XML.getParser();
10267
10957
  const xml = parser.parse(rawXml);
10268
10958
  if (!xml.Document) {
10269
- throw new InvalidXmlError("Invalid XML format");
10959
+ throw new InvalidXmlError('Invalid XML format');
10270
10960
  }
10271
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
10961
+ const namespace = (xml.Document['@_xmlns'] ||
10962
+ xml.Document['@_Xmlns']);
10272
10963
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.053.001.')) {
10273
10964
  throw new InvalidXmlNamespaceError('Invalid CAMT.053 namespace');
10274
10965
  }
@@ -10283,7 +10974,7 @@ class CashManagementEndOfDayReport {
10283
10974
  static fromJSON(json) {
10284
10975
  const obj = JSON.parse(json);
10285
10976
  if (!obj.Document) {
10286
- throw new InvalidXmlError("Invalid JSON format");
10977
+ throw new InvalidXmlError('Invalid JSON format');
10287
10978
  }
10288
10979
  return CashManagementEndOfDayReport.fromDocumentObject(obj);
10289
10980
  }
@@ -10293,10 +10984,12 @@ class CashManagementEndOfDayReport {
10293
10984
  GrpHdr: {
10294
10985
  MsgId: this._messageId,
10295
10986
  CreDtTm: this._creationDate.toISOString(),
10296
- MsgRcpt: this._recipient ? exportRecipient(this._recipient) : undefined,
10987
+ MsgRcpt: this._recipient
10988
+ ? exportRecipient(this._recipient)
10989
+ : undefined,
10297
10990
  },
10298
- Stmt: this._statements.map((stmt) => exportStatement(stmt)),
10299
- }
10991
+ Stmt: this._statements.map(stmt => exportStatement(stmt)),
10992
+ },
10300
10993
  };
10301
10994
  return { Document };
10302
10995
  }
@@ -10375,5 +11068,6 @@ exports.PaymentStatusCode = PaymentStatusCode;
10375
11068
  exports.PaymentStatusReport = PaymentStatusReport;
10376
11069
  exports.RTPCreditPaymentInitiation = RTPCreditPaymentInitiation;
10377
11070
  exports.SEPACreditPaymentInitiation = SEPACreditPaymentInitiation;
11071
+ exports.SEPADirectDebitPaymentInitiation = SEPADirectDebitPaymentInitiation;
10378
11072
  exports.SEPAMultiCreditPaymentInitiation = SEPAMultiCreditPaymentInitiation;
10379
11073
  exports.SWIFTCreditPaymentInitiation = SWIFTCreditPaymentInitiation;