@open-mercato/core 0.7.1-develop.7130.1.fef2396fd8 → 0.7.1-develop.7135.1.19bf969756

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 (242) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
  3. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +5 -0
  4. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
  5. package/dist/modules/auth/api/profile/route.js +5 -0
  6. package/dist/modules/auth/api/profile/route.js.map +2 -2
  7. package/dist/modules/communication_channels/api/post/test-seed/route.js +40 -2
  8. package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
  9. package/dist/modules/communication_channels/lib/access-control.js +6 -1
  10. package/dist/modules/communication_channels/lib/access-control.js.map +2 -2
  11. package/dist/modules/communication_channels/lib/system-user.js +8 -3
  12. package/dist/modules/communication_channels/lib/system-user.js.map +2 -2
  13. package/dist/modules/customers/api/activities/route.js +13 -0
  14. package/dist/modules/customers/api/activities/route.js.map +2 -2
  15. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +9 -0
  16. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  17. package/dist/modules/customers/api/dictionaries/[kind]/route.js +5 -0
  18. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  19. package/dist/modules/customers/api/dictionaries/kind-settings/route.js +5 -0
  20. package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +2 -2
  21. package/dist/modules/customers/api/interactions/cancel/route.js +5 -0
  22. package/dist/modules/customers/api/interactions/cancel/route.js.map +2 -2
  23. package/dist/modules/customers/api/interactions/complete/route.js +5 -0
  24. package/dist/modules/customers/api/interactions/complete/route.js.map +2 -2
  25. package/dist/modules/customers/api/labels/assign/route.js +5 -0
  26. package/dist/modules/customers/api/labels/assign/route.js.map +2 -2
  27. package/dist/modules/customers/api/labels/route.js +5 -0
  28. package/dist/modules/customers/api/labels/route.js.map +2 -2
  29. package/dist/modules/customers/api/labels/unassign/route.js +5 -0
  30. package/dist/modules/customers/api/labels/unassign/route.js.map +2 -2
  31. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +9 -0
  32. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
  33. package/dist/modules/customers/api/people/[id]/companies/route.js +5 -0
  34. package/dist/modules/customers/api/people/[id]/companies/route.js.map +2 -2
  35. package/dist/modules/customers/api/pipeline-stages/reorder/route.js +5 -0
  36. package/dist/modules/customers/api/pipeline-stages/reorder/route.js.map +2 -2
  37. package/dist/modules/customers/api/pipeline-stages/route.js +13 -0
  38. package/dist/modules/customers/api/pipeline-stages/route.js.map +2 -2
  39. package/dist/modules/customers/api/pipelines/route.js +13 -0
  40. package/dist/modules/customers/api/pipelines/route.js.map +2 -2
  41. package/dist/modules/customers/api/settings/address-format/route.js +5 -0
  42. package/dist/modules/customers/api/settings/address-format/route.js.map +2 -2
  43. package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js +5 -0
  44. package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js.map +2 -2
  45. package/dist/modules/customers/api/settings/stuck-threshold/route.js +5 -0
  46. package/dist/modules/customers/api/settings/stuck-threshold/route.js.map +2 -2
  47. package/dist/modules/customers/api/tags/assign/route.js +5 -0
  48. package/dist/modules/customers/api/tags/assign/route.js.map +2 -2
  49. package/dist/modules/customers/api/tags/unassign/route.js +5 -0
  50. package/dist/modules/customers/api/tags/unassign/route.js.map +2 -2
  51. package/dist/modules/customers/api/todos/route.js +13 -0
  52. package/dist/modules/customers/api/todos/route.js.map +2 -2
  53. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +9 -0
  54. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  55. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +5 -0
  56. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +2 -2
  57. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +5 -0
  58. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
  59. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +5 -0
  60. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +2 -2
  61. package/dist/modules/directory/api/organization-branding/route.js +5 -0
  62. package/dist/modules/directory/api/organization-branding/route.js.map +2 -2
  63. package/dist/modules/eudr/api/plots/import/route.js.map +2 -2
  64. package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js.map +2 -2
  65. package/dist/modules/feature_toggles/api/overrides/route.js +5 -0
  66. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  67. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js +5 -0
  68. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js.map +2 -2
  69. package/dist/modules/messages/api/[id]/conversation/archive/route.js +5 -0
  70. package/dist/modules/messages/api/[id]/conversation/archive/route.js.map +2 -2
  71. package/dist/modules/messages/api/[id]/conversation/read/route.js +5 -0
  72. package/dist/modules/messages/api/[id]/conversation/read/route.js.map +2 -2
  73. package/dist/modules/messages/api/[id]/conversation/route.js +5 -0
  74. package/dist/modules/messages/api/[id]/conversation/route.js.map +2 -2
  75. package/dist/modules/messages/api/[id]/forward/route.js +5 -0
  76. package/dist/modules/messages/api/[id]/forward/route.js.map +2 -2
  77. package/dist/modules/messages/api/[id]/reply/route.js +5 -0
  78. package/dist/modules/messages/api/[id]/reply/route.js.map +2 -2
  79. package/dist/modules/messages/api/[id]/route.js +9 -0
  80. package/dist/modules/messages/api/[id]/route.js.map +2 -2
  81. package/dist/modules/messages/api/token/[token]/route.js +5 -0
  82. package/dist/modules/messages/api/token/[token]/route.js.map +2 -2
  83. package/dist/modules/resources/api/resources/tags/assign/route.js +5 -0
  84. package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
  85. package/dist/modules/resources/api/resources/tags/unassign/route.js +5 -0
  86. package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
  87. package/dist/modules/sales/api/quotes/accept/route.js +5 -0
  88. package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
  89. package/dist/modules/sales/api/quotes/convert/route.js +5 -0
  90. package/dist/modules/sales/api/quotes/convert/route.js.map +2 -2
  91. package/dist/modules/sales/api/settings/document-numbers/route.js +5 -0
  92. package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
  93. package/dist/modules/sales/api/settings/order-editing/route.js +5 -0
  94. package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
  95. package/dist/modules/staff/api/leave-requests/accept/route.js +5 -0
  96. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  97. package/dist/modules/staff/api/leave-requests/reject/route.js +5 -0
  98. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  99. package/dist/modules/staff/api/team-members/self/route.js +5 -0
  100. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  101. package/dist/modules/staff/api/team-members/tags/assign/route.js +5 -0
  102. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  103. package/dist/modules/staff/api/team-members/tags/unassign/route.js +5 -0
  104. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  105. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +5 -0
  106. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
  107. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +9 -0
  108. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  109. package/dist/modules/warranty_claims/api/ai/assess/route.js +25 -18
  110. package/dist/modules/warranty_claims/api/ai/assess/route.js.map +2 -2
  111. package/dist/modules/warranty_claims/api/assign/route.js +5 -0
  112. package/dist/modules/warranty_claims/api/assign/route.js.map +2 -2
  113. package/dist/modules/warranty_claims/api/credit-memo/route.js +16 -12
  114. package/dist/modules/warranty_claims/api/credit-memo/route.js.map +2 -2
  115. package/dist/modules/warranty_claims/api/events/route.js +6 -1
  116. package/dist/modules/warranty_claims/api/events/route.js.map +2 -2
  117. package/dist/modules/warranty_claims/api/portal/attachments/route.js +24 -27
  118. package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
  119. package/dist/modules/warranty_claims/api/portal/claims/[id]/route.js +8 -10
  120. package/dist/modules/warranty_claims/api/portal/claims/[id]/route.js.map +2 -2
  121. package/dist/modules/warranty_claims/api/portal/claims/[id]/shared.js +4 -9
  122. package/dist/modules/warranty_claims/api/portal/claims/[id]/shared.js.map +2 -2
  123. package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js +8 -3
  124. package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js.map +2 -2
  125. package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js +8 -3
  126. package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js.map +2 -2
  127. package/dist/modules/warranty_claims/api/portal/claims/route.js +9 -9
  128. package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
  129. package/dist/modules/warranty_claims/api/portal/events/route.js +17 -13
  130. package/dist/modules/warranty_claims/api/portal/events/route.js.map +2 -2
  131. package/dist/modules/warranty_claims/api/receiving/route.js +19 -15
  132. package/dist/modules/warranty_claims/api/receiving/route.js.map +2 -2
  133. package/dist/modules/warranty_claims/api/registrations/route.js +9 -4
  134. package/dist/modules/warranty_claims/api/registrations/route.js.map +2 -2
  135. package/dist/modules/warranty_claims/api/replacement-order/route.js +16 -12
  136. package/dist/modules/warranty_claims/api/replacement-order/route.js.map +2 -2
  137. package/dist/modules/warranty_claims/api/return-label/route.js +25 -19
  138. package/dist/modules/warranty_claims/api/return-label/route.js.map +2 -2
  139. package/dist/modules/warranty_claims/api/risk/route.js +2 -1
  140. package/dist/modules/warranty_claims/api/risk/route.js.map +2 -2
  141. package/dist/modules/warranty_claims/api/sales-return/route.js +16 -12
  142. package/dist/modules/warranty_claims/api/sales-return/route.js.map +2 -2
  143. package/dist/modules/warranty_claims/api/settings-general/route.js +5 -0
  144. package/dist/modules/warranty_claims/api/settings-general/route.js.map +2 -2
  145. package/dist/modules/warranty_claims/api/submit/route.js +5 -0
  146. package/dist/modules/warranty_claims/api/submit/route.js.map +2 -2
  147. package/dist/modules/warranty_claims/api/transition/route.js +5 -0
  148. package/dist/modules/warranty_claims/api/transition/route.js.map +2 -2
  149. package/dist/modules/warranty_claims/api/troubleshooting-guides/route.js +22 -1
  150. package/dist/modules/warranty_claims/api/troubleshooting-guides/route.js.map +2 -2
  151. package/dist/modules/warranty_claims/api/vendor-recovery/route.js +5 -0
  152. package/dist/modules/warranty_claims/api/vendor-recovery/route.js.map +2 -2
  153. package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js +2 -1
  154. package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js.map +2 -2
  155. package/dist/modules/warranty_claims/commands/shared.js +2 -2
  156. package/dist/modules/warranty_claims/commands/shared.js.map +2 -2
  157. package/dist/modules/warranty_claims/lib/portalAuthGuard.js +31 -0
  158. package/dist/modules/warranty_claims/lib/portalAuthGuard.js.map +7 -0
  159. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js +5 -0
  160. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js.map +2 -2
  161. package/package.json +7 -7
  162. package/src/helpers/integration/communicationChannelsFixtures.ts +13 -0
  163. package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +5 -0
  164. package/src/modules/auth/api/profile/route.ts +5 -0
  165. package/src/modules/communication_channels/api/post/test-seed/route.ts +47 -2
  166. package/src/modules/communication_channels/lib/access-control.ts +28 -0
  167. package/src/modules/communication_channels/lib/system-user.ts +40 -22
  168. package/src/modules/customers/api/activities/route.ts +13 -0
  169. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +9 -0
  170. package/src/modules/customers/api/dictionaries/[kind]/route.ts +5 -0
  171. package/src/modules/customers/api/dictionaries/kind-settings/route.ts +5 -0
  172. package/src/modules/customers/api/interactions/cancel/route.ts +5 -0
  173. package/src/modules/customers/api/interactions/complete/route.ts +5 -0
  174. package/src/modules/customers/api/labels/assign/route.ts +5 -0
  175. package/src/modules/customers/api/labels/route.ts +5 -0
  176. package/src/modules/customers/api/labels/unassign/route.ts +5 -0
  177. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +9 -0
  178. package/src/modules/customers/api/people/[id]/companies/route.ts +5 -0
  179. package/src/modules/customers/api/pipeline-stages/reorder/route.ts +5 -0
  180. package/src/modules/customers/api/pipeline-stages/route.ts +13 -0
  181. package/src/modules/customers/api/pipelines/route.ts +13 -0
  182. package/src/modules/customers/api/settings/address-format/route.ts +5 -0
  183. package/src/modules/customers/api/settings/dictionary-sort-modes/route.ts +5 -0
  184. package/src/modules/customers/api/settings/stuck-threshold/route.ts +5 -0
  185. package/src/modules/customers/api/tags/assign/route.ts +5 -0
  186. package/src/modules/customers/api/tags/unassign/route.ts +5 -0
  187. package/src/modules/customers/api/todos/route.ts +13 -0
  188. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +9 -0
  189. package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +5 -0
  190. package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +5 -0
  191. package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +5 -0
  192. package/src/modules/directory/api/organization-branding/route.ts +5 -0
  193. package/src/modules/eudr/api/plots/import/route.ts +7 -0
  194. package/src/modules/eudr/api/product-mappings/suggestions/apply/route.ts +7 -0
  195. package/src/modules/feature_toggles/api/overrides/route.ts +5 -0
  196. package/src/modules/messages/api/[id]/actions/[actionId]/route.ts +5 -0
  197. package/src/modules/messages/api/[id]/conversation/archive/route.ts +5 -0
  198. package/src/modules/messages/api/[id]/conversation/read/route.ts +5 -0
  199. package/src/modules/messages/api/[id]/conversation/route.ts +5 -0
  200. package/src/modules/messages/api/[id]/forward/route.ts +5 -0
  201. package/src/modules/messages/api/[id]/reply/route.ts +5 -0
  202. package/src/modules/messages/api/[id]/route.ts +9 -0
  203. package/src/modules/messages/api/token/[token]/route.ts +5 -0
  204. package/src/modules/resources/api/resources/tags/assign/route.ts +5 -0
  205. package/src/modules/resources/api/resources/tags/unassign/route.ts +5 -0
  206. package/src/modules/sales/api/quotes/accept/route.ts +5 -0
  207. package/src/modules/sales/api/quotes/convert/route.ts +5 -0
  208. package/src/modules/sales/api/settings/document-numbers/route.ts +5 -0
  209. package/src/modules/sales/api/settings/order-editing/route.ts +5 -0
  210. package/src/modules/staff/api/leave-requests/accept/route.ts +5 -0
  211. package/src/modules/staff/api/leave-requests/reject/route.ts +5 -0
  212. package/src/modules/staff/api/team-members/self/route.ts +5 -0
  213. package/src/modules/staff/api/team-members/tags/assign/route.ts +5 -0
  214. package/src/modules/staff/api/team-members/tags/unassign/route.ts +5 -0
  215. package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +5 -0
  216. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +9 -0
  217. package/src/modules/warranty_claims/api/ai/assess/route.ts +28 -17
  218. package/src/modules/warranty_claims/api/assign/route.ts +5 -0
  219. package/src/modules/warranty_claims/api/credit-memo/route.ts +19 -13
  220. package/src/modules/warranty_claims/api/events/route.ts +6 -1
  221. package/src/modules/warranty_claims/api/portal/attachments/route.ts +29 -27
  222. package/src/modules/warranty_claims/api/portal/claims/[id]/route.ts +9 -10
  223. package/src/modules/warranty_claims/api/portal/claims/[id]/shared.ts +5 -9
  224. package/src/modules/warranty_claims/api/portal/claims/[id]/submit/route.ts +8 -3
  225. package/src/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.ts +8 -3
  226. package/src/modules/warranty_claims/api/portal/claims/route.ts +10 -9
  227. package/src/modules/warranty_claims/api/portal/events/route.ts +18 -13
  228. package/src/modules/warranty_claims/api/receiving/route.ts +22 -15
  229. package/src/modules/warranty_claims/api/registrations/route.ts +9 -3
  230. package/src/modules/warranty_claims/api/replacement-order/route.ts +19 -13
  231. package/src/modules/warranty_claims/api/return-label/route.ts +26 -17
  232. package/src/modules/warranty_claims/api/risk/route.ts +3 -1
  233. package/src/modules/warranty_claims/api/sales-return/route.ts +19 -13
  234. package/src/modules/warranty_claims/api/settings-general/route.ts +5 -0
  235. package/src/modules/warranty_claims/api/submit/route.ts +5 -0
  236. package/src/modules/warranty_claims/api/transition/route.ts +5 -0
  237. package/src/modules/warranty_claims/api/troubleshooting-guides/route.ts +23 -1
  238. package/src/modules/warranty_claims/api/vendor-recovery/route.ts +5 -0
  239. package/src/modules/warranty_claims/api/vendor-recovery-suggestions/route.ts +3 -1
  240. package/src/modules/warranty_claims/commands/shared.ts +7 -1
  241. package/src/modules/warranty_claims/lib/portalAuthGuard.ts +30 -0
  242. package/src/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.ts +5 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/warranty_claims/api/receiving/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { runRouteMutationGuards, type RouteMutationGuardResult } from '@open-mercato/shared/lib/crud/route-mutation-guard'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n claimConditionGradeSchema,\n claimLineReceiveSchema,\n claimLineReleaseQuarantineSchema,\n type ClaimLineReceiveInput,\n type ClaimLineReleaseQuarantineInput,\n} from '../../data/validators'\nimport { WARRANTY_CLAIM_LINE_RESOURCE_KIND } from '../../commands/shared'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('warranty_claims')\n\ntype ActionRouteContext = {\n ctx: CommandRuntimeContext\n tenantId: string\n organizationId: string\n translate: (key: string, fallback?: string) => string\n}\n\ntype ReceivingAction =\n | { kind: 'receive'; input: ClaimLineReceiveInput }\n | { kind: 'release'; input: ClaimLineReleaseQuarantineInput }\n\nconst uuid = z.string().uuid()\nconst optimisticLockTokenSchema = z.string().datetime().nullable().optional()\n\nconst receiveBodySchema = z\n .object({\n lineId: uuid,\n conditionGrade: claimConditionGradeSchema,\n inspectionNotes: z.string().trim().max(4000).optional(),\n updatedAt: optimisticLockTokenSchema,\n })\n .strict()\n\nconst releaseBodySchema = z\n .object({\n lineId: uuid,\n action: z.literal('release'),\n updatedAt: optimisticLockTokenSchema,\n })\n .strict()\n\nconst receivingBodySchema = z.union([releaseBodySchema, receiveBodySchema])\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.receiving.manage'] },\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\n\nfunction translateKey(key: string): string {\n return key\n}\n\nasync function resolveActionContext(req: Request): Promise<ActionRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: 'warranty_claims.errors.unauthorized' })\n }\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, { error: 'warranty_claims.errors.organization_required' })\n }\n return {\n ctx: {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n },\n tenantId: auth.tenantId,\n organizationId,\n translate: translateKey,\n }\n}\n\nfunction toReceivingAction(payload: Record<string, unknown>, context: ActionRouteContext): ReceivingAction {\n const releaseBody = releaseBodySchema.safeParse(payload)\n if (releaseBody.success) {\n const scopedPayload = withScopedPayload({\n id: releaseBody.data.lineId,\n updatedAt: releaseBody.data.updatedAt,\n }, context.ctx, context.translate)\n return { kind: 'release', input: claimLineReleaseQuarantineSchema.parse(scopedPayload) }\n }\n const body = receiveBodySchema.parse(payload)\n const scopedPayload = withScopedPayload({\n id: body.lineId,\n conditionGrade: body.conditionGrade,\n inspectionNotes: body.inspectionNotes,\n updatedAt: body.updatedAt,\n }, context.ctx, context.translate)\n return { kind: 'receive', input: claimLineReceiveSchema.parse(scopedPayload) }\n}\n\nfunction toGuardedAction(kind: ReceivingAction['kind'], payload: Record<string, unknown>): ReceivingAction {\n if (kind === 'release') {\n return { kind, input: claimLineReleaseQuarantineSchema.parse(payload) }\n }\n return { kind, input: claimLineReceiveSchema.parse(payload) }\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n action: ReceivingAction,\n): Promise<RouteMutationGuardResult> {\n const userId = context.ctx.auth?.sub\n if (!userId) {\n throw new CrudHttpError(401, { error: 'warranty_claims.errors.unauthorized' })\n }\n return runRouteMutationGuards({\n container: context.ctx.container,\n req,\n auth: {\n userId,\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n },\n input: {\n resourceKind: WARRANTY_CLAIM_LINE_RESOURCE_KIND,\n resourceId: action.input.id,\n operation: 'custom',\n mutationPayload: { ...action.input },\n },\n })\n}\n\nasync function executeReceivingAction(\n commandBus: CommandBus,\n action: ReceivingAction,\n ctx: CommandRuntimeContext,\n): Promise<{ lineId: string; claimId: string }> {\n if (action.kind === 'release') {\n const { result } = await commandBus.execute<ClaimLineReleaseQuarantineInput, { lineId: string; claimId: string }>(\n 'warranty_claims.claim_line.release_quarantine',\n { input: action.input, ctx },\n )\n if (!result) throw new CrudHttpError(400, { error: 'warranty_claims.errors.save_failed' })\n return result\n }\n const { result } = await commandBus.execute<ClaimLineReceiveInput, { lineId: string; claimId: string }>(\n 'warranty_claims.claim_line.receive',\n { input: action.input, ctx },\n )\n if (!result) throw new CrudHttpError(400, { error: 'warranty_claims.errors.save_failed' })\n return result\n}\n\nexport async function POST(req: Request) {\n try {\n const context = await resolveActionContext(req)\n const payload = toRecord(await readJsonSafe(req, {}))\n const action = toReceivingAction(payload, context)\n const guarded = await runGuard(req, context, action)\n if (!guarded.ok) {\n return guarded.response\n }\n const commandAction = guarded.modifiedPayload ? toGuardedAction(action.kind, guarded.modifiedPayload) : action\n\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const result = await executeReceivingAction(commandBus, commandAction, context.ctx)\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({ ok: true, lineId: result.lineId, claimId: result.claimId })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) {\n return NextResponse.json({ error: 'warranty_claims.errors.invalidInput' }, { status: 400 })\n }\n logger.error('warranty_claims.receiving.post failed', { err })\n return NextResponse.json({ error: 'warranty_claims.errors.save_failed' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Receive or release a warranty claim line',\n methods: {\n POST: {\n summary: 'Grade a received line or release its quarantine hold',\n requestBody: { contentType: 'application/json', schema: receivingBodySchema },\n responses: [\n {\n status: 200,\n description: 'Receiving action applied',\n schema: z.object({\n ok: z.boolean(),\n lineId: z.string().uuid(),\n claimId: z.string().uuid(),\n }),\n },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { runRouteMutationGuards, type RouteMutationGuardResult } from '@open-mercato/shared/lib/crud/route-mutation-guard'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n claimConditionGradeSchema,\n claimLineReceiveSchema,\n claimLineReleaseQuarantineSchema,\n type ClaimLineReceiveInput,\n type ClaimLineReleaseQuarantineInput,\n} from '../../data/validators'\nimport { WARRANTY_CLAIM_LINE_RESOURCE_KIND } from '../../commands/shared'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('warranty_claims')\n\ntype ActionRouteContext = {\n ctx: CommandRuntimeContext\n tenantId: string\n organizationId: string\n translate: (key: string, fallback?: string) => string\n}\n\ntype ReceivingAction =\n | { kind: 'receive'; input: ClaimLineReceiveInput }\n | { kind: 'release'; input: ClaimLineReleaseQuarantineInput }\n\nconst uuid = z.string().uuid()\nconst optimisticLockTokenSchema = z.string().datetime().nullable().optional()\n\nconst receiveBodySchema = z\n .object({\n lineId: uuid,\n conditionGrade: claimConditionGradeSchema,\n inspectionNotes: z.string().trim().max(4000).optional(),\n updatedAt: optimisticLockTokenSchema,\n })\n .strict()\n\nconst releaseBodySchema = z\n .object({\n lineId: uuid,\n action: z.literal('release'),\n updatedAt: optimisticLockTokenSchema,\n })\n .strict()\n\nconst receivingBodySchema = z.union([releaseBodySchema, receiveBodySchema])\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.receiving.manage'] },\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\n\nasync function resolveActionContext(\n req: Request,\n translate: ActionRouteContext['translate'],\n): Promise<ActionRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('warranty_claims.errors.unauthorized', 'Unauthorized') })\n }\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, { error: translate('warranty_claims.errors.organization_required', 'Organization context is required.') })\n }\n return {\n ctx: {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n },\n tenantId: auth.tenantId,\n organizationId,\n translate,\n }\n}\n\nfunction toReceivingAction(payload: Record<string, unknown>, context: ActionRouteContext): ReceivingAction {\n const releaseBody = releaseBodySchema.safeParse(payload)\n if (releaseBody.success) {\n const scopedPayload = withScopedPayload({\n id: releaseBody.data.lineId,\n updatedAt: releaseBody.data.updatedAt,\n }, context.ctx, context.translate)\n return { kind: 'release', input: claimLineReleaseQuarantineSchema.parse(scopedPayload) }\n }\n const body = receiveBodySchema.parse(payload)\n const scopedPayload = withScopedPayload({\n id: body.lineId,\n conditionGrade: body.conditionGrade,\n inspectionNotes: body.inspectionNotes,\n updatedAt: body.updatedAt,\n }, context.ctx, context.translate)\n return { kind: 'receive', input: claimLineReceiveSchema.parse(scopedPayload) }\n}\n\nfunction toGuardedAction(kind: ReceivingAction['kind'], payload: Record<string, unknown>): ReceivingAction {\n if (kind === 'release') {\n return { kind, input: claimLineReleaseQuarantineSchema.parse(payload) }\n }\n return { kind, input: claimLineReceiveSchema.parse(payload) }\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n action: ReceivingAction,\n): Promise<RouteMutationGuardResult> {\n const userId = context.ctx.auth?.sub\n if (!userId) {\n throw new CrudHttpError(401, { error: context.translate('warranty_claims.errors.unauthorized', 'Unauthorized') })\n }\n return runRouteMutationGuards({\n container: context.ctx.container,\n req,\n auth: {\n userId,\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n },\n input: {\n resourceKind: WARRANTY_CLAIM_LINE_RESOURCE_KIND,\n resourceId: action.input.id,\n operation: 'custom',\n mutationPayload: { ...action.input },\n },\n })\n}\n\nasync function executeReceivingAction(\n commandBus: CommandBus,\n action: ReceivingAction,\n ctx: CommandRuntimeContext,\n translate: ActionRouteContext['translate'],\n): Promise<{ lineId: string; claimId: string }> {\n if (action.kind === 'release') {\n const { result } = await commandBus.execute<ClaimLineReleaseQuarantineInput, { lineId: string; claimId: string }>(\n 'warranty_claims.claim_line.release_quarantine',\n { input: action.input, ctx },\n )\n if (!result) throw new CrudHttpError(400, { error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim.') })\n return result\n }\n const { result } = await commandBus.execute<ClaimLineReceiveInput, { lineId: string; claimId: string }>(\n 'warranty_claims.claim_line.receive',\n { input: action.input, ctx },\n )\n if (!result) throw new CrudHttpError(400, { error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim.') })\n return result\n}\n\nexport async function POST(req: Request) {\n const { translate } = await resolveTranslations()\n try {\n const context = await resolveActionContext(req, translate)\n const payload = toRecord(await readJsonSafe(req, {}))\n const action = toReceivingAction(payload, context)\n const guarded = await runGuard(req, context, action)\n if (!guarded.ok) {\n return guarded.response\n }\n const commandAction = guarded.modifiedPayload ? toGuardedAction(action.kind, guarded.modifiedPayload) : action\n\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const result = await executeReceivingAction(commandBus, commandAction, context.ctx, translate)\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({ ok: true, lineId: result.lineId, claimId: result.claimId })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n if (err instanceof z.ZodError) {\n return NextResponse.json({ error: translate('warranty_claims.errors.invalidInput', 'Invalid input') }, { status: 400 })\n }\n logger.error('warranty_claims.receiving.post failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim.') }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Receive or release a warranty claim line',\n methods: {\n POST: {\n summary: 'Grade a received line or release its quarantine hold',\n requestBody: { contentType: 'application/json', schema: receivingBodySchema },\n responses: [\n {\n status: 200,\n description: 'Receiving action applied',\n schema: z.object({\n ok: z.boolean(),\n lineId: z.string().uuid(),\n claimId: z.string().uuid(),\n }),\n },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["scopedPayload", "result"]
7
7
  }
@@ -3,6 +3,7 @@ import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
3
  import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
4
4
  import { buildIlikeTerm } from "@open-mercato/shared/lib/db/buildIlikeTerm";
5
5
  import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
6
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
6
7
  import { E } from "../../../../generated/entities.ids.generated.js";
7
8
  import * as F from "../../../../generated/entities/warranty_claim_registration/index.js";
8
9
  import { WarrantyClaimRegistration } from "../../data/entities.js";
@@ -67,7 +68,7 @@ function parseUpdateInput(input, ctx) {
67
68
  function hasOwn(input, key) {
68
69
  return Object.prototype.hasOwnProperty.call(input, key);
69
70
  }
70
- async function assertRegistrationSerialUnique(em, scope, serialNumber, excludeId) {
71
+ async function assertRegistrationSerialUnique(em, scope, serialNumber, excludeId, translate) {
71
72
  if (!serialNumber) return;
72
73
  const where = {
73
74
  serialNumber,
@@ -78,7 +79,9 @@ async function assertRegistrationSerialUnique(em, scope, serialNumber, excludeId
78
79
  if (excludeId) where.id = { $ne: excludeId };
79
80
  const existing = await em.count(WarrantyClaimRegistration, where);
80
81
  if (existing > 0) {
81
- throw new CrudHttpError(400, { error: "warranty_claims.errors.duplicateSerial" });
82
+ throw new CrudHttpError(400, {
83
+ error: translate("warranty_claims.errors.duplicateSerial", "A registration with this serial number already exists.")
84
+ });
82
85
  }
83
86
  }
84
87
  function parseDate(value) {
@@ -278,8 +281,9 @@ const crud = makeCrudRoute({
278
281
  const result = registrationCreateSchema.safeParse({ ...input, ...scope });
279
282
  if (!result.success) return;
280
283
  const em = ctx.container.resolve("em").fork();
284
+ const { translate } = await resolveTranslations();
281
285
  await assertOrderBelongsToCustomer(em, scope, result.data.orderId ?? null, result.data.customerId ?? null);
282
- await assertRegistrationSerialUnique(em, scope, result.data.serialNumber ?? null, null);
286
+ await assertRegistrationSerialUnique(em, scope, result.data.serialNumber ?? null, null, translate);
283
287
  },
284
288
  beforeUpdate: async (input, ctx) => {
285
289
  const scope = scopeFromContext(ctx);
@@ -304,7 +308,8 @@ const crud = makeCrudRoute({
304
308
  const effectiveOrderId = hasOwn(parsed, "orderId") ? parsed.orderId ?? null : existing.orderId ?? null;
305
309
  await assertOrderBelongsToCustomer(em, scope, effectiveOrderId, effectiveCustomerId);
306
310
  if (hasOwn(parsed, "serialNumber") && (parsed.serialNumber ?? null) !== (existing.serialNumber ?? null)) {
307
- await assertRegistrationSerialUnique(em, scope, parsed.serialNumber ?? null, existing.id);
311
+ const { translate } = await resolveTranslations();
312
+ await assertRegistrationSerialUnique(em, scope, parsed.serialNumber ?? null, existing.id, translate);
308
313
  }
309
314
  },
310
315
  afterCreate: async (entity) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/warranty_claims/api/registrations/route.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { buildIlikeTerm } from '@open-mercato/shared/lib/db/buildIlikeTerm'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { E } from '#generated/entities.ids.generated'\nimport * as F from '#generated/entities/warranty_claim_registration'\nimport { WarrantyClaimRegistration } from '../../data/entities'\nimport { assertOrderBelongsToCustomer } from '../../lib/orderOwnership'\nimport { emitWarrantyClaimsEvent } from '../../events'\nimport {\n registrationCreateSchema,\n registrationUpdateSchema,\n registrationCoverageTypeSchema,\n registrationSourceSchema,\n type RegistrationCreateInput,\n type RegistrationUpdateInput,\n} from '../../data/validators'\nimport { addWarrantyMonths } from '../../lib/warrantyPreview'\nimport {\n createPagedListResponseSchema,\n createWarrantyClaimsCrudOpenApi,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst rawBodySchema = z.object({}).passthrough()\nconst uuid = z.string().uuid()\n\nconst expiryWindowSchema = z.enum(['expired', 'expiring_30d', 'active'])\n\nconst EXPIRING_WINDOW_MS = 30 * 24 * 60 * 60 * 1000\n\nconst listSchema = z\n .object({\n id: uuid.optional(),\n serialNumber: z.string().trim().max(191).optional(),\n customerId: uuid.optional(),\n coverageType: registrationCoverageTypeSchema.optional(),\n source: registrationSourceSchema.optional(),\n expiry: expiryWindowSchema.optional(),\n search: z.string().trim().max(300).optional(),\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n sortField: z.enum(['serialNumber', 'productName', 'sku', 'warrantyExpiresAt', 'updatedAt', 'createdAt']).optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\ntype RegistrationListQuery = z.infer<typeof listSchema>\ntype RawRegistrationInput = z.infer<typeof rawBodySchema>\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['warranty_claims.registration.view'] },\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.registration.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['warranty_claims.registration.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['warranty_claims.registration.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nfunction scopeFromContext(ctx: CrudCtx): { organizationId: string; tenantId: string } {\n const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n const tenantId = ctx.auth?.tenantId ?? null\n if (!organizationId || !tenantId) {\n throw new CrudHttpError(400, { error: '[internal] warranty registration scope is missing' })\n }\n return { organizationId, tenantId }\n}\n\nfunction parseCreateInput(input: RawRegistrationInput, ctx: CrudCtx): RegistrationCreateInput {\n return registrationCreateSchema.parse({\n ...input,\n ...scopeFromContext(ctx),\n })\n}\n\nfunction parseUpdateInput(input: RawRegistrationInput, ctx: CrudCtx): RegistrationUpdateInput {\n return registrationUpdateSchema.parse({\n ...input,\n ...scopeFromContext(ctx),\n })\n}\n\nfunction hasOwn(input: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(input, key)\n}\n\nasync function assertRegistrationSerialUnique(\n em: EntityManager,\n scope: { organizationId: string; tenantId: string },\n serialNumber: string | null | undefined,\n excludeId: string | null,\n): Promise<void> {\n if (!serialNumber) return\n const where: FilterQuery<WarrantyClaimRegistration> = {\n serialNumber,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n }\n if (excludeId) where.id = { $ne: excludeId }\n const existing = await em.count(WarrantyClaimRegistration, where)\n if (existing > 0) {\n throw new CrudHttpError(400, { error: 'warranty_claims.errors.duplicateSerial' })\n }\n}\n\nfunction parseDate(value: string | Date | null | undefined): Date | null {\n if (value === null || value === undefined) return null\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? null : date\n}\n\nfunction resolveWarrantyExpiresAt(input: RegistrationCreateInput): Date | null {\n if (hasOwn(input, 'warrantyExpiresAt')) return parseDate(input.warrantyExpiresAt)\n const purchaseDate = parseDate(input.purchaseDate)\n return purchaseDate && input.warrantyMonths !== null && input.warrantyMonths !== undefined\n ? addWarrantyMonths(purchaseDate, input.warrantyMonths)\n : null\n}\n\nfunction resolveUpdatedWarrantyExpiresAt(\n entity: WarrantyClaimRegistration,\n input: RegistrationUpdateInput,\n): Date | null | undefined {\n if (hasOwn(input, 'warrantyExpiresAt')) return parseDate(input.warrantyExpiresAt)\n if (!hasOwn(input, 'purchaseDate') && !hasOwn(input, 'warrantyMonths')) return undefined\n const purchaseDate = hasOwn(input, 'purchaseDate') ? parseDate(input.purchaseDate) : entity.purchaseDate ?? null\n const warrantyMonths = hasOwn(input, 'warrantyMonths') ? input.warrantyMonths ?? null : entity.warrantyMonths ?? null\n return purchaseDate && warrantyMonths !== null ? addWarrantyMonths(purchaseDate, warrantyMonths) : null\n}\n\nfunction toRegistrationEntityData(input: RegistrationCreateInput): Record<string, unknown> {\n return {\n serialNumber: input.serialNumber ?? null,\n productId: input.productId ?? null,\n variantId: input.variantId ?? null,\n sku: input.sku ?? null,\n productName: input.productName ?? null,\n customerId: input.customerId ?? null,\n orderId: input.orderId ?? null,\n purchaseDate: parseDate(input.purchaseDate),\n warrantyMonths: input.warrantyMonths ?? null,\n warrantyExpiresAt: resolveWarrantyExpiresAt(input),\n coverageType: input.coverageType ?? null,\n source: input.source ?? null,\n proofAttachmentId: input.proofAttachmentId ?? null,\n notes: input.notes ?? null,\n }\n}\n\nfunction applyRegistrationUpdate(entity: WarrantyClaimRegistration, input: RegistrationUpdateInput): void {\n if (hasOwn(input, 'serialNumber')) entity.serialNumber = input.serialNumber ?? null\n if (hasOwn(input, 'productId')) entity.productId = input.productId ?? null\n if (hasOwn(input, 'variantId')) entity.variantId = input.variantId ?? null\n if (hasOwn(input, 'sku')) entity.sku = input.sku ?? null\n if (hasOwn(input, 'productName')) entity.productName = input.productName ?? null\n if (hasOwn(input, 'customerId')) entity.customerId = input.customerId ?? null\n if (hasOwn(input, 'orderId')) entity.orderId = input.orderId ?? null\n if (hasOwn(input, 'purchaseDate')) entity.purchaseDate = parseDate(input.purchaseDate)\n if (hasOwn(input, 'warrantyMonths')) entity.warrantyMonths = input.warrantyMonths ?? null\n const warrantyExpiresAt = resolveUpdatedWarrantyExpiresAt(entity, input)\n if (warrantyExpiresAt !== undefined) entity.warrantyExpiresAt = warrantyExpiresAt\n if (hasOwn(input, 'coverageType')) entity.coverageType = input.coverageType ?? null\n if (hasOwn(input, 'source')) entity.source = input.source ?? null\n if (hasOwn(input, 'proofAttachmentId')) entity.proofAttachmentId = input.proofAttachmentId ?? null\n if (hasOwn(input, 'notes')) entity.notes = input.notes ?? null\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\n\nexport async function emitRegistrationCreatedEvent(entity: unknown): Promise<void> {\n const record = toRecord(entity)\n const registrationId = typeof record.id === 'string' ? record.id : null\n const tenantId = typeof record.tenantId === 'string' ? record.tenantId : null\n const organizationId = typeof record.organizationId === 'string' ? record.organizationId : null\n if (!registrationId || !tenantId || !organizationId) return\n await emitWarrantyClaimsEvent('warranty_claims.registration.created', {\n registrationId,\n tenantId,\n organizationId,\n }, { persistent: true, tenantId, organizationId })\n}\n\nfunction readString(record: Record<string, unknown>, snakeKey: string, camelKey: string): string | null {\n const value = record[snakeKey] ?? record[camelKey]\n return typeof value === 'string' ? value : null\n}\n\nfunction readNumber(record: Record<string, unknown>, snakeKey: string, camelKey: string): number | null {\n const value = record[snakeKey] ?? record[camelKey]\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : null\n }\n return null\n}\n\nfunction toIso(value: unknown): string | null {\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'string') {\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? value : date.toISOString()\n }\n return null\n}\n\nfunction transformRegistrationItem(item: unknown): unknown {\n const record = toRecord(item)\n if (!Object.keys(record).length) return item\n return {\n id: readString(record, 'id', 'id'),\n organizationId: readString(record, 'organization_id', 'organizationId'),\n tenantId: readString(record, 'tenant_id', 'tenantId'),\n serialNumber: readString(record, 'serial_number', 'serialNumber'),\n productId: readString(record, 'product_id', 'productId'),\n variantId: readString(record, 'variant_id', 'variantId'),\n sku: readString(record, 'sku', 'sku'),\n productName: readString(record, 'product_name', 'productName'),\n customerId: readString(record, 'customer_id', 'customerId'),\n orderId: readString(record, 'order_id', 'orderId'),\n purchaseDate: toIso(record.purchase_date ?? record.purchaseDate),\n warrantyMonths: readNumber(record, 'warranty_months', 'warrantyMonths'),\n warrantyExpiresAt: toIso(record.warranty_expires_at ?? record.warrantyExpiresAt),\n coverageType: readString(record, 'coverage_type', 'coverageType'),\n source: readString(record, 'source', 'source'),\n proofAttachmentId: readString(record, 'proof_attachment_id', 'proofAttachmentId'),\n notes: readString(record, 'notes', 'notes'),\n createdAt: toIso(record.created_at ?? record.createdAt),\n updatedAt: toIso(record.updated_at ?? record.updatedAt),\n deletedAt: toIso(record.deleted_at ?? record.deletedAt),\n }\n}\n\nconst crud = makeCrudRoute<RawRegistrationInput, RawRegistrationInput, RegistrationListQuery>({\n metadata: routeMetadata,\n orm: {\n entity: WarrantyClaimRegistration,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.warranty_claims.warranty_claim_registration },\n list: {\n schema: listSchema,\n entityId: E.warranty_claims.warranty_claim_registration,\n fields: [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.serial_number,\n F.product_id,\n F.variant_id,\n F.sku,\n F.product_name,\n F.customer_id,\n F.order_id,\n F.purchase_date,\n F.warranty_months,\n F.warranty_expires_at,\n F.coverage_type,\n F.source,\n F.proof_attachment_id,\n F.notes,\n F.created_at,\n F.updated_at,\n F.deleted_at,\n ],\n sortFieldMap: {\n serialNumber: F.serial_number,\n productName: F.product_name,\n sku: F.sku,\n warrantyExpiresAt: F.warranty_expires_at,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: async (query) => {\n const filters: Record<string, unknown> = {}\n if (query.id) filters.id = { $eq: query.id }\n if (query.serialNumber) filters.serial_number = { $eq: query.serialNumber }\n if (query.customerId) filters.customer_id = { $eq: query.customerId }\n if (query.coverageType) filters.coverage_type = { $eq: query.coverageType }\n if (query.source) filters.source = { $eq: query.source }\n if (query.expiry) {\n const now = new Date()\n if (query.expiry === 'expired') {\n filters.warranty_expires_at = { $lt: now }\n } else if (query.expiry === 'expiring_30d') {\n filters.warranty_expires_at = { $gte: now, $lte: new Date(now.getTime() + EXPIRING_WINDOW_MS) }\n } else {\n filters.warranty_expires_at = { $gte: now }\n }\n }\n if (query.search) {\n const pattern = buildIlikeTerm(query.search)\n filters.$or = [\n { serial_number: { $ilike: pattern } },\n { sku: { $ilike: pattern } },\n { product_name: { $ilike: pattern } },\n ]\n }\n return filters\n },\n transformItem: transformRegistrationItem,\n },\n create: {\n schema: rawBodySchema,\n mapToEntity: (input, ctx) => toRegistrationEntityData(parseCreateInput(input, ctx)),\n },\n hooks: {\n beforeCreate: async (input, ctx) => {\n const scope = scopeFromContext(ctx)\n const result = registrationCreateSchema.safeParse({ ...input, ...scope })\n if (!result.success) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await assertOrderBelongsToCustomer(em, scope, result.data.orderId ?? null, result.data.customerId ?? null)\n await assertRegistrationSerialUnique(em, scope, result.data.serialNumber ?? null, null)\n },\n beforeUpdate: async (input, ctx) => {\n const scope = scopeFromContext(ctx)\n const result = registrationUpdateSchema.safeParse({ ...input, ...scope })\n if (!result.success) return\n const parsed = result.data\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await findOneWithDecryption(\n em,\n WarrantyClaimRegistration,\n {\n id: parsed.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n },\n {},\n scope,\n )\n if (!existing) return\n const effectiveCustomerId = hasOwn(parsed, 'customerId') ? (parsed.customerId ?? null) : (existing.customerId ?? null)\n const effectiveOrderId = hasOwn(parsed, 'orderId') ? (parsed.orderId ?? null) : (existing.orderId ?? null)\n await assertOrderBelongsToCustomer(em, scope, effectiveOrderId, effectiveCustomerId)\n if (hasOwn(parsed, 'serialNumber') && (parsed.serialNumber ?? null) !== (existing.serialNumber ?? null)) {\n await assertRegistrationSerialUnique(em, scope, parsed.serialNumber ?? null, existing.id)\n }\n },\n afterCreate: async (entity) => {\n await emitRegistrationCreatedEvent(entity)\n },\n },\n update: {\n schema: rawBodySchema,\n getId: (input) => {\n const id = input.id\n return typeof id === 'string' ? id : ''\n },\n applyToEntity: (entity, input, ctx) => {\n applyRegistrationUpdate(entity as WarrantyClaimRegistration, parseUpdateInput(input, ctx))\n },\n response: () => ({ ok: true }),\n },\n del: { idFrom: 'query', softDelete: true, response: () => ({ ok: true }) },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst registrationListItemSchema = z.object({\n id: z.string().uuid().nullable(),\n organizationId: z.string().uuid().nullable(),\n tenantId: z.string().uuid().nullable(),\n serialNumber: z.string().nullable(),\n productId: z.string().uuid().nullable(),\n variantId: z.string().uuid().nullable(),\n sku: z.string().nullable(),\n productName: z.string().nullable(),\n customerId: z.string().uuid().nullable(),\n orderId: z.string().uuid().nullable(),\n purchaseDate: z.string().nullable(),\n warrantyMonths: z.number().nullable(),\n warrantyExpiresAt: z.string().nullable(),\n coverageType: registrationCoverageTypeSchema.nullable(),\n source: registrationSourceSchema.nullable(),\n proofAttachmentId: z.string().uuid().nullable(),\n notes: z.string().nullable(),\n createdAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n}).passthrough()\n\nexport const openApi = createWarrantyClaimsCrudOpenApi({\n resourceName: 'WarrantyRegistration',\n pluralName: 'WarrantyRegistrations',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(registrationListItemSchema),\n create: {\n schema: registrationCreateSchema,\n responseSchema: z.object({ id: z.string().uuid() }),\n description: 'Creates a product warranty registration for entitlement resolution.',\n },\n update: {\n schema: registrationUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates a product warranty registration.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Soft-deletes a product warranty registration.',\n },\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { buildIlikeTerm } from '@open-mercato/shared/lib/db/buildIlikeTerm'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { E } from '#generated/entities.ids.generated'\nimport * as F from '#generated/entities/warranty_claim_registration'\nimport { WarrantyClaimRegistration } from '../../data/entities'\nimport { assertOrderBelongsToCustomer } from '../../lib/orderOwnership'\nimport { emitWarrantyClaimsEvent } from '../../events'\nimport {\n registrationCreateSchema,\n registrationUpdateSchema,\n registrationCoverageTypeSchema,\n registrationSourceSchema,\n type RegistrationCreateInput,\n type RegistrationUpdateInput,\n} from '../../data/validators'\nimport { addWarrantyMonths } from '../../lib/warrantyPreview'\nimport {\n createPagedListResponseSchema,\n createWarrantyClaimsCrudOpenApi,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst rawBodySchema = z.object({}).passthrough()\nconst uuid = z.string().uuid()\n\nconst expiryWindowSchema = z.enum(['expired', 'expiring_30d', 'active'])\n\nconst EXPIRING_WINDOW_MS = 30 * 24 * 60 * 60 * 1000\n\nconst listSchema = z\n .object({\n id: uuid.optional(),\n serialNumber: z.string().trim().max(191).optional(),\n customerId: uuid.optional(),\n coverageType: registrationCoverageTypeSchema.optional(),\n source: registrationSourceSchema.optional(),\n expiry: expiryWindowSchema.optional(),\n search: z.string().trim().max(300).optional(),\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n sortField: z.enum(['serialNumber', 'productName', 'sku', 'warrantyExpiresAt', 'updatedAt', 'createdAt']).optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\ntype RegistrationListQuery = z.infer<typeof listSchema>\ntype RawRegistrationInput = z.infer<typeof rawBodySchema>\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['warranty_claims.registration.view'] },\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.registration.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['warranty_claims.registration.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['warranty_claims.registration.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nfunction scopeFromContext(ctx: CrudCtx): { organizationId: string; tenantId: string } {\n const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n const tenantId = ctx.auth?.tenantId ?? null\n if (!organizationId || !tenantId) {\n throw new CrudHttpError(400, { error: '[internal] warranty registration scope is missing' })\n }\n return { organizationId, tenantId }\n}\n\nfunction parseCreateInput(input: RawRegistrationInput, ctx: CrudCtx): RegistrationCreateInput {\n return registrationCreateSchema.parse({\n ...input,\n ...scopeFromContext(ctx),\n })\n}\n\nfunction parseUpdateInput(input: RawRegistrationInput, ctx: CrudCtx): RegistrationUpdateInput {\n return registrationUpdateSchema.parse({\n ...input,\n ...scopeFromContext(ctx),\n })\n}\n\nfunction hasOwn(input: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(input, key)\n}\n\nasync function assertRegistrationSerialUnique(\n em: EntityManager,\n scope: { organizationId: string; tenantId: string },\n serialNumber: string | null | undefined,\n excludeId: string | null,\n translate: (key: string, fallback?: string) => string,\n): Promise<void> {\n if (!serialNumber) return\n const where: FilterQuery<WarrantyClaimRegistration> = {\n serialNumber,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n }\n if (excludeId) where.id = { $ne: excludeId }\n const existing = await em.count(WarrantyClaimRegistration, where)\n if (existing > 0) {\n throw new CrudHttpError(400, {\n error: translate('warranty_claims.errors.duplicateSerial', 'A registration with this serial number already exists.'),\n })\n }\n}\n\nfunction parseDate(value: string | Date | null | undefined): Date | null {\n if (value === null || value === undefined) return null\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? null : date\n}\n\nfunction resolveWarrantyExpiresAt(input: RegistrationCreateInput): Date | null {\n if (hasOwn(input, 'warrantyExpiresAt')) return parseDate(input.warrantyExpiresAt)\n const purchaseDate = parseDate(input.purchaseDate)\n return purchaseDate && input.warrantyMonths !== null && input.warrantyMonths !== undefined\n ? addWarrantyMonths(purchaseDate, input.warrantyMonths)\n : null\n}\n\nfunction resolveUpdatedWarrantyExpiresAt(\n entity: WarrantyClaimRegistration,\n input: RegistrationUpdateInput,\n): Date | null | undefined {\n if (hasOwn(input, 'warrantyExpiresAt')) return parseDate(input.warrantyExpiresAt)\n if (!hasOwn(input, 'purchaseDate') && !hasOwn(input, 'warrantyMonths')) return undefined\n const purchaseDate = hasOwn(input, 'purchaseDate') ? parseDate(input.purchaseDate) : entity.purchaseDate ?? null\n const warrantyMonths = hasOwn(input, 'warrantyMonths') ? input.warrantyMonths ?? null : entity.warrantyMonths ?? null\n return purchaseDate && warrantyMonths !== null ? addWarrantyMonths(purchaseDate, warrantyMonths) : null\n}\n\nfunction toRegistrationEntityData(input: RegistrationCreateInput): Record<string, unknown> {\n return {\n serialNumber: input.serialNumber ?? null,\n productId: input.productId ?? null,\n variantId: input.variantId ?? null,\n sku: input.sku ?? null,\n productName: input.productName ?? null,\n customerId: input.customerId ?? null,\n orderId: input.orderId ?? null,\n purchaseDate: parseDate(input.purchaseDate),\n warrantyMonths: input.warrantyMonths ?? null,\n warrantyExpiresAt: resolveWarrantyExpiresAt(input),\n coverageType: input.coverageType ?? null,\n source: input.source ?? null,\n proofAttachmentId: input.proofAttachmentId ?? null,\n notes: input.notes ?? null,\n }\n}\n\nfunction applyRegistrationUpdate(entity: WarrantyClaimRegistration, input: RegistrationUpdateInput): void {\n if (hasOwn(input, 'serialNumber')) entity.serialNumber = input.serialNumber ?? null\n if (hasOwn(input, 'productId')) entity.productId = input.productId ?? null\n if (hasOwn(input, 'variantId')) entity.variantId = input.variantId ?? null\n if (hasOwn(input, 'sku')) entity.sku = input.sku ?? null\n if (hasOwn(input, 'productName')) entity.productName = input.productName ?? null\n if (hasOwn(input, 'customerId')) entity.customerId = input.customerId ?? null\n if (hasOwn(input, 'orderId')) entity.orderId = input.orderId ?? null\n if (hasOwn(input, 'purchaseDate')) entity.purchaseDate = parseDate(input.purchaseDate)\n if (hasOwn(input, 'warrantyMonths')) entity.warrantyMonths = input.warrantyMonths ?? null\n const warrantyExpiresAt = resolveUpdatedWarrantyExpiresAt(entity, input)\n if (warrantyExpiresAt !== undefined) entity.warrantyExpiresAt = warrantyExpiresAt\n if (hasOwn(input, 'coverageType')) entity.coverageType = input.coverageType ?? null\n if (hasOwn(input, 'source')) entity.source = input.source ?? null\n if (hasOwn(input, 'proofAttachmentId')) entity.proofAttachmentId = input.proofAttachmentId ?? null\n if (hasOwn(input, 'notes')) entity.notes = input.notes ?? null\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\n\nexport async function emitRegistrationCreatedEvent(entity: unknown): Promise<void> {\n const record = toRecord(entity)\n const registrationId = typeof record.id === 'string' ? record.id : null\n const tenantId = typeof record.tenantId === 'string' ? record.tenantId : null\n const organizationId = typeof record.organizationId === 'string' ? record.organizationId : null\n if (!registrationId || !tenantId || !organizationId) return\n await emitWarrantyClaimsEvent('warranty_claims.registration.created', {\n registrationId,\n tenantId,\n organizationId,\n }, { persistent: true, tenantId, organizationId })\n}\n\nfunction readString(record: Record<string, unknown>, snakeKey: string, camelKey: string): string | null {\n const value = record[snakeKey] ?? record[camelKey]\n return typeof value === 'string' ? value : null\n}\n\nfunction readNumber(record: Record<string, unknown>, snakeKey: string, camelKey: string): number | null {\n const value = record[snakeKey] ?? record[camelKey]\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : null\n }\n return null\n}\n\nfunction toIso(value: unknown): string | null {\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'string') {\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? value : date.toISOString()\n }\n return null\n}\n\nfunction transformRegistrationItem(item: unknown): unknown {\n const record = toRecord(item)\n if (!Object.keys(record).length) return item\n return {\n id: readString(record, 'id', 'id'),\n organizationId: readString(record, 'organization_id', 'organizationId'),\n tenantId: readString(record, 'tenant_id', 'tenantId'),\n serialNumber: readString(record, 'serial_number', 'serialNumber'),\n productId: readString(record, 'product_id', 'productId'),\n variantId: readString(record, 'variant_id', 'variantId'),\n sku: readString(record, 'sku', 'sku'),\n productName: readString(record, 'product_name', 'productName'),\n customerId: readString(record, 'customer_id', 'customerId'),\n orderId: readString(record, 'order_id', 'orderId'),\n purchaseDate: toIso(record.purchase_date ?? record.purchaseDate),\n warrantyMonths: readNumber(record, 'warranty_months', 'warrantyMonths'),\n warrantyExpiresAt: toIso(record.warranty_expires_at ?? record.warrantyExpiresAt),\n coverageType: readString(record, 'coverage_type', 'coverageType'),\n source: readString(record, 'source', 'source'),\n proofAttachmentId: readString(record, 'proof_attachment_id', 'proofAttachmentId'),\n notes: readString(record, 'notes', 'notes'),\n createdAt: toIso(record.created_at ?? record.createdAt),\n updatedAt: toIso(record.updated_at ?? record.updatedAt),\n deletedAt: toIso(record.deleted_at ?? record.deletedAt),\n }\n}\n\nconst crud = makeCrudRoute<RawRegistrationInput, RawRegistrationInput, RegistrationListQuery>({\n metadata: routeMetadata,\n orm: {\n entity: WarrantyClaimRegistration,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.warranty_claims.warranty_claim_registration },\n list: {\n schema: listSchema,\n entityId: E.warranty_claims.warranty_claim_registration,\n fields: [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.serial_number,\n F.product_id,\n F.variant_id,\n F.sku,\n F.product_name,\n F.customer_id,\n F.order_id,\n F.purchase_date,\n F.warranty_months,\n F.warranty_expires_at,\n F.coverage_type,\n F.source,\n F.proof_attachment_id,\n F.notes,\n F.created_at,\n F.updated_at,\n F.deleted_at,\n ],\n sortFieldMap: {\n serialNumber: F.serial_number,\n productName: F.product_name,\n sku: F.sku,\n warrantyExpiresAt: F.warranty_expires_at,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: async (query) => {\n const filters: Record<string, unknown> = {}\n if (query.id) filters.id = { $eq: query.id }\n if (query.serialNumber) filters.serial_number = { $eq: query.serialNumber }\n if (query.customerId) filters.customer_id = { $eq: query.customerId }\n if (query.coverageType) filters.coverage_type = { $eq: query.coverageType }\n if (query.source) filters.source = { $eq: query.source }\n if (query.expiry) {\n const now = new Date()\n if (query.expiry === 'expired') {\n filters.warranty_expires_at = { $lt: now }\n } else if (query.expiry === 'expiring_30d') {\n filters.warranty_expires_at = { $gte: now, $lte: new Date(now.getTime() + EXPIRING_WINDOW_MS) }\n } else {\n filters.warranty_expires_at = { $gte: now }\n }\n }\n if (query.search) {\n const pattern = buildIlikeTerm(query.search)\n filters.$or = [\n { serial_number: { $ilike: pattern } },\n { sku: { $ilike: pattern } },\n { product_name: { $ilike: pattern } },\n ]\n }\n return filters\n },\n transformItem: transformRegistrationItem,\n },\n create: {\n schema: rawBodySchema,\n mapToEntity: (input, ctx) => toRegistrationEntityData(parseCreateInput(input, ctx)),\n },\n hooks: {\n beforeCreate: async (input, ctx) => {\n const scope = scopeFromContext(ctx)\n const result = registrationCreateSchema.safeParse({ ...input, ...scope })\n if (!result.success) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { translate } = await resolveTranslations()\n await assertOrderBelongsToCustomer(em, scope, result.data.orderId ?? null, result.data.customerId ?? null)\n await assertRegistrationSerialUnique(em, scope, result.data.serialNumber ?? null, null, translate)\n },\n beforeUpdate: async (input, ctx) => {\n const scope = scopeFromContext(ctx)\n const result = registrationUpdateSchema.safeParse({ ...input, ...scope })\n if (!result.success) return\n const parsed = result.data\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await findOneWithDecryption(\n em,\n WarrantyClaimRegistration,\n {\n id: parsed.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n },\n {},\n scope,\n )\n if (!existing) return\n const effectiveCustomerId = hasOwn(parsed, 'customerId') ? (parsed.customerId ?? null) : (existing.customerId ?? null)\n const effectiveOrderId = hasOwn(parsed, 'orderId') ? (parsed.orderId ?? null) : (existing.orderId ?? null)\n await assertOrderBelongsToCustomer(em, scope, effectiveOrderId, effectiveCustomerId)\n if (hasOwn(parsed, 'serialNumber') && (parsed.serialNumber ?? null) !== (existing.serialNumber ?? null)) {\n const { translate } = await resolveTranslations()\n await assertRegistrationSerialUnique(em, scope, parsed.serialNumber ?? null, existing.id, translate)\n }\n },\n afterCreate: async (entity) => {\n await emitRegistrationCreatedEvent(entity)\n },\n },\n update: {\n schema: rawBodySchema,\n getId: (input) => {\n const id = input.id\n return typeof id === 'string' ? id : ''\n },\n applyToEntity: (entity, input, ctx) => {\n applyRegistrationUpdate(entity as WarrantyClaimRegistration, parseUpdateInput(input, ctx))\n },\n response: () => ({ ok: true }),\n },\n del: { idFrom: 'query', softDelete: true, response: () => ({ ok: true }) },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst registrationListItemSchema = z.object({\n id: z.string().uuid().nullable(),\n organizationId: z.string().uuid().nullable(),\n tenantId: z.string().uuid().nullable(),\n serialNumber: z.string().nullable(),\n productId: z.string().uuid().nullable(),\n variantId: z.string().uuid().nullable(),\n sku: z.string().nullable(),\n productName: z.string().nullable(),\n customerId: z.string().uuid().nullable(),\n orderId: z.string().uuid().nullable(),\n purchaseDate: z.string().nullable(),\n warrantyMonths: z.number().nullable(),\n warrantyExpiresAt: z.string().nullable(),\n coverageType: registrationCoverageTypeSchema.nullable(),\n source: registrationSourceSchema.nullable(),\n proofAttachmentId: z.string().uuid().nullable(),\n notes: z.string().nullable(),\n createdAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n}).passthrough()\n\nexport const openApi = createWarrantyClaimsCrudOpenApi({\n resourceName: 'WarrantyRegistration',\n pluralName: 'WarrantyRegistrations',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(registrationListItemSchema),\n create: {\n schema: registrationCreateSchema,\n responseSchema: z.object({ id: z.string().uuid() }),\n description: 'Creates a product warranty registration for entitlement resolution.',\n },\n update: {\n schema: registrationUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates a product warranty registration.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Soft-deletes a product warranty registration.',\n },\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,9 @@ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
4
  import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
5
5
  import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
6
6
  import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
7
+ import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
7
8
  import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
9
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
8
10
  import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
9
11
  import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
10
12
  import {
@@ -28,22 +30,19 @@ const errorResponseSchema = z.object({
28
30
  const metadata = {
29
31
  POST: { requireAuth: true, requireFeatures: ["warranty_claims.claim.manage", "sales.orders.manage"] }
30
32
  };
31
- function translateKey(key) {
32
- return key;
33
- }
34
33
  function toRecord(value) {
35
34
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
36
35
  }
37
- async function resolveActionContext(req) {
36
+ async function resolveActionContext(req, translate) {
38
37
  const container = await createRequestContainer();
39
38
  const auth = await getAuthFromRequest(req);
40
39
  if (!auth || !auth.tenantId) {
41
- throw new CrudHttpError(401, { error: "warranty_claims.errors.unauthorized" });
40
+ throw new CrudHttpError(401, { error: translate("warranty_claims.errors.unauthorized", "Unauthorized") });
42
41
  }
43
42
  const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
44
43
  const organizationId = scope?.selectedId ?? auth.orgId ?? null;
45
44
  if (!organizationId) {
46
- throw new CrudHttpError(400, { error: "warranty_claims.errors.organization_required" });
45
+ throw new CrudHttpError(400, { error: translate("warranty_claims.errors.organization_required", "Organization context is required.") });
47
46
  }
48
47
  return {
49
48
  ctx: {
@@ -56,7 +55,7 @@ async function resolveActionContext(req) {
56
55
  },
57
56
  tenantId: auth.tenantId,
58
57
  organizationId,
59
- translate: translateKey
58
+ translate
60
59
  };
61
60
  }
62
61
  function toReplacementOrderRequest(payload) {
@@ -73,7 +72,7 @@ function toCommandInput(input, context) {
73
72
  async function runGuard(req, context, input) {
74
73
  const userId = context.ctx.auth?.sub;
75
74
  if (!userId) {
76
- throw new CrudHttpError(401, { error: "warranty_claims.errors.unauthorized" });
75
+ throw new CrudHttpError(401, { error: context.translate("warranty_claims.errors.unauthorized", "Unauthorized") });
77
76
  }
78
77
  return runRouteMutationGuards({
79
78
  container: context.ctx.container,
@@ -92,8 +91,9 @@ async function runGuard(req, context, input) {
92
91
  });
93
92
  }
94
93
  async function POST(req) {
94
+ const { translate } = await resolveTranslations();
95
95
  try {
96
- const context = await resolveActionContext(req);
96
+ const context = await resolveActionContext(req, translate);
97
97
  const requestInput = toReplacementOrderRequest(toRecord(await readJsonSafe(req, {})));
98
98
  const guarded = await runGuard(req, context, requestInput);
99
99
  if (!guarded.ok) {
@@ -105,7 +105,7 @@ async function POST(req) {
105
105
  "warranty_claims.claim.create_replacement_order",
106
106
  { input: toCommandInput(guardedInput, context), ctx: context.ctx }
107
107
  );
108
- if (!result) throw new CrudHttpError(400, { error: "warranty_claims.errors.save_failed" });
108
+ if (!result) throw new CrudHttpError(400, { error: translate("warranty_claims.errors.save_failed", "Failed to save warranty claim.") });
109
109
  await guarded.runAfterSuccess();
110
110
  return NextResponse.json({
111
111
  replacementOrderId: result.replacementOrderId,
@@ -113,11 +113,15 @@ async function POST(req) {
113
113
  });
114
114
  } catch (err) {
115
115
  if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status });
116
+ const interceptorRejection = getCommandInterceptorHttpRejection(err);
117
+ if (interceptorRejection) {
118
+ return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
119
+ }
116
120
  if (err instanceof z.ZodError) {
117
- return NextResponse.json({ error: "warranty_claims.errors.invalidInput" }, { status: 400 });
121
+ return NextResponse.json({ error: translate("warranty_claims.errors.invalidInput", "Invalid input") }, { status: 400 });
118
122
  }
119
123
  logger.error("warranty_claims.replacement-order.post failed", { err });
120
- return NextResponse.json({ error: "warranty_claims.errors.save_failed" }, { status: 500 });
124
+ return NextResponse.json({ error: translate("warranty_claims.errors.save_failed", "Failed to save warranty claim.") }, { status: 500 });
121
125
  }
122
126
  }
123
127
  const openApi = {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/warranty_claims/api/replacement-order/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { runRouteMutationGuards, type RouteMutationGuardResult } from '@open-mercato/shared/lib/crud/route-mutation-guard'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n claimCreateReplacementOrderSchema,\n type ClaimCreateReplacementOrderInput,\n} from '../../data/validators'\nimport { WARRANTY_CLAIM_RESOURCE_KIND } from '../../commands/shared'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('warranty_claims')\n\ntype ActionRouteContext = {\n ctx: CommandRuntimeContext\n tenantId: string\n organizationId: string\n translate: (key: string, fallback?: string) => string\n}\n\ntype ReplacementOrderCommandResult = {\n claimId: string\n replacementOrderId: string\n replacementOrderUpdatedAt: string | null\n skippedLineIds: string[]\n pricing: 'zero' | 'original'\n}\n\nconst replacementOrderRequestSchema = z\n .object({\n claimId: z.string().uuid(),\n pricing: z.enum(['zero', 'original']).optional(),\n updatedAt: z.string().datetime().nullable().optional(),\n })\n .strict()\n\ntype ReplacementOrderRequest = z.infer<typeof replacementOrderRequestSchema>\n\nconst replacementOrderResponseSchema = z.object({\n replacementOrderId: z.string().uuid(),\n skippedLineIds: z.array(z.string().uuid()),\n})\n\nconst errorResponseSchema = z.object({\n error: z.string(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.claim.manage', 'sales.orders.manage'] },\n}\n\nfunction translateKey(key: string): string {\n return key\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\n\nasync function resolveActionContext(req: Request): Promise<ActionRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: 'warranty_claims.errors.unauthorized' })\n }\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, { error: 'warranty_claims.errors.organization_required' })\n }\n return {\n ctx: {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n },\n tenantId: auth.tenantId,\n organizationId,\n translate: translateKey,\n }\n}\n\nfunction toReplacementOrderRequest(payload: Record<string, unknown>): ReplacementOrderRequest {\n return replacementOrderRequestSchema.parse(payload)\n}\n\nfunction toCommandInput(\n input: ReplacementOrderRequest,\n context: ActionRouteContext,\n): ClaimCreateReplacementOrderInput {\n const scopedPayload = withScopedPayload({\n id: input.claimId,\n pricing: input.pricing,\n updatedAt: input.updatedAt,\n }, context.ctx, context.translate)\n return claimCreateReplacementOrderSchema.parse(scopedPayload)\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: ReplacementOrderRequest,\n): Promise<RouteMutationGuardResult> {\n const userId = context.ctx.auth?.sub\n if (!userId) {\n throw new CrudHttpError(401, { error: 'warranty_claims.errors.unauthorized' })\n }\n return runRouteMutationGuards({\n container: context.ctx.container,\n req,\n auth: {\n userId,\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n },\n input: {\n resourceKind: WARRANTY_CLAIM_RESOURCE_KIND,\n resourceId: input.claimId,\n operation: 'custom',\n mutationPayload: { ...input },\n },\n })\n}\n\nexport async function POST(req: Request) {\n try {\n const context = await resolveActionContext(req)\n const requestInput = toReplacementOrderRequest(toRecord(await readJsonSafe(req, {})))\n const guarded = await runGuard(req, context, requestInput)\n if (!guarded.ok) {\n return guarded.response\n }\n const guardedInput = guarded.modifiedPayload\n ? toReplacementOrderRequest(guarded.modifiedPayload)\n : requestInput\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<ClaimCreateReplacementOrderInput, ReplacementOrderCommandResult>(\n 'warranty_claims.claim.create_replacement_order',\n { input: toCommandInput(guardedInput, context), ctx: context.ctx },\n )\n if (!result) throw new CrudHttpError(400, { error: 'warranty_claims.errors.save_failed' })\n await guarded.runAfterSuccess()\n return NextResponse.json({\n replacementOrderId: result.replacementOrderId,\n skippedLineIds: result.skippedLineIds,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) {\n return NextResponse.json({ error: 'warranty_claims.errors.invalidInput' }, { status: 400 })\n }\n logger.error('warranty_claims.replacement-order.post failed', { err })\n return NextResponse.json({ error: 'warranty_claims.errors.save_failed' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Create a replacement sales order from a warranty claim',\n methods: {\n POST: {\n summary: 'Create and link a replacement order from eligible replace-disposition claim lines',\n description: 'Zero pricing is the default. Original pricing copies the source order lines\\' pre-discount unit prices.',\n requestBody: { contentType: 'application/json', schema: replacementOrderRequestSchema },\n responses: [\n {\n status: 200,\n description: 'Replacement order created and linked; ineligible or unresolvable claim lines are reported as skipped',\n schema: replacementOrderResponseSchema,\n },\n { status: 400, description: 'Invalid request or claim is not eligible for replacement-order creation', schema: errorResponseSchema },\n { status: 401, description: 'Authentication required', schema: errorResponseSchema },\n { status: 403, description: 'Insufficient permissions', schema: errorResponseSchema },\n { status: 409, description: 'Optimistic lock conflict', schema: errorResponseSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { runRouteMutationGuards, type RouteMutationGuardResult } from '@open-mercato/shared/lib/crud/route-mutation-guard'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n claimCreateReplacementOrderSchema,\n type ClaimCreateReplacementOrderInput,\n} from '../../data/validators'\nimport { WARRANTY_CLAIM_RESOURCE_KIND } from '../../commands/shared'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('warranty_claims')\n\ntype ActionRouteContext = {\n ctx: CommandRuntimeContext\n tenantId: string\n organizationId: string\n translate: (key: string, fallback?: string) => string\n}\n\ntype ReplacementOrderCommandResult = {\n claimId: string\n replacementOrderId: string\n replacementOrderUpdatedAt: string | null\n skippedLineIds: string[]\n pricing: 'zero' | 'original'\n}\n\nconst replacementOrderRequestSchema = z\n .object({\n claimId: z.string().uuid(),\n pricing: z.enum(['zero', 'original']).optional(),\n updatedAt: z.string().datetime().nullable().optional(),\n })\n .strict()\n\ntype ReplacementOrderRequest = z.infer<typeof replacementOrderRequestSchema>\n\nconst replacementOrderResponseSchema = z.object({\n replacementOrderId: z.string().uuid(),\n skippedLineIds: z.array(z.string().uuid()),\n})\n\nconst errorResponseSchema = z.object({\n error: z.string(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.claim.manage', 'sales.orders.manage'] },\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\n\nasync function resolveActionContext(\n req: Request,\n translate: ActionRouteContext['translate'],\n): Promise<ActionRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('warranty_claims.errors.unauthorized', 'Unauthorized') })\n }\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, { error: translate('warranty_claims.errors.organization_required', 'Organization context is required.') })\n }\n return {\n ctx: {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n },\n tenantId: auth.tenantId,\n organizationId,\n translate,\n }\n}\n\nfunction toReplacementOrderRequest(payload: Record<string, unknown>): ReplacementOrderRequest {\n return replacementOrderRequestSchema.parse(payload)\n}\n\nfunction toCommandInput(\n input: ReplacementOrderRequest,\n context: ActionRouteContext,\n): ClaimCreateReplacementOrderInput {\n const scopedPayload = withScopedPayload({\n id: input.claimId,\n pricing: input.pricing,\n updatedAt: input.updatedAt,\n }, context.ctx, context.translate)\n return claimCreateReplacementOrderSchema.parse(scopedPayload)\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: ReplacementOrderRequest,\n): Promise<RouteMutationGuardResult> {\n const userId = context.ctx.auth?.sub\n if (!userId) {\n throw new CrudHttpError(401, { error: context.translate('warranty_claims.errors.unauthorized', 'Unauthorized') })\n }\n return runRouteMutationGuards({\n container: context.ctx.container,\n req,\n auth: {\n userId,\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n },\n input: {\n resourceKind: WARRANTY_CLAIM_RESOURCE_KIND,\n resourceId: input.claimId,\n operation: 'custom',\n mutationPayload: { ...input },\n },\n })\n}\n\nexport async function POST(req: Request) {\n const { translate } = await resolveTranslations()\n try {\n const context = await resolveActionContext(req, translate)\n const requestInput = toReplacementOrderRequest(toRecord(await readJsonSafe(req, {})))\n const guarded = await runGuard(req, context, requestInput)\n if (!guarded.ok) {\n return guarded.response\n }\n const guardedInput = guarded.modifiedPayload\n ? toReplacementOrderRequest(guarded.modifiedPayload)\n : requestInput\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<ClaimCreateReplacementOrderInput, ReplacementOrderCommandResult>(\n 'warranty_claims.claim.create_replacement_order',\n { input: toCommandInput(guardedInput, context), ctx: context.ctx },\n )\n if (!result) throw new CrudHttpError(400, { error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim.') })\n await guarded.runAfterSuccess()\n return NextResponse.json({\n replacementOrderId: result.replacementOrderId,\n skippedLineIds: result.skippedLineIds,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n if (err instanceof z.ZodError) {\n return NextResponse.json({ error: translate('warranty_claims.errors.invalidInput', 'Invalid input') }, { status: 400 })\n }\n logger.error('warranty_claims.replacement-order.post failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim.') }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Create a replacement sales order from a warranty claim',\n methods: {\n POST: {\n summary: 'Create and link a replacement order from eligible replace-disposition claim lines',\n description: 'Zero pricing is the default. Original pricing copies the source order lines\\' pre-discount unit prices.',\n requestBody: { contentType: 'application/json', schema: replacementOrderRequestSchema },\n responses: [\n {\n status: 200,\n description: 'Replacement order created and linked; ineligible or unresolvable claim lines are reported as skipped',\n schema: replacementOrderResponseSchema,\n },\n { status: 400, description: 'Invalid request or claim is not eligible for replacement-order creation', schema: errorResponseSchema },\n { status: 401, description: 'Authentication required', schema: errorResponseSchema },\n { status: 403, description: 'Insufficient permissions', schema: errorResponseSchema },\n { status: 409, description: 'Optimistic lock conflict', schema: errorResponseSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,9 @@ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
4
  import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
5
5
  import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
6
6
  import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
7
+ import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
7
8
  import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
9
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
8
10
  import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
9
11
  import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
10
12
  import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
@@ -40,22 +42,19 @@ const returnLabelResponseSchema = z.discriminatedUnion("status", [
40
42
  const metadata = {
41
43
  POST: { requireAuth: true, requireFeatures: ["warranty_claims.claim.manage"] }
42
44
  };
43
- function translateKey(key) {
44
- return key;
45
- }
46
45
  function toRecord(value) {
47
46
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
48
47
  }
49
- async function resolveActionContext(req) {
48
+ async function resolveActionContext(req, translate) {
50
49
  const container = await createRequestContainer();
51
50
  const auth = await getAuthFromRequest(req);
52
51
  if (!auth || !auth.tenantId) {
53
- throw new CrudHttpError(401, { error: "warranty_claims.errors.unauthorized" });
52
+ throw new CrudHttpError(401, { error: translate("warranty_claims.errors.unauthorized", "Unauthorized") });
54
53
  }
55
54
  const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
56
55
  const organizationId = scope?.selectedId ?? auth.orgId ?? null;
57
56
  if (!organizationId) {
58
- throw new CrudHttpError(400, { error: "warranty_claims.errors.organization_required" });
57
+ throw new CrudHttpError(400, { error: translate("warranty_claims.errors.organization_required", "Organization context is required.") });
59
58
  }
60
59
  return {
61
60
  ctx: {
@@ -68,7 +67,7 @@ async function resolveActionContext(req) {
68
67
  },
69
68
  tenantId: auth.tenantId,
70
69
  organizationId,
71
- translate: translateKey
70
+ translate
72
71
  };
73
72
  }
74
73
  function toReturnLabelRequest(payload) {
@@ -97,7 +96,7 @@ function toSetReturnLabelInput(input, context) {
97
96
  async function runGuard(req, context, input) {
98
97
  const userId = context.ctx.auth?.sub;
99
98
  if (!userId) {
100
- throw new CrudHttpError(401, { error: "warranty_claims.errors.unauthorized" });
99
+ throw new CrudHttpError(401, { error: context.translate("warranty_claims.errors.unauthorized", "Unauthorized") });
101
100
  }
102
101
  return runRouteMutationGuards({
103
102
  container: context.ctx.container,
@@ -118,7 +117,7 @@ async function runGuard(req, context, input) {
118
117
  async function loadClaimAndLines(context, claimId) {
119
118
  const scope = { tenantId: context.tenantId, organizationId: context.organizationId };
120
119
  const em = context.ctx.container.resolve("em").fork();
121
- const claim = await requireScopedClaim(em, claimId, scope);
120
+ const claim = await requireScopedClaim(em, claimId, scope, {}, context.translate("warranty_claims.errors.notFound", "Claim not found."));
122
121
  const lines = await findWithDecryption(
123
122
  em,
124
123
  WarrantyClaimLine,
@@ -128,17 +127,17 @@ async function loadClaimAndLines(context, claimId) {
128
127
  );
129
128
  return { claim, lines };
130
129
  }
131
- function assertGeneratableStatus(claim) {
130
+ function assertGeneratableStatus(claim, translate) {
132
131
  if (claim.status !== "approved" && claim.status !== "awaiting_return") {
133
- throw new CrudHttpError(400, { error: "warranty_claims.errors.returnLabelInvalidStatus" });
132
+ throw new CrudHttpError(400, { error: translate("warranty_claims.errors.returnLabelInvalidStatus", "Return labels can only be created for approved claims that are awaiting return.") });
134
133
  }
135
134
  }
136
- async function executeSetReturnLabel(commandBus, input, ctx) {
135
+ async function executeSetReturnLabel(commandBus, input, ctx, translate) {
137
136
  const { result } = await commandBus.execute(
138
137
  "warranty_claims.claim.set_return_label",
139
138
  { input, ctx }
140
139
  );
141
- if (!result) throw new CrudHttpError(400, { error: "warranty_claims.errors.save_failed" });
140
+ if (!result) throw new CrudHttpError(400, { error: translate("warranty_claims.errors.save_failed", "Failed to save warranty claim.") });
142
141
  return {
143
142
  status: "created",
144
143
  labelUrl: result.labelUrl,
@@ -153,8 +152,9 @@ function firstTranslatableIssueKey(err) {
153
152
  return keyed ?? "warranty_claims.errors.invalidInput";
154
153
  }
155
154
  async function POST(req) {
155
+ const { translate } = await resolveTranslations();
156
156
  try {
157
- const context = await resolveActionContext(req);
157
+ const context = await resolveActionContext(req, translate);
158
158
  const requestInput = toReturnLabelRequest(toRecord(await readJsonSafe(req, {})));
159
159
  const guarded = await runGuard(req, context, requestInput);
160
160
  if (!guarded.ok) {
@@ -166,13 +166,14 @@ async function POST(req) {
166
166
  const response2 = await executeSetReturnLabel(
167
167
  commandBus,
168
168
  toSetReturnLabelInput(guardedInput, context),
169
- context.ctx
169
+ context.ctx,
170
+ translate
170
171
  );
171
172
  await guarded.runAfterSuccess();
172
173
  return NextResponse.json(response2);
173
174
  }
174
175
  const { claim, lines } = await loadClaimAndLines(context, guardedInput.claimId);
175
- assertGeneratableStatus(claim);
176
+ assertGeneratableStatus(claim, translate);
176
177
  await enforceWarrantyClaimOptimisticLock(
177
178
  context.ctx,
178
179
  claim,
@@ -196,17 +197,22 @@ async function POST(req) {
196
197
  trackingNumber: result.trackingNumber,
197
198
  carrier: result.carrier
198
199
  }, context),
199
- context.ctx
200
+ context.ctx,
201
+ translate
200
202
  );
201
203
  await guarded.runAfterSuccess();
202
204
  return NextResponse.json(response);
203
205
  } catch (err) {
204
206
  if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status });
207
+ const interceptorRejection = getCommandInterceptorHttpRejection(err);
208
+ if (interceptorRejection) {
209
+ return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
210
+ }
205
211
  if (err instanceof z.ZodError) {
206
- return NextResponse.json({ error: firstTranslatableIssueKey(err) }, { status: 400 });
212
+ return NextResponse.json({ error: translate(firstTranslatableIssueKey(err), "Invalid input") }, { status: 400 });
207
213
  }
208
214
  logger.error("warranty_claims.return-label.post failed", { err });
209
- return NextResponse.json({ error: "warranty_claims.errors.save_failed" }, { status: 500 });
215
+ return NextResponse.json({ error: translate("warranty_claims.errors.save_failed", "Failed to save warranty claim.") }, { status: 500 });
210
216
  }
211
217
  }
212
218
  const openApi = {