@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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +5 -0
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
- package/dist/modules/auth/api/profile/route.js +5 -0
- package/dist/modules/auth/api/profile/route.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +13 -0
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +9 -0
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/route.js +5 -0
- package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/kind-settings/route.js +5 -0
- package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/cancel/route.js +5 -0
- package/dist/modules/customers/api/interactions/cancel/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/complete/route.js +5 -0
- package/dist/modules/customers/api/interactions/complete/route.js.map +2 -2
- package/dist/modules/customers/api/labels/assign/route.js +5 -0
- package/dist/modules/customers/api/labels/assign/route.js.map +2 -2
- package/dist/modules/customers/api/labels/route.js +5 -0
- package/dist/modules/customers/api/labels/route.js.map +2 -2
- package/dist/modules/customers/api/labels/unassign/route.js +5 -0
- package/dist/modules/customers/api/labels/unassign/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +9 -0
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/route.js +5 -0
- package/dist/modules/customers/api/people/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js +5 -0
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/route.js +13 -0
- package/dist/modules/customers/api/pipeline-stages/route.js.map +2 -2
- package/dist/modules/customers/api/pipelines/route.js +13 -0
- package/dist/modules/customers/api/pipelines/route.js.map +2 -2
- package/dist/modules/customers/api/settings/address-format/route.js +5 -0
- package/dist/modules/customers/api/settings/address-format/route.js.map +2 -2
- package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js +5 -0
- package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js.map +2 -2
- package/dist/modules/customers/api/settings/stuck-threshold/route.js +5 -0
- package/dist/modules/customers/api/settings/stuck-threshold/route.js.map +2 -2
- package/dist/modules/customers/api/tags/assign/route.js +5 -0
- package/dist/modules/customers/api/tags/assign/route.js.map +2 -2
- package/dist/modules/customers/api/tags/unassign/route.js +5 -0
- package/dist/modules/customers/api/tags/unassign/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +13 -0
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +5 -117
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -3
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +33 -9
- package/dist/modules/customers/commands/deals.js.map +3 -3
- package/dist/modules/customers/components/AddressEditor.js +71 -1
- package/dist/modules/customers/components/AddressEditor.js.map +2 -2
- package/dist/modules/customers/utils/addressFormat.js +18 -2
- package/dist/modules/customers/utils/addressFormat.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +9 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +5 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +5 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +5 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +2 -2
- package/dist/modules/directory/api/organization-branding/route.js +5 -0
- package/dist/modules/directory/api/organization-branding/route.js.map +2 -2
- package/dist/modules/eudr/api/plots/import/route.js.map +2 -2
- package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +5 -0
- package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/actions/[actionId]/route.js +5 -0
- package/dist/modules/messages/api/[id]/actions/[actionId]/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/conversation/archive/route.js +5 -0
- package/dist/modules/messages/api/[id]/conversation/archive/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/conversation/read/route.js +5 -0
- package/dist/modules/messages/api/[id]/conversation/read/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/conversation/route.js +5 -0
- package/dist/modules/messages/api/[id]/conversation/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/forward/route.js +5 -0
- package/dist/modules/messages/api/[id]/forward/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/reply/route.js +5 -0
- package/dist/modules/messages/api/[id]/reply/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +9 -0
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/api/token/[token]/route.js +5 -0
- package/dist/modules/messages/api/token/[token]/route.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/assign/route.js +5 -0
- package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/unassign/route.js +5 -0
- package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/accept/route.js +5 -0
- package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/convert/route.js +5 -0
- package/dist/modules/sales/api/quotes/convert/route.js.map +2 -2
- package/dist/modules/sales/api/settings/document-numbers/route.js +5 -0
- package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
- package/dist/modules/sales/api/settings/order-editing/route.js +5 -0
- package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +17 -2
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +7 -24
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/components/documents/normalizeAddressDraft.js +29 -0
- package/dist/modules/sales/components/documents/normalizeAddressDraft.js.map +7 -0
- package/dist/modules/staff/api/leave-requests/accept/route.js +5 -0
- package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/reject/route.js +5 -0
- package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/self/route.js +5 -0
- package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/assign/route.js +5 -0
- package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/unassign/route.js +5 -0
- package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +5 -0
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +9 -0
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/ai/assess/route.js +5 -0
- package/dist/modules/warranty_claims/api/ai/assess/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/assign/route.js +5 -0
- package/dist/modules/warranty_claims/api/assign/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/credit-memo/route.js +5 -0
- package/dist/modules/warranty_claims/api/credit-memo/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/events/route.js +5 -0
- package/dist/modules/warranty_claims/api/events/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js +5 -0
- package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js +5 -0
- package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js +5 -0
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/events/route.js +5 -0
- package/dist/modules/warranty_claims/api/portal/events/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/receiving/route.js +5 -0
- package/dist/modules/warranty_claims/api/receiving/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/replacement-order/route.js +5 -0
- package/dist/modules/warranty_claims/api/replacement-order/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/return-label/route.js +5 -0
- package/dist/modules/warranty_claims/api/return-label/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/sales-return/route.js +5 -0
- package/dist/modules/warranty_claims/api/sales-return/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/settings-general/route.js +5 -0
- package/dist/modules/warranty_claims/api/settings-general/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/submit/route.js +5 -0
- package/dist/modules/warranty_claims/api/submit/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/transition/route.js +5 -0
- package/dist/modules/warranty_claims/api/transition/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery/route.js +5 -0
- package/dist/modules/warranty_claims/api/vendor-recovery/route.js.map +2 -2
- package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js +5 -0
- package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +5 -0
- package/src/modules/auth/api/profile/route.ts +5 -0
- package/src/modules/customers/api/activities/route.ts +13 -0
- package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +9 -0
- package/src/modules/customers/api/dictionaries/[kind]/route.ts +5 -0
- package/src/modules/customers/api/dictionaries/kind-settings/route.ts +5 -0
- package/src/modules/customers/api/interactions/cancel/route.ts +5 -0
- package/src/modules/customers/api/interactions/complete/route.ts +5 -0
- package/src/modules/customers/api/labels/assign/route.ts +5 -0
- package/src/modules/customers/api/labels/route.ts +5 -0
- package/src/modules/customers/api/labels/unassign/route.ts +5 -0
- package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +9 -0
- package/src/modules/customers/api/people/[id]/companies/route.ts +5 -0
- package/src/modules/customers/api/pipeline-stages/reorder/route.ts +5 -0
- package/src/modules/customers/api/pipeline-stages/route.ts +13 -0
- package/src/modules/customers/api/pipelines/route.ts +13 -0
- package/src/modules/customers/api/settings/address-format/route.ts +5 -0
- package/src/modules/customers/api/settings/dictionary-sort-modes/route.ts +5 -0
- package/src/modules/customers/api/settings/stuck-threshold/route.ts +5 -0
- package/src/modules/customers/api/tags/assign/route.ts +5 -0
- package/src/modules/customers/api/tags/unassign/route.ts +5 -0
- package/src/modules/customers/api/todos/route.ts +13 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/types.ts +0 -23
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +11 -172
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -1
- package/src/modules/customers/commands/deals.ts +84 -9
- package/src/modules/customers/components/AddressEditor.tsx +116 -1
- package/src/modules/customers/i18n/de.json +6 -0
- package/src/modules/customers/i18n/en.json +6 -0
- package/src/modules/customers/i18n/es.json +6 -0
- package/src/modules/customers/i18n/ko.json +6 -0
- package/src/modules/customers/i18n/pl.json +6 -0
- package/src/modules/customers/utils/addressFormat.tsx +59 -1
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +9 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +5 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +5 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +5 -0
- package/src/modules/directory/api/organization-branding/route.ts +5 -0
- package/src/modules/eudr/api/plots/import/route.ts +7 -0
- package/src/modules/eudr/api/product-mappings/suggestions/apply/route.ts +7 -0
- package/src/modules/feature_toggles/api/overrides/route.ts +5 -0
- package/src/modules/messages/api/[id]/actions/[actionId]/route.ts +5 -0
- package/src/modules/messages/api/[id]/conversation/archive/route.ts +5 -0
- package/src/modules/messages/api/[id]/conversation/read/route.ts +5 -0
- package/src/modules/messages/api/[id]/conversation/route.ts +5 -0
- package/src/modules/messages/api/[id]/forward/route.ts +5 -0
- package/src/modules/messages/api/[id]/reply/route.ts +5 -0
- package/src/modules/messages/api/[id]/route.ts +9 -0
- package/src/modules/messages/api/token/[token]/route.ts +5 -0
- package/src/modules/resources/api/resources/tags/assign/route.ts +5 -0
- package/src/modules/resources/api/resources/tags/unassign/route.ts +5 -0
- package/src/modules/sales/api/quotes/accept/route.ts +5 -0
- package/src/modules/sales/api/quotes/convert/route.ts +5 -0
- package/src/modules/sales/api/settings/document-numbers/route.ts +5 -0
- package/src/modules/sales/api/settings/order-editing/route.ts +5 -0
- package/src/modules/sales/components/documents/AddressesSection.tsx +48 -5
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +5 -23
- package/src/modules/sales/components/documents/normalizeAddressDraft.ts +29 -0
- package/src/modules/staff/api/leave-requests/accept/route.ts +5 -0
- package/src/modules/staff/api/leave-requests/reject/route.ts +5 -0
- package/src/modules/staff/api/team-members/self/route.ts +5 -0
- package/src/modules/staff/api/team-members/tags/assign/route.ts +5 -0
- package/src/modules/staff/api/team-members/tags/unassign/route.ts +5 -0
- package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +5 -0
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +9 -0
- package/src/modules/warranty_claims/api/ai/assess/route.ts +5 -0
- package/src/modules/warranty_claims/api/assign/route.ts +5 -0
- package/src/modules/warranty_claims/api/credit-memo/route.ts +5 -0
- package/src/modules/warranty_claims/api/events/route.ts +5 -0
- package/src/modules/warranty_claims/api/portal/claims/[id]/submit/route.ts +5 -0
- package/src/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.ts +5 -0
- package/src/modules/warranty_claims/api/portal/claims/route.ts +5 -0
- package/src/modules/warranty_claims/api/portal/events/route.ts +5 -0
- package/src/modules/warranty_claims/api/receiving/route.ts +5 -0
- package/src/modules/warranty_claims/api/replacement-order/route.ts +5 -0
- package/src/modules/warranty_claims/api/return-label/route.ts +5 -0
- package/src/modules/warranty_claims/api/sales-return/route.ts +5 -0
- package/src/modules/warranty_claims/api/settings-general/route.ts +5 -0
- package/src/modules/warranty_claims/api/submit/route.ts +5 -0
- package/src/modules/warranty_claims/api/transition/route.ts +5 -0
- package/src/modules/warranty_claims/api/vendor-recovery/route.ts +5 -0
- 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/sales-return/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 { claimCreateSalesReturnSchema, type ClaimCreateSalesReturnInput } 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 SalesReturnCommandResult = {\n claimId: string\n salesReturnId: string\n salesReturnUpdatedAt: string | null\n skippedLineIds: string[]\n}\n\nconst uuid = z.string().uuid()\nconst optimisticLockTokenSchema = z.string().datetime().nullable().optional()\n\nconst salesReturnRequestSchema = z\n .object({\n claimId: uuid,\n updatedAt: optimisticLockTokenSchema,\n })\n .strict()\n\ntype SalesReturnRequest = z.infer<typeof salesReturnRequestSchema>\n\nconst salesReturnResponseSchema = z.object({\n salesReturnId: z.string(),\n skippedLineIds: z.array(z.string()),\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.returns.create'] },\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 toSalesReturnRequest(payload: Record<string, unknown>): SalesReturnRequest {\n return salesReturnRequestSchema.parse({\n claimId: payload.claimId ?? payload.id,\n updatedAt: payload.updatedAt,\n })\n}\n\nfunction toCommandInput(input: SalesReturnRequest, context: ActionRouteContext): ClaimCreateSalesReturnInput {\n const scopedPayload = withScopedPayload({\n id: input.claimId,\n updatedAt: input.updatedAt,\n }, context.ctx, context.translate)\n return claimCreateSalesReturnSchema.parse(scopedPayload)\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: SalesReturnRequest,\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 = toSalesReturnRequest(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 ? toSalesReturnRequest(guarded.modifiedPayload) : requestInput\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<ClaimCreateSalesReturnInput, SalesReturnCommandResult>(\n 'warranty_claims.claim.create_sales_return',\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({ salesReturnId: result.salesReturnId, skippedLineIds: result.skippedLineIds })\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.sales-return.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 sales return from an approved warranty claim',\n methods: {\n POST: {\n summary: 'Create a sales return document from the claim\\'s eligible lines and link it to the claim',\n requestBody: {\n contentType: 'application/json',\n schema: salesReturnRequestSchema,\n description: 'Use claimId to identify the warranty claim. The id field is also accepted as an alias for claimId.',\n },\n responses: [\n {\n status: 200,\n description: 'Sales return created and linked; lines without an order-line reference are reported as skipped',\n schema: salesReturnResponseSchema,\n },\n { status: 400, description: 'Invalid request or claim is not eligible for sales-return 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 { 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 { claimCreateSalesReturnSchema, type ClaimCreateSalesReturnInput } 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 SalesReturnCommandResult = {\n claimId: string\n salesReturnId: string\n salesReturnUpdatedAt: string | null\n skippedLineIds: string[]\n}\n\nconst uuid = z.string().uuid()\nconst optimisticLockTokenSchema = z.string().datetime().nullable().optional()\n\nconst salesReturnRequestSchema = z\n .object({\n claimId: uuid,\n updatedAt: optimisticLockTokenSchema,\n })\n .strict()\n\ntype SalesReturnRequest = z.infer<typeof salesReturnRequestSchema>\n\nconst salesReturnResponseSchema = z.object({\n salesReturnId: z.string(),\n skippedLineIds: z.array(z.string()),\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.returns.create'] },\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 toSalesReturnRequest(payload: Record<string, unknown>): SalesReturnRequest {\n return salesReturnRequestSchema.parse({\n claimId: payload.claimId ?? payload.id,\n updatedAt: payload.updatedAt,\n })\n}\n\nfunction toCommandInput(input: SalesReturnRequest, context: ActionRouteContext): ClaimCreateSalesReturnInput {\n const scopedPayload = withScopedPayload({\n id: input.claimId,\n updatedAt: input.updatedAt,\n }, context.ctx, context.translate)\n return claimCreateSalesReturnSchema.parse(scopedPayload)\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: SalesReturnRequest,\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 = toSalesReturnRequest(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 ? toSalesReturnRequest(guarded.modifiedPayload) : requestInput\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<ClaimCreateSalesReturnInput, SalesReturnCommandResult>(\n 'warranty_claims.claim.create_sales_return',\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({ salesReturnId: result.salesReturnId, skippedLineIds: result.skippedLineIds })\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: 'warranty_claims.errors.invalidInput' }, { status: 400 })\n }\n logger.error('warranty_claims.sales-return.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 sales return from an approved warranty claim',\n methods: {\n POST: {\n summary: 'Create a sales return document from the claim\\'s eligible lines and link it to the claim',\n requestBody: {\n contentType: 'application/json',\n schema: salesReturnRequestSchema,\n description: 'Use claimId to identify the warranty claim. The id field is also accepted as an alias for claimId.',\n },\n responses: [\n {\n status: 200,\n description: 'Sales return created and linked; lines without an order-line reference are reported as skipped',\n schema: salesReturnResponseSchema,\n },\n { status: 400, description: 'Invalid request or claim is not eligible for sales-return 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
|
}
|
|
@@ -5,6 +5,7 @@ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
|
5
5
|
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
6
|
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
7
7
|
import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
8
|
+
import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
|
|
8
9
|
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
9
10
|
import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
|
|
10
11
|
import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
|
|
@@ -127,6 +128,10 @@ async function PUT(req) {
|
|
|
127
128
|
});
|
|
128
129
|
} catch (err) {
|
|
129
130
|
if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status });
|
|
131
|
+
const interceptorRejection = getCommandInterceptorHttpRejection(err);
|
|
132
|
+
if (interceptorRejection) {
|
|
133
|
+
return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
|
|
134
|
+
}
|
|
130
135
|
const { translate } = await resolveTranslations();
|
|
131
136
|
if (err instanceof z.ZodError) {
|
|
132
137
|
return NextResponse.json({ error: translate("warranty_claims.errors.invalidInput", "Invalid input") }, { status: 400 });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/warranty_claims/api/settings-general/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\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 { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { runRouteMutationGuards } 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 warrantyClaimSettingsSaveSchema,\n warrantyClaimSettingsUpdateSchema,\n type WarrantyClaimSettingsSaveInput,\n} from '../../data/validators'\nimport {\n loadWarrantyClaimSettings,\n resolveEffectiveWarrantyClaimSettings,\n type WarrantyClaimEffectiveSettings,\n} from '../../lib/settings'\nimport { WARRANTY_CLAIM_SETTINGS_RESOURCE_KIND, type SaveWarrantyClaimSettingsResult } from '../../commands/settings'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('warranty_claims')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['warranty_claims.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['warranty_claims.settings.manage'] },\n}\n\ntype SettingsRouteContext = {\n ctx: CommandRuntimeContext\n em: EntityManager\n tenantId: string\n organizationId: string\n userId: string\n translate: (key: string, fallback?: string) => string\n}\n\ntype SettingsResponseResult = WarrantyClaimEffectiveSettings & {\n returnWindowDays: number | null\n updatedAt: string | 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\nfunction toIso(value: Date | string | null | undefined): string | null {\n if (!value) return null\n const date = value instanceof Date ? value : new Date(value)\n return Number.isNaN(date.getTime()) ? null : date.toISOString()\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('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 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 return {\n ctx,\n em: container.resolve('em') as EntityManager,\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n translate,\n }\n}\n\nasync function buildSettingsResult(\n em: EntityManager,\n scope: { tenantId: string; organizationId: string },\n): Promise<SettingsResponseResult> {\n const record = await loadWarrantyClaimSettings(em, scope)\n const effectiveSettings = await resolveEffectiveWarrantyClaimSettings(em, scope)\n return {\n ...effectiveSettings,\n returnWindowDays: record?.returnWindowDays ?? null,\n updatedAt: toIso(record?.updatedAt),\n }\n}\n\nexport async function GET(req: Request) {\n try {\n const { em, tenantId, organizationId } = await resolveSettingsContext(req)\n const result = await buildSettingsResult(em, { tenantId, organizationId })\n return NextResponse.json({ ok: true, result })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n const { translate } = await resolveTranslations()\n logger.error('warranty_claims.settings-general.get failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.load_failed', 'Failed to load warranty claim data.') }, { status: 500 })\n }\n}\n\nexport async function PUT(req: Request) {\n try {\n const { ctx, em, tenantId, organizationId, userId, translate } = await resolveSettingsContext(req)\n const payload = toRecord(await readJsonSafe(req, {}))\n const parsed = warrantyClaimSettingsUpdateSchema.parse(payload)\n const parsedPayload: Record<string, unknown> = { ...parsed }\n const existing = await loadWarrantyClaimSettings(em, { tenantId, organizationId })\n const guarded = await runRouteMutationGuards({\n container: ctx.container,\n req,\n auth: { userId, tenantId, organizationId },\n input: {\n resourceKind: WARRANTY_CLAIM_SETTINGS_RESOURCE_KIND,\n resourceId: existing?.id ?? null,\n operation: existing ? 'update' : 'create',\n mutationPayload: parsedPayload,\n },\n })\n if (!guarded.ok) return guarded.response\n\n const guardedPayload = guarded.modifiedPayload\n ? warrantyClaimSettingsUpdateSchema.parse({ ...parsedPayload, ...guarded.modifiedPayload })\n : parsed\n const commandInput = warrantyClaimSettingsSaveSchema.parse(withScopedPayload({ ...guardedPayload }, ctx, translate))\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<\n WarrantyClaimSettingsSaveInput,\n SaveWarrantyClaimSettingsResult\n >('warranty_claims.settings.save', { input: commandInput, ctx })\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({\n ok: true,\n result: {\n slaHours: result.slaHours,\n slaPauseOnInfoRequested: result.slaPauseOnInfoRequested,\n slaAtRiskThresholdPct: result.slaAtRiskThresholdPct,\n autoApproveEnabled: result.autoApproveEnabled,\n autoApproveMaxAmount: result.autoApproveMaxAmount,\n autoApproveCurrencyCode: result.autoApproveCurrencyCode,\n autoApproveRequireInWarranty: result.autoApproveRequireInWarranty,\n defaultWarrantyMonths: result.defaultWarrantyMonths,\n businessHours: result.businessHours,\n escalationTiers: result.escalationTiers,\n adjudicationUseRules: result.adjudicationUseRules,\n quarantineGrades: result.quarantineGrades,\n returnLabelProvider: result.returnLabelProvider,\n returnWindowDays: result.returnWindowDays,\n updatedAt: result.updatedAt,\n },\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n const { translate } = await resolveTranslations()\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.settings-general.put failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim') }, { status: 400 })\n }\n}\n\nconst settingsResultSchema = z.object({\n slaHours: z.number(),\n slaPauseOnInfoRequested: z.boolean(),\n slaAtRiskThresholdPct: z.number(),\n autoApproveEnabled: z.boolean(),\n autoApproveMaxAmount: z.number().nullable(),\n autoApproveCurrencyCode: z.string().nullable(),\n autoApproveRequireInWarranty: z.boolean(),\n defaultWarrantyMonths: z.number().nullable(),\n businessHours: z.record(z.string(), z.unknown()).nullable(),\n escalationTiers: z.array(z.unknown()).nullable(),\n adjudicationUseRules: z.boolean(),\n quarantineGrades: z.array(z.string()).nullable(),\n returnLabelProvider: z.string().nullable(),\n returnWindowDays: z.number().nullable(),\n updatedAt: z.string().nullable(),\n})\n\nconst settingsResponseSchema = z.object({\n ok: z.boolean(),\n result: settingsResultSchema,\n})\n\nconst settingsErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Warranty claim general settings',\n methods: {\n GET: {\n summary: 'Get warranty claim general settings',\n responses: [\n { status: 200, description: 'Current warranty claim general settings', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Invalid scope', schema: settingsErrorSchema },\n ],\n },\n PUT: {\n summary: 'Update warranty claim general settings',\n requestBody: {\n contentType: 'application/json',\n schema: warrantyClaimSettingsUpdateSchema,\n },\n responses: [\n { status: 200, description: 'Updated warranty claim general settings', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Invalid payload', schema: settingsErrorSchema },\n { status: 409, description: 'Optimistic lock conflict', 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 type { EntityManager } from '@mikro-orm/postgresql'\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 { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\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 { runRouteMutationGuards } 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 warrantyClaimSettingsSaveSchema,\n warrantyClaimSettingsUpdateSchema,\n type WarrantyClaimSettingsSaveInput,\n} from '../../data/validators'\nimport {\n loadWarrantyClaimSettings,\n resolveEffectiveWarrantyClaimSettings,\n type WarrantyClaimEffectiveSettings,\n} from '../../lib/settings'\nimport { WARRANTY_CLAIM_SETTINGS_RESOURCE_KIND, type SaveWarrantyClaimSettingsResult } from '../../commands/settings'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('warranty_claims')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['warranty_claims.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['warranty_claims.settings.manage'] },\n}\n\ntype SettingsRouteContext = {\n ctx: CommandRuntimeContext\n em: EntityManager\n tenantId: string\n organizationId: string\n userId: string\n translate: (key: string, fallback?: string) => string\n}\n\ntype SettingsResponseResult = WarrantyClaimEffectiveSettings & {\n returnWindowDays: number | null\n updatedAt: string | 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\nfunction toIso(value: Date | string | null | undefined): string | null {\n if (!value) return null\n const date = value instanceof Date ? value : new Date(value)\n return Number.isNaN(date.getTime()) ? null : date.toISOString()\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('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 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 return {\n ctx,\n em: container.resolve('em') as EntityManager,\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n translate,\n }\n}\n\nasync function buildSettingsResult(\n em: EntityManager,\n scope: { tenantId: string; organizationId: string },\n): Promise<SettingsResponseResult> {\n const record = await loadWarrantyClaimSettings(em, scope)\n const effectiveSettings = await resolveEffectiveWarrantyClaimSettings(em, scope)\n return {\n ...effectiveSettings,\n returnWindowDays: record?.returnWindowDays ?? null,\n updatedAt: toIso(record?.updatedAt),\n }\n}\n\nexport async function GET(req: Request) {\n try {\n const { em, tenantId, organizationId } = await resolveSettingsContext(req)\n const result = await buildSettingsResult(em, { tenantId, organizationId })\n return NextResponse.json({ ok: true, result })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n const { translate } = await resolveTranslations()\n logger.error('warranty_claims.settings-general.get failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.load_failed', 'Failed to load warranty claim data.') }, { status: 500 })\n }\n}\n\nexport async function PUT(req: Request) {\n try {\n const { ctx, em, tenantId, organizationId, userId, translate } = await resolveSettingsContext(req)\n const payload = toRecord(await readJsonSafe(req, {}))\n const parsed = warrantyClaimSettingsUpdateSchema.parse(payload)\n const parsedPayload: Record<string, unknown> = { ...parsed }\n const existing = await loadWarrantyClaimSettings(em, { tenantId, organizationId })\n const guarded = await runRouteMutationGuards({\n container: ctx.container,\n req,\n auth: { userId, tenantId, organizationId },\n input: {\n resourceKind: WARRANTY_CLAIM_SETTINGS_RESOURCE_KIND,\n resourceId: existing?.id ?? null,\n operation: existing ? 'update' : 'create',\n mutationPayload: parsedPayload,\n },\n })\n if (!guarded.ok) return guarded.response\n\n const guardedPayload = guarded.modifiedPayload\n ? warrantyClaimSettingsUpdateSchema.parse({ ...parsedPayload, ...guarded.modifiedPayload })\n : parsed\n const commandInput = warrantyClaimSettingsSaveSchema.parse(withScopedPayload({ ...guardedPayload }, ctx, translate))\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<\n WarrantyClaimSettingsSaveInput,\n SaveWarrantyClaimSettingsResult\n >('warranty_claims.settings.save', { input: commandInput, ctx })\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({\n ok: true,\n result: {\n slaHours: result.slaHours,\n slaPauseOnInfoRequested: result.slaPauseOnInfoRequested,\n slaAtRiskThresholdPct: result.slaAtRiskThresholdPct,\n autoApproveEnabled: result.autoApproveEnabled,\n autoApproveMaxAmount: result.autoApproveMaxAmount,\n autoApproveCurrencyCode: result.autoApproveCurrencyCode,\n autoApproveRequireInWarranty: result.autoApproveRequireInWarranty,\n defaultWarrantyMonths: result.defaultWarrantyMonths,\n businessHours: result.businessHours,\n escalationTiers: result.escalationTiers,\n adjudicationUseRules: result.adjudicationUseRules,\n quarantineGrades: result.quarantineGrades,\n returnLabelProvider: result.returnLabelProvider,\n returnWindowDays: result.returnWindowDays,\n updatedAt: result.updatedAt,\n },\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 const { translate } = await resolveTranslations()\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.settings-general.put failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim') }, { status: 400 })\n }\n}\n\nconst settingsResultSchema = z.object({\n slaHours: z.number(),\n slaPauseOnInfoRequested: z.boolean(),\n slaAtRiskThresholdPct: z.number(),\n autoApproveEnabled: z.boolean(),\n autoApproveMaxAmount: z.number().nullable(),\n autoApproveCurrencyCode: z.string().nullable(),\n autoApproveRequireInWarranty: z.boolean(),\n defaultWarrantyMonths: z.number().nullable(),\n businessHours: z.record(z.string(), z.unknown()).nullable(),\n escalationTiers: z.array(z.unknown()).nullable(),\n adjudicationUseRules: z.boolean(),\n quarantineGrades: z.array(z.string()).nullable(),\n returnLabelProvider: z.string().nullable(),\n returnWindowDays: z.number().nullable(),\n updatedAt: z.string().nullable(),\n})\n\nconst settingsResponseSchema = z.object({\n ok: z.boolean(),\n result: settingsResultSchema,\n})\n\nconst settingsErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Warranty claim general settings',\n methods: {\n GET: {\n summary: 'Get warranty claim general settings',\n responses: [\n { status: 200, description: 'Current warranty claim general settings', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Invalid scope', schema: settingsErrorSchema },\n ],\n },\n PUT: {\n summary: 'Update warranty claim general settings',\n requestBody: {\n contentType: 'application/json',\n schema: warrantyClaimSettingsUpdateSchema,\n },\n responses: [\n { status: 200, description: 'Updated warranty claim general settings', schema: settingsResponseSchema },\n { status: 401, description: 'Unauthorized', schema: settingsErrorSchema },\n { status: 400, description: 'Invalid payload', schema: settingsErrorSchema },\n { status: 409, description: 'Optimistic lock conflict', schema: settingsErrorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,6 +5,7 @@ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
|
5
5
|
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
6
|
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
7
7
|
import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
8
|
+
import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
|
|
8
9
|
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
9
10
|
import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
|
|
10
11
|
import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
|
|
@@ -87,6 +88,10 @@ async function POST(req) {
|
|
|
87
88
|
return NextResponse.json({ ok: true, claimId: result?.claimId ?? commandInput.id });
|
|
88
89
|
} catch (err) {
|
|
89
90
|
if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status });
|
|
91
|
+
const interceptorRejection = getCommandInterceptorHttpRejection(err);
|
|
92
|
+
if (interceptorRejection) {
|
|
93
|
+
return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
|
|
94
|
+
}
|
|
90
95
|
const { translate } = await resolveTranslations();
|
|
91
96
|
if (err instanceof z.ZodError) {
|
|
92
97
|
return NextResponse.json({ error: translate("warranty_claims.errors.invalidInput", "Invalid input") }, { status: 400 });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/warranty_claims/api/submit/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 { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\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 { WARRANTY_CLAIM_RESOURCE_KIND } from '../../commands/shared'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('warranty_claims')\n\n// Scope is derived from the authenticated principal, never accepted from the body \u2014\n// mirroring the sibling transition/assign routes. `withScopedPayload` prefers a\n// caller-supplied tenantId/organizationId over the actor's context, so admitting them\n// here would let the request choose its own scope.\nconst submitSchema = z\n .object({\n id: z.string().uuid(),\n })\n .strict()\n\ntype SubmitInput = z.infer<typeof submitSchema>\n\ntype ActionRouteContext = {\n ctx: CommandRuntimeContext\n tenantId: string\n organizationId: string\n translate: (key: string, fallback?: string) => string\n}\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.claim.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(req: Request): Promise<ActionRouteContext> {\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('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\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: SubmitInput,\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.id,\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 payload = toRecord(await readJsonSafe(req, {}))\n const scopedPayload = toRecord(withScopedPayload(payload, context.ctx, context.translate))\n const input = submitSchema.parse({ id: scopedPayload.id })\n const guarded = await runGuard(req, context, input)\n if (!guarded.ok) {\n return guarded.response\n }\n const commandInput = guarded.modifiedPayload ? submitSchema.parse(guarded.modifiedPayload) : input\n\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<SubmitInput, { claimId: string }>(\n 'warranty_claims.claim.submit',\n { input: commandInput, ctx: context.ctx },\n )\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({ ok: true, claimId: result?.claimId ?? commandInput.id })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n const { translate } = await resolveTranslations()\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.submit.post failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Submit warranty claim',\n methods: {\n POST: {\n summary: 'Submit a draft claim',\n requestBody: { contentType: 'application/json', schema: submitSchema },\n responses: [\n {\n status: 200,\n description: 'Claim submitted',\n schema: z.object({ ok: z.boolean(), claimId: z.string().uuid() }),\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 { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\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 { 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 { WARRANTY_CLAIM_RESOURCE_KIND } from '../../commands/shared'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('warranty_claims')\n\n// Scope is derived from the authenticated principal, never accepted from the body \u2014\n// mirroring the sibling transition/assign routes. `withScopedPayload` prefers a\n// caller-supplied tenantId/organizationId over the actor's context, so admitting them\n// here would let the request choose its own scope.\nconst submitSchema = z\n .object({\n id: z.string().uuid(),\n })\n .strict()\n\ntype SubmitInput = z.infer<typeof submitSchema>\n\ntype ActionRouteContext = {\n ctx: CommandRuntimeContext\n tenantId: string\n organizationId: string\n translate: (key: string, fallback?: string) => string\n}\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.claim.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(req: Request): Promise<ActionRouteContext> {\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('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\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: SubmitInput,\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.id,\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 payload = toRecord(await readJsonSafe(req, {}))\n const scopedPayload = toRecord(withScopedPayload(payload, context.ctx, context.translate))\n const input = submitSchema.parse({ id: scopedPayload.id })\n const guarded = await runGuard(req, context, input)\n if (!guarded.ok) {\n return guarded.response\n }\n const commandInput = guarded.modifiedPayload ? submitSchema.parse(guarded.modifiedPayload) : input\n\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<SubmitInput, { claimId: string }>(\n 'warranty_claims.claim.submit',\n { input: commandInput, ctx: context.ctx },\n )\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({ ok: true, claimId: result?.claimId ?? commandInput.id })\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 const { translate } = await resolveTranslations()\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.submit.post failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Submit warranty claim',\n methods: {\n POST: {\n summary: 'Submit a draft claim',\n requestBody: { contentType: 'application/json', schema: submitSchema },\n responses: [\n {\n status: 200,\n description: 'Claim submitted',\n schema: z.object({ ok: z.boolean(), claimId: z.string().uuid() }),\n },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,6 +5,7 @@ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
|
5
5
|
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
6
|
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
7
7
|
import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
8
|
+
import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
|
|
8
9
|
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
9
10
|
import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
|
|
10
11
|
import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
|
|
@@ -93,6 +94,10 @@ async function POST(req) {
|
|
|
93
94
|
return NextResponse.json({ ok: true, claimId: result?.claimId ?? commandInput.id });
|
|
94
95
|
} catch (err) {
|
|
95
96
|
if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status });
|
|
97
|
+
const interceptorRejection = getCommandInterceptorHttpRejection(err);
|
|
98
|
+
if (interceptorRejection) {
|
|
99
|
+
return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
|
|
100
|
+
}
|
|
96
101
|
const { translate } = await resolveTranslations();
|
|
97
102
|
if (err instanceof z.ZodError) {
|
|
98
103
|
return NextResponse.json({ error: translate("warranty_claims.errors.invalidInput", "Invalid input") }, { status: 400 });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/warranty_claims/api/transition/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 { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\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 { transitionClaimInputSchema, type TransitionClaimInput } 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\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.claim.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(req: Request): Promise<ActionRouteContext> {\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('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 toTransitionInput(scopedPayload: Record<string, unknown>): TransitionClaimInput {\n return transitionClaimInputSchema.parse({\n id: scopedPayload.id,\n toStatus: scopedPayload.toStatus,\n rejectionReasonCode: scopedPayload.rejectionReasonCode,\n resolutionSummary: scopedPayload.resolutionSummary,\n })\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: TransitionClaimInput,\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.id,\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 payload = toRecord(await readJsonSafe(req, {}))\n const scopedPayload = withScopedPayload(payload, context.ctx, context.translate)\n const input = toTransitionInput(scopedPayload)\n const guarded = await runGuard(req, context, input)\n if (!guarded.ok) {\n return guarded.response\n }\n const commandInput = guarded.modifiedPayload ? toTransitionInput(guarded.modifiedPayload) : input\n\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<TransitionClaimInput, { claimId: string }>(\n 'warranty_claims.claim.transition',\n { input: commandInput, ctx: context.ctx },\n )\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({ ok: true, claimId: result?.claimId ?? commandInput.id })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n const { translate } = await resolveTranslations()\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.transition.post failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Transition warranty claim',\n methods: {\n POST: {\n summary: 'Move a claim through the lifecycle',\n requestBody: { contentType: 'application/json', schema: transitionClaimInputSchema },\n responses: [\n {\n status: 200,\n description: 'Claim transitioned',\n schema: z.object({ ok: z.boolean(), claimId: z.string().uuid() }),\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 { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\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 { 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 { transitionClaimInputSchema, type TransitionClaimInput } 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\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.claim.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(req: Request): Promise<ActionRouteContext> {\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('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 toTransitionInput(scopedPayload: Record<string, unknown>): TransitionClaimInput {\n return transitionClaimInputSchema.parse({\n id: scopedPayload.id,\n toStatus: scopedPayload.toStatus,\n rejectionReasonCode: scopedPayload.rejectionReasonCode,\n resolutionSummary: scopedPayload.resolutionSummary,\n })\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: TransitionClaimInput,\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.id,\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 payload = toRecord(await readJsonSafe(req, {}))\n const scopedPayload = withScopedPayload(payload, context.ctx, context.translate)\n const input = toTransitionInput(scopedPayload)\n const guarded = await runGuard(req, context, input)\n if (!guarded.ok) {\n return guarded.response\n }\n const commandInput = guarded.modifiedPayload ? toTransitionInput(guarded.modifiedPayload) : input\n\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<TransitionClaimInput, { claimId: string }>(\n 'warranty_claims.claim.transition',\n { input: commandInput, ctx: context.ctx },\n )\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({ ok: true, claimId: result?.claimId ?? commandInput.id })\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 const { translate } = await resolveTranslations()\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.transition.post failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Transition warranty claim',\n methods: {\n POST: {\n summary: 'Move a claim through the lifecycle',\n requestBody: { contentType: 'application/json', schema: transitionClaimInputSchema },\n responses: [\n {\n status: 200,\n description: 'Claim transitioned',\n schema: z.object({ ok: z.boolean(), claimId: z.string().uuid() }),\n },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,6 +5,7 @@ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
|
5
5
|
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
6
|
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
7
7
|
import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
8
|
+
import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
|
|
8
9
|
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
9
10
|
import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
|
|
10
11
|
import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
|
|
@@ -97,6 +98,10 @@ async function POST(req) {
|
|
|
97
98
|
return NextResponse.json({ ok: true, claimId: createdClaimId });
|
|
98
99
|
} catch (err) {
|
|
99
100
|
if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status });
|
|
101
|
+
const interceptorRejection = getCommandInterceptorHttpRejection(err);
|
|
102
|
+
if (interceptorRejection) {
|
|
103
|
+
return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
|
|
104
|
+
}
|
|
100
105
|
const { translate } = await resolveTranslations();
|
|
101
106
|
if (err instanceof z.ZodError) {
|
|
102
107
|
return NextResponse.json({ error: translate("warranty_claims.errors.invalidInput", "Invalid input") }, { status: 400 });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/warranty_claims/api/vendor-recovery/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 { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\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 { vendorRecoveryInputSchema, type VendorRecoveryInput } 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\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.claim.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(req: Request): Promise<ActionRouteContext> {\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('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 toVendorRecoveryInput(scopedPayload: Record<string, unknown>): VendorRecoveryInput {\n return vendorRecoveryInputSchema.parse({\n claimId: scopedPayload.claimId,\n lineIds: scopedPayload.lineIds,\n vendorName: scopedPayload.vendorName,\n vendorRef: scopedPayload.vendorRef,\n })\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: VendorRecoveryInput,\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 try {\n const context = await resolveActionContext(req)\n const payload = toRecord(await readJsonSafe(req, {}))\n const scopedPayload = withScopedPayload(payload, context.ctx, context.translate)\n const input = toVendorRecoveryInput(scopedPayload)\n const guarded = await runGuard(req, context, input)\n if (!guarded.ok) {\n return guarded.response\n }\n const commandInput = guarded.modifiedPayload ? toVendorRecoveryInput(guarded.modifiedPayload) : input\n\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<VendorRecoveryInput, { claimId: string }>(\n 'warranty_claims.claim.create_vendor_recovery',\n { input: commandInput, ctx: context.ctx },\n )\n const createdClaimId = result?.claimId\n if (typeof createdClaimId !== 'string') {\n throw new CrudHttpError(400, { error: context.translate('warranty_claims.errors.notFound', 'Warranty claim not found.') })\n }\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({ ok: true, claimId: createdClaimId })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n const { translate } = await resolveTranslations()\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.vendor-recovery.post failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Create vendor recovery claim',\n methods: {\n POST: {\n summary: 'Create a linked vendor-recovery claim from resolved source lines',\n requestBody: { contentType: 'application/json', schema: vendorRecoveryInputSchema },\n responses: [\n {\n status: 200,\n description: 'Vendor recovery claim created',\n schema: z.object({ ok: z.boolean(), claimId: z.string().uuid() }),\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 { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\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 { 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 { vendorRecoveryInputSchema, type VendorRecoveryInput } 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\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['warranty_claims.claim.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(req: Request): Promise<ActionRouteContext> {\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('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 toVendorRecoveryInput(scopedPayload: Record<string, unknown>): VendorRecoveryInput {\n return vendorRecoveryInputSchema.parse({\n claimId: scopedPayload.claimId,\n lineIds: scopedPayload.lineIds,\n vendorName: scopedPayload.vendorName,\n vendorRef: scopedPayload.vendorRef,\n })\n}\n\nasync function runGuard(\n req: Request,\n context: ActionRouteContext,\n input: VendorRecoveryInput,\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 try {\n const context = await resolveActionContext(req)\n const payload = toRecord(await readJsonSafe(req, {}))\n const scopedPayload = withScopedPayload(payload, context.ctx, context.translate)\n const input = toVendorRecoveryInput(scopedPayload)\n const guarded = await runGuard(req, context, input)\n if (!guarded.ok) {\n return guarded.response\n }\n const commandInput = guarded.modifiedPayload ? toVendorRecoveryInput(guarded.modifiedPayload) : input\n\n const commandBus = context.ctx.container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute<VendorRecoveryInput, { claimId: string }>(\n 'warranty_claims.claim.create_vendor_recovery',\n { input: commandInput, ctx: context.ctx },\n )\n const createdClaimId = result?.claimId\n if (typeof createdClaimId !== 'string') {\n throw new CrudHttpError(400, { error: context.translate('warranty_claims.errors.notFound', 'Warranty claim not found.') })\n }\n\n await guarded.runAfterSuccess()\n\n return NextResponse.json({ ok: true, claimId: createdClaimId })\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 const { translate } = await resolveTranslations()\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.vendor-recovery.post failed', { err })\n return NextResponse.json({ error: translate('warranty_claims.errors.save_failed', 'Failed to save warranty claim') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Warranty Claims',\n summary: 'Create vendor recovery claim',\n methods: {\n POST: {\n summary: 'Create a linked vendor-recovery claim from resolved source lines',\n requestBody: { contentType: 'application/json', schema: vendorRecoveryInputSchema },\n responses: [\n {\n status: 200,\n description: 'Vendor recovery claim created',\n schema: z.object({ ok: z.boolean(), claimId: z.string().uuid() }),\n },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -14,6 +14,7 @@ import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
|
14
14
|
import { salesOrderWarehouseAssignBodySchema } from "../../../../data/validators.js";
|
|
15
15
|
import { loadSalesOrderWarehouseAssignmentView } from "../../../../lib/salesOrderWarehouseAssignment.js";
|
|
16
16
|
import { executeWmsCustomPostRoute } from "../../../inventory/helpers.js";
|
|
17
|
+
import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
|
|
17
18
|
const logger = createLogger("wms");
|
|
18
19
|
const paramsSchema = z.object({
|
|
19
20
|
salesOrderId: z.string().uuid()
|
|
@@ -208,6 +209,10 @@ async function DELETE(request, routeContext) {
|
|
|
208
209
|
}
|
|
209
210
|
return NextResponse.json(intercepted.body, { status: intercepted.statusCode });
|
|
210
211
|
} catch (error) {
|
|
212
|
+
const interceptorRejection = getCommandInterceptorHttpRejection(error);
|
|
213
|
+
if (interceptorRejection) {
|
|
214
|
+
return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
|
|
215
|
+
}
|
|
211
216
|
if (error instanceof CrudHttpError) {
|
|
212
217
|
return NextResponse.json(error.body, { status: error.status });
|
|
213
218
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/wms/api/sales-orders/%5BsalesOrderId%5D/warehouse-assignment/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\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 } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { runCustomRouteAfterInterceptors } from '@open-mercato/shared/lib/crud/custom-route-interceptor'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { salesOrderWarehouseAssignBodySchema } from '../../../../data/validators'\nimport { loadSalesOrderWarehouseAssignmentView } from '../../../../lib/salesOrderWarehouseAssignment'\nimport { executeWmsCustomPostRoute } from '../../../inventory/helpers'\n\nconst logger = createLogger('wms')\n\nconst paramsSchema = z.object({\n salesOrderId: z.string().uuid(),\n})\n\nconst assignmentResponseSchema = z.object({\n assignment: z\n .object({\n id: z.string().uuid(),\n salesOrderId: z.string().uuid(),\n warehouseId: z.string().uuid(),\n warehouseName: z.string().nullable(),\n warehouseCode: z.string().nullable(),\n notes: z.string().nullable(),\n assignedBy: z.string().uuid().nullable(),\n })\n .nullable(),\n})\n\nconst assignSuccessSchema = z.object({\n ok: z.literal(true),\n assignmentId: z.string().uuid(),\n warehouseId: z.string().uuid(),\n})\n\nconst okSchema = z.object({ ok: z.literal(true) })\nconst errorSchema = z.object({ error: z.string() })\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['wms.view'] },\n PUT: { requireAuth: true, requireFeatures: ['wms.manage_reservations'] },\n PATCH: { requireAuth: true, requireFeatures: ['wms.manage_reservations'] },\n DELETE: { requireAuth: true, requireFeatures: ['wms.manage_reservations'] },\n}\n\nasync function resolveCommandContext(request: Request): Promise<CommandRuntimeContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(request)\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const organizationScope = await resolveOrganizationScopeForRequest({\n container,\n auth,\n request,\n })\n return {\n container,\n auth,\n organizationScope,\n selectedOrganizationId: organizationScope?.selectedId ?? auth.orgId ?? null,\n organizationIds: organizationScope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request,\n }\n}\n\nfunction resolveScope(ctx: CommandRuntimeContext) {\n const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n const tenantId = ctx.auth?.tenantId ?? null\n if (!organizationId || !tenantId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n return { organizationId, tenantId }\n}\n\nexport async function GET(\n request: Request,\n { params }: { params: { salesOrderId: string } },\n) {\n try {\n const parsedParams = paramsSchema.parse(params)\n const ctx = await resolveCommandContext(request)\n const scope = resolveScope(ctx)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const assignment = await loadSalesOrderWarehouseAssignmentView(\n em,\n parsedParams.salesOrderId,\n scope,\n )\n return NextResponse.json({ assignment })\n } catch (error) {\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })\n }\n logger.error('GET warehouse-assignment failed', { err: error })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nasync function executeAssignMutation(request: Request, salesOrderId: string) {\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsedBody = salesOrderWarehouseAssignBodySchema.parse(body)\n const scopedRequest = new Request(request.url, {\n method: 'POST',\n headers: request.headers,\n body: JSON.stringify({\n ...parsedBody,\n salesOrderId,\n }),\n })\n return executeWmsCustomPostRoute({\n request: scopedRequest,\n routePath: `wms/sales-orders/${salesOrderId}/warehouse-assignment`,\n inputSchema: z.object({\n salesOrderId: z.string().uuid(),\n warehouseId: z.string().uuid(),\n notes: z.string().trim().max(500).optional(),\n tenantId: z.string().uuid().optional(),\n organizationId: z.string().uuid().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n }),\n commandId: 'wms.sales-order.assign-warehouse',\n describeResource: (input) => ({\n resourceKind: 'wms.sales_order_warehouse_assignment',\n resourceId: input.salesOrderId,\n }),\n mapSuccess: (result: { assignmentId: string; warehouseId: string }) => ({\n ok: true,\n assignmentId: result.assignmentId,\n warehouseId: result.warehouseId,\n }),\n })\n}\n\nexport async function PUT(\n request: Request,\n routeContext: { params: { salesOrderId: string } },\n) {\n const parsedParams = paramsSchema.parse(routeContext.params)\n return executeAssignMutation(request, parsedParams.salesOrderId)\n}\n\nexport async function PATCH(\n request: Request,\n routeContext: { params: { salesOrderId: string } },\n) {\n const parsedParams = paramsSchema.parse(routeContext.params)\n return executeAssignMutation(request, parsedParams.salesOrderId)\n}\n\nexport async function DELETE(\n request: Request,\n routeContext: { params: { salesOrderId: string } },\n) {\n try {\n const parsedParams = paramsSchema.parse(routeContext.params)\n const ctx = await resolveCommandContext(request)\n const scope = resolveScope(ctx)\n const resource = {\n resourceKind: 'wms.sales_order_warehouse_assignment',\n resourceId: parsedParams.salesOrderId,\n }\n const guardResult = await validateCrudMutationGuard(ctx.container, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n userId: ctx.auth?.sub ?? '',\n resourceKind: resource.resourceKind,\n resourceId: resource.resourceId,\n operation: 'custom',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: { salesOrderId: parsedParams.salesOrderId },\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 await commandBus.execute('wms.sales-order.unassign-warehouse', {\n input: {\n salesOrderId: parsedParams.salesOrderId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n },\n ctx,\n })\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(ctx.container, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n userId: ctx.auth?.sub ?? '',\n resourceKind: resource.resourceKind,\n resourceId: resource.resourceId,\n operation: 'custom',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const responseBody = { ok: true as const }\n const intercepted = await runCustomRouteAfterInterceptors({\n routePath: `wms/sales-orders/${parsedParams.salesOrderId}/warehouse-assignment`,\n method: 'DELETE',\n request: {\n method: 'DELETE',\n url: request.url,\n body: { salesOrderId: parsedParams.salesOrderId },\n headers: Object.fromEntries(request.headers.entries()),\n },\n response: {\n statusCode: 200,\n body: responseBody,\n headers: {},\n },\n context: {\n em: ctx.container.resolve('em'),\n container: ctx.container,\n userId: ctx.auth?.sub ?? '',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n },\n })\n if (!intercepted.ok) {\n return NextResponse.json(intercepted.body, { status: intercepted.statusCode })\n }\n return NextResponse.json(intercepted.body, { status: intercepted.statusCode })\n } catch (error) {\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })\n }\n logger.error('DELETE warehouse-assignment failed', { err: error })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'WMS',\n summary: 'Sales order warehouse assignment',\n methods: {\n GET: {\n summary: 'Get warehouse assignment for sales order',\n description:\n 'Returns the explicit WMS warehouse assignment for a sales order, or null when none is set.',\n responses: [\n { status: 200, description: 'Assignment state', schema: assignmentResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n PUT: {\n summary: 'Assign warehouse to sales order',\n description:\n 'Creates or replaces the explicit warehouse assignment for a sales order.',\n requestBody: { contentType: 'application/json', schema: salesOrderWarehouseAssignBodySchema },\n responses: [\n { status: 200, description: 'Warehouse assigned', schema: assignSuccessSchema },\n { status: 201, description: 'Warehouse assigned', schema: assignSuccessSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Warehouse not found', schema: errorSchema },\n { status: 422, description: 'Warehouse is inactive', schema: errorSchema },\n ],\n },\n PATCH: {\n summary: 'Patch warehouse assignment for sales order',\n description: 'Same as PUT \u2014 upserts the explicit warehouse assignment.',\n requestBody: { contentType: 'application/json', schema: salesOrderWarehouseAssignBodySchema },\n responses: [{ status: 200, description: 'Warehouse assigned', schema: assignSuccessSchema }],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n DELETE: {\n summary: 'Remove warehouse assignment from sales order',\n description: 'Clears the explicit assignment so enricher and automation fall back again.',\n responses: [{ status: 200, description: 'Assignment removed', schema: okSchema }],\n errors: [\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAGlB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AAEnD,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,uCAAuC;AAChD,SAAS,oBAAoB;AAC7B,SAAS,2CAA2C;AACpD,SAAS,6CAA6C;AACtD,SAAS,iCAAiC;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\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 } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { runCustomRouteAfterInterceptors } from '@open-mercato/shared/lib/crud/custom-route-interceptor'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { salesOrderWarehouseAssignBodySchema } from '../../../../data/validators'\nimport { loadSalesOrderWarehouseAssignmentView } from '../../../../lib/salesOrderWarehouseAssignment'\nimport { executeWmsCustomPostRoute } from '../../../inventory/helpers'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\n\nconst logger = createLogger('wms')\n\nconst paramsSchema = z.object({\n salesOrderId: z.string().uuid(),\n})\n\nconst assignmentResponseSchema = z.object({\n assignment: z\n .object({\n id: z.string().uuid(),\n salesOrderId: z.string().uuid(),\n warehouseId: z.string().uuid(),\n warehouseName: z.string().nullable(),\n warehouseCode: z.string().nullable(),\n notes: z.string().nullable(),\n assignedBy: z.string().uuid().nullable(),\n })\n .nullable(),\n})\n\nconst assignSuccessSchema = z.object({\n ok: z.literal(true),\n assignmentId: z.string().uuid(),\n warehouseId: z.string().uuid(),\n})\n\nconst okSchema = z.object({ ok: z.literal(true) })\nconst errorSchema = z.object({ error: z.string() })\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['wms.view'] },\n PUT: { requireAuth: true, requireFeatures: ['wms.manage_reservations'] },\n PATCH: { requireAuth: true, requireFeatures: ['wms.manage_reservations'] },\n DELETE: { requireAuth: true, requireFeatures: ['wms.manage_reservations'] },\n}\n\nasync function resolveCommandContext(request: Request): Promise<CommandRuntimeContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(request)\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const organizationScope = await resolveOrganizationScopeForRequest({\n container,\n auth,\n request,\n })\n return {\n container,\n auth,\n organizationScope,\n selectedOrganizationId: organizationScope?.selectedId ?? auth.orgId ?? null,\n organizationIds: organizationScope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request,\n }\n}\n\nfunction resolveScope(ctx: CommandRuntimeContext) {\n const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n const tenantId = ctx.auth?.tenantId ?? null\n if (!organizationId || !tenantId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n return { organizationId, tenantId }\n}\n\nexport async function GET(\n request: Request,\n { params }: { params: { salesOrderId: string } },\n) {\n try {\n const parsedParams = paramsSchema.parse(params)\n const ctx = await resolveCommandContext(request)\n const scope = resolveScope(ctx)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const assignment = await loadSalesOrderWarehouseAssignmentView(\n em,\n parsedParams.salesOrderId,\n scope,\n )\n return NextResponse.json({ assignment })\n } catch (error) {\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })\n }\n logger.error('GET warehouse-assignment failed', { err: error })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nasync function executeAssignMutation(request: Request, salesOrderId: string) {\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsedBody = salesOrderWarehouseAssignBodySchema.parse(body)\n const scopedRequest = new Request(request.url, {\n method: 'POST',\n headers: request.headers,\n body: JSON.stringify({\n ...parsedBody,\n salesOrderId,\n }),\n })\n return executeWmsCustomPostRoute({\n request: scopedRequest,\n routePath: `wms/sales-orders/${salesOrderId}/warehouse-assignment`,\n inputSchema: z.object({\n salesOrderId: z.string().uuid(),\n warehouseId: z.string().uuid(),\n notes: z.string().trim().max(500).optional(),\n tenantId: z.string().uuid().optional(),\n organizationId: z.string().uuid().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n }),\n commandId: 'wms.sales-order.assign-warehouse',\n describeResource: (input) => ({\n resourceKind: 'wms.sales_order_warehouse_assignment',\n resourceId: input.salesOrderId,\n }),\n mapSuccess: (result: { assignmentId: string; warehouseId: string }) => ({\n ok: true,\n assignmentId: result.assignmentId,\n warehouseId: result.warehouseId,\n }),\n })\n}\n\nexport async function PUT(\n request: Request,\n routeContext: { params: { salesOrderId: string } },\n) {\n const parsedParams = paramsSchema.parse(routeContext.params)\n return executeAssignMutation(request, parsedParams.salesOrderId)\n}\n\nexport async function PATCH(\n request: Request,\n routeContext: { params: { salesOrderId: string } },\n) {\n const parsedParams = paramsSchema.parse(routeContext.params)\n return executeAssignMutation(request, parsedParams.salesOrderId)\n}\n\nexport async function DELETE(\n request: Request,\n routeContext: { params: { salesOrderId: string } },\n) {\n try {\n const parsedParams = paramsSchema.parse(routeContext.params)\n const ctx = await resolveCommandContext(request)\n const scope = resolveScope(ctx)\n const resource = {\n resourceKind: 'wms.sales_order_warehouse_assignment',\n resourceId: parsedParams.salesOrderId,\n }\n const guardResult = await validateCrudMutationGuard(ctx.container, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n userId: ctx.auth?.sub ?? '',\n resourceKind: resource.resourceKind,\n resourceId: resource.resourceId,\n operation: 'custom',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: { salesOrderId: parsedParams.salesOrderId },\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 await commandBus.execute('wms.sales-order.unassign-warehouse', {\n input: {\n salesOrderId: parsedParams.salesOrderId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n },\n ctx,\n })\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(ctx.container, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n userId: ctx.auth?.sub ?? '',\n resourceKind: resource.resourceKind,\n resourceId: resource.resourceId,\n operation: 'custom',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const responseBody = { ok: true as const }\n const intercepted = await runCustomRouteAfterInterceptors({\n routePath: `wms/sales-orders/${parsedParams.salesOrderId}/warehouse-assignment`,\n method: 'DELETE',\n request: {\n method: 'DELETE',\n url: request.url,\n body: { salesOrderId: parsedParams.salesOrderId },\n headers: Object.fromEntries(request.headers.entries()),\n },\n response: {\n statusCode: 200,\n body: responseBody,\n headers: {},\n },\n context: {\n em: ctx.container.resolve('em'),\n container: ctx.container,\n userId: ctx.auth?.sub ?? '',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n },\n })\n if (!intercepted.ok) {\n return NextResponse.json(intercepted.body, { status: intercepted.statusCode })\n }\n return NextResponse.json(intercepted.body, { status: intercepted.statusCode })\n } catch (error) {\n const interceptorRejection = getCommandInterceptorHttpRejection(error)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })\n }\n logger.error('DELETE warehouse-assignment failed', { err: error })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'WMS',\n summary: 'Sales order warehouse assignment',\n methods: {\n GET: {\n summary: 'Get warehouse assignment for sales order',\n description:\n 'Returns the explicit WMS warehouse assignment for a sales order, or null when none is set.',\n responses: [\n { status: 200, description: 'Assignment state', schema: assignmentResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n PUT: {\n summary: 'Assign warehouse to sales order',\n description:\n 'Creates or replaces the explicit warehouse assignment for a sales order.',\n requestBody: { contentType: 'application/json', schema: salesOrderWarehouseAssignBodySchema },\n responses: [\n { status: 200, description: 'Warehouse assigned', schema: assignSuccessSchema },\n { status: 201, description: 'Warehouse assigned', schema: assignSuccessSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Warehouse not found', schema: errorSchema },\n { status: 422, description: 'Warehouse is inactive', schema: errorSchema },\n ],\n },\n PATCH: {\n summary: 'Patch warehouse assignment for sales order',\n description: 'Same as PUT \u2014 upserts the explicit warehouse assignment.',\n requestBody: { contentType: 'application/json', schema: salesOrderWarehouseAssignBodySchema },\n responses: [{ status: 200, description: 'Warehouse assigned', schema: assignSuccessSchema }],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n DELETE: {\n summary: 'Remove warehouse assignment from sales order',\n description: 'Clears the explicit assignment so enricher and automation fall back again.',\n responses: [{ status: 200, description: 'Assignment removed', schema: okSchema }],\n errors: [\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.7.1-develop.
|
|
3
|
+
"version": "0.7.1-develop.7131.1.20abf9e885",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -252,16 +252,16 @@
|
|
|
252
252
|
"zod": "^4.4.3"
|
|
253
253
|
},
|
|
254
254
|
"peerDependencies": {
|
|
255
|
-
"@open-mercato/ai-assistant": "0.7.1-develop.
|
|
256
|
-
"@open-mercato/shared": "0.7.1-develop.
|
|
257
|
-
"@open-mercato/ui": "0.7.1-develop.
|
|
255
|
+
"@open-mercato/ai-assistant": "0.7.1-develop.7131.1.20abf9e885",
|
|
256
|
+
"@open-mercato/shared": "0.7.1-develop.7131.1.20abf9e885",
|
|
257
|
+
"@open-mercato/ui": "0.7.1-develop.7131.1.20abf9e885",
|
|
258
258
|
"react": "^19.0.0",
|
|
259
259
|
"react-dom": "^19.0.0"
|
|
260
260
|
},
|
|
261
261
|
"devDependencies": {
|
|
262
|
-
"@open-mercato/ai-assistant": "0.7.1-develop.
|
|
263
|
-
"@open-mercato/shared": "0.7.1-develop.
|
|
264
|
-
"@open-mercato/ui": "0.7.1-develop.
|
|
262
|
+
"@open-mercato/ai-assistant": "0.7.1-develop.7131.1.20abf9e885",
|
|
263
|
+
"@open-mercato/shared": "0.7.1-develop.7131.1.20abf9e885",
|
|
264
|
+
"@open-mercato/ui": "0.7.1-develop.7131.1.20abf9e885",
|
|
265
265
|
"@testing-library/dom": "^10.4.1",
|
|
266
266
|
"@testing-library/jest-dom": "^7.0.0",
|
|
267
267
|
"@testing-library/react": "^16.3.1",
|
|
@@ -13,6 +13,7 @@ import type { ActionLog } from '@open-mercato/core/modules/audit_logs/data/entit
|
|
|
13
13
|
import { z } from 'zod'
|
|
14
14
|
import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
15
15
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
16
|
+
import { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'
|
|
16
17
|
|
|
17
18
|
const logger = createLogger('audit_logs').child({ component: 'redo' })
|
|
18
19
|
|
|
@@ -167,6 +168,10 @@ export async function POST(req: Request) {
|
|
|
167
168
|
logger.warn('Redo rejected', { err })
|
|
168
169
|
return NextResponse.json(err.body, { status: err.status })
|
|
169
170
|
}
|
|
171
|
+
const interceptorRejection = getCommandInterceptorHttpRejection(err)
|
|
172
|
+
if (interceptorRejection) {
|
|
173
|
+
return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })
|
|
174
|
+
}
|
|
170
175
|
logger.error('Redo failed', { err })
|
|
171
176
|
return NextResponse.json({ error: 'Redo failed' }, { status: 400 })
|
|
172
177
|
}
|
|
@@ -13,6 +13,7 @@ import type { EntityManager } from '@mikro-orm/postgresql'
|
|
|
13
13
|
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
14
14
|
import { buildPasswordSchema } from '@open-mercato/shared/lib/auth/passwordPolicy'
|
|
15
15
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
16
|
+
import { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'
|
|
16
17
|
|
|
17
18
|
const logger = createLogger('auth').child({ component: 'profile' })
|
|
18
19
|
|
|
@@ -202,6 +203,10 @@ export async function PUT(req: Request) {
|
|
|
202
203
|
if (isCrudHttpError(err)) {
|
|
203
204
|
return NextResponse.json(err.body, { status: err.status })
|
|
204
205
|
}
|
|
206
|
+
const interceptorRejection = getCommandInterceptorHttpRejection(err)
|
|
207
|
+
if (interceptorRejection) {
|
|
208
|
+
return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })
|
|
209
|
+
}
|
|
205
210
|
logger.error('Profile update failed', { err })
|
|
206
211
|
return NextResponse.json({ error: translate('auth.profile.form.errors.save', 'Failed to update profile.') }, { status: 400 })
|
|
207
212
|
}
|