@open-mercato/core 0.6.6-develop.6304.1.4cf2b975cb → 0.6.6-develop.6309.1.983aeec27a

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.
@@ -1058,12 +1058,18 @@ async function applyDocumentUpdate({
1058
1058
  if (input.channelId === null) {
1059
1059
  entity.channelId = null;
1060
1060
  } else {
1061
- const channel = await em.findOne(SalesChannel, {
1062
- id: input.channelId,
1063
- organizationId,
1064
- tenantId,
1065
- deletedAt: null,
1066
- });
1061
+ const channel = await findOneWithDecryption(
1062
+ em,
1063
+ SalesChannel,
1064
+ {
1065
+ id: input.channelId,
1066
+ organizationId,
1067
+ tenantId,
1068
+ deletedAt: null,
1069
+ },
1070
+ {},
1071
+ { tenantId, organizationId },
1072
+ );
1067
1073
  if (!channel) {
1068
1074
  throw new CrudHttpError(400, {
1069
1075
  error: translate(
@@ -3793,7 +3799,16 @@ async function restoreQuoteGraph(
3793
3799
  em: EntityManager,
3794
3800
  snapshot: QuoteGraphSnapshot,
3795
3801
  ): Promise<SalesQuote> {
3796
- let quote = await em.findOne(SalesQuote, { id: snapshot.quote.id });
3802
+ let quote = await findOneWithDecryption(
3803
+ em,
3804
+ SalesQuote,
3805
+ { id: snapshot.quote.id },
3806
+ {},
3807
+ {
3808
+ tenantId: snapshot.quote.tenantId,
3809
+ organizationId: snapshot.quote.organizationId,
3810
+ },
3811
+ );
3797
3812
  if (!quote) {
3798
3813
  quote = em.create(SalesQuote, {
3799
3814
  id: snapshot.quote.id,
@@ -4085,7 +4100,16 @@ async function restoreOrderGraph(
4085
4100
  em: EntityManager,
4086
4101
  snapshot: OrderGraphSnapshot,
4087
4102
  ): Promise<SalesOrder> {
4088
- let order = await em.findOne(SalesOrder, { id: snapshot.order.id });
4103
+ let order = await findOneWithDecryption(
4104
+ em,
4105
+ SalesOrder,
4106
+ { id: snapshot.order.id },
4107
+ {},
4108
+ {
4109
+ tenantId: snapshot.order.tenantId,
4110
+ organizationId: snapshot.order.organizationId,
4111
+ },
4112
+ );
4089
4113
  if (!order) {
4090
4114
  order = em.create(SalesOrder, {
4091
4115
  id: snapshot.order.id,
@@ -4783,7 +4807,16 @@ const createQuoteCommand: CommandHandler<
4783
4807
  const after = payload?.after;
4784
4808
  if (!after) return;
4785
4809
  const em = (ctx.container.resolve("em") as EntityManager).fork();
4786
- const quote = await em.findOne(SalesQuote, { id: after.quote.id });
4810
+ const quote = await findOneWithDecryption(
4811
+ em,
4812
+ SalesQuote,
4813
+ { id: after.quote.id },
4814
+ {},
4815
+ {
4816
+ tenantId: after.quote.tenantId,
4817
+ organizationId: after.quote.organizationId,
4818
+ },
4819
+ );
4787
4820
  if (!quote) return;
4788
4821
  ensureQuoteScope(ctx, quote.organizationId, quote.tenantId);
4789
4822
  await em.nativeDelete(SalesQuoteAdjustment, { quote: quote.id });
@@ -4814,7 +4847,7 @@ const deleteQuoteCommand: CommandHandler<
4814
4847
  async execute(input, ctx) {
4815
4848
  const id = requireId(input, "Quote id is required");
4816
4849
  const em = (ctx.container.resolve("em") as EntityManager).fork();
4817
- const quote = await em.findOne(SalesQuote, { id });
4850
+ const quote = await findOneWithDecryption(em, SalesQuote, { id });
4818
4851
  if (!quote)
4819
4852
  throw new CrudHttpError(404, { error: "Sales quote not found" });
4820
4853
  ensureQuoteScope(ctx, quote.organizationId, quote.tenantId);
@@ -4941,7 +4974,7 @@ const updateQuoteCommand: CommandHandler<
4941
4974
  async execute(rawInput, ctx) {
4942
4975
  const parsed = documentUpdateSchema.parse(rawInput ?? {});
4943
4976
  const em = (ctx.container.resolve("em") as EntityManager).fork();
4944
- const quote = await em.findOne(SalesQuote, {
4977
+ const quote = await findOneWithDecryption(em, SalesQuote, {
4945
4978
  id: parsed.id,
4946
4979
  deletedAt: null,
4947
4980
  });
@@ -5173,7 +5206,7 @@ const updateOrderCommand: CommandHandler<
5173
5206
  async execute(rawInput, ctx) {
5174
5207
  const parsed = documentUpdateSchema.parse(rawInput ?? {});
5175
5208
  const em = (ctx.container.resolve("em") as EntityManager).fork();
5176
- const order = await em.findOne(SalesOrder, {
5209
+ const order = await findOneWithDecryption(em, SalesOrder, {
5177
5210
  id: parsed.id,
5178
5211
  deletedAt: null,
5179
5212
  });
@@ -5779,7 +5812,16 @@ const createOrderCommand: CommandHandler<
5779
5812
  const after = payload?.after;
5780
5813
  if (!after) return;
5781
5814
  const em = (ctx.container.resolve("em") as EntityManager).fork();
5782
- const order = await em.findOne(SalesOrder, { id: after.order.id });
5815
+ const order = await findOneWithDecryption(
5816
+ em,
5817
+ SalesOrder,
5818
+ { id: after.order.id },
5819
+ {},
5820
+ {
5821
+ tenantId: after.order.tenantId,
5822
+ organizationId: after.order.organizationId,
5823
+ },
5824
+ );
5783
5825
  if (!order) return;
5784
5826
  ensureOrderScope(ctx, order.organizationId, order.tenantId);
5785
5827
  await em.nativeDelete(SalesOrderAdjustment, { order: order.id });
@@ -5810,7 +5852,7 @@ const deleteOrderCommand: CommandHandler<
5810
5852
  async execute(input, ctx) {
5811
5853
  const id = requireId(input, "Order id is required");
5812
5854
  const em = (ctx.container.resolve("em") as EntityManager).fork();
5813
- const order = await em.findOne(SalesOrder, { id });
5855
+ const order = await findOneWithDecryption(em, SalesOrder, { id });
5814
5856
  if (!order)
5815
5857
  throw new CrudHttpError(404, { error: "Sales order not found" });
5816
5858
  ensureOrderScope(ctx, order.organizationId, order.tenantId);
@@ -6246,14 +6288,32 @@ const convertQuoteToOrderCommand: CommandHandler<
6246
6288
  });
6247
6289
 
6248
6290
  const [addresses, notes, tags] = await Promise.all([
6249
- em.find(SalesDocumentAddress, {
6250
- documentId: snapshot.quote.id,
6251
- documentKind: "quote",
6252
- }),
6253
- em.find(SalesNote, {
6254
- contextType: "quote",
6255
- contextId: snapshot.quote.id,
6256
- }),
6291
+ findWithDecryption(
6292
+ em,
6293
+ SalesDocumentAddress,
6294
+ {
6295
+ documentId: snapshot.quote.id,
6296
+ documentKind: "quote",
6297
+ },
6298
+ {},
6299
+ {
6300
+ tenantId: snapshot.quote.tenantId,
6301
+ organizationId: snapshot.quote.organizationId,
6302
+ },
6303
+ ),
6304
+ findWithDecryption(
6305
+ em,
6306
+ SalesNote,
6307
+ {
6308
+ contextType: "quote",
6309
+ contextId: snapshot.quote.id,
6310
+ },
6311
+ {},
6312
+ {
6313
+ tenantId: snapshot.quote.tenantId,
6314
+ organizationId: snapshot.quote.organizationId,
6315
+ },
6316
+ ),
6257
6317
  em.find(SalesDocumentTagAssignment, {
6258
6318
  documentId: snapshot.quote.id,
6259
6319
  documentKind: "quote",
@@ -6478,7 +6538,7 @@ const orderLineUpsertCommand: CommandHandler<
6478
6538
  const rawBody = (input?.body as Record<string, unknown> | undefined) ?? {};
6479
6539
  const parsed = orderLineUpsertSchema.parse(rawBody);
6480
6540
  const em = (ctx.container.resolve("em") as EntityManager).fork();
6481
- const order = await em.findOne(SalesOrder, {
6541
+ const order = await findOneWithDecryption(em, SalesOrder, {
6482
6542
  id: parsed.orderId,
6483
6543
  deletedAt: null,
6484
6544
  });
@@ -6794,7 +6854,7 @@ const orderLineDeleteCommand: CommandHandler<
6794
6854
  (input?.body as Record<string, unknown> | undefined) ?? {},
6795
6855
  );
6796
6856
  const em = (ctx.container.resolve("em") as EntityManager).fork();
6797
- const order = await em.findOne(SalesOrder, {
6857
+ const order = await findOneWithDecryption(em, SalesOrder, {
6798
6858
  id: parsed.orderId,
6799
6859
  deletedAt: null,
6800
6860
  });
@@ -6970,7 +7030,7 @@ const quoteLineUpsertCommand: CommandHandler<
6970
7030
  const rawBody = (input?.body as Record<string, unknown> | undefined) ?? {};
6971
7031
  const parsed = quoteLineUpsertSchema.parse(rawBody);
6972
7032
  const em = (ctx.container.resolve("em") as EntityManager).fork();
6973
- const quote = await em.findOne(SalesQuote, {
7033
+ const quote = await findOneWithDecryption(em, SalesQuote, {
6974
7034
  id: parsed.quoteId,
6975
7035
  deletedAt: null,
6976
7036
  });
@@ -7282,7 +7342,7 @@ const quoteLineDeleteCommand: CommandHandler<
7282
7342
  (input?.body as Record<string, unknown> | undefined) ?? {},
7283
7343
  );
7284
7344
  const em = (ctx.container.resolve("em") as EntityManager).fork();
7285
- const quote = await em.findOne(SalesQuote, {
7345
+ const quote = await findOneWithDecryption(em, SalesQuote, {
7286
7346
  id: parsed.quoteId,
7287
7347
  deletedAt: null,
7288
7348
  });
@@ -7436,7 +7496,7 @@ const orderAdjustmentUpsertCommand: CommandHandler<
7436
7496
  (input?.body as Record<string, unknown> | undefined) ?? {},
7437
7497
  );
7438
7498
  const em = (ctx.container.resolve("em") as EntityManager).fork();
7439
- const order = await em.findOne(SalesOrder, {
7499
+ const order = await findOneWithDecryption(em, SalesOrder, {
7440
7500
  id: parsed.orderId,
7441
7501
  deletedAt: null,
7442
7502
  });
@@ -7730,7 +7790,7 @@ const orderAdjustmentDeleteCommand: CommandHandler<
7730
7790
  (input?.body as Record<string, unknown> | undefined) ?? {},
7731
7791
  );
7732
7792
  const em = (ctx.container.resolve("em") as EntityManager).fork();
7733
- const order = await em.findOne(SalesOrder, {
7793
+ const order = await findOneWithDecryption(em, SalesOrder, {
7734
7794
  id: parsed.orderId,
7735
7795
  deletedAt: null,
7736
7796
  });
@@ -7895,7 +7955,7 @@ const quoteAdjustmentUpsertCommand: CommandHandler<
7895
7955
  (input?.body as Record<string, unknown> | undefined) ?? {},
7896
7956
  );
7897
7957
  const em = (ctx.container.resolve("em") as EntityManager).fork();
7898
- const quote = await em.findOne(SalesQuote, {
7958
+ const quote = await findOneWithDecryption(em, SalesQuote, {
7899
7959
  id: parsed.quoteId,
7900
7960
  deletedAt: null,
7901
7961
  });
@@ -8187,7 +8247,7 @@ const quoteAdjustmentDeleteCommand: CommandHandler<
8187
8247
  (input?.body as Record<string, unknown> | undefined) ?? {},
8188
8248
  );
8189
8249
  const em = (ctx.container.resolve("em") as EntityManager).fork();
8190
- const quote = await em.findOne(SalesQuote, {
8250
+ const quote = await findOneWithDecryption(em, SalesQuote, {
8191
8251
  id: parsed.quoteId,
8192
8252
  deletedAt: null,
8193
8253
  });
@@ -8379,12 +8439,21 @@ const createInvoiceCommand: CommandHandler<
8379
8439
 
8380
8440
  // Validate orderId belongs to same org/tenant
8381
8441
  if (parsed.orderId) {
8382
- const orderExists = await em.findOne(SalesOrder, {
8383
- id: parsed.orderId,
8384
- organizationId: parsed.organizationId,
8385
- tenantId: parsed.tenantId,
8386
- deletedAt: null,
8387
- });
8442
+ const orderExists = await findOneWithDecryption(
8443
+ em,
8444
+ SalesOrder,
8445
+ {
8446
+ id: parsed.orderId,
8447
+ organizationId: parsed.organizationId,
8448
+ tenantId: parsed.tenantId,
8449
+ deletedAt: null,
8450
+ },
8451
+ {},
8452
+ {
8453
+ tenantId: parsed.tenantId,
8454
+ organizationId: parsed.organizationId,
8455
+ },
8456
+ );
8388
8457
  if (!orderExists) {
8389
8458
  throw new CrudHttpError(400, { error: "Referenced order not found in current scope." });
8390
8459
  }
@@ -8869,12 +8938,21 @@ const createCreditMemoCommand: CommandHandler<
8869
8938
 
8870
8939
  // Validate orderId belongs to same org/tenant
8871
8940
  if (parsed.orderId) {
8872
- const orderExists = await em.findOne(SalesOrder, {
8873
- id: parsed.orderId,
8874
- organizationId: parsed.organizationId,
8875
- tenantId: parsed.tenantId,
8876
- deletedAt: null,
8877
- });
8941
+ const orderExists = await findOneWithDecryption(
8942
+ em,
8943
+ SalesOrder,
8944
+ {
8945
+ id: parsed.orderId,
8946
+ organizationId: parsed.organizationId,
8947
+ tenantId: parsed.tenantId,
8948
+ deletedAt: null,
8949
+ },
8950
+ {},
8951
+ {
8952
+ tenantId: parsed.tenantId,
8953
+ organizationId: parsed.organizationId,
8954
+ },
8955
+ );
8878
8956
  if (!orderExists) {
8879
8957
  throw new CrudHttpError(400, { error: "Referenced order not found in current scope." });
8880
8958
  }
@@ -64,7 +64,7 @@ const noteCrudEvents: CrudEventsConfig = {
64
64
  }
65
65
 
66
66
  async function loadNoteSnapshot(em: EntityManager, id: string): Promise<NoteSnapshot | null> {
67
- const note = await em.findOne(SalesNote, { id })
67
+ const note = await findOneWithDecryption(em, SalesNote, { id }, {})
68
68
  if (!note) return null
69
69
  return {
70
70
  id: note.id,
@@ -94,7 +94,7 @@ async function requireContext(
94
94
  quote?: SalesQuote | null
95
95
  }> {
96
96
  if (contextType === 'order') {
97
- const order = await em.findOne(SalesOrder, { id: contextId })
97
+ const order = await findOneWithDecryption(em, SalesOrder, { id: contextId }, {}, { tenantId, organizationId })
98
98
  if (!order) {
99
99
  throw new CrudHttpError(404, { error: 'sales.notes.context_not_found' })
100
100
  }
@@ -109,7 +109,7 @@ async function requireContext(
109
109
  }
110
110
  }
111
111
  if (contextType === 'quote') {
112
- const quote = await em.findOne(SalesQuote, { id: contextId })
112
+ const quote = await findOneWithDecryption(em, SalesQuote, { id: contextId }, {}, { tenantId, organizationId })
113
113
  if (!quote) {
114
114
  throw new CrudHttpError(404, { error: 'sales.notes.context_not_found' })
115
115
  }
@@ -216,7 +216,7 @@ const createNoteCommand: CommandHandler<NoteCreateInput, { noteId: string; autho
216
216
  const noteId = logEntry?.resourceId ?? null
217
217
  if (!noteId) return
218
218
  const em = (ctx.container.resolve('em') as EntityManager).fork()
219
- const existing = await em.findOne(SalesNote, { id: noteId })
219
+ const existing = await findOneWithDecryption(em, SalesNote, { id: noteId }, {})
220
220
  if (existing) {
221
221
  em.remove(existing)
222
222
  await em.flush()
@@ -272,7 +272,7 @@ const updateNoteCommand: CommandHandler<NoteUpdateInput, { noteId: string }> = {
272
272
  async execute(rawInput, ctx) {
273
273
  const parsed = noteUpdateSchema.parse(rawInput ?? {})
274
274
  const em = (ctx.container.resolve('em') as EntityManager).fork()
275
- const note = await em.findOne(SalesNote, { id: parsed.id })
275
+ const note = await findOneWithDecryption(em, SalesNote, { id: parsed.id }, {})
276
276
  if (!note) throw new CrudHttpError(404, { error: 'sales.notes.not_found' })
277
277
  ensureTenantScope(ctx, note.tenantId)
278
278
  ensureOrganizationScope(ctx, note.organizationId)
@@ -344,7 +344,7 @@ const updateNoteCommand: CommandHandler<NoteUpdateInput, { noteId: string }> = {
344
344
  const em = (ctx.container.resolve('em') as EntityManager).fork()
345
345
  const context = await requireContext(em, before.contextType, before.contextId).catch(() => null)
346
346
  if (!context) return
347
- let note = await em.findOne(SalesNote, { id: before.id })
347
+ let note = await findOneWithDecryption(em, SalesNote, { id: before.id }, {}, { tenantId: before.tenantId, organizationId: before.organizationId })
348
348
  if (!note) {
349
349
  note = em.create(SalesNote, {
350
350
  id: before.id,
@@ -404,7 +404,7 @@ const deleteNoteCommand: CommandHandler<{ body?: Record<string, unknown>; query?
404
404
  async execute(input, ctx) {
405
405
  const id = requireId(input, 'Note id required')
406
406
  const em = (ctx.container.resolve('em') as EntityManager).fork()
407
- const note = await em.findOne(SalesNote, { id })
407
+ const note = await findOneWithDecryption(em, SalesNote, { id }, {})
408
408
  if (!note) throw new CrudHttpError(404, { error: 'sales.notes.not_found' })
409
409
  ensureTenantScope(ctx, note.tenantId)
410
410
  ensureOrganizationScope(ctx, note.organizationId)
@@ -453,7 +453,7 @@ const deleteNoteCommand: CommandHandler<{ body?: Record<string, unknown>; query?
453
453
  const em = (ctx.container.resolve('em') as EntityManager).fork()
454
454
  const context = await requireContext(em, before.contextType, before.contextId).catch(() => null)
455
455
  if (!context) return
456
- let note = await em.findOne(SalesNote, { id: before.id })
456
+ let note = await findOneWithDecryption(em, SalesNote, { id: before.id }, {}, { tenantId: before.tenantId, organizationId: before.organizationId })
457
457
  if (!note) {
458
458
  note = em.create(SalesNote, {
459
459
  id: before.id,
@@ -253,12 +253,7 @@ async function recomputeOrderPaymentTotals(
253
253
  const scope = { organizationId: order.organizationId, tenantId: order.tenantId }
254
254
 
255
255
  if (options?.lock) {
256
- // Raw findOne is intentional: this acquires a row lock only no encrypted
257
- // SalesOrder field is read, so decryption (findOneWithDecryption) is unnecessary.
258
- // Scope filter is defence-in-depth (#2111): the caller is expected to pass a
259
- // correctly scoped order, but filtering here ensures we never lock a foreign
260
- // tenant's row even if a caller messed up.
261
- await em.findOne(SalesOrder, { id: orderId, ...scope }, { lockMode: LockMode.PESSIMISTIC_WRITE })
256
+ await findOneWithDecryption(em, SalesOrder, { id: orderId, ...scope }, { lockMode: LockMode.PESSIMISTIC_WRITE }, scope)
262
257
  }
263
258
 
264
259
  const allocations = await findWithDecryption(
@@ -666,11 +661,9 @@ const createPaymentCommand: CommandHandler<
666
661
  if (recomputed && (!totals || orderId === after.orderId)) {
667
662
  totals = recomputed
668
663
  }
669
- // Raw findOne is intentional: the order is fetched only to read its id/scope
670
- // for cache invalidation — no encrypted field is read, so decryption is unnecessary.
671
664
  // Scope filter (#2111): never cache-invalidate a foreign tenant's order even
672
665
  // if a snapshot's orderId was somehow tampered with.
673
- const target = await em.findOne(SalesOrder, { id: orderId, organizationId: after.organizationId, tenantId: after.tenantId })
666
+ const target = await findOneWithDecryption(em, SalesOrder, { id: orderId, organizationId: after.organizationId, tenantId: after.tenantId }, {}, { tenantId: after.tenantId, organizationId: after.organizationId })
674
667
  if (target) {
675
668
  ensureSameScope(target, after.organizationId, after.tenantId)
676
669
  await invalidateOrderCache(ctx.container, target, ctx.auth?.tenantId ?? null)
@@ -939,10 +932,12 @@ const updatePaymentCommand: CommandHandler<
939
932
  totals = await em.transactional(async (tx) => {
940
933
  // Scope filter (#2111): never lock or recompute totals on a foreign
941
934
  // tenant's order, even if payment.order somehow points there.
942
- const lockedOrder = await tx.findOne(
935
+ const lockedOrder = await findOneWithDecryption(
936
+ tx,
943
937
  SalesOrder,
944
938
  { id: nextOrderId, organizationId: payment.organizationId, tenantId: payment.tenantId },
945
939
  { lockMode: LockMode.PESSIMISTIC_WRITE },
940
+ { tenantId: payment.tenantId, organizationId: payment.organizationId },
946
941
  )
947
942
  if (!lockedOrder) return undefined
948
943
  ensureSameScope(lockedOrder, payment.organizationId, payment.tenantId)
@@ -951,10 +946,8 @@ const updatePaymentCommand: CommandHandler<
951
946
  return result
952
947
  })
953
948
  if (totals) {
954
- // Raw findOne is intentional: the order is fetched only to read its id/scope
955
- // for cache invalidation — no encrypted field is read, so decryption is unnecessary.
956
949
  // Scope filter (#2111): same rationale as the lock above.
957
- const nextOrder = await em.findOne(SalesOrder, { id: nextOrderId, organizationId: payment.organizationId, tenantId: payment.tenantId })
950
+ const nextOrder = await findOneWithDecryption(em, SalesOrder, { id: nextOrderId, organizationId: payment.organizationId, tenantId: payment.tenantId }, {}, { tenantId: payment.tenantId, organizationId: payment.organizationId })
958
951
  if (nextOrder) {
959
952
  ensureSameScope(nextOrder, payment.organizationId, payment.tenantId)
960
953
  await invalidateOrderCache(ctx.container, nextOrder, ctx.auth?.tenantId ?? null)
@@ -966,10 +959,12 @@ const updatePaymentCommand: CommandHandler<
966
959
  // Scope filter (#2111): previousOrder was already loaded via the
967
960
  // payment's scope, so its tenant/org match the payment's. Filter
968
961
  // the lock query the same way as defence-in-depth.
969
- const lockedOrder = await tx.findOne(
962
+ const lockedOrder = await findOneWithDecryption(
963
+ tx,
970
964
  SalesOrder,
971
965
  { id: previousOrder.id, organizationId: payment.organizationId, tenantId: payment.tenantId },
972
966
  { lockMode: LockMode.PESSIMISTIC_WRITE },
967
+ { tenantId: payment.tenantId, organizationId: payment.organizationId },
973
968
  )
974
969
  if (!lockedOrder) return
975
970
  ensureSameScope(lockedOrder, payment.organizationId, payment.tenantId)
@@ -1098,10 +1093,12 @@ const deletePaymentCommand: CommandHandler<
1098
1093
  const recomputed = await em.transactional(async (tx) => {
1099
1094
  // Scope filter (#2111): never lock or recompute totals on a foreign
1100
1095
  // tenant's order, even if a payment allocation somehow points there.
1101
- const lockedOrder = await tx.findOne(
1096
+ const lockedOrder = await findOneWithDecryption(
1097
+ tx,
1102
1098
  SalesOrder,
1103
1099
  { id: orderId, organizationId: payment.organizationId, tenantId: payment.tenantId },
1104
1100
  { lockMode: LockMode.PESSIMISTIC_WRITE },
1101
+ { tenantId: payment.tenantId, organizationId: payment.organizationId },
1105
1102
  )
1106
1103
  if (!lockedOrder) return undefined
1107
1104
  ensureSameScope(lockedOrder, payment.organizationId, payment.tenantId)
@@ -1112,10 +1109,8 @@ const deletePaymentCommand: CommandHandler<
1112
1109
  if (recomputed && (!totals || (primaryOrderId && orderId === primaryOrderId))) {
1113
1110
  totals = recomputed
1114
1111
  }
1115
- // Raw findOne is intentional: the order is fetched only to read its id/scope
1116
- // for cache invalidation — no encrypted field is read, so decryption is unnecessary.
1117
1112
  // Scope filter (#2111): same rationale as the lock above.
1118
- const target = await em.findOne(SalesOrder, { id: orderId, organizationId: payment.organizationId, tenantId: payment.tenantId })
1113
+ const target = await findOneWithDecryption(em, SalesOrder, { id: orderId, organizationId: payment.organizationId, tenantId: payment.tenantId }, {}, { tenantId: payment.tenantId, organizationId: payment.organizationId })
1119
1114
  if (target) {
1120
1115
  ensureSameScope(target, payment.organizationId, payment.tenantId)
1121
1116
  await invalidateOrderCache(ctx.container, target, ctx.auth?.tenantId ?? null)
@@ -219,7 +219,7 @@ export async function loadShipmentSnapshot(em: EntityManager, id: string): Promi
219
219
  }
220
220
 
221
221
  export async function restoreShipmentSnapshot(em: EntityManager, snapshot: ShipmentSnapshot): Promise<void> {
222
- const order = await em.findOne(SalesOrder, { id: snapshot.orderId })
222
+ const order = await findOneWithDecryption(em, SalesOrder, { id: snapshot.orderId }, {}, { tenantId: snapshot.tenantId, organizationId: snapshot.organizationId })
223
223
  if (!order) return
224
224
  const existing = await em.findOne(SalesShipment, { id: snapshot.id })
225
225
  const entity =
@@ -330,8 +330,12 @@ async function recomputeFulfilledQuantities(em: EntityManager, order: SalesOrder
330
330
  })
331
331
  }
332
332
 
333
- async function loadOrder(em: EntityManager, id: string): Promise<SalesOrder> {
334
- const order = await em.findOne(SalesOrder, { id, deletedAt: null })
333
+ async function loadOrder(
334
+ em: EntityManager,
335
+ id: string,
336
+ scope?: { tenantId: string; organizationId: string }
337
+ ): Promise<SalesOrder> {
338
+ const order = await findOneWithDecryption(em, SalesOrder, { id, deletedAt: null }, {}, scope)
335
339
  if (!order) throw new CrudHttpError(404, { error: 'sales.shipments.not_found' })
336
340
  return order
337
341
  }
@@ -436,7 +440,7 @@ const createShipmentCommand: CommandHandler<ShipmentCreateInput, { shipmentId: s
436
440
  const em = (ctx.container.resolve('em') as EntityManager).fork()
437
441
  const { translate } = await resolveTranslations()
438
442
  const shipment = await em.transactional(async (tx) => {
439
- const order = await loadOrder(tx, input.orderId)
443
+ const order = await loadOrder(tx, input.orderId, { tenantId: input.tenantId, organizationId: input.organizationId })
440
444
  ensureSameScope(order, input.organizationId, input.tenantId)
441
445
  const { items: normalizedItems, lineMap } = await validateShipmentItems({
442
446
  em: tx,
@@ -601,7 +605,7 @@ const createShipmentCommand: CommandHandler<ShipmentCreateInput, { shipmentId: s
601
605
  const em = (ctx.container.resolve('em') as EntityManager).fork()
602
606
  await em.transactional(async (tx) => {
603
607
  await restoreShipmentSnapshot(tx, after)
604
- const order = await tx.findOne(SalesOrder, { id: after.orderId })
608
+ const order = await findOneWithDecryption(tx, SalesOrder, { id: after.orderId }, {}, { tenantId: after.tenantId, organizationId: after.organizationId })
605
609
  await tx.flush()
606
610
  if (order) {
607
611
  await recomputeFulfilledQuantities(tx, order)
@@ -872,7 +876,7 @@ const updateShipmentCommand: CommandHandler<ShipmentUpdateInput, { shipmentId: s
872
876
  const em = (ctx.container.resolve('em') as EntityManager).fork()
873
877
  await em.transactional(async (tx) => {
874
878
  await restoreShipmentSnapshot(tx, before)
875
- const order = await tx.findOne(SalesOrder, { id: before.orderId })
879
+ const order = await findOneWithDecryption(tx, SalesOrder, { id: before.orderId }, {}, { tenantId: before.tenantId, organizationId: before.organizationId })
876
880
  await tx.flush()
877
881
  if (order) {
878
882
  await recomputeFulfilledQuantities(tx, order)
@@ -1021,7 +1025,7 @@ const deleteShipmentCommand: CommandHandler<
1021
1025
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1022
1026
  await em.transactional(async (tx) => {
1023
1027
  await restoreShipmentSnapshot(tx, snapshot)
1024
- const order = await tx.findOne(SalesOrder, { id: snapshot.orderId })
1028
+ const order = await findOneWithDecryption(tx, SalesOrder, { id: snapshot.orderId }, {}, { tenantId: snapshot.tenantId, organizationId: snapshot.organizationId })
1025
1029
  await tx.flush()
1026
1030
  if (order) {
1027
1031
  await recomputeFulfilledQuantities(tx, order)