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