@develit-services/bank 4.1.0 → 4.2.1

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.
Files changed (32) hide show
  1. package/dist/database/schema.d.cts +1 -1
  2. package/dist/database/schema.d.mts +1 -1
  3. package/dist/database/schema.d.ts +1 -1
  4. package/dist/export/worker.cjs +217 -17
  5. package/dist/export/worker.d.cts +3 -2
  6. package/dist/export/worker.d.mts +3 -2
  7. package/dist/export/worker.d.ts +3 -2
  8. package/dist/export/worker.mjs +217 -17
  9. package/dist/export/workflows.cjs +102 -87
  10. package/dist/export/workflows.mjs +102 -87
  11. package/dist/export/wrangler.d.cts +2 -1
  12. package/dist/export/wrangler.d.mts +2 -1
  13. package/dist/export/wrangler.d.ts +2 -1
  14. package/dist/shared/{bank.C0JeMUxQ.d.cts → bank.BCqBwSKC.d.cts} +22 -3
  15. package/dist/shared/{bank.C0JeMUxQ.d.mts → bank.BCqBwSKC.d.mts} +22 -3
  16. package/dist/shared/{bank.C0JeMUxQ.d.ts → bank.BCqBwSKC.d.ts} +22 -3
  17. package/dist/shared/{bank.BScD3GXI.mjs → bank.BELDXSDV.mjs} +1 -1
  18. package/dist/shared/{bank.BxZARqNE.mjs → bank.BOMobxtA.mjs} +45 -18
  19. package/dist/shared/{bank.DflRiCrT.d.ts → bank.BmX_IG66.d.ts} +1 -1
  20. package/dist/shared/{bank.CjPpPiJF.d.mts → bank.BnCJmT6k.d.mts} +1 -1
  21. package/dist/shared/{bank.DNFep60v.cjs → bank.CioJeFzf.cjs} +1 -1
  22. package/dist/shared/{bank.xrNekjj9.cjs → bank.DiJmJkDt.cjs} +44 -16
  23. package/dist/shared/{bank.BydmpvCs.d.ts → bank.Dq24vYU7.d.cts} +1 -0
  24. package/dist/shared/{bank.BydmpvCs.d.cts → bank.Dq24vYU7.d.mts} +1 -0
  25. package/dist/shared/{bank.BydmpvCs.d.mts → bank.Dq24vYU7.d.ts} +1 -0
  26. package/dist/shared/{bank.CwB3cDIG.d.cts → bank.mHFTrKBv.d.cts} +1 -1
  27. package/dist/types.cjs +2 -1
  28. package/dist/types.d.cts +5 -5
  29. package/dist/types.d.mts +5 -5
  30. package/dist/types.d.ts +5 -5
  31. package/dist/types.mjs +1 -1
  32. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { bankAccountMetadataSchema, structuredAddressSchema, uuidv4, first, buildMultiFilterConditions as buildMultiFilterConditions$1, workflowInstanceStatusSchema, develitWorker, createInternalError, action, service } from '@develit-io/backend-sdk';
2
- import { B as tables, g as accountInsertSchema, G as relations, H as initiateConnector, o as isProcessedStatus, p as isTerminalStatus, J as getNonTerminalPaymentRequestsQuery, x as toIncomingPayment, j as assignAccount, u as toBatchedPayment, y as toPaymentRequestInsert, a as FinbricksClient, F as FINBRICKS_ENDPOINTS } from '../shared/bank.BxZARqNE.mjs';
2
+ import { G as tables, g as accountInsertSchema, H as relations, J as initiateConnector, o as isProcessedStatus, p as isTerminalStatus, L as getNonTerminalPaymentRequestsQuery, x as toIncomingPayment, j as assignAccount, u as toBatchedPayment, y as toPaymentRequestInsert, a as FinbricksClient, F as FINBRICKS_ENDPOINTS } from '../shared/bank.BOMobxtA.mjs';
3
3
  import { eq, sql, and, like, asc, desc, inArray, gte, lte, isNull, count } from 'drizzle-orm';
4
4
  import { WorkerEntrypoint } from 'cloudflare:workers';
5
5
  import { drizzle } from 'drizzle-orm/d1';
@@ -9,10 +9,69 @@ import { I as INSTRUCTION_PRIORITIES, C as CHARGE_BEARERS, g as PAYMENT_TYPES, b
9
9
  import { CURRENCY_CODES } from '@develit-io/general-codes';
10
10
  import 'date-fns';
11
11
  import 'node:crypto';
12
- import { h as encrypt, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, a as getPaymentRequestsByBatchIdQuery, g as getBatchByIdQuery, u as upsertBatchCommand, i as importAesKey, f as createPaymentCommand, b as getAccountByIdQuery } from '../shared/bank.BScD3GXI.mjs';
12
+ import { h as encrypt, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, a as getPaymentRequestsByBatchIdQuery, g as getBatchByIdQuery, u as upsertBatchCommand, i as importAesKey, f as createPaymentCommand, b as getAccountByIdQuery } from '../shared/bank.BELDXSDV.mjs';
13
13
  import 'drizzle-orm/zod';
14
14
  import 'drizzle-orm/sqlite-core';
15
15
 
16
+ const SYNC_WORKFLOW_HEARTBEAT_CRON = "0 */8 * * *";
17
+ const DEAD_STATUSES = /* @__PURE__ */ new Set([
18
+ "complete",
19
+ "terminated",
20
+ "errored",
21
+ "unknown"
22
+ ]);
23
+ async function heartbeatSyncWorkflows({
24
+ entities,
25
+ resetAfterIterations,
26
+ getInstance,
27
+ createInstance,
28
+ logger
29
+ }) {
30
+ await Promise.all(
31
+ entities.map(async ({ id, iterationCount }) => {
32
+ try {
33
+ const instance = await getInstance(id);
34
+ const { status } = await instance.status();
35
+ if (DEAD_STATUSES.has(status)) {
36
+ await instance.restart();
37
+ logger.info("sync-workflow.heartbeat.zombie-recovery", {
38
+ id,
39
+ previousStatus: status
40
+ });
41
+ return;
42
+ }
43
+ if (iterationCount == null) {
44
+ logger.warn("sync-workflow.heartbeat.iteration-count-missing", {
45
+ id,
46
+ status
47
+ });
48
+ return;
49
+ }
50
+ if (iterationCount >= resetAfterIterations) {
51
+ await instance.restart();
52
+ logger.info("sync-workflow.heartbeat.scheduled-reset", {
53
+ id,
54
+ iterationCount
55
+ });
56
+ }
57
+ } catch (err) {
58
+ try {
59
+ await createInstance(id);
60
+ logger.info("sync-workflow.heartbeat.created-missing-instance", {
61
+ id
62
+ });
63
+ } catch (createErr) {
64
+ logger.error("sync-workflow.heartbeat.failed", {
65
+ id,
66
+ error: err instanceof Error ? err.message : String(err),
67
+ createError: createErr instanceof Error ? createErr.message : String(createErr)
68
+ });
69
+ }
70
+ }
71
+ })
72
+ );
73
+ }
74
+
16
75
  const sendPaymentInputSchema = z.object({
17
76
  correlationId: z.string().min(1),
18
77
  refId: z.string().optional(),
@@ -755,6 +814,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
755
814
  const byConnector = Map.groupBy(allPRs, (pr) => pr.connectorKey);
756
815
  let processed = 0;
757
816
  let statusChanged = 0;
817
+ let skippedNoBankRefId = 0;
758
818
  const eventsToEmit = [];
759
819
  for (const [connectorKey, requests] of byConnector) {
760
820
  let connector;
@@ -767,10 +827,30 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
767
827
  continue;
768
828
  }
769
829
  for (const pr of requests) {
830
+ if (!pr.bankRefId && pr.connectorKey === "DBU") {
831
+ skippedNoBankRefId++;
832
+ console.warn(
833
+ "[_resolvePaymentRequestStatuses] Skipping DBU PR without bankRefId",
834
+ {
835
+ prId: pr.id,
836
+ status: pr.status,
837
+ connectorKey: pr.connectorKey,
838
+ createdAt: pr.createdAt
839
+ }
840
+ );
841
+ continue;
842
+ }
770
843
  try {
771
844
  const paymentId = pr.bankRefId ?? pr.id;
772
845
  const newStatus = await connector.getPaymentStatus({ paymentId });
773
846
  if (newStatus !== pr.status) {
847
+ console.log("[_resolvePaymentRequestStatuses] Status changed", {
848
+ prId: pr.id,
849
+ connectorKey: pr.connectorKey,
850
+ bankRefId: pr.bankRefId,
851
+ oldStatus: pr.status,
852
+ newStatus
853
+ });
774
854
  await updatePaymentRequestStatusCommand(this.db, {
775
855
  id: pr.id,
776
856
  status: newStatus,
@@ -783,17 +863,34 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
783
863
  }
784
864
  processed++;
785
865
  } catch (err) {
786
- this.logError({
787
- message: `Failed to resolve status for PR ${pr.id}: ${err}`
788
- });
866
+ console.error(
867
+ "[_resolvePaymentRequestStatuses] Failed to get payment status",
868
+ {
869
+ prId: pr.id,
870
+ connectorKey: pr.connectorKey,
871
+ status: pr.status,
872
+ bankRefId: pr.bankRefId,
873
+ error: err instanceof Error ? err.message : String(err)
874
+ }
875
+ );
789
876
  }
790
877
  }
791
878
  }
792
879
  if (eventsToEmit.length > 0) {
793
- await this.pushToQueue(
794
- this.env.QUEUE_BUS_QUEUE,
795
- eventsToEmit
796
- );
880
+ try {
881
+ await this.pushToQueue(
882
+ this.env.QUEUE_BUS_QUEUE,
883
+ eventsToEmit
884
+ );
885
+ } catch (err) {
886
+ console.error(
887
+ "[_resolvePaymentRequestStatuses] Failed to push events to queue",
888
+ {
889
+ eventCount: eventsToEmit.length,
890
+ error: err instanceof Error ? err.message : String(err)
891
+ }
892
+ );
893
+ }
797
894
  }
798
895
  const affectedBatchIds = [
799
896
  ...new Set(
@@ -801,7 +898,32 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
801
898
  )
802
899
  ];
803
900
  for (const batchId of affectedBatchIds) {
804
- await this._deriveBatchStatus(batchId);
901
+ try {
902
+ await this._deriveBatchStatus(batchId);
903
+ } catch (err) {
904
+ console.error(
905
+ "[_resolvePaymentRequestStatuses] Failed to derive batch status",
906
+ {
907
+ batchId,
908
+ error: err instanceof Error ? err.message : String(err)
909
+ }
910
+ );
911
+ }
912
+ }
913
+ console.log("[_resolvePaymentRequestStatuses] Summary", {
914
+ total: allPRs.length,
915
+ processed,
916
+ statusChanged,
917
+ skippedNoBankRefId
918
+ });
919
+ if (skippedNoBankRefId > 5) {
920
+ console.warn(
921
+ "[_resolvePaymentRequestStatuses] HIGH NUMBER of PRs without bankRefId",
922
+ {
923
+ count: skippedNoBankRefId,
924
+ note: "These PRs may be orphaned - payment sent but bankRefId not saved"
925
+ }
926
+ );
805
927
  }
806
928
  return { processed, statusChanged };
807
929
  }
@@ -816,8 +938,9 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
816
938
  if (!batch || batch.status === "COMPLETED" || batch.status === "FAILED")
817
939
  return;
818
940
  if (allPRs.length === 0) return;
941
+ const connectorKey = allPRs[0]?.connectorKey;
819
942
  const allTerminal = allPRs.every(
820
- (pr) => isTerminalStatus(pr.status)
943
+ (pr) => isTerminalStatus(pr.status, connectorKey)
821
944
  );
822
945
  const allAuthorizedOrHigher = allPRs.every((pr) => pr.status !== "OPENED");
823
946
  if (allTerminal) {
@@ -838,16 +961,49 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
838
961
  null,
839
962
  { successMessage: "Payment request statuses updated" },
840
963
  async () => {
964
+ const startTime = Date.now();
965
+ console.log("[updatePaymentRequestStatuses] Starting", {
966
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
967
+ });
841
968
  const nonTerminalPRs = await getNonTerminalPaymentRequestsQuery(this.db);
842
969
  if (nonTerminalPRs.length === 0) {
970
+ console.log(
971
+ "[updatePaymentRequestStatuses] No non-terminal PRs found",
972
+ {
973
+ duration: `${Date.now() - startTime}ms`
974
+ }
975
+ );
843
976
  return { processed: 0, statusChanged: 0 };
844
977
  }
978
+ const byConnector = nonTerminalPRs.reduce(
979
+ (acc, pr) => {
980
+ const key = pr.connectorKey || "unknown";
981
+ acc[key] = (acc[key] || 0) + 1;
982
+ return acc;
983
+ },
984
+ {}
985
+ );
986
+ console.log("[updatePaymentRequestStatuses] By connector", byConnector);
845
987
  const now = Date.now();
846
988
  const pollableIds = [];
847
989
  for (const pr of nonTerminalPRs) {
848
990
  const status = pr.status;
991
+ if (isTerminalStatus(status, pr.connectorKey)) {
992
+ continue;
993
+ }
849
994
  if (status === "OPENED" || status === "AUTHORIZED") {
850
995
  if (pr.createdAt != null && now - pr.createdAt.getTime() > this.POLLING_TIMEOUT_MS) {
996
+ console.warn(
997
+ "[updatePaymentRequestStatuses] Closing PR due to timeout",
998
+ {
999
+ prId: pr.id,
1000
+ status: pr.status,
1001
+ connectorKey: pr.connectorKey,
1002
+ createdAt: pr.createdAt,
1003
+ bankRefId: pr.bankRefId,
1004
+ age: `${Math.floor((now - pr.createdAt.getTime()) / (24 * 60 * 60 * 1e3))} days`
1005
+ }
1006
+ );
851
1007
  await updatePaymentRequestStatusCommand(this.db, {
852
1008
  id: pr.id,
853
1009
  status: "CLOSED",
@@ -857,14 +1013,20 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
857
1013
  continue;
858
1014
  }
859
1015
  pollableIds.push(pr.id);
860
- } else if (status === "COMPLETED" || status === "BOOKED") {
861
- if (pr.processedAt != null && now - pr.processedAt.getTime() > this.COMPLETED_POLLING_WINDOW_MS) {
862
- continue;
863
- }
864
- pollableIds.push(pr.id);
865
1016
  }
866
1017
  }
867
- return this._resolvePaymentRequestStatuses(pollableIds);
1018
+ const result = await this._resolvePaymentRequestStatuses(pollableIds);
1019
+ const duration = Date.now() - startTime;
1020
+ console.log("[updatePaymentRequestStatuses] Completed", {
1021
+ duration: `${duration}ms`,
1022
+ metrics: {
1023
+ total: nonTerminalPRs.length,
1024
+ polled: pollableIds.length,
1025
+ processed: result.processed,
1026
+ statusChanged: result.statusChanged
1027
+ }
1028
+ });
1029
+ return result;
868
1030
  }
869
1031
  );
870
1032
  }
@@ -872,8 +1034,46 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
872
1034
  if (controller.cron === this.env.CRON_PAYMENT_STATUSES) {
873
1035
  console.log("Scheduled CRON payment request statuses");
874
1036
  await this.updatePaymentRequestStatuses();
1037
+ return;
1038
+ }
1039
+ if (controller.cron === SYNC_WORKFLOW_HEARTBEAT_CRON) {
1040
+ console.log("Scheduled CRON sync workflow heartbeat");
1041
+ await this.heartbeatSyncWorkflows();
875
1042
  }
876
1043
  }
1044
+ async heartbeatSyncWorkflows() {
1045
+ const accounts = await this.db.select({
1046
+ id: tables.account.id,
1047
+ lastSyncMetadata: tables.account.lastSyncMetadata
1048
+ }).from(tables.account).where(eq(tables.account.status, "AUTHORIZED")).all();
1049
+ const resetAfterIterations = Number(
1050
+ this.env.SYNC_WORKFLOW_RESET_AFTER_ITERATIONS
1051
+ );
1052
+ if (!Number.isFinite(resetAfterIterations) || resetAfterIterations <= 0) {
1053
+ console.error(
1054
+ "Invalid SYNC_WORKFLOW_RESET_AFTER_ITERATIONS, skipping heartbeat",
1055
+ { value: this.env.SYNC_WORKFLOW_RESET_AFTER_ITERATIONS }
1056
+ );
1057
+ return;
1058
+ }
1059
+ await heartbeatSyncWorkflows({
1060
+ entities: accounts.map((a) => ({
1061
+ id: a.id,
1062
+ iterationCount: a.lastSyncMetadata?.iterationCount
1063
+ })),
1064
+ resetAfterIterations,
1065
+ getInstance: (id) => this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(id),
1066
+ createInstance: (id) => this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create({
1067
+ id,
1068
+ params: { accountId: id }
1069
+ }),
1070
+ logger: {
1071
+ info: (event, data) => console.log(JSON.stringify({ level: "info", event, ...data })),
1072
+ warn: (event, data) => console.warn(JSON.stringify({ level: "warn", event, ...data })),
1073
+ error: (event, data) => console.error(JSON.stringify({ level: "error", event, ...data }))
1074
+ }
1075
+ });
1076
+ }
877
1077
  async handleAuthorizationCallback(input) {
878
1078
  return this.handleAction(
879
1079
  { data: input, schema: handleAuthorizationCallbackInputSchema },
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const backendSdk = require('@develit-io/backend-sdk');
4
- const ott_zod = require('../shared/bank.xrNekjj9.cjs');
4
+ const ott_zod = require('../shared/bank.DiJmJkDt.cjs');
5
5
  const batchLifecycle = require('../shared/bank.NF8bZBy0.cjs');
6
6
  const drizzleOrm = require('drizzle-orm');
7
- const credentialsResolver = require('../shared/bank.DNFep60v.cjs');
7
+ const credentialsResolver = require('../shared/bank.CioJeFzf.cjs');
8
8
  const cloudflare_workers = require('cloudflare:workers');
9
9
  const cloudflare_workflows = require('cloudflare:workflows');
10
10
  const d1 = require('drizzle-orm/d1');
@@ -305,6 +305,10 @@ function createWorkflowLogger(instanceId) {
305
305
  };
306
306
  }
307
307
 
308
+ function getStepCount(ctx) {
309
+ return ctx.step?.count ?? 0;
310
+ }
311
+
308
312
  async function pushToQueue(queue, message) {
309
313
  if (!Array.isArray(message)) {
310
314
  await queue.send(message, { contentType: "v8" });
@@ -325,6 +329,10 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
325
329
  if (!accountId) {
326
330
  throw new cloudflare_workflows.NonRetryableError(`Haven't obtained accountId to load.`);
327
331
  }
332
+ const workflowStartedAt = await step.do(
333
+ "capture workflow start time",
334
+ async () => Date.now()
335
+ );
328
336
  while (true) {
329
337
  const now = /* @__PURE__ */ new Date();
330
338
  const account = await step.do("load account", async () => {
@@ -390,99 +398,106 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
390
398
  const paymentsToProcess = payments.filter(
391
399
  (p) => ott_zod.isPaymentCompleted(p.parsed)
392
400
  );
393
- if (paymentsToProcess.length) {
394
- const lastSyncBankRefIds = account.lastSyncMetadata?.lastSyncBankRefIds || [];
395
- const paymentsToInsert = paymentsToProcess.filter(
396
- (p) => !lastSyncBankRefIds.includes(p.parsed.bankRefId)
397
- );
398
- await step.do(
399
- "process new payments and update lastSyncAt",
400
- async () => {
401
- const eventsToEmit = [];
402
- const bankRefIds = paymentsToInsert.map((p) => p.parsed.bankRefId).filter((id) => id != null);
403
- const matchingRequests = bankRefIds.length > 0 ? await db.select().from(ott_zod.tables.paymentRequest).where(
401
+ const lastSyncBankRefIds = account.lastSyncMetadata?.lastSyncBankRefIds || [];
402
+ const paymentsToInsert = paymentsToProcess.filter(
403
+ (p) => !lastSyncBankRefIds.includes(p.parsed.bankRefId)
404
+ );
405
+ await step.do(
406
+ "process new payments and update lastSyncAt",
407
+ async (ctx) => {
408
+ const eventsToEmit = [];
409
+ const bankRefIds = paymentsToInsert.map((p) => p.parsed.bankRefId).filter((id) => id != null);
410
+ const BANK_REF_ID_CHUNK_SIZE = 90;
411
+ const matchingRequests = [];
412
+ for (let i = 0; i < bankRefIds.length; i += BANK_REF_ID_CHUNK_SIZE) {
413
+ const chunkIds = bankRefIds.slice(i, i + BANK_REF_ID_CHUNK_SIZE);
414
+ const rows = await db.select().from(ott_zod.tables.paymentRequest).where(
404
415
  drizzleOrm.and(
405
- drizzleOrm.inArray(ott_zod.tables.paymentRequest.bankRefId, bankRefIds),
416
+ drizzleOrm.inArray(ott_zod.tables.paymentRequest.bankRefId, chunkIds),
406
417
  drizzleOrm.eq(ott_zod.tables.paymentRequest.accountId, account.id),
407
- drizzleOrm.eq(
408
- ott_zod.tables.paymentRequest.connectorKey,
409
- account.connectorKey
410
- )
418
+ drizzleOrm.eq(ott_zod.tables.paymentRequest.connectorKey, account.connectorKey)
411
419
  )
412
- ) : [];
413
- const requestByBankRefId = Object.fromEntries(
414
- matchingRequests.map((r) => [r.bankRefId, r])
415
420
  );
416
- const enrichedPayments = paymentsToInsert.map((p) => {
417
- const req = p.parsed.bankRefId && requestByBankRefId[p.parsed.bankRefId] || null;
418
- if (!req) return p;
419
- return {
420
- ...p,
421
- parsed: {
422
- ...p.parsed,
423
- // queue-bus: transaction matching (DBU doesn't echo these in statements)
424
- vs: p.parsed.vs ?? req.vs,
425
- ss: p.parsed.ss ?? req.ss,
426
- ks: p.parsed.ks ?? req.ks,
427
- message: p.parsed.message ?? req.message,
428
- // queue-bus: party creation
429
- creditor: {
430
- ...p.parsed.creditor,
431
- holderName: p.parsed.creditor?.holderName ?? req.creditor?.holderName
432
- },
433
- debtor: {
434
- ...p.parsed.debtor,
435
- holderName: p.parsed.debtor?.holderName ?? req.debtor?.holderName
436
- }
437
- // NOT enriched: chargeBearer, instructionPriority, refId, batchId,
438
- // createdAt, address, swiftBic — no downstream consumer in payment table
421
+ matchingRequests.push(...rows);
422
+ }
423
+ const requestByBankRefId = Object.fromEntries(
424
+ matchingRequests.map((r) => [r.bankRefId, r])
425
+ );
426
+ const enrichedPayments = paymentsToInsert.map((p) => {
427
+ const req = p.parsed.bankRefId && requestByBankRefId[p.parsed.bankRefId] || null;
428
+ if (!req) return p;
429
+ return {
430
+ ...p,
431
+ parsed: {
432
+ ...p.parsed,
433
+ // queue-bus: transaction matching (DBU doesn't echo these in statements)
434
+ vs: p.parsed.vs ?? req.vs,
435
+ ss: p.parsed.ss ?? req.ss,
436
+ ks: p.parsed.ks ?? req.ks,
437
+ message: p.parsed.message ?? req.message,
438
+ // queue-bus: party creation
439
+ creditor: {
440
+ ...p.parsed.creditor,
441
+ holderName: p.parsed.creditor?.holderName ?? req.creditor?.holderName
442
+ },
443
+ debtor: {
444
+ ...p.parsed.debtor,
445
+ holderName: p.parsed.debtor?.holderName ?? req.debtor?.holderName
439
446
  }
440
- };
441
- });
442
- const createCommands = enrichedPayments.map(
443
- (p) => credentialsResolver.createPaymentCommand(db, { payment: p.parsed }).command
447
+ // NOT enriched: chargeBearer, instructionPriority, refId, batchId,
448
+ // createdAt, address, swiftBic — no downstream consumer in payment table
449
+ }
450
+ };
451
+ });
452
+ const createCommands = enrichedPayments.map(
453
+ (p) => credentialsResolver.createPaymentCommand(db, { payment: p.parsed }).command
454
+ );
455
+ eventsToEmit.push(
456
+ ...enrichedPayments.map((p) => ({
457
+ eventType: "BANK_PAYMENT",
458
+ eventSignal: "paymentFetched",
459
+ bankPayment: p.parsed,
460
+ metadata: {
461
+ correlationId: p.parsed.correlationId,
462
+ entityId: p.parsed.id,
463
+ timestamp: /* @__PURE__ */ new Date()
464
+ }
465
+ }))
466
+ );
467
+ const lastSyncMetadata = {
468
+ payments: payments.length,
469
+ paymentsToProcess: paymentsToProcess.length,
470
+ paymentsInserted: paymentsToInsert.length,
471
+ lastSyncBankRefIds: paymentsToProcess.filter((p) => p.parsed.status === "BOOKED").map((p) => p.parsed.bankRefId),
472
+ lastSyncPayments: lastSyncBankRefIds.length,
473
+ eventsEmitted: eventsToEmit.length,
474
+ iterationCount: getStepCount(ctx),
475
+ workflowStartedAt
476
+ };
477
+ const updateLastSyncCommand = updateAccountLastSyncCommand(db, {
478
+ accountId: account.id,
479
+ lastSyncAt: now,
480
+ lastSyncMetadata
481
+ }).command;
482
+ if (createCommands.length) {
483
+ await db.batch(
484
+ backendSdk.asNonEmpty([updateLastSyncCommand, ...createCommands])
444
485
  );
445
- eventsToEmit.push(
446
- ...enrichedPayments.map((p) => ({
447
- eventType: "BANK_PAYMENT",
448
- eventSignal: "paymentFetched",
449
- bankPayment: p.parsed,
450
- metadata: {
451
- correlationId: p.parsed.correlationId,
452
- entityId: p.parsed.id,
453
- timestamp: /* @__PURE__ */ new Date()
454
- }
455
- }))
486
+ } else {
487
+ await updateLastSyncCommand;
488
+ }
489
+ if (eventsToEmit.length) {
490
+ await pushToQueue(
491
+ this.env.QUEUE_BUS_QUEUE,
492
+ eventsToEmit
456
493
  );
457
- const lastSyncMetadata = {
458
- payments: payments.length,
459
- paymentsToProcess: paymentsToProcess.length,
460
- paymentsInserted: paymentsToInsert.length,
461
- lastSyncBankRefIds: paymentsToProcess.filter((p) => p.parsed.status === "BOOKED").map((p) => p.parsed.bankRefId),
462
- lastSyncPayments: lastSyncBankRefIds.length,
463
- eventsEmitted: eventsToEmit.length
464
- };
465
- const updateLastSyncCommand = updateAccountLastSyncCommand(db, {
466
- accountId: account.id,
467
- lastSyncAt: now,
468
- lastSyncMetadata
469
- }).command;
470
- if (eventsToEmit.length) {
471
- await db.batch(
472
- backendSdk.asNonEmpty([updateLastSyncCommand, ...createCommands])
473
- );
474
- await pushToQueue(
475
- this.env.QUEUE_BUS_QUEUE,
476
- eventsToEmit
477
- );
478
- }
479
- return {
480
- ...lastSyncMetadata,
481
- newLastSyncAt: now
482
- };
483
494
  }
484
- );
485
- }
495
+ return {
496
+ ...lastSyncMetadata,
497
+ newLastSyncAt: now
498
+ };
499
+ }
500
+ );
486
501
  await step.sleep(
487
502
  "Sleep for next sync",
488
503
  `${account.syncIntervalS} seconds`