@lucianpacurar/iso20022.js 0.2.10 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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,11 +8079,12 @@ 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',
8018
8086
  '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
8087
+ '@xsi:schemaLocation': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03 pain.001.001.03.xsd',
8019
8088
  CstmrCdtTrfInitn: {
8020
8089
  GrpHdr: {
8021
8090
  MsgId: this.messageId,
@@ -8036,7 +8105,7 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8036
8105
  },
8037
8106
  },
8038
8107
  PmtInf: paymentInfoEntries,
8039
- }
8108
+ },
8040
8109
  },
8041
8110
  };
8042
8111
  return builder.build(xml);
@@ -8054,10 +8123,11 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8054
8123
  const xml = parser.parse(rawXml);
8055
8124
  // Validate XML structure
8056
8125
  if (!xml.Document) {
8057
- throw new InvalidXmlError("Invalid XML format");
8126
+ throw new InvalidXmlError('Invalid XML format');
8058
8127
  }
8059
8128
  // Validate namespace
8060
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8129
+ const namespace = (xml.Document['@_xmlns'] ||
8130
+ xml.Document['@_Xmlns']);
8061
8131
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8062
8132
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8063
8133
  }
@@ -8067,7 +8137,8 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8067
8137
  // Extract top-level initiating party from GrpHdr
8068
8138
  const topLevelInitiatingParty = {
8069
8139
  name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm,
8070
- id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id?.OrgId?.Othr?.Id,
8140
+ id: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Id?.OrgId?.Othr
8141
+ ?.Id,
8071
8142
  };
8072
8143
  // Normalize PmtInf to array (handle both single object and array cases)
8073
8144
  const rawPmtInf = Array.isArray(xml.Document.CstmrCdtTrfInitn.PmtInf)
@@ -8085,7 +8156,9 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8085
8156
  // Extract optional category purpose
8086
8157
  const categoryPurpose = pmtInf.PmtTpInf?.CtgyPurp?.Cd;
8087
8158
  // Extract requested execution date
8088
- const requestedExecutionDate = pmtInf.ReqdExctnDt ? new Date(pmtInf.ReqdExctnDt) : undefined;
8159
+ const requestedExecutionDate = pmtInf.ReqdExctnDt
8160
+ ? new Date(pmtInf.ReqdExctnDt)
8161
+ : undefined;
8089
8162
  // Normalize CdtTrfTxInf to array
8090
8163
  const rawInstructions = Array.isArray(pmtInf.CdtTrfTxInf)
8091
8164
  ? pmtInf.CdtTrfTxInf
@@ -8096,29 +8169,56 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
8096
8169
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8097
8170
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8098
8171
  return {
8099
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8100
- ...(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
+ }),
8101
8178
  type: 'sepa',
8102
8179
  direction: 'credit',
8103
8180
  amount: amount,
8104
8181
  currency: currency,
8105
- ...(requestedExecutionDate && { requestedPaymentExecutionDate: requestedExecutionDate }),
8182
+ ...(requestedExecutionDate && {
8183
+ requestedPaymentExecutionDate: requestedExecutionDate,
8184
+ }),
8106
8185
  creditor: {
8107
8186
  name: inst.Cdtr?.Nm,
8108
8187
  agent: parseAgent(inst.CdtrAgt),
8109
8188
  account: parseAccount(inst.CdtrAcct),
8110
- ...((rawPostalAddress && (rawPostalAddress.StrtNm || rawPostalAddress.BldgNb || rawPostalAddress.PstCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8111
- address: {
8112
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8113
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8114
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8115
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8116
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8117
- ...(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
+ },
8118
8216
  }
8119
- } : {}),
8217
+ : {}),
8120
8218
  },
8121
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8219
+ ...(inst.RmtInf?.Ustrd && {
8220
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8221
+ }),
8122
8222
  };
8123
8223
  });
8124
8224
  return {
@@ -8166,7 +8266,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8166
8266
  paymentInformationId;
8167
8267
  formattedPaymentSum;
8168
8268
  constructor(config) {
8169
- super({ type: "rtp" });
8269
+ super({ type: 'rtp' });
8170
8270
  this.initiatingParty = config.initiatingParty;
8171
8271
  this.paymentInstructions = config.paymentInstructions;
8172
8272
  this.messageId = config.messageId || v4().replace(/-/g, '');
@@ -8184,9 +8284,11 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8184
8284
  */
8185
8285
  sumPaymentInstructions(instructions) {
8186
8286
  const instructionDineros = instructions.map(instruction => Dinero({ amount: instruction.amount, currency: instruction.currency }));
8187
- return instructionDineros.reduce((acc, next) => {
8287
+ return instructionDineros
8288
+ .reduce((acc, next) => {
8188
8289
  return acc.add(next);
8189
- }, Dinero({ amount: 0, currency: instructions[0].currency })).toFormat('0.00');
8290
+ }, Dinero({ amount: 0, currency: instructions[0].currency }))
8291
+ .toFormat('0.00');
8190
8292
  }
8191
8293
  /**
8192
8294
  * Validates the payment initiation data according to SEPA requirements.
@@ -8208,7 +8310,10 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8208
8310
  creditTransfer(instruction) {
8209
8311
  const paymentInstructionId = sanitize(instruction.id || v4(), 35);
8210
8312
  const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
8211
- const dinero = Dinero({ amount: instruction.amount, currency: instruction.currency });
8313
+ const dinero = Dinero({
8314
+ amount: instruction.amount,
8315
+ currency: instruction.currency,
8316
+ });
8212
8317
  return {
8213
8318
  PmtId: {
8214
8319
  InstrId: paymentInstructionId,
@@ -8229,9 +8334,11 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8229
8334
  },
8230
8335
  },
8231
8336
  },
8232
- RmtInf: instruction.remittanceInformation ? {
8233
- Ustrd: instruction.remittanceInformation,
8234
- } : undefined,
8337
+ RmtInf: instruction.remittanceInformation
8338
+ ? {
8339
+ Ustrd: instruction.remittanceInformation,
8340
+ }
8341
+ : undefined,
8235
8342
  };
8236
8343
  }
8237
8344
  /**
@@ -8243,7 +8350,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8243
8350
  const xml = {
8244
8351
  '?xml': {
8245
8352
  '@version': '1.0',
8246
- '@encoding': 'UTF-8'
8353
+ '@encoding': 'UTF-8',
8247
8354
  },
8248
8355
  Document: {
8249
8356
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
@@ -8272,7 +8379,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8272
8379
  CtrlSum: this.formattedPaymentSum,
8273
8380
  PmtTpInf: {
8274
8381
  SvcLvl: { Cd: 'URNS' },
8275
- LclInstrm: { Prtry: "RTP" },
8382
+ LclInstrm: { Prtry: 'RTP' },
8276
8383
  },
8277
8384
  ReqdExctnDt: this.creationDate.toISOString().split('T').at(0),
8278
8385
  Dbtr: this.party(this.initiatingParty),
@@ -8281,8 +8388,8 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8281
8388
  ChrgBr: 'SLEV',
8282
8389
  // payments[]
8283
8390
  CdtTrfTxInf: this.paymentInstructions.map(p => this.creditTransfer(p)),
8284
- }
8285
- }
8391
+ },
8392
+ },
8286
8393
  },
8287
8394
  };
8288
8395
  return builder.build(xml);
@@ -8291,9 +8398,10 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8291
8398
  const parser = new fxp.XMLParser({ ignoreAttributes: false });
8292
8399
  const xml = parser.parse(rawXml);
8293
8400
  if (!xml.Document) {
8294
- throw new InvalidXmlError("Invalid XML format");
8401
+ throw new InvalidXmlError('Invalid XML format');
8295
8402
  }
8296
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8403
+ const namespace = (xml.Document['@_xmlns'] ||
8404
+ xml.Document['@_Xmlns']);
8297
8405
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8298
8406
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8299
8407
  }
@@ -8304,19 +8412,27 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8304
8412
  }
8305
8413
  // Assuming we have one PmtInf / one Debtor, we can hack together this information from InitgPty / Dbtr
8306
8414
  const initiatingParty = {
8307
- name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm || xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
8308
- 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,
8309
8419
  agent: parseAgent(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt),
8310
- account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct)
8420
+ account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct),
8311
8421
  };
8312
- 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];
8313
8425
  const paymentInstructions = rawInstructions.map((inst) => {
8314
8426
  const currency = inst.Amt.InstdAmt['@_Ccy'];
8315
8427
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8316
8428
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8317
8429
  return {
8318
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8319
- ...(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
+ }),
8320
8436
  type: 'sepa',
8321
8437
  direction: 'credit',
8322
8438
  amount: amount,
@@ -8325,25 +8441,46 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
8325
8441
  name: inst.Cdtr?.Nm,
8326
8442
  agent: parseAgent(inst.CdtrAgt),
8327
8443
  account: parseAccount(inst.CdtrAcct),
8328
- ...((rawPostalAddress && (rawPostalAddress.StreetName || rawPostalAddress.BldgNb || rawPostalAddress.PstlCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8329
- address: {
8330
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8331
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8332
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8333
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8334
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8335
- ...(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
+ },
8336
8471
  }
8337
- } : {}),
8472
+ : {}),
8338
8473
  },
8339
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8474
+ ...(inst.RmtInf?.Ustrd && {
8475
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8476
+ }),
8340
8477
  };
8341
8478
  });
8342
8479
  return new RTPCreditPaymentInitiation({
8343
8480
  messageId: messageId,
8344
8481
  creationDate: creationDate,
8345
8482
  initiatingParty: initiatingParty,
8346
- paymentInstructions: paymentInstructions
8483
+ paymentInstructions: paymentInstructions,
8347
8484
  });
8348
8485
  }
8349
8486
  }
@@ -8378,14 +8515,14 @@ const ACHLocalInstrumentCode = {
8378
8515
  RepresentedCheck: 'RCK',
8379
8516
  };
8380
8517
  const ACHLocalInstrumentCodeDescriptionMap = {
8381
- 'CCD': 'Corporate Credit or Debit',
8382
- 'PPD': 'Prearranged Payment and Deposit',
8383
- 'WEB': 'Internet-Initiated Entry',
8384
- 'TEL': 'Telephone-Initiated Entry',
8385
- 'POP': 'Point-of-Purchase Entry',
8386
- 'ARC': 'Accounts Receivable Entry',
8387
- 'BOC': 'Back Office Conversion',
8388
- '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',
8389
8526
  };
8390
8527
 
8391
8528
  /**
@@ -8444,13 +8581,14 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8444
8581
  instructionPriority;
8445
8582
  formattedPaymentSum;
8446
8583
  constructor(config) {
8447
- super({ type: "ach" });
8584
+ super({ type: 'ach' });
8448
8585
  this.initiatingParty = config.initiatingParty;
8449
8586
  this.paymentInstructions = config.paymentInstructions;
8450
8587
  this.messageId = config.messageId || v4().replace(/-/g, '');
8451
8588
  this.creationDate = config.creationDate || new Date();
8452
8589
  this.paymentInformationId = sanitize(v4(), 35);
8453
- this.localInstrument = config.localInstrument || ACHLocalInstrumentCode.CorporateCreditDebit;
8590
+ this.localInstrument =
8591
+ config.localInstrument || ACHLocalInstrumentCode.CorporateCreditDebit;
8454
8592
  this.serviceLevel = 'NURG'; // Normal Urgency
8455
8593
  this.instructionPriority = 'NORM'; // Normal Priority
8456
8594
  this.formattedPaymentSum = this.sumPaymentInstructions(this.paymentInstructions);
@@ -8465,9 +8603,11 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8465
8603
  */
8466
8604
  sumPaymentInstructions(instructions) {
8467
8605
  const instructionDineros = instructions.map(instruction => Dinero({ amount: instruction.amount, currency: instruction.currency }));
8468
- return instructionDineros.reduce((acc, next) => {
8606
+ return instructionDineros
8607
+ .reduce((acc, next) => {
8469
8608
  return acc.add(next);
8470
- }, Dinero({ amount: 0, currency: instructions[0].currency })).toFormat('0.00');
8609
+ }, Dinero({ amount: 0, currency: instructions[0].currency }))
8610
+ .toFormat('0.00');
8471
8611
  }
8472
8612
  /**
8473
8613
  * Validates the payment initiation data according to ACH requirements.
@@ -8495,7 +8635,10 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8495
8635
  creditTransfer(instruction) {
8496
8636
  const paymentInstructionId = sanitize(instruction.id || v4(), 35);
8497
8637
  const endToEndId = sanitize(instruction.endToEndId || instruction.id || v4(), 35);
8498
- const dinero = Dinero({ amount: instruction.amount, currency: instruction.currency });
8638
+ const dinero = Dinero({
8639
+ amount: instruction.amount,
8640
+ currency: instruction.currency,
8641
+ });
8499
8642
  return {
8500
8643
  PmtId: {
8501
8644
  InstrId: paymentInstructionId,
@@ -8520,9 +8663,11 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8520
8663
  },
8521
8664
  Ccy: instruction.currency,
8522
8665
  },
8523
- RmtInf: instruction.remittanceInformation ? {
8524
- Ustrd: instruction.remittanceInformation,
8525
- } : undefined,
8666
+ RmtInf: instruction.remittanceInformation
8667
+ ? {
8668
+ Ustrd: instruction.remittanceInformation,
8669
+ }
8670
+ : undefined,
8526
8671
  };
8527
8672
  }
8528
8673
  /**
@@ -8534,7 +8679,7 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8534
8679
  const xml = {
8535
8680
  '?xml': {
8536
8681
  '@version': '1.0',
8537
- '@encoding': 'UTF-8'
8682
+ '@encoding': 'UTF-8',
8538
8683
  },
8539
8684
  Document: {
8540
8685
  '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03',
@@ -8572,8 +8717,8 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8572
8717
  ChrgBr: 'SHAR',
8573
8718
  // payments[]
8574
8719
  CdtTrfTxInf: this.paymentInstructions.map(p => this.creditTransfer(p)),
8575
- }
8576
- }
8720
+ },
8721
+ },
8577
8722
  },
8578
8723
  };
8579
8724
  return builder.build(xml);
@@ -8587,12 +8732,17 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8587
8732
  * @throws {Error} If multiple payment information blocks are found.
8588
8733
  */
8589
8734
  static fromXML(rawXml) {
8590
- 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
+ });
8591
8740
  const xml = parser.parse(rawXml);
8592
8741
  if (!xml.Document) {
8593
- throw new InvalidXmlError("Invalid XML format");
8742
+ throw new InvalidXmlError('Invalid XML format');
8594
8743
  }
8595
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
8744
+ const namespace = (xml.Document['@_xmlns'] ||
8745
+ xml.Document['@_Xmlns']);
8596
8746
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03')) {
8597
8747
  throw new InvalidXmlNamespaceError('Invalid PAIN.001 namespace');
8598
8748
  }
@@ -8605,19 +8755,27 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8605
8755
  xml.Document.CstmrCdtTrfInitn.PmtInf.PmtTpInf;
8606
8756
  // Assuming we have one PmtInf / one Debtor, we can hack together this information from InitgPty / Dbtr
8607
8757
  const initiatingParty = {
8608
- name: xml.Document.CstmrCdtTrfInitn.GrpHdr.InitgPty.Nm || xml.Document.CstmrCdtTrfInitn.PmtInf.Dbtr.Nm,
8609
- 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,
8610
8762
  agent: parseAgent(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAgt),
8611
- account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct)
8763
+ account: parseAccount(xml.Document.CstmrCdtTrfInitn.PmtInf.DbtrAcct),
8612
8764
  };
8613
- 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];
8614
8768
  const paymentInstructions = rawInstructions.map((inst) => {
8615
8769
  const currency = inst.Amt.InstdAmt['@_Ccy'];
8616
8770
  const amount = parseAmountToMinorUnits(Number(inst.Amt.InstdAmt['#text']), currency);
8617
8771
  const rawPostalAddress = inst.Cdtr.PstlAdr;
8618
8772
  return {
8619
- ...(inst.PmtId.InstrId && { id: inst.PmtId.InstrId.toString() }),
8620
- ...(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
+ }),
8621
8779
  type: 'ach',
8622
8780
  direction: 'credit',
8623
8781
  amount: amount,
@@ -8626,41 +8784,458 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
8626
8784
  name: inst.Cdtr?.Nm,
8627
8785
  agent: parseAgent(inst.CdtrAgt),
8628
8786
  account: parseAccount(inst.CdtrAcct),
8629
- ...((rawPostalAddress && (rawPostalAddress.StrtNm || rawPostalAddress.BldgNb || rawPostalAddress.PstCd || rawPostalAddress.TwnNm || rawPostalAddress.Ctry)) ? {
8630
- address: {
8631
- ...(rawPostalAddress.StrtNm && { streetName: rawPostalAddress.StrtNm.toString() }),
8632
- ...(rawPostalAddress.BldgNb && { buildingNumber: rawPostalAddress.BldgNb.toString() }),
8633
- ...(rawPostalAddress.TwnNm && { townName: rawPostalAddress.TwnNm.toString() }),
8634
- ...(rawPostalAddress.CtrySubDvsn && { countrySubDivision: rawPostalAddress.CtrySubDvsn.toString() }),
8635
- ...(rawPostalAddress.PstCd && { postalCode: rawPostalAddress.PstCd.toString() }),
8636
- ...(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
+ },
8637
8814
  }
8638
- } : {}),
8815
+ : {}),
8639
8816
  },
8640
- ...(inst.RmtInf?.Ustrd && { remittanceInformation: inst.RmtInf.Ustrd.toString() })
8817
+ ...(inst.RmtInf?.Ustrd && {
8818
+ remittanceInformation: inst.RmtInf.Ustrd.toString(),
8819
+ }),
8641
8820
  };
8642
8821
  });
8643
8822
  return new ACHCreditPaymentInitiation({
8644
8823
  messageId: messageId,
8645
8824
  creationDate: creationDate,
8646
8825
  initiatingParty: initiatingParty,
8647
- 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,
8648
9223
  });
8649
9224
  }
8650
9225
  }
8651
9226
 
8652
9227
  const ISO20022Messages = {
8653
- CAMT_003: "CAMT.003",
8654
- CAMT_004: "CAMT.004",
8655
- CAMT_005: "CAMT.005",
8656
- CAMT_006: "CAMT.006",
8657
- CAMT_053: "CAMT.053",
8658
- PAIN_001: "PAIN.001",
8659
- 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',
8660
9235
  };
8661
9236
  const ISO20022Implementations = new Map();
8662
9237
  function registerISO20022Implementation(cl) {
8663
- cl.supportedMessages().forEach((msg) => {
9238
+ cl.supportedMessages().forEach(msg => {
8664
9239
  ISO20022Implementations.set(msg, cl);
8665
9240
  });
8666
9241
  }
@@ -8716,12 +9291,12 @@ class CashManagementGetAccount {
8716
9291
  static fromDocumentOject(doc) {
8717
9292
  const rawHeader = doc.Document?.GetAcct?.MsgHdr;
8718
9293
  if (!rawHeader) {
8719
- throw new InvalidStructureError("Invalid CAMT.003 document: missing MsgHdr");
9294
+ throw new InvalidStructureError('Invalid CAMT.003 document: missing MsgHdr');
8720
9295
  }
8721
9296
  const header = parseMessageHeader(rawHeader);
8722
9297
  const newCrit = doc.Document?.GetAcct?.AcctQryDef?.AcctCrit?.NewCrit;
8723
9298
  if (!newCrit) {
8724
- 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');
8725
9300
  }
8726
9301
  const name = newCrit.NewQryNm;
8727
9302
  let searchCriteria = [];
@@ -8731,16 +9306,19 @@ class CashManagementGetAccount {
8731
9306
  }
8732
9307
  rawCriterias = rawCriterias.filter((c) => !!c);
8733
9308
  if (rawCriterias.length === 0) {
8734
- throw new InvalidStructureError("Invalid CAMT.003 document: missing search criteria");
9309
+ throw new InvalidStructureError('Invalid CAMT.003 document: missing search criteria');
8735
9310
  }
8736
9311
  for (const rawCriterium of rawCriterias) {
8737
9312
  const crit = {};
8738
9313
  // search on Ids, only one criterium supported for now
8739
9314
  if (rawCriterium.AcctId) {
8740
- if (Array.isArray(rawCriterium.AcctId) && rawCriterium.AcctId.length > 1) {
8741
- 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');
8742
9318
  }
8743
- 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;
8744
9322
  if (acctId.CTTxt) {
8745
9323
  crit.accountRegExp = `.*${acctId.CTTxt}.*`; // contains
8746
9324
  }
@@ -8754,19 +9332,23 @@ class CashManagementGetAccount {
8754
9332
  // search on currency
8755
9333
  if (rawCriterium.Ccy) {
8756
9334
  if (Array.isArray(rawCriterium.Ccy) && rawCriterium.Ccy.length > 1) {
8757
- 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');
8758
9336
  }
8759
- 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;
8760
9340
  crit.currencyEqualTo = ccy;
8761
9341
  }
8762
9342
  // search on balance as of date
8763
9343
  if (rawCriterium.Bal) {
8764
9344
  if (Array.isArray(rawCriterium.Bal) && rawCriterium.Bal.length > 1) {
8765
- 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');
8766
9346
  }
8767
- 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;
8768
9350
  if (bal?.ValDt && Array.isArray(bal.ValDt) && bal.ValDt.length > 1) {
8769
- 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');
8770
9352
  }
8771
9353
  const valDt = Array.isArray(bal?.ValDt) ? bal.ValDt[0] : bal?.ValDt;
8772
9354
  if (valDt?.Dt?.EQDt) {
@@ -8787,9 +9369,10 @@ class CashManagementGetAccount {
8787
9369
  const parser = XML.getParser();
8788
9370
  const doc = parser.parse(xml);
8789
9371
  if (!doc.Document) {
8790
- throw new Error("Invalid XML format");
9372
+ throw new Error('Invalid XML format');
8791
9373
  }
8792
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
9374
+ const namespace = (doc.Document['@_xmlns'] ||
9375
+ doc.Document['@_Xmlns']);
8793
9376
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.003.001.')) {
8794
9377
  throw new InvalidXmlNamespaceError('Invalid CAMT.003 namespace');
8795
9378
  }
@@ -8798,7 +9381,7 @@ class CashManagementGetAccount {
8798
9381
  static fromJSON(json) {
8799
9382
  const obj = JSON.parse(json);
8800
9383
  if (!obj.Document) {
8801
- throw new Error("Invalid JSON format");
9384
+ throw new Error('Invalid JSON format');
8802
9385
  }
8803
9386
  return CashManagementGetAccount.fromDocumentOject(obj);
8804
9387
  }
@@ -8818,39 +9401,55 @@ class CashManagementGetAccount {
8818
9401
  AcctCrit: {
8819
9402
  NewCrit: {
8820
9403
  NewQryNm: this._data.newCriteria?.name,
8821
- SchCrit: this._data.newCriteria?.searchCriteria.map((c) => {
9404
+ SchCrit: this._data.newCriteria?.searchCriteria.map(c => {
8822
9405
  const obj = {};
8823
9406
  if (c.accountRegExp) {
8824
- if (c.accountRegExp.startsWith('.*') && c.accountRegExp.endsWith('.*')) {
8825
- 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
8826
9414
  }
8827
- else if (c.accountRegExp.startsWith('^((?!') && c.accountRegExp.endsWith(').)*$')) {
8828
- 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
8829
9422
  }
8830
9423
  }
8831
9424
  else if (c.accountEqualTo) {
8832
9425
  obj.AcctId = {
8833
- EQ: exportAccountIdentification(c.accountEqualTo)
9426
+ EQ: exportAccountIdentification(c.accountEqualTo),
8834
9427
  };
8835
9428
  }
8836
9429
  if (c.currencyEqualTo) {
8837
9430
  obj.Ccy = [c.currencyEqualTo];
8838
9431
  }
8839
9432
  if (c.balanceAsOfDateEqualTo) {
8840
- obj.Bal = [{
8841
- ValDt: [{
9433
+ obj.Bal = [
9434
+ {
9435
+ ValDt: [
9436
+ {
8842
9437
  Dt: {
8843
- EQDt: c.balanceAsOfDateEqualTo.toISOString().slice(0, 10)
8844
- }
8845
- }]
8846
- }];
9438
+ EQDt: c.balanceAsOfDateEqualTo
9439
+ .toISOString()
9440
+ .slice(0, 10),
9441
+ },
9442
+ },
9443
+ ],
9444
+ },
9445
+ ];
8847
9446
  }
8848
9447
  return obj;
8849
9448
  }),
8850
- }
8851
- }
8852
- }
8853
- }
9449
+ },
9450
+ },
9451
+ },
9452
+ },
8854
9453
  };
8855
9454
  return { Document };
8856
9455
  }
@@ -8950,10 +9549,10 @@ const exportStatement = (stmt) => {
8950
9549
  },
8951
9550
  Acct: {
8952
9551
  ...exportAccount(stmt.account),
8953
- Svcr: exportAgent(stmt.agent)
9552
+ Svcr: exportAgent(stmt.agent),
8954
9553
  },
8955
- Bal: stmt.balances.map((bal) => exportBalance(bal)),
8956
- Ntry: stmt.entries.map((entry) => exportEntry(entry)),
9554
+ Bal: stmt.balances.map(bal => exportBalance(bal)),
9555
+ Ntry: stmt.entries.map(entry => exportEntry(entry)),
8957
9556
  };
8958
9557
  return obj;
8959
9558
  };
@@ -9077,7 +9676,9 @@ const exportEntry = (entry) => {
9077
9676
  BkTxCd: exportBankTransactionCode(entry.bankTransactionCode, entry.proprietaryCode),
9078
9677
  AddtlNtryInf: entry.additionalInformation,
9079
9678
  AcctSvcrRef: entry.accountServicerReferenceId,
9080
- NtryDtls: entry.transactions.map((tx) => ({ TxDtls: exportTransactionDetails(tx) }))
9679
+ NtryDtls: entry.transactions.map(tx => ({
9680
+ TxDtls: exportTransactionDetails(tx),
9681
+ })),
9081
9682
  };
9082
9683
  return obj;
9083
9684
  };
@@ -9170,7 +9771,9 @@ const exportTransactionDetails = (tx) => {
9170
9771
  Dbtr: {
9171
9772
  Nm: tx.debtor.name,
9172
9773
  },
9173
- DbtrAcct: tx.debtor.account ? exportAccount(tx.debtor.account) : undefined,
9774
+ DbtrAcct: tx.debtor.account
9775
+ ? exportAccount(tx.debtor.account)
9776
+ : undefined,
9174
9777
  };
9175
9778
  obj.RltdAgts = {
9176
9779
  DbtrAgt: tx.debtor.agent ? exportAgent(tx.debtor.agent) : undefined,
@@ -9182,7 +9785,9 @@ const exportTransactionDetails = (tx) => {
9182
9785
  Cdtr: {
9183
9786
  Nm: tx.creditor.name,
9184
9787
  },
9185
- CdtrAcct: tx.creditor.account ? exportAccount(tx.creditor.account) : undefined,
9788
+ CdtrAcct: tx.creditor.account
9789
+ ? exportAccount(tx.creditor.account)
9790
+ : undefined,
9186
9791
  };
9187
9792
  obj.RltdAgts = {
9188
9793
  CdtrAgt: tx.creditor.agent ? exportAgent(tx.creditor.agent) : undefined,
@@ -9227,7 +9832,7 @@ const exportBankTransactionCode = (bankTransactionCode, proprietaryCode) => {
9227
9832
  return obj;
9228
9833
  };
9229
9834
  const parseBusinessError = (bizErr) => {
9230
- const code = bizErr.Err?.Cd || bizErr.Err?.Prtry || "UKNW";
9835
+ const code = bizErr.Err?.Cd || bizErr.Err?.Prtry || 'UKNW';
9231
9836
  const description = bizErr.Desc;
9232
9837
  return {
9233
9838
  code,
@@ -9258,7 +9863,7 @@ class CashManagementReturnAccount {
9258
9863
  static fromDocumentOject(doc) {
9259
9864
  const rawHeader = doc.Document?.RtrAcct?.MsgHdr;
9260
9865
  if (!rawHeader) {
9261
- throw new InvalidStructureError("Invalid CAMT.004 document: missing MsgHdr");
9866
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing MsgHdr');
9262
9867
  }
9263
9868
  const header = parseMessageHeader(rawHeader);
9264
9869
  // interpret the report
@@ -9273,7 +9878,7 @@ class CashManagementReturnAccount {
9273
9878
  if (r.AcctOrErr?.Acct) {
9274
9879
  // report
9275
9880
  if (!r.AcctOrErr.Acct.Ccy) {
9276
- throw new InvalidStructureError("Invalid CAMT.004 document: missing Ccy in Acct");
9881
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing Ccy in Acct');
9277
9882
  }
9278
9883
  let rawMulBal = r.AcctOrErr.Acct.MulBal;
9279
9884
  if (!Array.isArray(rawMulBal))
@@ -9286,7 +9891,7 @@ class CashManagementReturnAccount {
9286
9891
  balances: rawMulBal.map((bal) => parseBalanceReport(r.AcctOrErr.Acct.Ccy, bal)),
9287
9892
  };
9288
9893
  if (report.balances.length === 0) {
9289
- throw new InvalidStructureError("Invalid CAMT.004 document: missing MulBal in Acct");
9894
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing MulBal in Acct');
9290
9895
  }
9291
9896
  }
9292
9897
  else if (r.AcctOrErr?.BizErr) {
@@ -9294,7 +9899,7 @@ class CashManagementReturnAccount {
9294
9899
  error = parseBusinessError(r.AcctOrErr.BizErr);
9295
9900
  }
9296
9901
  else {
9297
- throw new InvalidStructureError("Invalid CAMT.004 document: missing AcctOrErr");
9902
+ throw new InvalidStructureError('Invalid CAMT.004 document: missing AcctOrErr');
9298
9903
  }
9299
9904
  return { accountId, report, error };
9300
9905
  });
@@ -9307,9 +9912,10 @@ class CashManagementReturnAccount {
9307
9912
  const parser = XML.getParser();
9308
9913
  const doc = parser.parse(xml);
9309
9914
  if (!doc.Document) {
9310
- throw new Error("Invalid XML format");
9915
+ throw new Error('Invalid XML format');
9311
9916
  }
9312
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
9917
+ const namespace = (doc.Document['@_xmlns'] ||
9918
+ doc.Document['@_Xmlns']);
9313
9919
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.004.001.')) {
9314
9920
  throw new InvalidXmlNamespaceError('Invalid CAMT.004 namespace');
9315
9921
  }
@@ -9318,7 +9924,7 @@ class CashManagementReturnAccount {
9318
9924
  static fromJSON(json) {
9319
9925
  const obj = JSON.parse(json);
9320
9926
  if (!obj.Document) {
9321
- throw new Error("Invalid JSON format");
9927
+ throw new Error('Invalid JSON format');
9322
9928
  }
9323
9929
  return CashManagementReturnAccount.fromDocumentOject(obj);
9324
9930
  }
@@ -9335,7 +9941,7 @@ class CashManagementReturnAccount {
9335
9941
  RtrAcct: {
9336
9942
  MsgHdr: exportMessageHeader(this._data.header),
9337
9943
  RptOrErr: {
9338
- AcctRpt: this._data.reports.map((report) => {
9944
+ AcctRpt: this._data.reports.map(report => {
9339
9945
  const obj = {
9340
9946
  AcctId: exportAccountIdentification(report.accountId),
9341
9947
  AcctOrErr: {}, // filled below
@@ -9345,16 +9951,16 @@ class CashManagementReturnAccount {
9345
9951
  Ccy: report.report.currency,
9346
9952
  Nm: report.report.name,
9347
9953
  Tp: { Cd: report.report.type }, // TODO add Prtry handling
9348
- MulBal: report.report.balances.map((bal) => exportBalanceReport(report.report.currency, bal)),
9954
+ MulBal: report.report.balances.map(bal => exportBalanceReport(report.report.currency, bal)),
9349
9955
  };
9350
9956
  }
9351
9957
  else if (report.error) {
9352
9958
  obj.AcctOrErr.BizErr = exportBusinessError(report.error);
9353
9959
  }
9354
9960
  return obj;
9355
- })
9356
- }
9357
- }
9961
+ }),
9962
+ },
9963
+ },
9358
9964
  };
9359
9965
  return { Document };
9360
9966
  }
@@ -9375,12 +9981,12 @@ class CashManagementGetTransaction {
9375
9981
  static fromDocumentOject(doc) {
9376
9982
  const rawHeader = doc.Document?.GetTx?.MsgHdr;
9377
9983
  if (!rawHeader) {
9378
- throw new InvalidStructureError("Invalid CAMT.005 document: missing MsgHdr");
9984
+ throw new InvalidStructureError('Invalid CAMT.005 document: missing MsgHdr');
9379
9985
  }
9380
9986
  const header = parseMessageHeader(rawHeader);
9381
9987
  const newCrit = doc.Document?.GetTx?.TxQryDef?.TxCrit?.NewCrit;
9382
9988
  if (!newCrit) {
9383
- 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');
9384
9990
  }
9385
9991
  const name = newCrit.NewQryNm;
9386
9992
  let searchCriteria = [];
@@ -9390,35 +9996,42 @@ class CashManagementGetTransaction {
9390
9996
  }
9391
9997
  rawCriterias = rawCriterias.filter((c) => !!c);
9392
9998
  if (rawCriterias.length === 0) {
9393
- throw new InvalidStructureError("Invalid CAMT.005 document: missing search criteria");
9999
+ throw new InvalidStructureError('Invalid CAMT.005 document: missing search criteria');
9394
10000
  }
9395
10001
  for (const rawCriterium of rawCriterias) {
9396
10002
  // search on Ids
9397
10003
  if (rawCriterium.PmtSch.MsgId) {
9398
10004
  searchCriteria.push({
9399
- type: "PmtSch.MsgId",
9400
- 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],
9401
10009
  });
9402
10010
  }
9403
10011
  // seach on date
9404
10012
  if (rawCriterium.PmtSch.ReqdExctnDt) {
9405
- if (Array.isArray(rawCriterium.PmtSch.ReqdExctnDt) && rawCriterium.PmtSch.ReqdExctnDt.length > 1) {
9406
- 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');
9407
10016
  }
9408
- 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;
9409
10020
  if (criterium?.DtSch?.EQDt) {
9410
10021
  searchCriteria.push({
9411
- type: "PmtSch.ReqdExctnDt",
10022
+ type: 'PmtSch.ReqdExctnDt',
9412
10023
  dateEqualTo: parseDate(criterium.DtSch.EQDt),
9413
10024
  });
9414
10025
  }
9415
10026
  }
9416
- let pmtIds = Array.isArray(rawCriterium.PmtSch.PmtId) ? rawCriterium.PmtSch.PmtId : [rawCriterium.PmtSch.PmtId];
9417
- 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);
9418
10031
  if (pmtIds.length > 0) {
9419
10032
  searchCriteria.push({
9420
- type: "PmtSch.PmtId.LngBizId.EndToEndId",
9421
- endToEndIdEqualTo: pmtIds.map((id) => id.LngBizId.EndToEndId),
10033
+ type: 'PmtSch.PmtId.LngBizId.EndToEndId',
10034
+ endToEndIdEqualTo: pmtIds.map(id => id.LngBizId.EndToEndId),
9422
10035
  });
9423
10036
  }
9424
10037
  }
@@ -9434,9 +10047,10 @@ class CashManagementGetTransaction {
9434
10047
  const parser = XML.getParser();
9435
10048
  const doc = parser.parse(xml);
9436
10049
  if (!doc.Document) {
9437
- throw new Error("Invalid XML format");
10050
+ throw new Error('Invalid XML format');
9438
10051
  }
9439
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
10052
+ const namespace = (doc.Document['@_xmlns'] ||
10053
+ doc.Document['@_Xmlns']);
9440
10054
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.005.001.')) {
9441
10055
  throw new InvalidXmlNamespaceError('Invalid CAMT.005 namespace');
9442
10056
  }
@@ -9445,7 +10059,7 @@ class CashManagementGetTransaction {
9445
10059
  static fromJSON(json) {
9446
10060
  const obj = JSON.parse(json);
9447
10061
  if (!obj.Document) {
9448
- throw new Error("Invalid JSON format");
10062
+ throw new Error('Invalid JSON format');
9449
10063
  }
9450
10064
  return CashManagementGetTransaction.fromDocumentOject(obj);
9451
10065
  }
@@ -9465,37 +10079,38 @@ class CashManagementGetTransaction {
9465
10079
  TxCrit: {
9466
10080
  NewCrit: {
9467
10081
  NewQryNm: this._data.newCriteria?.name,
9468
- SchCrit: this._data.newCriteria?.searchCriteria.map((c) => {
10082
+ SchCrit: this._data.newCriteria?.searchCriteria.map(c => {
9469
10083
  const obj = {};
9470
- if (c.type === "PmtSch.MsgId" && c.msgIdsEqualTo) {
10084
+ if (c.type === 'PmtSch.MsgId' && c.msgIdsEqualTo) {
9471
10085
  obj.PmtSch = {
9472
- MsgId: c.msgIdsEqualTo
10086
+ MsgId: c.msgIdsEqualTo,
9473
10087
  };
9474
10088
  }
9475
- if (c.type === "PmtSch.ReqdExctnDt" && c.dateEqualTo) {
10089
+ if (c.type === 'PmtSch.ReqdExctnDt' && c.dateEqualTo) {
9476
10090
  obj.PmtSch = {
9477
10091
  ReqdExctnDt: {
9478
10092
  DtSch: {
9479
10093
  EQDt: c.dateEqualTo.toISOString().slice(0, 10),
9480
- }
9481
- }
10094
+ },
10095
+ },
9482
10096
  };
9483
10097
  }
9484
- if (c.type === "PmtSch.PmtId.LngBizId.EndToEndId" && c.endToEndIdEqualTo) {
10098
+ if (c.type === 'PmtSch.PmtId.LngBizId.EndToEndId' &&
10099
+ c.endToEndIdEqualTo) {
9485
10100
  obj.PmtSch = {
9486
- PmtId: c.endToEndIdEqualTo.map((id) => ({
10101
+ PmtId: c.endToEndIdEqualTo.map(id => ({
9487
10102
  LngBizId: {
9488
10103
  EndToEndId: id,
9489
- }
9490
- }))
10104
+ },
10105
+ })),
9491
10106
  };
9492
10107
  }
9493
10108
  return obj;
9494
10109
  }),
9495
- }
9496
- }
9497
- }
9498
- }
10110
+ },
10111
+ },
10112
+ },
10113
+ },
9499
10114
  };
9500
10115
  return { Document };
9501
10116
  }
@@ -9516,7 +10131,7 @@ class CashManagementReturnTransaction {
9516
10131
  static fromDocumentOject(doc) {
9517
10132
  const rawHeader = doc.Document?.RtrTx?.MsgHdr;
9518
10133
  if (!rawHeader) {
9519
- throw new InvalidStructureError("Invalid CAMT.006 document: missing MsgHdr");
10134
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing MsgHdr');
9520
10135
  }
9521
10136
  const header = parseMessageHeader(rawHeader);
9522
10137
  // interpret the report
@@ -9525,7 +10140,8 @@ class CashManagementReturnTransaction {
9525
10140
  rawReports = [rawReports];
9526
10141
  rawReports = rawReports.filter((r) => !!r); // remove null/undefined
9527
10142
  const reports = rawReports.map((r) => {
9528
- 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
9529
10145
  const paymentId = {
9530
10146
  currency: r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Ccy,
9531
10147
  amount: parseAmountToMinorUnits(rawAmount, r.PmtId?.LngBizId?.IntrBkSttlmAmt?.Ccy),
@@ -9535,20 +10151,24 @@ class CashManagementReturnTransaction {
9535
10151
  };
9536
10152
  // check required fields
9537
10153
  if (!paymentId.currency) {
9538
- 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');
9539
10155
  }
9540
- if (paymentId.amount === undefined || paymentId.amount === null || isNaN(paymentId.amount)) {
9541
- 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');
9542
10160
  }
9543
10161
  if (!paymentId.endToEndId) {
9544
- 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');
9545
10163
  }
9546
10164
  let report = undefined;
9547
10165
  let error = undefined;
9548
10166
  if (r.TxOrErr?.Tx) {
9549
10167
  // report
9550
10168
  const msgId = r.TxOrErr.Tx.Pmt?.MsgId;
9551
- 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;
9552
10172
  const status = ((sts) => {
9553
10173
  if (!sts)
9554
10174
  return undefined;
@@ -9556,9 +10176,13 @@ class CashManagementReturnTransaction {
9556
10176
  return undefined;
9557
10177
  if (Array.isArray(sts))
9558
10178
  sts = sts[0]; // take the first one only
9559
- 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;
9560
10184
  if (code)
9561
- 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
9562
10186
  else
9563
10187
  return undefined;
9564
10188
  const reason = sts.Rsn?.Prtry;
@@ -9573,7 +10197,7 @@ class CashManagementReturnTransaction {
9573
10197
  }
9574
10198
  function parseAgent(agent) {
9575
10199
  if (!agent)
9576
- return { bic: "" };
10200
+ return { bic: '' };
9577
10201
  return { bic: agent?.FinInstnId?.BICFI };
9578
10202
  }
9579
10203
  report = {
@@ -9587,10 +10211,10 @@ class CashManagementReturnTransaction {
9587
10211
  };
9588
10212
  // check the debtor and creditor required fields
9589
10213
  if (!report.debtor.id) {
9590
- 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');
9591
10215
  }
9592
10216
  if (!report.creditor.id) {
9593
- 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');
9594
10218
  }
9595
10219
  }
9596
10220
  else if (r.TxOrErr?.BizErr) {
@@ -9598,7 +10222,7 @@ class CashManagementReturnTransaction {
9598
10222
  error = parseBusinessError(r.TxOrErr.BizErr);
9599
10223
  }
9600
10224
  else {
9601
- throw new InvalidStructureError("Invalid CAMT.006 document: missing TxOrErr");
10225
+ throw new InvalidStructureError('Invalid CAMT.006 document: missing TxOrErr');
9602
10226
  }
9603
10227
  return { paymentId, report, error };
9604
10228
  });
@@ -9611,9 +10235,10 @@ class CashManagementReturnTransaction {
9611
10235
  const parser = XML.getParser();
9612
10236
  const doc = parser.parse(xml);
9613
10237
  if (!doc.Document) {
9614
- throw new Error("Invalid XML format");
10238
+ throw new Error('Invalid XML format');
9615
10239
  }
9616
- const namespace = (doc.Document['@_xmlns'] || doc.Document['@_Xmlns']);
10240
+ const namespace = (doc.Document['@_xmlns'] ||
10241
+ doc.Document['@_Xmlns']);
9617
10242
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.004.001.')) {
9618
10243
  throw new InvalidXmlNamespaceError('Invalid CAMT.004 namespace');
9619
10244
  }
@@ -9622,7 +10247,7 @@ class CashManagementReturnTransaction {
9622
10247
  static fromJSON(json) {
9623
10248
  const obj = JSON.parse(json);
9624
10249
  if (!obj.Document) {
9625
- throw new Error("Invalid JSON format");
10250
+ throw new Error('Invalid JSON format');
9626
10251
  }
9627
10252
  return CashManagementReturnTransaction.fromDocumentOject(obj);
9628
10253
  }
@@ -9640,7 +10265,7 @@ class CashManagementReturnTransaction {
9640
10265
  MsgHdr: exportMessageHeader(this._data.header),
9641
10266
  RptOrErr: {
9642
10267
  BizRpt: {
9643
- TxRpt: this._data.reports.map((report) => {
10268
+ TxRpt: this._data.reports.map(report => {
9644
10269
  const obj = {
9645
10270
  PmtId: {
9646
10271
  LngBizId: {
@@ -9652,7 +10277,7 @@ class CashManagementReturnTransaction {
9652
10277
  UETR: report.paymentId.uetr,
9653
10278
  TxId: report.paymentId.transactionId,
9654
10279
  EndToEndId: report.paymentId.endToEndId,
9655
- }
10280
+ },
9656
10281
  },
9657
10282
  TxOrErr: {}, // filled below
9658
10283
  };
@@ -9671,38 +10296,46 @@ class CashManagementReturnTransaction {
9671
10296
  function exportAgent(a) {
9672
10297
  if (!a)
9673
10298
  return undefined;
9674
- if ("bic" in a && a.bic)
10299
+ if ('bic' in a && a.bic)
9675
10300
  return { FinInstnId: { BICFI: a.bic } };
9676
- if ("abaRoutingNumber" in a && a.abaRoutingNumber)
10301
+ if ('abaRoutingNumber' in a && a.abaRoutingNumber)
9677
10302
  return { FinInstId: { Othr: { Id: a.abaRoutingNumber } } };
9678
10303
  return undefined;
9679
10304
  }
9680
- 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];
9681
10308
  obj.TxOrErr.Tx = {
9682
10309
  Pmt: {
9683
10310
  MsgId: report.report.msgId,
9684
- ReqdExctnDt: { Dt: report.report.reqExecutionDate?.toISOString()?.slice(0, 10) },
10311
+ ReqdExctnDt: {
10312
+ Dt: report.report.reqExecutionDate
10313
+ ?.toISOString()
10314
+ ?.slice(0, 10),
10315
+ },
9685
10316
  Sts: {
9686
10317
  Cd: codeType ? { [codeType]: code } : undefined,
9687
- 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,
9688
10321
  },
9689
10322
  Pties: {
9690
10323
  Dbtr: exportParty(report.report.debtor),
9691
10324
  DbtrAgt: exportAgent(report.report.debtorAgent),
9692
10325
  Cdtr: exportParty(report.report.creditor),
9693
10326
  CdtrAgt: exportAgent(report.report.creditorAgent),
9694
- }
9695
- }
10327
+ },
10328
+ },
9696
10329
  };
9697
10330
  }
9698
10331
  else if (report.error) {
9699
10332
  obj.TxOrErr.BizErr = exportBusinessError(report.error);
9700
10333
  }
9701
10334
  return obj;
9702
- })
9703
- }
9704
- }
9705
- }
10335
+ }),
10336
+ },
10337
+ },
10338
+ },
9706
10339
  };
9707
10340
  return { Document };
9708
10341
  }
@@ -9742,17 +10375,17 @@ const BalanceTypeCode = {
9742
10375
  * Description mapping of BalanceTypeCode values to their names.
9743
10376
  */
9744
10377
  const BalanceTypeCodeDescriptionMap = {
9745
- 'CLAV': 'Closing Available',
9746
- 'CLBD': 'Closing Booked',
9747
- 'FWAV': 'Forward Available',
9748
- 'INFO': 'Information',
9749
- 'ITAV': 'Interim Available',
9750
- 'ITBD': 'Interim Booked',
9751
- 'OPAV': 'Opening Available',
9752
- 'OPBD': 'Opening Booked',
9753
- 'PRCD': 'Previously Closed Booked',
9754
- 'XPCD': 'Expected',
9755
- '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',
9756
10389
  };
9757
10390
 
9758
10391
  /**
@@ -9975,6 +10608,64 @@ class ISO20022 {
9975
10608
  creationDate: config.creationDate,
9976
10609
  });
9977
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
+ }
9978
10669
  /** Create a message CAMT or other */
9979
10670
  createMessage(type, config) {
9980
10671
  const implementation = getISO20022Implementation(type);
@@ -10263,9 +10954,10 @@ class CashManagementEndOfDayReport {
10263
10954
  const parser = XML.getParser();
10264
10955
  const xml = parser.parse(rawXml);
10265
10956
  if (!xml.Document) {
10266
- throw new InvalidXmlError("Invalid XML format");
10957
+ throw new InvalidXmlError('Invalid XML format');
10267
10958
  }
10268
- const namespace = (xml.Document['@_xmlns'] || xml.Document['@_Xmlns']);
10959
+ const namespace = (xml.Document['@_xmlns'] ||
10960
+ xml.Document['@_Xmlns']);
10269
10961
  if (!namespace.startsWith('urn:iso:std:iso:20022:tech:xsd:camt.053.001.')) {
10270
10962
  throw new InvalidXmlNamespaceError('Invalid CAMT.053 namespace');
10271
10963
  }
@@ -10280,7 +10972,7 @@ class CashManagementEndOfDayReport {
10280
10972
  static fromJSON(json) {
10281
10973
  const obj = JSON.parse(json);
10282
10974
  if (!obj.Document) {
10283
- throw new InvalidXmlError("Invalid JSON format");
10975
+ throw new InvalidXmlError('Invalid JSON format');
10284
10976
  }
10285
10977
  return CashManagementEndOfDayReport.fromDocumentObject(obj);
10286
10978
  }
@@ -10290,10 +10982,12 @@ class CashManagementEndOfDayReport {
10290
10982
  GrpHdr: {
10291
10983
  MsgId: this._messageId,
10292
10984
  CreDtTm: this._creationDate.toISOString(),
10293
- MsgRcpt: this._recipient ? exportRecipient(this._recipient) : undefined,
10985
+ MsgRcpt: this._recipient
10986
+ ? exportRecipient(this._recipient)
10987
+ : undefined,
10294
10988
  },
10295
- Stmt: this._statements.map((stmt) => exportStatement(stmt)),
10296
- }
10989
+ Stmt: this._statements.map(stmt => exportStatement(stmt)),
10990
+ },
10297
10991
  };
10298
10992
  return { Document };
10299
10993
  }
@@ -10358,4 +11052,4 @@ class CashManagementEndOfDayReport {
10358
11052
  }
10359
11053
  registerISO20022Implementation(CashManagementEndOfDayReport);
10360
11054
 
10361
- 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 };