@open-mercato/core 0.6.7-develop.6553.1.2ec7246e04 → 0.6.7-develop.6566.1.15385fa179

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 (143) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/attachments/api/partitions/route.js.map +1 -1
  3. package/dist/modules/attachments/lib/reconcileOrganization.js +9 -7
  4. package/dist/modules/attachments/lib/reconcileOrganization.js.map +2 -2
  5. package/dist/modules/catalog/api/products/route.js.map +1 -1
  6. package/dist/modules/customers/api/companies/[id]/people/route.js +2 -2
  7. package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
  8. package/dist/modules/customers/api/deals/[id]/companies/route.js +2 -2
  9. package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
  10. package/dist/modules/customers/api/deals/[id]/people/route.js +2 -2
  11. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  12. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +4 -4
  13. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  14. package/dist/modules/customers/api/entity-roles-factory.js +3 -3
  15. package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
  16. package/dist/modules/customers/api/labels/assign/route.js +2 -2
  17. package/dist/modules/customers/api/labels/assign/route.js.map +2 -2
  18. package/dist/modules/customers/api/labels/unassign/route.js +2 -2
  19. package/dist/modules/customers/api/labels/unassign/route.js.map +2 -2
  20. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +3 -7
  21. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
  22. package/dist/modules/customers/api/people/[id]/companies/context.js +3 -3
  23. package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
  24. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +2 -2
  25. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
  26. package/dist/modules/customers/api/todos/route.js +2 -2
  27. package/dist/modules/customers/api/todos/route.js.map +2 -2
  28. package/dist/modules/customers/commands/addresses.js +3 -3
  29. package/dist/modules/customers/commands/addresses.js.map +2 -2
  30. package/dist/modules/customers/commands/comments.js +3 -3
  31. package/dist/modules/customers/commands/comments.js.map +2 -2
  32. package/dist/modules/customers/commands/companies.js +2 -2
  33. package/dist/modules/customers/commands/companies.js.map +2 -2
  34. package/dist/modules/customers/commands/deals.js +3 -3
  35. package/dist/modules/customers/commands/deals.js.map +2 -2
  36. package/dist/modules/customers/commands/dictionaries.js +3 -3
  37. package/dist/modules/customers/commands/dictionaries.js.map +2 -2
  38. package/dist/modules/customers/commands/entity-roles.js +3 -3
  39. package/dist/modules/customers/commands/entity-roles.js.map +2 -2
  40. package/dist/modules/customers/commands/interactions.js +6 -6
  41. package/dist/modules/customers/commands/interactions.js.map +2 -2
  42. package/dist/modules/customers/commands/labels.js +7 -7
  43. package/dist/modules/customers/commands/labels.js.map +2 -2
  44. package/dist/modules/customers/commands/people.js +3 -3
  45. package/dist/modules/customers/commands/people.js.map +2 -2
  46. package/dist/modules/customers/commands/personCompanyLinks.js +6 -6
  47. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  48. package/dist/modules/customers/commands/pipeline-stages.js +3 -3
  49. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  50. package/dist/modules/customers/commands/pipelines.js +3 -3
  51. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  52. package/dist/modules/customers/commands/shared.js +3 -3
  53. package/dist/modules/customers/commands/shared.js.map +2 -2
  54. package/dist/modules/customers/commands/tags.js +7 -7
  55. package/dist/modules/customers/commands/tags.js.map +2 -2
  56. package/dist/modules/customers/commands/todos.js +3 -3
  57. package/dist/modules/customers/commands/todos.js.map +2 -2
  58. package/dist/modules/customers/lib/personCompanies.js +4 -4
  59. package/dist/modules/customers/lib/personCompanies.js.map +2 -2
  60. package/dist/modules/perspectives/data/validators.js +4 -0
  61. package/dist/modules/perspectives/data/validators.js.map +2 -2
  62. package/dist/modules/sales/api/notes/route.js +2 -4
  63. package/dist/modules/sales/api/notes/route.js.map +2 -2
  64. package/dist/modules/sales/api/quotes/accept/route.js +2 -2
  65. package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
  66. package/dist/modules/sales/api/quotes/public/[token]/route.js +3 -7
  67. package/dist/modules/sales/api/quotes/public/[token]/route.js.map +2 -2
  68. package/dist/modules/sales/api/quotes/send/route.js +2 -2
  69. package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
  70. package/dist/modules/sales/api/returns/[id]/route.js +2 -2
  71. package/dist/modules/sales/api/returns/[id]/route.js.map +2 -2
  72. package/dist/modules/sales/commands/configuration.js +11 -11
  73. package/dist/modules/sales/commands/configuration.js.map +2 -2
  74. package/dist/modules/sales/commands/documentAddresses.js +3 -3
  75. package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
  76. package/dist/modules/sales/commands/documents.js +31 -39
  77. package/dist/modules/sales/commands/documents.js.map +2 -2
  78. package/dist/modules/sales/commands/notes.js +7 -7
  79. package/dist/modules/sales/commands/notes.js.map +2 -2
  80. package/dist/modules/sales/commands/payments.js +2 -2
  81. package/dist/modules/sales/commands/payments.js.map +2 -2
  82. package/dist/modules/sales/commands/returns.js +8 -8
  83. package/dist/modules/sales/commands/returns.js.map +2 -2
  84. package/dist/modules/sales/commands/shared.js +2 -2
  85. package/dist/modules/sales/commands/shared.js.map +2 -2
  86. package/dist/modules/sales/commands/shipments.js +5 -5
  87. package/dist/modules/sales/commands/shipments.js.map +2 -2
  88. package/dist/modules/sales/commands/statuses.js +2 -2
  89. package/dist/modules/sales/commands/statuses.js.map +2 -2
  90. package/dist/modules/sales/commands/tags.js +3 -3
  91. package/dist/modules/sales/commands/tags.js.map +2 -2
  92. package/package.json +8 -8
  93. package/src/modules/attachments/api/partitions/route.ts +1 -1
  94. package/src/modules/attachments/lib/reconcileOrganization.ts +16 -7
  95. package/src/modules/catalog/api/products/route.ts +1 -1
  96. package/src/modules/customer_accounts/i18n/de.json +12 -0
  97. package/src/modules/customer_accounts/i18n/en.json +12 -0
  98. package/src/modules/customer_accounts/i18n/es.json +34 -22
  99. package/src/modules/customer_accounts/i18n/pl.json +32 -20
  100. package/src/modules/customers/api/companies/[id]/people/route.ts +2 -2
  101. package/src/modules/customers/api/deals/[id]/companies/route.ts +2 -2
  102. package/src/modules/customers/api/deals/[id]/people/route.ts +2 -2
  103. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +4 -4
  104. package/src/modules/customers/api/entity-roles-factory.ts +3 -3
  105. package/src/modules/customers/api/labels/assign/route.ts +2 -2
  106. package/src/modules/customers/api/labels/unassign/route.ts +2 -2
  107. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +3 -7
  108. package/src/modules/customers/api/people/[id]/companies/context.ts +3 -3
  109. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +2 -2
  110. package/src/modules/customers/api/todos/route.ts +2 -2
  111. package/src/modules/customers/commands/addresses.ts +3 -3
  112. package/src/modules/customers/commands/comments.ts +3 -3
  113. package/src/modules/customers/commands/companies.ts +2 -2
  114. package/src/modules/customers/commands/deals.ts +3 -3
  115. package/src/modules/customers/commands/dictionaries.ts +3 -3
  116. package/src/modules/customers/commands/entity-roles.ts +3 -3
  117. package/src/modules/customers/commands/interactions.ts +6 -6
  118. package/src/modules/customers/commands/labels.ts +7 -7
  119. package/src/modules/customers/commands/people.ts +3 -3
  120. package/src/modules/customers/commands/personCompanyLinks.ts +6 -6
  121. package/src/modules/customers/commands/pipeline-stages.ts +3 -3
  122. package/src/modules/customers/commands/pipelines.ts +3 -3
  123. package/src/modules/customers/commands/shared.ts +3 -3
  124. package/src/modules/customers/commands/tags.ts +7 -7
  125. package/src/modules/customers/commands/todos.ts +3 -3
  126. package/src/modules/customers/lib/personCompanies.ts +4 -4
  127. package/src/modules/perspectives/data/validators.ts +4 -0
  128. package/src/modules/sales/api/notes/route.ts +2 -4
  129. package/src/modules/sales/api/quotes/accept/route.ts +2 -2
  130. package/src/modules/sales/api/quotes/public/[token]/route.ts +3 -7
  131. package/src/modules/sales/api/quotes/send/route.ts +2 -2
  132. package/src/modules/sales/api/returns/[id]/route.ts +2 -2
  133. package/src/modules/sales/commands/configuration.ts +11 -11
  134. package/src/modules/sales/commands/documentAddresses.ts +3 -3
  135. package/src/modules/sales/commands/documents.ts +23 -31
  136. package/src/modules/sales/commands/notes.ts +7 -7
  137. package/src/modules/sales/commands/payments.ts +2 -2
  138. package/src/modules/sales/commands/returns.ts +8 -8
  139. package/src/modules/sales/commands/shared.ts +2 -2
  140. package/src/modules/sales/commands/shipments.ts +5 -5
  141. package/src/modules/sales/commands/statuses.ts +2 -2
  142. package/src/modules/sales/commands/tags.ts +3 -3
  143. package/tsconfig.json +0 -2
@@ -38,7 +38,7 @@ import {
38
38
  loadCustomFieldSnapshot,
39
39
  buildCustomFieldResetMap,
40
40
  } from '@open-mercato/shared/lib/commands/customFieldSnapshots'
41
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
41
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
42
42
  import { enforceRecordGoneIsConflict, enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
43
43
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
44
44
  import type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'
@@ -642,7 +642,7 @@ const updateInteractionCommand: CommandHandler<InteractionUpdateInput, { interac
642
642
  const interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: parsed.id, deletedAt: null })
643
643
  if (!interaction) {
644
644
  enforceRecordGoneIsConflict({ resourceKind: 'customers.interaction', resourceId: parsed.id, request: ctx.request ?? null })
645
- throw new CrudHttpError(404, { error: 'Interaction not found' })
645
+ throw notFound('Interaction not found')
646
646
  }
647
647
  ensureTenantScope(ctx, interaction.tenantId)
648
648
  ensureOrganizationScope(ctx, interaction.organizationId)
@@ -684,7 +684,7 @@ const updateInteractionCommand: CommandHandler<InteractionUpdateInput, { interac
684
684
  userFeatures: undefined,
685
685
  })
686
686
  ) {
687
- throw new CrudHttpError(404, { error: 'Email not found' })
687
+ throw notFound('Email not found')
688
688
  }
689
689
  }
690
690
 
@@ -915,7 +915,7 @@ const completeInteractionCommand: CommandHandler<InteractionCompleteInput, { int
915
915
  const interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: parsed.id, deletedAt: null })
916
916
  if (!interaction) {
917
917
  enforceRecordGoneIsConflict({ resourceKind: 'customers.interaction', resourceId: parsed.id, request: ctx.request ?? null })
918
- throw new CrudHttpError(404, { error: 'Interaction not found' })
918
+ throw notFound('Interaction not found')
919
919
  }
920
920
  ensureTenantScope(ctx, interaction.tenantId)
921
921
  ensureOrganizationScope(ctx, interaction.organizationId)
@@ -1055,7 +1055,7 @@ const cancelInteractionCommand: CommandHandler<InteractionCancelInput, { interac
1055
1055
  const interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: parsed.id, deletedAt: null })
1056
1056
  if (!interaction) {
1057
1057
  enforceRecordGoneIsConflict({ resourceKind: 'customers.interaction', resourceId: parsed.id, request: ctx.request ?? null })
1058
- throw new CrudHttpError(404, { error: 'Interaction not found' })
1058
+ throw notFound('Interaction not found')
1059
1059
  }
1060
1060
  ensureTenantScope(ctx, interaction.tenantId)
1061
1061
  ensureOrganizationScope(ctx, interaction.organizationId)
@@ -1193,7 +1193,7 @@ const deleteInteractionCommand: CommandHandler<{ body?: Record<string, unknown>;
1193
1193
  const interaction = await findOneWithDecryption(trx, CustomerInteraction, { id, deletedAt: null })
1194
1194
  if (!interaction) {
1195
1195
  enforceRecordGoneIsConflict({ resourceKind: 'customers.interaction', resourceId: id, request: ctx.request ?? null })
1196
- throw new CrudHttpError(404, { error: 'Interaction not found' })
1196
+ throw notFound('Interaction not found')
1197
1197
  }
1198
1198
  ensureTenantScope(ctx, interaction.tenantId)
1199
1199
  ensureOrganizationScope(ctx, interaction.organizationId)
@@ -2,7 +2,7 @@ import { registerCommand } from '@open-mercato/shared/lib/commands'
2
2
  import type { CommandHandler } from '@open-mercato/shared/lib/commands'
3
3
  import type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'
4
4
  import { emitCrudSideEffects, emitCrudUndoSideEffects } from '@open-mercato/shared/lib/commands/helpers'
5
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
5
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
6
6
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
7
7
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
8
8
  import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
@@ -287,7 +287,7 @@ const assignLabelCommand: CommandHandler<LabelAssignCommandInput, { assignmentId
287
287
  { tenantId: parsed.tenantId, organizationId: parsed.organizationId },
288
288
  )
289
289
  if (!label) {
290
- throw new CrudHttpError(404, { error: 'Label not found' })
290
+ throw notFound('Label not found')
291
291
  }
292
292
 
293
293
  const entity = await findOneWithDecryption(
@@ -298,7 +298,7 @@ const assignLabelCommand: CommandHandler<LabelAssignCommandInput, { assignmentId
298
298
  { tenantId: parsed.tenantId, organizationId: parsed.organizationId },
299
299
  )
300
300
  if (!entity) {
301
- throw new CrudHttpError(404, { error: 'Entity not found' })
301
+ throw notFound('Entity not found')
302
302
  }
303
303
 
304
304
  const existing = await findOneWithDecryption(
@@ -441,7 +441,7 @@ const assignLabelCommand: CommandHandler<LabelAssignCommandInput, { assignmentId
441
441
  { tenantId: after.tenantId, organizationId: after.organizationId },
442
442
  )
443
443
  if (!label) {
444
- throw new CrudHttpError(404, { error: 'Label not found' })
444
+ throw notFound('Label not found')
445
445
  }
446
446
  const entity = await findOneWithDecryption(
447
447
  em,
@@ -451,7 +451,7 @@ const assignLabelCommand: CommandHandler<LabelAssignCommandInput, { assignmentId
451
451
  { tenantId: after.tenantId, organizationId: after.organizationId },
452
452
  )
453
453
  if (!entity) {
454
- throw new CrudHttpError(404, { error: 'Entity not found' })
454
+ throw notFound('Entity not found')
455
455
  }
456
456
 
457
457
  let assignment = await findOneWithDecryption(
@@ -570,7 +570,7 @@ const unassignLabelCommand: CommandHandler<LabelUnassignCommandInput, { assignme
570
570
  { tenantId: parsed.tenantId, organizationId: parsed.organizationId },
571
571
  )
572
572
  if (!label) {
573
- throw new CrudHttpError(404, { error: 'Label not found' })
573
+ throw notFound('Label not found')
574
574
  }
575
575
 
576
576
  const entity = await findOneWithDecryption(
@@ -581,7 +581,7 @@ const unassignLabelCommand: CommandHandler<LabelUnassignCommandInput, { assignme
581
581
  { tenantId: parsed.tenantId, organizationId: parsed.organizationId },
582
582
  )
583
583
  if (!entity) {
584
- throw new CrudHttpError(404, { error: 'Entity not found' })
584
+ throw notFound('Entity not found')
585
585
  }
586
586
 
587
587
  const existing = await findOneWithDecryption(
@@ -46,7 +46,7 @@ import {
46
46
  } from './shared'
47
47
  import { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'
48
48
  import { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'
49
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
49
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
50
50
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
51
51
  import {
52
52
  loadCustomFieldSnapshot,
@@ -851,7 +851,7 @@ const createPersonCommand: CommandHandler<PersonCreateInput, { entityId: string;
851
851
  undefined,
852
852
  { tenantId: after.entity.tenantId, organizationId: after.entity.organizationId },
853
853
  )
854
- if (!existingProfile) throw new CrudHttpError(404, { error: 'Person profile not found' })
854
+ if (!existingProfile) throw notFound('Person profile not found')
855
855
  profile = existingProfile
856
856
  const survivingEntity = entity
857
857
  await withAtomicFlush(em, [
@@ -927,7 +927,7 @@ const updatePersonCommand: CommandHandler<PersonUpdateInput, { entityId: string
927
927
  ensureTenantScope(ctx, record.tenantId)
928
928
  ensureOrganizationScope(ctx, record.organizationId)
929
929
  const profile = await em.findOne(CustomerPersonProfile, { entity: record })
930
- if (!profile) throw new CrudHttpError(404, { error: 'Person profile not found' })
930
+ if (!profile) throw notFound('Person profile not found')
931
931
 
932
932
  if (parsed.displayName !== undefined) {
933
933
  const nextDisplayName = parsed.displayName.trim()
@@ -2,7 +2,7 @@ import { registerCommand } from '@open-mercato/shared/lib/commands'
2
2
  import type { CommandHandler } from '@open-mercato/shared/lib/commands'
3
3
  import type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'
4
4
  import { emitCrudSideEffects, emitCrudUndoSideEffects } from '@open-mercato/shared/lib/commands/helpers'
5
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
5
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
6
6
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
7
7
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
8
8
  import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
@@ -126,7 +126,7 @@ async function requirePersonEntity(
126
126
  { tenantId, organizationId },
127
127
  )
128
128
  if (!person) {
129
- throw new CrudHttpError(404, { error: 'Person not found' })
129
+ throw notFound('Person not found')
130
130
  }
131
131
  return person
132
132
  }
@@ -145,7 +145,7 @@ async function requireCompanyEntity(
145
145
  { tenantId, organizationId },
146
146
  )
147
147
  if (!company) {
148
- throw new CrudHttpError(404, { error: 'Company not found' })
148
+ throw notFound('Company not found')
149
149
  }
150
150
  return company
151
151
  }
@@ -162,7 +162,7 @@ async function requirePersonProfile(
162
162
  { tenantId: person.tenantId, organizationId: person.organizationId },
163
163
  )
164
164
  if (!profile) {
165
- throw new CrudHttpError(404, { error: 'Person profile not found' })
165
+ throw notFound('Person profile not found')
166
166
  }
167
167
  return profile
168
168
  }
@@ -433,7 +433,7 @@ const updatePersonCompanyLinkCommand: CommandHandler<PersonCompanyLinkUpdateInpu
433
433
  { tenantId: parsed.tenantId, organizationId: parsed.organizationId },
434
434
  )
435
435
  if (!link) {
436
- throw new CrudHttpError(404, { error: 'Company link not found' })
436
+ throw notFound('Company link not found')
437
437
  }
438
438
 
439
439
  const personId = typeof link.person === 'string' ? link.person : link.person.id
@@ -606,7 +606,7 @@ const deletePersonCompanyLinkCommand: CommandHandler<PersonCompanyLinkDeleteInpu
606
606
  { tenantId: parsed.tenantId, organizationId: parsed.organizationId },
607
607
  )
608
608
  if (!link) {
609
- throw new CrudHttpError(404, { error: 'Company link not found' })
609
+ throw notFound('Company link not found')
610
610
  }
611
611
 
612
612
  const personId = typeof link.person === 'string' ? link.person : link.person.id
@@ -14,7 +14,7 @@ import {
14
14
  type PipelineStageReorderInput,
15
15
  } from '../data/validators'
16
16
  import { ensureOrganizationScope, ensureTenantScope, ensureDictionaryEntry } from './shared'
17
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
17
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
18
18
  import { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'
19
19
  import {
20
20
  enforceCommandOptimisticLockWithGuards,
@@ -112,7 +112,7 @@ const updatePipelineStageCommand: CommandHandler<PipelineStageUpdateInput, void>
112
112
  })
113
113
  if (!stage) {
114
114
  enforceRecordGoneIsConflict({ resourceKind: 'customers.pipelineStage', resourceId: parsed.id, request: ctx.request ?? null })
115
- throw new CrudHttpError(404, { error: 'Pipeline stage not found' })
115
+ throw notFound('Pipeline stage not found')
116
116
  }
117
117
 
118
118
  ensureTenantScope(ctx, stage.tenantId)
@@ -164,7 +164,7 @@ const deletePipelineStageCommand: CommandHandler<PipelineStageDeleteInput, void>
164
164
  })
165
165
  if (!stage) {
166
166
  enforceRecordGoneIsConflict({ resourceKind: 'customers.pipelineStage', resourceId: parsed.id, request: ctx.request ?? null })
167
- throw new CrudHttpError(404, { error: 'Pipeline stage not found' })
167
+ throw notFound('Pipeline stage not found')
168
168
  }
169
169
 
170
170
  ensureTenantScope(ctx, stage.tenantId)
@@ -11,7 +11,7 @@ import {
11
11
  type PipelineDeleteInput,
12
12
  } from '../data/validators'
13
13
  import { ensureOrganizationScope, ensureTenantScope } from './shared'
14
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
14
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
15
15
  import {
16
16
  enforceCommandOptimisticLockWithGuards,
17
17
  enforceRecordGoneIsConflict,
@@ -62,7 +62,7 @@ const updatePipelineCommand: CommandHandler<PipelineUpdateInput, void> = {
62
62
  const pipeline = await em.findOne(CustomerPipeline, { id: parsed.id })
63
63
  if (!pipeline) {
64
64
  enforceRecordGoneIsConflict({ resourceKind: 'customers.pipeline', resourceId: parsed.id, request: ctx.request ?? null })
65
- throw new CrudHttpError(404, { error: 'Pipeline not found' })
65
+ throw notFound('Pipeline not found')
66
66
  }
67
67
 
68
68
  ensureTenantScope(ctx, pipeline.tenantId)
@@ -102,7 +102,7 @@ const deletePipelineCommand: CommandHandler<PipelineDeleteInput, void> = {
102
102
  const pipeline = await em.findOne(CustomerPipeline, { id: parsed.id })
103
103
  if (!pipeline) {
104
104
  enforceRecordGoneIsConflict({ resourceKind: 'customers.pipeline', resourceId: parsed.id, request: ctx.request ?? null })
105
- throw new CrudHttpError(404, { error: 'Pipeline not found' })
105
+ throw notFound('Pipeline not found')
106
106
  }
107
107
 
108
108
  ensureTenantScope(ctx, pipeline.tenantId)
@@ -1,6 +1,6 @@
1
1
  import type { EntityManager } from '@mikro-orm/postgresql'
2
2
  import { CustomerDeal, CustomerEntity, CustomerTag, CustomerTagAssignment, CustomerDictionaryEntry, type CustomerEntityKind } from '../data/entities'
3
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
3
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
4
4
  import type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
5
5
  import { ensureOrganizationScope, ensureSameScope } from '@open-mercato/shared/lib/commands/scope'
6
6
  import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
@@ -47,7 +47,7 @@ export async function requireCustomerEntity(
47
47
  tenantId: scope.tenantId,
48
48
  organizationId: scope.organizationId,
49
49
  })
50
- if (!entity) throw new CrudHttpError(404, { error: message })
50
+ if (!entity) throw notFound(message)
51
51
  if (kind && entity.kind !== kind) {
52
52
  throw new CrudHttpError(400, { error: 'Invalid entity type' })
53
53
  }
@@ -80,7 +80,7 @@ export async function requireTimelineParentEntity(
80
80
  if (deal) {
81
81
  throw new CrudHttpError(422, { error: 'entityId must reference a person or company, not a deal' })
82
82
  }
83
- throw new CrudHttpError(404, { error: 'Customer not found' })
83
+ throw notFound('Customer not found')
84
84
  }
85
85
 
86
86
  export async function syncEntityTags(
@@ -21,7 +21,7 @@ import {
21
21
  loadEntityTagIds,
22
22
  } from './shared'
23
23
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
24
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
24
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
25
25
  import type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'
26
26
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
27
27
  import { emitCustomersEvent } from '../events'
@@ -172,7 +172,7 @@ const updateTagCommand: CommandHandler<TagUpdateInput, { tagId: string }> = {
172
172
  const parsed = tagUpdateSchema.parse(rawInput)
173
173
  const em = (ctx.container.resolve('em') as EntityManager).fork()
174
174
  const tag = await em.findOne(CustomerTag, { id: parsed.id })
175
- if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })
175
+ if (!tag) throw notFound('Tag not found')
176
176
  ensureTenantScope(ctx, tag.tenantId)
177
177
  ensureOrganizationScope(ctx, tag.organizationId)
178
178
 
@@ -290,7 +290,7 @@ const deleteTagCommand: CommandHandler<{ body?: Record<string, unknown>; query?:
290
290
  const id = requireId(input, 'Tag id required')
291
291
  const em = (ctx.container.resolve('em') as EntityManager).fork()
292
292
  const tag = await em.findOne(CustomerTag, { id })
293
- if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })
293
+ if (!tag) throw notFound('Tag not found')
294
294
  ensureTenantScope(ctx, tag.tenantId)
295
295
  ensureOrganizationScope(ctx, tag.organizationId)
296
296
  await withAtomicFlush(em, [
@@ -386,7 +386,7 @@ const assignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: strin
386
386
 
387
387
  const em = (ctx.container.resolve('em') as EntityManager).fork()
388
388
  const tag = await em.findOne(CustomerTag, { id: parsed.tagId, tenantId: parsed.tenantId, organizationId: parsed.organizationId })
389
- if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })
389
+ if (!tag) throw notFound('Tag not found')
390
390
  const entity = await requireCustomerEntity(em, parsed.entityId, { tenantId: parsed.tenantId, organizationId: parsed.organizationId }, undefined, 'Customer not found')
391
391
  ensureSameScope(entity, parsed.organizationId, parsed.tenantId)
392
392
  const tagIds = await loadEntityTagIds(em, entity)
@@ -477,7 +477,7 @@ const assignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: strin
477
477
  const assignmentId = logEntry?.resourceId ?? null
478
478
  const em = (ctx.container.resolve('em') as EntityManager).fork()
479
479
  const tag = await em.findOne(CustomerTag, { id: before.tagId })
480
- if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })
480
+ if (!tag) throw notFound('Tag not found')
481
481
  const entity = await requireCustomerEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId }, undefined, 'Customer not found')
482
482
  ensureSameScope(entity, before.organizationId, before.tenantId)
483
483
 
@@ -537,7 +537,7 @@ const unassignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: str
537
537
  tenantId: parsed.tenantId,
538
538
  organizationId: parsed.organizationId,
539
539
  })
540
- if (!existing) throw new CrudHttpError(404, { error: 'Tag assignment not found' })
540
+ if (!existing) throw notFound('Tag assignment not found')
541
541
  await em.remove(existing).flush()
542
542
 
543
543
  const de = (ctx.container.resolve('dataEngine') as DataEngine)
@@ -591,7 +591,7 @@ const unassignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: str
591
591
  const tag = await em.findOne(CustomerTag, { id: before.tagId })
592
592
  const entity = await requireCustomerEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId }, undefined, 'Customer not found')
593
593
  ensureSameScope(entity, before.organizationId, before.tenantId)
594
- if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })
594
+ if (!tag) throw notFound('Tag not found')
595
595
  const existing = await em.findOne(CustomerTagAssignment, {
596
596
  tag,
597
597
  entity,
@@ -16,7 +16,7 @@ import {
16
16
  resolveParentResourceKind,
17
17
  } from './shared'
18
18
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
19
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
19
+ import { notFound } from '@open-mercato/shared/lib/crud/errors'
20
20
  import {
21
21
  CUSTOMER_INTERACTION_TASK_SOURCE,
22
22
  CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,
@@ -290,7 +290,7 @@ async function resolveTodoTarget(
290
290
  const em = (ctx.container.resolve('em') as EntityManager).fork()
291
291
  const legacyLink = await em.findOne(CustomerTodoLink, { id: linkId }, { populate: ['entity'] })
292
292
  if (!legacyLink) {
293
- throw new CrudHttpError(404, { error: 'Todo link not found' })
293
+ throw notFound('Todo link not found')
294
294
  }
295
295
 
296
296
  const bridgedSnapshot = await loadInteractionSnapshot(legacyLink.todoId, ctx)
@@ -333,7 +333,7 @@ const unlinkTodoCommand: CommandHandler<
333
333
  const target = await resolveTodoTarget(parsed.linkId, ctx)
334
334
  if (!target.canonicalExists) {
335
335
  if (!target.legacyLink) {
336
- throw new CrudHttpError(404, { error: 'Todo link not found' })
336
+ throw notFound('Todo link not found')
337
337
  }
338
338
  const canonicalCreate = getRequiredHandler<
339
339
  InteractionCreateInput & { customValues?: Record<string, unknown> },
@@ -1,5 +1,5 @@
1
1
  import type { EntityManager } from '@mikro-orm/postgresql'
2
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
2
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
3
3
  import { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
4
4
  import {
5
5
  CustomerEntity,
@@ -48,7 +48,7 @@ async function requireCompany(
48
48
  ): Promise<CustomerEntity> {
49
49
  const company = await findOneWithDecryption(em, CustomerEntity, { id: companyId, kind: 'company', deletedAt: null }, {}, { tenantId, organizationId })
50
50
  if (!company) {
51
- throw new CrudHttpError(404, { error: 'Company not found' })
51
+ throw notFound('Company not found')
52
52
  }
53
53
  if (company.organizationId !== organizationId || company.tenantId !== tenantId) {
54
54
  throw new CrudHttpError(403, { error: 'Cannot link company outside current scope' })
@@ -260,7 +260,7 @@ export async function updatePersonCompanyLink(
260
260
  }
261
261
 
262
262
  if (!link) {
263
- throw new CrudHttpError(404, { error: 'Company link not found' })
263
+ throw notFound('Company link not found')
264
264
  }
265
265
 
266
266
  if (patch.isPrimary === true) {
@@ -301,7 +301,7 @@ export async function removePersonCompanyLink(
301
301
  profile.company = null
302
302
  return
303
303
  }
304
- throw new CrudHttpError(404, { error: 'Company link not found' })
304
+ throw notFound('Company link not found')
305
305
  }
306
306
 
307
307
  const removedCompanyId = typeof link.company === 'string' ? link.company : link.company.id
@@ -4,6 +4,10 @@ import type { PerspectiveSettings } from '@open-mercato/shared/modules/perspecti
4
4
  export const perspectiveSettingsSchema: z.ZodType<PerspectiveSettings> = z.object({
5
5
  columnOrder: z.array(z.string().min(1)).max(120).optional(),
6
6
  columnVisibility: z.record(z.string(), z.boolean()).optional(),
7
+ // User-resized column widths in pixels, keyed by column id (#1835). Clamped to
8
+ // the same [60, 900] bound the client enforces so a saved perspective cannot
9
+ // carry a column width that collapses or blows out the table.
10
+ columnSizing: z.record(z.string().min(1), z.number().int().min(60).max(900)).optional(),
7
11
  filters: z.record(z.string(), z.unknown()).optional(),
8
12
  sorting: z
9
13
  .array(z.object({ id: z.string().min(1), desc: z.boolean().optional() }))
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod'
2
2
  import type { EntityManager } from '@mikro-orm/postgresql'
3
3
  import { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'
4
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
4
+ import { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
5
5
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
6
6
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
7
7
  import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
@@ -97,9 +97,7 @@ async function loadNoteForPermission(
97
97
  })
98
98
 
99
99
  if (!note) {
100
- throw new CrudHttpError(404, {
101
- error: translate('sales.documents.detail.error', 'Document not found or inaccessible.'),
102
- })
100
+ throw notFound(translate('sales.documents.detail.error', 'Document not found or inaccessible.'))
103
101
  }
104
102
 
105
103
  return note
@@ -3,7 +3,7 @@ import { z } from 'zod'
3
3
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
4
  import type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
5
5
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
6
- import { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
6
+ import { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
7
7
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
8
8
  import type { EntityManager } from '@mikro-orm/postgresql'
9
9
  import { LockMode } from '@mikro-orm/core'
@@ -93,7 +93,7 @@ export async function POST(req: Request) {
93
93
  )
94
94
  const quote = (await findQuoteByToken(hashedToken)) ?? (await findQuoteByToken(token))
95
95
  if (!quote) {
96
- throw new CrudHttpError(404, { error: translate('sales.quotes.accept.notFound', 'Quote not found.') })
96
+ throw notFound(translate('sales.quotes.accept.notFound', 'Quote not found.'))
97
97
  }
98
98
 
99
99
  const now = new Date()
@@ -2,7 +2,7 @@ import { NextResponse } from "next/server";
2
2
  import { z } from "zod";
3
3
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
- import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
5
+ import { isCrudHttpError, notFound } from "@open-mercato/shared/lib/crud/errors";
6
6
  import type { OpenApiRouteDoc } from "@open-mercato/shared/lib/openapi";
7
7
  import type { EntityManager } from "@mikro-orm/postgresql";
8
8
  import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
@@ -43,16 +43,12 @@ export async function GET(req: Request, ctx: { params: { token: string } }) {
43
43
  }));
44
44
  const { translate } = await resolveTranslations();
45
45
  if (!quote) {
46
- throw new CrudHttpError(404, {
47
- error: translate("sales.quotes.public.notFound", "Quote not found."),
48
- });
46
+ throw notFound(translate("sales.quotes.public.notFound", "Quote not found."));
49
47
  }
50
48
 
51
49
  const auth = await getAuthFromRequest(req);
52
50
  if (auth?.tenantId && quote.tenantId !== auth.tenantId) {
53
- throw new CrudHttpError(404, {
54
- error: translate("sales.quotes.public.notFound", "Quote not found."),
55
- });
51
+ throw notFound(translate("sales.quotes.public.notFound", "Quote not found."));
56
52
  }
57
53
 
58
54
  const now = new Date();
@@ -5,7 +5,7 @@ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
5
5
  import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
6
6
  import type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
7
7
  import { resolveTranslations, detectLocale } from '@open-mercato/shared/lib/i18n/server'
8
- import { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
8
+ import { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
9
9
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
10
10
  import {
11
11
  bridgeLegacyGuard,
@@ -151,7 +151,7 @@ export async function POST(req: Request) {
151
151
  const tenantScope = ctx.auth?.tenantId ? { tenantId: ctx.auth.tenantId } : undefined
152
152
  const quote = await findOneWithDecryption(em, SalesQuote, { id: input.quoteId, deletedAt: null }, {}, tenantScope)
153
153
  if (!quote) {
154
- throw new CrudHttpError(404, { error: translate('sales.documents.detail.error', 'Document not found or inaccessible.') })
154
+ throw notFound(translate('sales.documents.detail.error', 'Document not found or inaccessible.'))
155
155
  }
156
156
  if (quote.tenantId !== ctx.auth?.tenantId || quote.organizationId !== ctx.selectedOrganizationId) {
157
157
  throw new CrudHttpError(403, { error: translate('sales.documents.errors.forbidden', 'Forbidden') })
@@ -6,7 +6,7 @@ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
6
6
  import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
7
7
  import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
8
8
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
9
- import { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
9
+ import { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
10
10
  import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
11
11
  import { SalesReturn, SalesReturnLine } from '../../../data/entities'
12
12
  import { createLogger } from '@open-mercato/shared/lib/logger'
@@ -56,7 +56,7 @@ export async function GET(req: Request, ctx: { params: { id: string } }) {
56
56
  { tenantId: auth.tenantId, organizationId },
57
57
  )
58
58
  if (!header || !header.order) {
59
- throw new CrudHttpError(404, { error: translate('sales.returns.notFound', 'Return not found.') })
59
+ throw notFound(translate('sales.returns.notFound', 'Return not found.'))
60
60
  }
61
61
 
62
62
  const lines = await findWithDecryption(
@@ -9,7 +9,7 @@ import {
9
9
  emitCrudUndoSideEffects,
10
10
  } from '@open-mercato/shared/lib/commands/helpers'
11
11
  import type { EntityManager } from '@mikro-orm/postgresql'
12
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
12
+ import { notFound } from '@open-mercato/shared/lib/crud/errors'
13
13
  import { loadCustomFieldSnapshot, buildCustomFieldResetMap } from '@open-mercato/shared/lib/commands/customFieldSnapshots'
14
14
  import { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'
15
15
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
@@ -751,7 +751,7 @@ const updateChannelCommand: CommandHandler<ChannelUpdateInput, { channelId: stri
751
751
  const { parsed, custom } = parseWithCustomFields(channelUpdateSchema, rawInput)
752
752
  const em = (ctx.container.resolve('em') as EntityManager).fork()
753
753
  const record = await findOneWithDecryption(em, SalesChannel, { id: parsed.id, deletedAt: null }, {}, { tenantId: parsed.tenantId, organizationId: parsed.organizationId })
754
- if (!record) throw new CrudHttpError(404, { error: 'Channel not found' })
754
+ if (!record) throw notFound('Channel not found')
755
755
  const dataEngine = ctx.container.resolve('dataEngine') as DataEngine
756
756
  const scope = resolveScopeFromUpdate(record, parsed, ctx)
757
757
 
@@ -899,7 +899,7 @@ const deleteChannelCommand: CommandHandler<
899
899
  const id = requireId(input, 'Channel id is required')
900
900
  const em = (ctx.container.resolve('em') as EntityManager).fork()
901
901
  const record = await findOneWithDecryption(em, SalesChannel, { id }, {})
902
- if (!record) throw new CrudHttpError(404, { error: 'Channel not found' })
902
+ if (!record) throw notFound('Channel not found')
903
903
  ensureTenantScope(ctx, record.tenantId)
904
904
  ensureOrganizationScope(ctx, record.organizationId)
905
905
  em.remove(record)
@@ -1097,7 +1097,7 @@ const updateDeliveryWindowCommand: CommandHandler<
1097
1097
  const { parsed, custom } = parseWithCustomFields(deliveryWindowUpdateSchema, rawInput)
1098
1098
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1099
1099
  const record = await em.findOne(SalesDeliveryWindow, { id: parsed.id, deletedAt: null })
1100
- if (!record) throw new CrudHttpError(404, { error: 'Delivery window not found' })
1100
+ if (!record) throw notFound('Delivery window not found')
1101
1101
  const scope = resolveScopeFromUpdate(record, parsed, ctx)
1102
1102
  record.organizationId = scope.organizationId
1103
1103
  record.tenantId = scope.tenantId
@@ -1201,7 +1201,7 @@ const deleteDeliveryWindowCommand: CommandHandler<
1201
1201
  const id = requireId(input, 'Delivery window id is required')
1202
1202
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1203
1203
  const record = await em.findOne(SalesDeliveryWindow, { id })
1204
- if (!record) throw new CrudHttpError(404, { error: 'Delivery window not found' })
1204
+ if (!record) throw notFound('Delivery window not found')
1205
1205
  ensureTenantScope(ctx, record.tenantId)
1206
1206
  ensureOrganizationScope(ctx, record.organizationId)
1207
1207
  em.remove(record)
@@ -1377,7 +1377,7 @@ const updateShippingMethodCommand: CommandHandler<
1377
1377
  const { parsed, custom } = parseWithCustomFields(shippingMethodUpdateSchema, rawInput)
1378
1378
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1379
1379
  const record = await em.findOne(SalesShippingMethod, { id: parsed.id, deletedAt: null })
1380
- if (!record) throw new CrudHttpError(404, { error: 'Shipping method not found' })
1380
+ if (!record) throw notFound('Shipping method not found')
1381
1381
  const scope = resolveScopeFromUpdate(record, parsed, ctx)
1382
1382
  record.organizationId = scope.organizationId
1383
1383
  record.tenantId = scope.tenantId
@@ -1501,7 +1501,7 @@ const deleteShippingMethodCommand: CommandHandler<
1501
1501
  const id = requireId(input, 'Shipping method id is required')
1502
1502
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1503
1503
  const record = await em.findOne(SalesShippingMethod, { id })
1504
- if (!record) throw new CrudHttpError(404, { error: 'Shipping method not found' })
1504
+ if (!record) throw notFound('Shipping method not found')
1505
1505
  ensureTenantScope(ctx, record.tenantId)
1506
1506
  ensureOrganizationScope(ctx, record.organizationId)
1507
1507
  em.remove(record)
@@ -1672,7 +1672,7 @@ const updatePaymentMethodCommand: CommandHandler<
1672
1672
  const { parsed, custom } = parseWithCustomFields(paymentMethodUpdateSchema, rawInput)
1673
1673
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1674
1674
  const record = await em.findOne(SalesPaymentMethod, { id: parsed.id, deletedAt: null })
1675
- if (!record) throw new CrudHttpError(404, { error: 'Payment method not found' })
1675
+ if (!record) throw notFound('Payment method not found')
1676
1676
  const scope = resolveScopeFromUpdate(record, parsed, ctx)
1677
1677
  record.organizationId = scope.organizationId
1678
1678
  record.tenantId = scope.tenantId
@@ -1785,7 +1785,7 @@ const deletePaymentMethodCommand: CommandHandler<
1785
1785
  const id = requireId(input, 'Payment method id is required')
1786
1786
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1787
1787
  const record = await em.findOne(SalesPaymentMethod, { id })
1788
- if (!record) throw new CrudHttpError(404, { error: 'Payment method not found' })
1788
+ if (!record) throw notFound('Payment method not found')
1789
1789
  ensureTenantScope(ctx, record.tenantId)
1790
1790
  ensureOrganizationScope(ctx, record.organizationId)
1791
1791
  em.remove(record)
@@ -1971,7 +1971,7 @@ const updateTaxRateCommand: CommandHandler<TaxRateUpdateInput, { taxRateId: stri
1971
1971
  const { parsed, custom } = parseWithCustomFields(taxRateUpdateSchema, rawInput)
1972
1972
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1973
1973
  const record = await em.findOne(SalesTaxRate, { id: parsed.id, deletedAt: null })
1974
- if (!record) throw new CrudHttpError(404, { error: 'Tax rate not found' })
1974
+ if (!record) throw notFound('Tax rate not found')
1975
1975
  const scope = resolveScopeFromUpdate(record, parsed, ctx)
1976
1976
  record.organizationId = scope.organizationId
1977
1977
  record.tenantId = scope.tenantId
@@ -2102,7 +2102,7 @@ const deleteTaxRateCommand: CommandHandler<
2102
2102
  const id = requireId(input, 'Tax rate id is required')
2103
2103
  const em = (ctx.container.resolve('em') as EntityManager).fork()
2104
2104
  const record = await em.findOne(SalesTaxRate, { id })
2105
- if (!record) throw new CrudHttpError(404, { error: 'Tax rate not found' })
2105
+ if (!record) throw notFound('Tax rate not found')
2106
2106
  ensureTenantScope(ctx, record.tenantId)
2107
2107
  ensureOrganizationScope(ctx, record.organizationId)
2108
2108
  const snapshot = await loadTaxRateSnapshot((ctx.container.resolve('em') as EntityManager), id)