@open-mercato/core 0.7.1-develop.7123.1.25365e718d → 0.7.1-develop.7131.1.20abf9e885

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 (234) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +5 -0
  3. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
  4. package/dist/modules/auth/api/profile/route.js +5 -0
  5. package/dist/modules/auth/api/profile/route.js.map +2 -2
  6. package/dist/modules/customers/api/activities/route.js +13 -0
  7. package/dist/modules/customers/api/activities/route.js.map +2 -2
  8. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +9 -0
  9. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  10. package/dist/modules/customers/api/dictionaries/[kind]/route.js +5 -0
  11. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  12. package/dist/modules/customers/api/dictionaries/kind-settings/route.js +5 -0
  13. package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +2 -2
  14. package/dist/modules/customers/api/interactions/cancel/route.js +5 -0
  15. package/dist/modules/customers/api/interactions/cancel/route.js.map +2 -2
  16. package/dist/modules/customers/api/interactions/complete/route.js +5 -0
  17. package/dist/modules/customers/api/interactions/complete/route.js.map +2 -2
  18. package/dist/modules/customers/api/labels/assign/route.js +5 -0
  19. package/dist/modules/customers/api/labels/assign/route.js.map +2 -2
  20. package/dist/modules/customers/api/labels/route.js +5 -0
  21. package/dist/modules/customers/api/labels/route.js.map +2 -2
  22. package/dist/modules/customers/api/labels/unassign/route.js +5 -0
  23. package/dist/modules/customers/api/labels/unassign/route.js.map +2 -2
  24. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +9 -0
  25. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
  26. package/dist/modules/customers/api/people/[id]/companies/route.js +5 -0
  27. package/dist/modules/customers/api/people/[id]/companies/route.js.map +2 -2
  28. package/dist/modules/customers/api/pipeline-stages/reorder/route.js +5 -0
  29. package/dist/modules/customers/api/pipeline-stages/reorder/route.js.map +2 -2
  30. package/dist/modules/customers/api/pipeline-stages/route.js +13 -0
  31. package/dist/modules/customers/api/pipeline-stages/route.js.map +2 -2
  32. package/dist/modules/customers/api/pipelines/route.js +13 -0
  33. package/dist/modules/customers/api/pipelines/route.js.map +2 -2
  34. package/dist/modules/customers/api/settings/address-format/route.js +5 -0
  35. package/dist/modules/customers/api/settings/address-format/route.js.map +2 -2
  36. package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js +5 -0
  37. package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js.map +2 -2
  38. package/dist/modules/customers/api/settings/stuck-threshold/route.js +5 -0
  39. package/dist/modules/customers/api/settings/stuck-threshold/route.js.map +2 -2
  40. package/dist/modules/customers/api/tags/assign/route.js +5 -0
  41. package/dist/modules/customers/api/tags/assign/route.js.map +2 -2
  42. package/dist/modules/customers/api/tags/unassign/route.js +5 -0
  43. package/dist/modules/customers/api/tags/unassign/route.js.map +2 -2
  44. package/dist/modules/customers/api/todos/route.js +13 -0
  45. package/dist/modules/customers/api/todos/route.js.map +2 -2
  46. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +5 -117
  47. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
  48. package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -3
  49. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  50. package/dist/modules/customers/commands/deals.js +33 -9
  51. package/dist/modules/customers/commands/deals.js.map +3 -3
  52. package/dist/modules/customers/components/AddressEditor.js +71 -1
  53. package/dist/modules/customers/components/AddressEditor.js.map +2 -2
  54. package/dist/modules/customers/utils/addressFormat.js +18 -2
  55. package/dist/modules/customers/utils/addressFormat.js.map +2 -2
  56. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +9 -0
  57. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  58. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +5 -0
  59. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +2 -2
  60. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +5 -0
  61. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
  62. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +5 -0
  63. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +2 -2
  64. package/dist/modules/directory/api/organization-branding/route.js +5 -0
  65. package/dist/modules/directory/api/organization-branding/route.js.map +2 -2
  66. package/dist/modules/eudr/api/plots/import/route.js.map +2 -2
  67. package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js.map +2 -2
  68. package/dist/modules/feature_toggles/api/overrides/route.js +5 -0
  69. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  70. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js +5 -0
  71. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js.map +2 -2
  72. package/dist/modules/messages/api/[id]/conversation/archive/route.js +5 -0
  73. package/dist/modules/messages/api/[id]/conversation/archive/route.js.map +2 -2
  74. package/dist/modules/messages/api/[id]/conversation/read/route.js +5 -0
  75. package/dist/modules/messages/api/[id]/conversation/read/route.js.map +2 -2
  76. package/dist/modules/messages/api/[id]/conversation/route.js +5 -0
  77. package/dist/modules/messages/api/[id]/conversation/route.js.map +2 -2
  78. package/dist/modules/messages/api/[id]/forward/route.js +5 -0
  79. package/dist/modules/messages/api/[id]/forward/route.js.map +2 -2
  80. package/dist/modules/messages/api/[id]/reply/route.js +5 -0
  81. package/dist/modules/messages/api/[id]/reply/route.js.map +2 -2
  82. package/dist/modules/messages/api/[id]/route.js +9 -0
  83. package/dist/modules/messages/api/[id]/route.js.map +2 -2
  84. package/dist/modules/messages/api/token/[token]/route.js +5 -0
  85. package/dist/modules/messages/api/token/[token]/route.js.map +2 -2
  86. package/dist/modules/resources/api/resources/tags/assign/route.js +5 -0
  87. package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
  88. package/dist/modules/resources/api/resources/tags/unassign/route.js +5 -0
  89. package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
  90. package/dist/modules/sales/api/quotes/accept/route.js +5 -0
  91. package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
  92. package/dist/modules/sales/api/quotes/convert/route.js +5 -0
  93. package/dist/modules/sales/api/quotes/convert/route.js.map +2 -2
  94. package/dist/modules/sales/api/settings/document-numbers/route.js +5 -0
  95. package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
  96. package/dist/modules/sales/api/settings/order-editing/route.js +5 -0
  97. package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
  98. package/dist/modules/sales/components/documents/AddressesSection.js +17 -2
  99. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  100. package/dist/modules/sales/components/documents/SalesDocumentForm.js +7 -24
  101. package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
  102. package/dist/modules/sales/components/documents/normalizeAddressDraft.js +29 -0
  103. package/dist/modules/sales/components/documents/normalizeAddressDraft.js.map +7 -0
  104. package/dist/modules/staff/api/leave-requests/accept/route.js +5 -0
  105. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  106. package/dist/modules/staff/api/leave-requests/reject/route.js +5 -0
  107. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  108. package/dist/modules/staff/api/team-members/self/route.js +5 -0
  109. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  110. package/dist/modules/staff/api/team-members/tags/assign/route.js +5 -0
  111. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  112. package/dist/modules/staff/api/team-members/tags/unassign/route.js +5 -0
  113. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  114. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +5 -0
  115. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
  116. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +9 -0
  117. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  118. package/dist/modules/warranty_claims/api/ai/assess/route.js +5 -0
  119. package/dist/modules/warranty_claims/api/ai/assess/route.js.map +2 -2
  120. package/dist/modules/warranty_claims/api/assign/route.js +5 -0
  121. package/dist/modules/warranty_claims/api/assign/route.js.map +2 -2
  122. package/dist/modules/warranty_claims/api/credit-memo/route.js +5 -0
  123. package/dist/modules/warranty_claims/api/credit-memo/route.js.map +2 -2
  124. package/dist/modules/warranty_claims/api/events/route.js +5 -0
  125. package/dist/modules/warranty_claims/api/events/route.js.map +2 -2
  126. package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js +5 -0
  127. package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js.map +2 -2
  128. package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js +5 -0
  129. package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js.map +2 -2
  130. package/dist/modules/warranty_claims/api/portal/claims/route.js +5 -0
  131. package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
  132. package/dist/modules/warranty_claims/api/portal/events/route.js +5 -0
  133. package/dist/modules/warranty_claims/api/portal/events/route.js.map +2 -2
  134. package/dist/modules/warranty_claims/api/receiving/route.js +5 -0
  135. package/dist/modules/warranty_claims/api/receiving/route.js.map +2 -2
  136. package/dist/modules/warranty_claims/api/replacement-order/route.js +5 -0
  137. package/dist/modules/warranty_claims/api/replacement-order/route.js.map +2 -2
  138. package/dist/modules/warranty_claims/api/return-label/route.js +5 -0
  139. package/dist/modules/warranty_claims/api/return-label/route.js.map +2 -2
  140. package/dist/modules/warranty_claims/api/sales-return/route.js +5 -0
  141. package/dist/modules/warranty_claims/api/sales-return/route.js.map +2 -2
  142. package/dist/modules/warranty_claims/api/settings-general/route.js +5 -0
  143. package/dist/modules/warranty_claims/api/settings-general/route.js.map +2 -2
  144. package/dist/modules/warranty_claims/api/submit/route.js +5 -0
  145. package/dist/modules/warranty_claims/api/submit/route.js.map +2 -2
  146. package/dist/modules/warranty_claims/api/transition/route.js +5 -0
  147. package/dist/modules/warranty_claims/api/transition/route.js.map +2 -2
  148. package/dist/modules/warranty_claims/api/vendor-recovery/route.js +5 -0
  149. package/dist/modules/warranty_claims/api/vendor-recovery/route.js.map +2 -2
  150. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js +5 -0
  151. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js.map +2 -2
  152. package/package.json +7 -7
  153. package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +5 -0
  154. package/src/modules/auth/api/profile/route.ts +5 -0
  155. package/src/modules/customers/api/activities/route.ts +13 -0
  156. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +9 -0
  157. package/src/modules/customers/api/dictionaries/[kind]/route.ts +5 -0
  158. package/src/modules/customers/api/dictionaries/kind-settings/route.ts +5 -0
  159. package/src/modules/customers/api/interactions/cancel/route.ts +5 -0
  160. package/src/modules/customers/api/interactions/complete/route.ts +5 -0
  161. package/src/modules/customers/api/labels/assign/route.ts +5 -0
  162. package/src/modules/customers/api/labels/route.ts +5 -0
  163. package/src/modules/customers/api/labels/unassign/route.ts +5 -0
  164. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +9 -0
  165. package/src/modules/customers/api/people/[id]/companies/route.ts +5 -0
  166. package/src/modules/customers/api/pipeline-stages/reorder/route.ts +5 -0
  167. package/src/modules/customers/api/pipeline-stages/route.ts +13 -0
  168. package/src/modules/customers/api/pipelines/route.ts +13 -0
  169. package/src/modules/customers/api/settings/address-format/route.ts +5 -0
  170. package/src/modules/customers/api/settings/dictionary-sort-modes/route.ts +5 -0
  171. package/src/modules/customers/api/settings/stuck-threshold/route.ts +5 -0
  172. package/src/modules/customers/api/tags/assign/route.ts +5 -0
  173. package/src/modules/customers/api/tags/unassign/route.ts +5 -0
  174. package/src/modules/customers/api/todos/route.ts +13 -0
  175. package/src/modules/customers/backend/customers/deals/[id]/hooks/types.ts +0 -23
  176. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +11 -172
  177. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -1
  178. package/src/modules/customers/commands/deals.ts +84 -9
  179. package/src/modules/customers/components/AddressEditor.tsx +116 -1
  180. package/src/modules/customers/i18n/de.json +6 -0
  181. package/src/modules/customers/i18n/en.json +6 -0
  182. package/src/modules/customers/i18n/es.json +6 -0
  183. package/src/modules/customers/i18n/ko.json +6 -0
  184. package/src/modules/customers/i18n/pl.json +6 -0
  185. package/src/modules/customers/utils/addressFormat.tsx +59 -1
  186. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +9 -0
  187. package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +5 -0
  188. package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +5 -0
  189. package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +5 -0
  190. package/src/modules/directory/api/organization-branding/route.ts +5 -0
  191. package/src/modules/eudr/api/plots/import/route.ts +7 -0
  192. package/src/modules/eudr/api/product-mappings/suggestions/apply/route.ts +7 -0
  193. package/src/modules/feature_toggles/api/overrides/route.ts +5 -0
  194. package/src/modules/messages/api/[id]/actions/[actionId]/route.ts +5 -0
  195. package/src/modules/messages/api/[id]/conversation/archive/route.ts +5 -0
  196. package/src/modules/messages/api/[id]/conversation/read/route.ts +5 -0
  197. package/src/modules/messages/api/[id]/conversation/route.ts +5 -0
  198. package/src/modules/messages/api/[id]/forward/route.ts +5 -0
  199. package/src/modules/messages/api/[id]/reply/route.ts +5 -0
  200. package/src/modules/messages/api/[id]/route.ts +9 -0
  201. package/src/modules/messages/api/token/[token]/route.ts +5 -0
  202. package/src/modules/resources/api/resources/tags/assign/route.ts +5 -0
  203. package/src/modules/resources/api/resources/tags/unassign/route.ts +5 -0
  204. package/src/modules/sales/api/quotes/accept/route.ts +5 -0
  205. package/src/modules/sales/api/quotes/convert/route.ts +5 -0
  206. package/src/modules/sales/api/settings/document-numbers/route.ts +5 -0
  207. package/src/modules/sales/api/settings/order-editing/route.ts +5 -0
  208. package/src/modules/sales/components/documents/AddressesSection.tsx +48 -5
  209. package/src/modules/sales/components/documents/SalesDocumentForm.tsx +5 -23
  210. package/src/modules/sales/components/documents/normalizeAddressDraft.ts +29 -0
  211. package/src/modules/staff/api/leave-requests/accept/route.ts +5 -0
  212. package/src/modules/staff/api/leave-requests/reject/route.ts +5 -0
  213. package/src/modules/staff/api/team-members/self/route.ts +5 -0
  214. package/src/modules/staff/api/team-members/tags/assign/route.ts +5 -0
  215. package/src/modules/staff/api/team-members/tags/unassign/route.ts +5 -0
  216. package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +5 -0
  217. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +9 -0
  218. package/src/modules/warranty_claims/api/ai/assess/route.ts +5 -0
  219. package/src/modules/warranty_claims/api/assign/route.ts +5 -0
  220. package/src/modules/warranty_claims/api/credit-memo/route.ts +5 -0
  221. package/src/modules/warranty_claims/api/events/route.ts +5 -0
  222. package/src/modules/warranty_claims/api/portal/claims/[id]/submit/route.ts +5 -0
  223. package/src/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.ts +5 -0
  224. package/src/modules/warranty_claims/api/portal/claims/route.ts +5 -0
  225. package/src/modules/warranty_claims/api/portal/events/route.ts +5 -0
  226. package/src/modules/warranty_claims/api/receiving/route.ts +5 -0
  227. package/src/modules/warranty_claims/api/replacement-order/route.ts +5 -0
  228. package/src/modules/warranty_claims/api/return-label/route.ts +5 -0
  229. package/src/modules/warranty_claims/api/sales-return/route.ts +5 -0
  230. package/src/modules/warranty_claims/api/settings-general/route.ts +5 -0
  231. package/src/modules/warranty_claims/api/submit/route.ts +5 -0
  232. package/src/modules/warranty_claims/api/transition/route.ts +5 -0
  233. package/src/modules/warranty_claims/api/vendor-recovery/route.ts +5 -0
  234. 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/sales/api/quotes/convert/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 { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n bridgeLegacyGuard,\n runMutationGuards,\n type MutationGuard,\n type MutationGuardInput,\n} from '@open-mercato/shared/lib/crud/mutation-guard-registry'\nimport { withScopedPayload } from '../../utils'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nconst convertSchema = z.object({\n quoteId: z.string().uuid(),\n orderId: z.string().uuid().optional(),\n orderNumber: z.string().trim().max(191).optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['sales.quotes.manage', 'sales.orders.manage'] },\n}\n\ntype RequestContext = {\n ctx: CommandRuntimeContext\n}\n\nfunction resolveUserFeatures(auth: unknown): string[] {\n const features = (auth as { features?: unknown })?.features\n if (!Array.isArray(features)) return []\n return features.filter((value): value is string => typeof value === 'string')\n}\n\nasync function runGuards(\n ctx: CommandRuntimeContext,\n input: MutationGuardInput,\n): Promise<{\n ok: boolean\n errorBody?: Record<string, unknown>\n errorStatus?: number\n afterSuccessCallbacks: Array<{ guard: MutationGuard; metadata: Record<string, unknown> | null }>\n}> {\n const legacyGuard = bridgeLegacyGuard(ctx.container)\n if (!legacyGuard) {\n return { ok: true, afterSuccessCallbacks: [] }\n }\n\n return runMutationGuards([legacyGuard], input, {\n userFeatures: resolveUserFeatures(ctx.auth),\n })\n}\n\nasync function runGuardAfterSuccessCallbacks(\n callbacks: Array<{ guard: MutationGuard; metadata: Record<string, unknown> | null }>,\n input: {\n tenantId: string\n organizationId: string | null\n userId: string\n resourceKind: string\n resourceId: string\n operation: 'create' | 'update' | 'delete'\n requestMethod: string\n requestHeaders: Headers\n },\n): Promise<void> {\n for (const callback of callbacks) {\n if (!callback.guard.afterSuccess) continue\n await callback.guard.afterSuccess({\n ...input,\n metadata: callback.metadata ?? null,\n })\n }\n}\n\nasync function resolveRequestContext(req: Request): Promise<RequestContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('sales.documents.errors.unauthorized', 'Unauthorized') })\n }\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, {\n error: translate('sales.documents.errors.organization_required', 'Organization context is required'),\n })\n }\n\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n return { ctx }\n}\n\nexport async function POST(req: Request) {\n try {\n const { ctx } = await resolveRequestContext(req)\n const { translate } = await resolveTranslations()\n const payload = await req.json().catch(() => ({}))\n const scoped = withScopedPayload(payload ?? {}, ctx, translate)\n const input = convertSchema.parse(scoped)\n const guardResult = await runGuards(ctx, {\n tenantId: ctx.auth?.tenantId ?? '',\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n userId: ctx.auth?.sub ?? '',\n resourceKind: 'sales.quote',\n resourceId: input.quoteId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n if (!guardResult.ok) {\n return NextResponse.json(guardResult.errorBody ?? { error: 'Operation blocked by guard' }, { status: guardResult.errorStatus ?? 422 })\n }\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<\n { quoteId: string; orderId?: string; orderNumber?: string },\n { orderId: string }\n >('sales.quotes.convert_to_order', { input, ctx })\n\n const orderId = result?.orderId ?? input.orderId ?? input.quoteId\n const jsonResponse = NextResponse.json({ orderId })\n\n if (logEntry?.undoToken && logEntry?.id && logEntry?.commandId) {\n jsonResponse.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? 'sales.order',\n resourceId: logEntry.resourceId ?? orderId,\n executedAt: logEntry.createdAt instanceof Date\n ? logEntry.createdAt.toISOString()\n : typeof logEntry.createdAt === 'string'\n ? logEntry.createdAt\n : new Date().toISOString(),\n })\n )\n }\n\n if (guardResult.afterSuccessCallbacks.length) {\n await runGuardAfterSuccessCallbacks(guardResult.afterSuccessCallbacks, {\n tenantId: ctx.auth?.tenantId ?? '',\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n userId: ctx.auth?.sub ?? '',\n resourceKind: 'sales.quote',\n resourceId: input.quoteId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n }\n\n return jsonResponse\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.quotes.convert failed', { err })\n return NextResponse.json(\n { error: translate('sales.documents.detail.convertError', 'Failed to convert quote.') },\n { status: 400 }\n )\n }\n}\n\nconst convertResponseSchema = z.object({\n orderId: z.string().uuid(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Convert quote to order',\n methods: {\n POST: {\n summary: 'Convert quote',\n description: 'Creates a sales order from a quote and removes the original quote record.',\n requestBody: {\n contentType: 'application/json',\n schema: convertSchema,\n },\n responses: [\n { status: 200, description: 'Conversion succeeded', schema: convertResponseSchema },\n { status: 400, description: 'Invalid payload', schema: z.object({ error: z.string() }) },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'Forbidden', schema: z.object({ error: z.string() }) },\n { status: 409, description: 'Conflict detected', schema: z.object({ error: z.string(), code: z.string().optional() }) },\n { status: 423, description: 'Record locked', schema: z.object({ error: z.string(), code: z.string().optional() }) },\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 { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n bridgeLegacyGuard,\n runMutationGuards,\n type MutationGuard,\n type MutationGuardInput,\n} from '@open-mercato/shared/lib/crud/mutation-guard-registry'\nimport { withScopedPayload } from '../../utils'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\n\nconst logger = createLogger('sales')\n\nconst convertSchema = z.object({\n quoteId: z.string().uuid(),\n orderId: z.string().uuid().optional(),\n orderNumber: z.string().trim().max(191).optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['sales.quotes.manage', 'sales.orders.manage'] },\n}\n\ntype RequestContext = {\n ctx: CommandRuntimeContext\n}\n\nfunction resolveUserFeatures(auth: unknown): string[] {\n const features = (auth as { features?: unknown })?.features\n if (!Array.isArray(features)) return []\n return features.filter((value): value is string => typeof value === 'string')\n}\n\nasync function runGuards(\n ctx: CommandRuntimeContext,\n input: MutationGuardInput,\n): Promise<{\n ok: boolean\n errorBody?: Record<string, unknown>\n errorStatus?: number\n afterSuccessCallbacks: Array<{ guard: MutationGuard; metadata: Record<string, unknown> | null }>\n}> {\n const legacyGuard = bridgeLegacyGuard(ctx.container)\n if (!legacyGuard) {\n return { ok: true, afterSuccessCallbacks: [] }\n }\n\n return runMutationGuards([legacyGuard], input, {\n userFeatures: resolveUserFeatures(ctx.auth),\n })\n}\n\nasync function runGuardAfterSuccessCallbacks(\n callbacks: Array<{ guard: MutationGuard; metadata: Record<string, unknown> | null }>,\n input: {\n tenantId: string\n organizationId: string | null\n userId: string\n resourceKind: string\n resourceId: string\n operation: 'create' | 'update' | 'delete'\n requestMethod: string\n requestHeaders: Headers\n },\n): Promise<void> {\n for (const callback of callbacks) {\n if (!callback.guard.afterSuccess) continue\n await callback.guard.afterSuccess({\n ...input,\n metadata: callback.metadata ?? null,\n })\n }\n}\n\nasync function resolveRequestContext(req: Request): Promise<RequestContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('sales.documents.errors.unauthorized', 'Unauthorized') })\n }\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, {\n error: translate('sales.documents.errors.organization_required', 'Organization context is required'),\n })\n }\n\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n return { ctx }\n}\n\nexport async function POST(req: Request) {\n try {\n const { ctx } = await resolveRequestContext(req)\n const { translate } = await resolveTranslations()\n const payload = await req.json().catch(() => ({}))\n const scoped = withScopedPayload(payload ?? {}, ctx, translate)\n const input = convertSchema.parse(scoped)\n const guardResult = await runGuards(ctx, {\n tenantId: ctx.auth?.tenantId ?? '',\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n userId: ctx.auth?.sub ?? '',\n resourceKind: 'sales.quote',\n resourceId: input.quoteId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n if (!guardResult.ok) {\n return NextResponse.json(guardResult.errorBody ?? { error: 'Operation blocked by guard' }, { status: guardResult.errorStatus ?? 422 })\n }\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<\n { quoteId: string; orderId?: string; orderNumber?: string },\n { orderId: string }\n >('sales.quotes.convert_to_order', { input, ctx })\n\n const orderId = result?.orderId ?? input.orderId ?? input.quoteId\n const jsonResponse = NextResponse.json({ orderId })\n\n if (logEntry?.undoToken && logEntry?.id && logEntry?.commandId) {\n jsonResponse.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? 'sales.order',\n resourceId: logEntry.resourceId ?? orderId,\n executedAt: logEntry.createdAt instanceof Date\n ? logEntry.createdAt.toISOString()\n : typeof logEntry.createdAt === 'string'\n ? logEntry.createdAt\n : new Date().toISOString(),\n })\n )\n }\n\n if (guardResult.afterSuccessCallbacks.length) {\n await runGuardAfterSuccessCallbacks(guardResult.afterSuccessCallbacks, {\n tenantId: ctx.auth?.tenantId ?? '',\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n userId: ctx.auth?.sub ?? '',\n resourceKind: 'sales.quote',\n resourceId: input.quoteId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n }\n\n return jsonResponse\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.quotes.convert failed', { err })\n return NextResponse.json(\n { error: translate('sales.documents.detail.convertError', 'Failed to convert quote.') },\n { status: 400 }\n )\n }\n}\n\nconst convertResponseSchema = z.object({\n orderId: z.string().uuid(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Convert quote to order',\n methods: {\n POST: {\n summary: 'Convert quote',\n description: 'Creates a sales order from a quote and removes the original quote record.',\n requestBody: {\n contentType: 'application/json',\n schema: convertSchema,\n },\n responses: [\n { status: 200, description: 'Conversion succeeded', schema: convertResponseSchema },\n { status: 400, description: 'Invalid payload', schema: z.object({ error: z.string() }) },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'Forbidden', schema: z.object({ error: z.string() }) },\n { status: 409, description: 'Conflict detected', schema: z.object({ error: z.string(), code: z.string().optional() }) },\n { status: 423, description: 'Record locked', schema: z.object({ error: z.string(), code: z.string().optional() }) },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -15,6 +15,7 @@ import {
15
15
  validateCrudMutationGuard
16
16
  } from "@open-mercato/shared/lib/crud/mutation-guard";
17
17
  import { createLogger } from "@open-mercato/shared/lib/logger";
18
+ import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
18
19
  const logger = createLogger("sales");
19
20
  const metadata = {
20
21
  GET: { requireAuth: true, requireFeatures: ["sales.settings.manage"] },
@@ -124,6 +125,10 @@ async function PUT(req) {
124
125
  if (isCrudHttpError(err)) {
125
126
  return NextResponse.json(err.body, { status: err.status });
126
127
  }
128
+ const interceptorRejection = getCommandInterceptorHttpRejection(err);
129
+ if (interceptorRejection) {
130
+ return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
131
+ }
127
132
  const { translate } = await resolveTranslations();
128
133
  logger.error("sales.settings.document-numbers.put failed", { err });
129
134
  return NextResponse.json(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/sales/api/settings/document-numbers/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 type { EntityManager } from '@mikro-orm/postgresql'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { salesSettingsUpsertSchema, type SalesSettingsUpsertInput } from '../../../data/validators'\nimport { loadSalesSettings } from '../../../commands/settings'\nimport { SalesDocumentNumberGenerator } from '../../../services/salesDocumentNumberGenerator'\nimport { DOCUMENT_NUMBER_TOKENS, DEFAULT_ORDER_NUMBER_FORMAT, DEFAULT_QUOTE_NUMBER_FORMAT } from '../../../lib/documentNumberTokens'\nimport { withScopedPayload } from '../../utils'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },\n}\n\ntype SettingsRouteContext = {\n ctx: CommandRuntimeContext\n em: EntityManager\n generator: SalesDocumentNumberGenerator\n translate: (key: string, fallback?: string) => string\n organizationId: string\n tenantId: string\n}\n\nasync function resolveSettingsContext(req: Request): Promise<SettingsRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('sales.settings.errors.unauthorized', 'Unauthorized') })\n }\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, {\n error: translate('sales.settings.errors.organization_required', 'Organization context is required'),\n })\n }\n\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n const em = container.resolve('em') as EntityManager\n const generator = container.resolve('salesDocumentNumberGenerator') as SalesDocumentNumberGenerator\n\n return {\n ctx,\n em,\n generator,\n translate,\n tenantId: auth.tenantId,\n organizationId,\n }\n}\n\nexport async function GET(req: Request) {\n try {\n const { em, generator, organizationId, tenantId } = await resolveSettingsContext(req)\n const record = await loadSalesSettings(em, { tenantId, organizationId })\n const sequences = await generator.peekSequences({ organizationId, tenantId })\n return NextResponse.json({\n orderNumberFormat: record?.orderNumberFormat ?? DEFAULT_ORDER_NUMBER_FORMAT,\n quoteNumberFormat: record?.quoteNumberFormat ?? DEFAULT_QUOTE_NUMBER_FORMAT,\n nextOrderNumber: sequences.order,\n nextQuoteNumber: sequences.quote,\n tokens: DOCUMENT_NUMBER_TOKENS,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.settings.document-numbers.get failed', { err })\n return NextResponse.json(\n { error: translate('sales.settings.errors.load_failed', 'Failed to load sales settings') },\n { status: 400 }\n )\n }\n}\n\nexport async function PUT(req: Request) {\n try {\n const { ctx, translate, generator, organizationId, tenantId } = await resolveSettingsContext(req)\n const payload = await readJsonSafe(req, {})\n const scoped = withScopedPayload(payload, ctx, translate)\n const input = salesSettingsUpsertSchema.parse(scoped)\n\n const guardResult = await validateCrudMutationGuard(ctx.container, {\n tenantId,\n organizationId,\n userId: ctx.auth!.sub,\n resourceKind: 'sales.settings',\n resourceId: organizationId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: input,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<\n SalesSettingsUpsertInput,\n {\n settingsId: string\n orderNumberFormat: string\n quoteNumberFormat: string\n nextOrderNumber: number\n nextQuoteNumber: number\n }\n >('sales.settings.save', { input, ctx })\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(ctx.container, {\n tenantId,\n organizationId,\n userId: ctx.auth!.sub,\n resourceKind: 'sales.settings',\n resourceId: organizationId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const sequences = await generator.peekSequences({ organizationId, tenantId })\n\n return NextResponse.json({\n orderNumberFormat: result?.orderNumberFormat ?? input.orderNumberFormat,\n quoteNumberFormat: result?.quoteNumberFormat ?? input.quoteNumberFormat,\n nextOrderNumber: result?.nextOrderNumber ?? sequences.order,\n nextQuoteNumber: result?.nextQuoteNumber ?? sequences.quote,\n tokens: DOCUMENT_NUMBER_TOKENS,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.settings.document-numbers.put failed', { err })\n return NextResponse.json(\n { error: translate('sales.settings.errors.save_failed', 'Failed to save sales settings') },\n { status: 400 }\n )\n }\n}\n\nconst settingsResponseSchema = z.object({\n orderNumberFormat: z.string(),\n quoteNumberFormat: z.string(),\n nextOrderNumber: z.number(),\n nextQuoteNumber: z.number(),\n tokens: z\n .array(\n z.object({\n token: z.string(),\n description: z.string(),\n })\n )\n .optional(),\n})\n\nconst settingsErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Sales document numbering settings',\n methods: {\n GET: {\n summary: 'Get document numbering settings',\n responses: [\n { status: 200, description: 'Current numbering formats and counters', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Missing scope', schema: settingsErrorSchema },\n ],\n },\n PUT: {\n summary: 'Update document numbering settings',\n requestBody: {\n contentType: 'application/json',\n schema: salesSettingsUpsertSchema,\n },\n responses: [\n { status: 200, description: 'Updated numbering formats and counters', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Invalid payload', schema: settingsErrorSchema },\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 type { EntityManager } from '@mikro-orm/postgresql'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { salesSettingsUpsertSchema, type SalesSettingsUpsertInput } from '../../../data/validators'\nimport { loadSalesSettings } from '../../../commands/settings'\nimport { SalesDocumentNumberGenerator } from '../../../services/salesDocumentNumberGenerator'\nimport { DOCUMENT_NUMBER_TOKENS, DEFAULT_ORDER_NUMBER_FORMAT, DEFAULT_QUOTE_NUMBER_FORMAT } from '../../../lib/documentNumberTokens'\nimport { withScopedPayload } from '../../utils'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\n\nconst logger = createLogger('sales')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },\n}\n\ntype SettingsRouteContext = {\n ctx: CommandRuntimeContext\n em: EntityManager\n generator: SalesDocumentNumberGenerator\n translate: (key: string, fallback?: string) => string\n organizationId: string\n tenantId: string\n}\n\nasync function resolveSettingsContext(req: Request): Promise<SettingsRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('sales.settings.errors.unauthorized', 'Unauthorized') })\n }\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, {\n error: translate('sales.settings.errors.organization_required', 'Organization context is required'),\n })\n }\n\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n const em = container.resolve('em') as EntityManager\n const generator = container.resolve('salesDocumentNumberGenerator') as SalesDocumentNumberGenerator\n\n return {\n ctx,\n em,\n generator,\n translate,\n tenantId: auth.tenantId,\n organizationId,\n }\n}\n\nexport async function GET(req: Request) {\n try {\n const { em, generator, organizationId, tenantId } = await resolveSettingsContext(req)\n const record = await loadSalesSettings(em, { tenantId, organizationId })\n const sequences = await generator.peekSequences({ organizationId, tenantId })\n return NextResponse.json({\n orderNumberFormat: record?.orderNumberFormat ?? DEFAULT_ORDER_NUMBER_FORMAT,\n quoteNumberFormat: record?.quoteNumberFormat ?? DEFAULT_QUOTE_NUMBER_FORMAT,\n nextOrderNumber: sequences.order,\n nextQuoteNumber: sequences.quote,\n tokens: DOCUMENT_NUMBER_TOKENS,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.settings.document-numbers.get failed', { err })\n return NextResponse.json(\n { error: translate('sales.settings.errors.load_failed', 'Failed to load sales settings') },\n { status: 400 }\n )\n }\n}\n\nexport async function PUT(req: Request) {\n try {\n const { ctx, translate, generator, organizationId, tenantId } = await resolveSettingsContext(req)\n const payload = await readJsonSafe(req, {})\n const scoped = withScopedPayload(payload, ctx, translate)\n const input = salesSettingsUpsertSchema.parse(scoped)\n\n const guardResult = await validateCrudMutationGuard(ctx.container, {\n tenantId,\n organizationId,\n userId: ctx.auth!.sub,\n resourceKind: 'sales.settings',\n resourceId: organizationId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: input,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<\n SalesSettingsUpsertInput,\n {\n settingsId: string\n orderNumberFormat: string\n quoteNumberFormat: string\n nextOrderNumber: number\n nextQuoteNumber: number\n }\n >('sales.settings.save', { input, ctx })\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(ctx.container, {\n tenantId,\n organizationId,\n userId: ctx.auth!.sub,\n resourceKind: 'sales.settings',\n resourceId: organizationId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const sequences = await generator.peekSequences({ organizationId, tenantId })\n\n return NextResponse.json({\n orderNumberFormat: result?.orderNumberFormat ?? input.orderNumberFormat,\n quoteNumberFormat: result?.quoteNumberFormat ?? input.quoteNumberFormat,\n nextOrderNumber: result?.nextOrderNumber ?? sequences.order,\n nextQuoteNumber: result?.nextQuoteNumber ?? sequences.quote,\n tokens: DOCUMENT_NUMBER_TOKENS,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.settings.document-numbers.put failed', { err })\n return NextResponse.json(\n { error: translate('sales.settings.errors.save_failed', 'Failed to save sales settings') },\n { status: 400 }\n )\n }\n}\n\nconst settingsResponseSchema = z.object({\n orderNumberFormat: z.string(),\n quoteNumberFormat: z.string(),\n nextOrderNumber: z.number(),\n nextQuoteNumber: z.number(),\n tokens: z\n .array(\n z.object({\n token: z.string(),\n description: z.string(),\n })\n )\n .optional(),\n})\n\nconst settingsErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Sales document numbering settings',\n methods: {\n GET: {\n summary: 'Get document numbering settings',\n responses: [\n { status: 200, description: 'Current numbering formats and counters', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Missing scope', schema: settingsErrorSchema },\n ],\n },\n PUT: {\n summary: 'Update document numbering settings',\n requestBody: {\n contentType: 'application/json',\n schema: salesSettingsUpsertSchema,\n },\n responses: [\n { status: 200, description: 'Updated numbering formats and counters', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Invalid payload', schema: settingsErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -17,6 +17,7 @@ import {
17
17
  import { ensureSalesDictionary } from "../../../lib/dictionaries.js";
18
18
  import { DictionaryEntry } from "@open-mercato/core/modules/dictionaries/data/entities";
19
19
  import { createLogger } from "@open-mercato/shared/lib/logger";
20
+ import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
20
21
  const logger = createLogger("sales");
21
22
  const metadata = {
22
23
  GET: { requireAuth: true, requireFeatures: ["sales.settings.manage"] },
@@ -151,6 +152,10 @@ async function PUT(req) {
151
152
  if (isCrudHttpError(err)) {
152
153
  return NextResponse.json(err.body, { status: err.status });
153
154
  }
155
+ const interceptorRejection = getCommandInterceptorHttpRejection(err);
156
+ if (interceptorRejection) {
157
+ return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
158
+ }
154
159
  const { translate } = await resolveTranslations();
155
160
  logger.error("sales.settings.order-editing.put failed", { err });
156
161
  return NextResponse.json(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/sales/api/settings/order-editing/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 type { EntityManager } from '@mikro-orm/postgresql'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { salesEditingSettingsSchema, salesSettingsUpsertSchema } from '../../../data/validators'\nimport { loadSalesSettings } from '../../../commands/settings'\nimport { DEFAULT_ORDER_NUMBER_FORMAT, DEFAULT_QUOTE_NUMBER_FORMAT } from '../../../lib/documentNumberTokens'\nimport { withScopedPayload } from '../../utils'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { ensureSalesDictionary } from '../../../lib/dictionaries'\nimport { DictionaryEntry } from '@open-mercato/core/modules/dictionaries/data/entities'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },\n}\n\ntype SettingsRouteContext = {\n ctx: CommandRuntimeContext\n em: EntityManager\n translate: (key: string, fallback?: string) => string\n organizationId: string\n tenantId: string\n}\n\nasync function resolveSettingsContext(req: Request): Promise<SettingsRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('sales.settings.errors.unauthorized', 'Unauthorized') })\n }\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, {\n error: translate('sales.settings.errors.organization_required', 'Organization context is required'),\n })\n }\n\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n const em = container.resolve('em') as EntityManager\n\n return {\n ctx,\n em,\n translate,\n tenantId: auth.tenantId,\n organizationId,\n }\n}\n\nasync function loadStatusOptions(em: EntityManager, tenantId: string, organizationId: string) {\n const dictionary = await ensureSalesDictionary({\n em,\n tenantId,\n organizationId,\n kind: 'order-status',\n })\n const entries = await em.find(\n DictionaryEntry,\n {\n dictionary,\n tenantId,\n organizationId,\n },\n { orderBy: { value: 'asc' } }\n )\n return entries.map((entry) => ({\n id: entry.id,\n value: entry.value ?? '',\n label: entry.label ?? entry.value ?? '',\n }))\n}\n\nexport async function GET(req: Request) {\n try {\n const { em, organizationId, tenantId } = await resolveSettingsContext(req)\n const record = await loadSalesSettings(em, { tenantId, organizationId })\n const orderStatuses = await loadStatusOptions(em, tenantId, organizationId)\n\n return NextResponse.json({\n orderCustomerEditableStatuses: record?.orderCustomerEditableStatuses ?? null,\n orderAddressEditableStatuses: record?.orderAddressEditableStatuses ?? null,\n orderStatuses,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.settings.order-editing.get failed', { err })\n return NextResponse.json(\n { error: translate('sales.settings.errors.load_failed', 'Failed to load sales settings') },\n { status: 400 }\n )\n }\n}\n\nexport async function PUT(req: Request) {\n try {\n const { ctx, translate, organizationId, tenantId, em } = await resolveSettingsContext(req)\n const payload = (await readJsonSafe<Record<string, unknown>>(req, {})) ?? {}\n const scoped = withScopedPayload(payload, ctx, translate)\n const parsed = salesEditingSettingsSchema.parse(scoped)\n\n const guardResult = await validateCrudMutationGuard(ctx.container, {\n tenantId,\n organizationId,\n userId: ctx.auth!.sub,\n resourceKind: 'sales.settings',\n resourceId: organizationId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const current = await loadSalesSettings(em, { tenantId, organizationId })\n const commandInput = salesSettingsUpsertSchema.parse({\n ...parsed,\n orderNumberFormat: parsed.orderNumberFormat ?? current?.orderNumberFormat ?? DEFAULT_ORDER_NUMBER_FORMAT,\n quoteNumberFormat: parsed.quoteNumberFormat ?? current?.quoteNumberFormat ?? DEFAULT_QUOTE_NUMBER_FORMAT,\n orderNextNumber: payload.orderNextNumber,\n quoteNextNumber: payload.quoteNextNumber,\n })\n\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const response = await commandBus.execute('sales.settings.save', { input: commandInput, ctx })\n const result = (response as { result?: { orderCustomerEditableStatuses?: string[] | null; orderAddressEditableStatuses?: string[] | null } }).result\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(ctx.container, {\n tenantId,\n organizationId,\n userId: ctx.auth!.sub,\n resourceKind: 'sales.settings',\n resourceId: organizationId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const orderStatuses = await loadStatusOptions(em, tenantId, organizationId)\n\n return NextResponse.json({\n orderCustomerEditableStatuses: result?.orderCustomerEditableStatuses ?? null,\n orderAddressEditableStatuses: result?.orderAddressEditableStatuses ?? null,\n orderStatuses,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.settings.order-editing.put failed', { err })\n return NextResponse.json(\n { error: translate('sales.settings.errors.save_failed', 'Failed to save sales settings') },\n { status: 400 }\n )\n }\n}\n\nconst orderStatusOptionSchema = z.object({\n id: z.string().uuid(),\n value: z.string(),\n label: z.string(),\n})\n\nconst settingsResponseSchema = z.object({\n orderCustomerEditableStatuses: z.array(z.string()).nullable(),\n orderAddressEditableStatuses: z.array(z.string()).nullable(),\n orderStatuses: z.array(orderStatusOptionSchema),\n})\n\nconst settingsErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Sales order editing settings',\n methods: {\n GET: {\n summary: 'Get order editing guards',\n responses: [\n { status: 200, description: 'Current order editing guards', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Missing scope', schema: settingsErrorSchema },\n ],\n },\n PUT: {\n summary: 'Update order editing guards',\n requestBody: {\n contentType: 'application/json',\n schema: salesEditingSettingsSchema,\n },\n responses: [\n { status: 200, description: 'Updated order editing guards', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Invalid payload', schema: settingsErrorSchema },\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 type { EntityManager } from '@mikro-orm/postgresql'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { salesEditingSettingsSchema, salesSettingsUpsertSchema } from '../../../data/validators'\nimport { loadSalesSettings } from '../../../commands/settings'\nimport { DEFAULT_ORDER_NUMBER_FORMAT, DEFAULT_QUOTE_NUMBER_FORMAT } from '../../../lib/documentNumberTokens'\nimport { withScopedPayload } from '../../utils'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { ensureSalesDictionary } from '../../../lib/dictionaries'\nimport { DictionaryEntry } from '@open-mercato/core/modules/dictionaries/data/entities'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\n\nconst logger = createLogger('sales')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },\n}\n\ntype SettingsRouteContext = {\n ctx: CommandRuntimeContext\n em: EntityManager\n translate: (key: string, fallback?: string) => string\n organizationId: string\n tenantId: string\n}\n\nasync function resolveSettingsContext(req: Request): Promise<SettingsRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('sales.settings.errors.unauthorized', 'Unauthorized') })\n }\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, {\n error: translate('sales.settings.errors.organization_required', 'Organization context is required'),\n })\n }\n\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n const em = container.resolve('em') as EntityManager\n\n return {\n ctx,\n em,\n translate,\n tenantId: auth.tenantId,\n organizationId,\n }\n}\n\nasync function loadStatusOptions(em: EntityManager, tenantId: string, organizationId: string) {\n const dictionary = await ensureSalesDictionary({\n em,\n tenantId,\n organizationId,\n kind: 'order-status',\n })\n const entries = await em.find(\n DictionaryEntry,\n {\n dictionary,\n tenantId,\n organizationId,\n },\n { orderBy: { value: 'asc' } }\n )\n return entries.map((entry) => ({\n id: entry.id,\n value: entry.value ?? '',\n label: entry.label ?? entry.value ?? '',\n }))\n}\n\nexport async function GET(req: Request) {\n try {\n const { em, organizationId, tenantId } = await resolveSettingsContext(req)\n const record = await loadSalesSettings(em, { tenantId, organizationId })\n const orderStatuses = await loadStatusOptions(em, tenantId, organizationId)\n\n return NextResponse.json({\n orderCustomerEditableStatuses: record?.orderCustomerEditableStatuses ?? null,\n orderAddressEditableStatuses: record?.orderAddressEditableStatuses ?? null,\n orderStatuses,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.settings.order-editing.get failed', { err })\n return NextResponse.json(\n { error: translate('sales.settings.errors.load_failed', 'Failed to load sales settings') },\n { status: 400 }\n )\n }\n}\n\nexport async function PUT(req: Request) {\n try {\n const { ctx, translate, organizationId, tenantId, em } = await resolveSettingsContext(req)\n const payload = (await readJsonSafe<Record<string, unknown>>(req, {})) ?? {}\n const scoped = withScopedPayload(payload, ctx, translate)\n const parsed = salesEditingSettingsSchema.parse(scoped)\n\n const guardResult = await validateCrudMutationGuard(ctx.container, {\n tenantId,\n organizationId,\n userId: ctx.auth!.sub,\n resourceKind: 'sales.settings',\n resourceId: organizationId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const current = await loadSalesSettings(em, { tenantId, organizationId })\n const commandInput = salesSettingsUpsertSchema.parse({\n ...parsed,\n orderNumberFormat: parsed.orderNumberFormat ?? current?.orderNumberFormat ?? DEFAULT_ORDER_NUMBER_FORMAT,\n quoteNumberFormat: parsed.quoteNumberFormat ?? current?.quoteNumberFormat ?? DEFAULT_QUOTE_NUMBER_FORMAT,\n orderNextNumber: payload.orderNextNumber,\n quoteNextNumber: payload.quoteNextNumber,\n })\n\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const response = await commandBus.execute('sales.settings.save', { input: commandInput, ctx })\n const result = (response as { result?: { orderCustomerEditableStatuses?: string[] | null; orderAddressEditableStatuses?: string[] | null } }).result\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(ctx.container, {\n tenantId,\n organizationId,\n userId: ctx.auth!.sub,\n resourceKind: 'sales.settings',\n resourceId: organizationId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const orderStatuses = await loadStatusOptions(em, tenantId, organizationId)\n\n return NextResponse.json({\n orderCustomerEditableStatuses: result?.orderCustomerEditableStatuses ?? null,\n orderAddressEditableStatuses: result?.orderAddressEditableStatuses ?? null,\n orderStatuses,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.settings.order-editing.put failed', { err })\n return NextResponse.json(\n { error: translate('sales.settings.errors.save_failed', 'Failed to save sales settings') },\n { status: 400 }\n )\n }\n}\n\nconst orderStatusOptionSchema = z.object({\n id: z.string().uuid(),\n value: z.string(),\n label: z.string(),\n})\n\nconst settingsResponseSchema = z.object({\n orderCustomerEditableStatuses: z.array(z.string()).nullable(),\n orderAddressEditableStatuses: z.array(z.string()).nullable(),\n orderStatuses: z.array(orderStatusOptionSchema),\n})\n\nconst settingsErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Sales order editing settings',\n methods: {\n GET: {\n summary: 'Get order editing guards',\n responses: [\n { status: 200, description: 'Current order editing guards', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Missing scope', schema: settingsErrorSchema },\n ],\n },\n PUT: {\n summary: 'Update order editing guards',\n requestBody: {\n contentType: 'application/json',\n schema: salesEditingSettingsSchema,\n },\n responses: [\n { status: 200, description: 'Updated order editing guards', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Invalid payload', schema: settingsErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -38,6 +38,9 @@ const emptyDraft = {
38
38
  region: "",
39
39
  postalCode: "",
40
40
  country: "",
41
+ taxId: "",
42
+ taxIdType: "",
43
+ phone: "",
41
44
  isPrimary: false
42
45
  };
43
46
  const EDITABLE_SNAPSHOT_KEYS = new Set(Object.keys(emptyDraft));
@@ -64,6 +67,9 @@ function normalizeAddressDraft(draft, previous) {
64
67
  assign("region", "region");
65
68
  assign("postalCode", "postalCode");
66
69
  assign("country", "country");
70
+ assign("taxId", "taxId");
71
+ assign("taxIdType", "taxIdType");
72
+ assign("phone", "phone");
67
73
  assign("isPrimary", "isPrimary");
68
74
  if (!hasEditableContent) return null;
69
75
  if (previous) {
@@ -89,6 +95,9 @@ function draftFromSnapshot(snapshot) {
89
95
  region: typeof record.region === "string" ? record.region : "",
90
96
  postalCode: typeof record.postalCode === "string" ? record.postalCode : "",
91
97
  country: typeof record.country === "string" ? record.country : "",
98
+ taxId: typeof record.taxId === "string" ? record.taxId : "",
99
+ taxIdType: typeof record.taxIdType === "string" ? record.taxIdType : "",
100
+ phone: typeof record.phone === "string" ? record.phone : "",
92
101
  isPrimary: record.isPrimary === true
93
102
  };
94
103
  }
@@ -921,9 +930,12 @@ function SalesDocumentAddressesSection({
921
930
  {
922
931
  value: shippingDraft,
923
932
  format: addressFormat,
933
+ showPhoneField: true,
934
+ showTaxIdField: true,
924
935
  t,
925
936
  onChange: (next) => setShippingDraft(next),
926
- hidePrimaryToggle: true
937
+ hidePrimaryToggle: true,
938
+ disabled: locked
927
939
  }
928
940
  ),
929
941
  /* @__PURE__ */ jsx(
@@ -988,9 +1000,12 @@ function SalesDocumentAddressesSection({
988
1000
  {
989
1001
  value: billingDraft,
990
1002
  format: addressFormat,
1003
+ showPhoneField: true,
1004
+ showTaxIdField: true,
991
1005
  t,
992
1006
  onChange: (next) => setBillingDraft(next),
993
- hidePrimaryToggle: true
1007
+ hidePrimaryToggle: true,
1008
+ disabled: locked
994
1009
  }
995
1010
  ),
996
1011
  /* @__PURE__ */ jsx(