@open-mercato/core 0.8.1-develop.7458.1.3847638f67 → 0.9.1-develop.7459.1.99e3accd30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/availability/api/policies/route.js +6 -6
  3. package/dist/modules/availability/api/policies/route.js.map +2 -2
  4. package/dist/modules/availability/backend/availability/check/page.js +4 -3
  5. package/dist/modules/availability/backend/availability/check/page.js.map +2 -2
  6. package/dist/modules/availability/backend/availability/policies/create/page.js +3 -0
  7. package/dist/modules/availability/backend/availability/policies/create/page.js.map +2 -2
  8. package/dist/modules/availability/lib/organizationScope.js +24 -1
  9. package/dist/modules/availability/lib/organizationScope.js.map +2 -2
  10. package/dist/modules/catalog/api/categories/bulk-create/route.js +16 -2
  11. package/dist/modules/catalog/api/categories/bulk-create/route.js.map +2 -2
  12. package/dist/modules/catalog/api/products/bulk-create/route.js +16 -2
  13. package/dist/modules/catalog/api/products/bulk-create/route.js.map +2 -2
  14. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +1 -0
  15. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  16. package/dist/modules/catalog/components/prices/PriceScopeSelectors.js +2 -2
  17. package/dist/modules/catalog/components/prices/PriceScopeSelectors.js.map +2 -2
  18. package/dist/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].js +78 -0
  19. package/dist/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].js.map +7 -0
  20. package/dist/modules/customer_groups/api/customer-groups/price-kinds/route.js +90 -0
  21. package/dist/modules/customer_groups/api/customer-groups/price-kinds/route.js.map +7 -0
  22. package/dist/modules/customer_groups/backend/customer-groups/page.js +5 -1
  23. package/dist/modules/customer_groups/backend/customer-groups/page.js.map +2 -2
  24. package/dist/modules/customer_groups/components/CustomerGroupTermsPriceKindField.js +2 -2
  25. package/dist/modules/customer_groups/components/CustomerGroupTermsPriceKindField.js.map +2 -2
  26. package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js +3 -1
  27. package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js.map +2 -2
  28. package/dist/modules/customer_groups/lib/priceKindScope.js +35 -1
  29. package/dist/modules/customer_groups/lib/priceKindScope.js.map +2 -2
  30. package/dist/modules/customer_groups/widgets/injection/person-groups-explain-terms.js +1 -1
  31. package/dist/modules/customer_groups/widgets/injection/person-groups-explain-terms.js.map +2 -2
  32. package/dist/modules/customers/commands/companies.js +14 -1
  33. package/dist/modules/customers/commands/companies.js.map +2 -2
  34. package/dist/modules/dictionaries/components/DictionariesManager.js +98 -87
  35. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  36. package/dist/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.js +3 -3
  37. package/dist/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.js.map +2 -2
  38. package/dist/modules/forms/backend/forms/[id]/submissions/components/formSummary.js +9 -0
  39. package/dist/modules/forms/backend/forms/[id]/submissions/components/formSummary.js.map +7 -0
  40. package/dist/modules/forms/backend/forms/[id]/submissions/page.js +3 -6
  41. package/dist/modules/forms/backend/forms/[id]/submissions/page.js.map +2 -2
  42. package/dist/modules/forms/commands/distribution.js +7 -3
  43. package/dist/modules/forms/commands/distribution.js.map +2 -2
  44. package/dist/modules/forms/commands/form-version.js +9 -4
  45. package/dist/modules/forms/commands/form-version.js.map +2 -2
  46. package/dist/modules/forms/commands/form.js +9 -4
  47. package/dist/modules/forms/commands/form.js.map +2 -2
  48. package/dist/modules/forms/commands/invitation.js +7 -3
  49. package/dist/modules/forms/commands/invitation.js.map +2 -2
  50. package/dist/modules/forms/commands/submission.js +13 -6
  51. package/dist/modules/forms/commands/submission.js.map +2 -2
  52. package/package.json +8 -8
  53. package/src/modules/availability/api/policies/route.ts +10 -11
  54. package/src/modules/availability/backend/availability/check/page.tsx +38 -35
  55. package/src/modules/availability/backend/availability/policies/create/page.tsx +3 -0
  56. package/src/modules/availability/i18n/de.json +1 -0
  57. package/src/modules/availability/i18n/en.json +1 -0
  58. package/src/modules/availability/i18n/es.json +1 -0
  59. package/src/modules/availability/i18n/ko.json +1 -0
  60. package/src/modules/availability/i18n/pl.json +1 -0
  61. package/src/modules/availability/lib/organizationScope.ts +37 -0
  62. package/src/modules/catalog/api/categories/bulk-create/route.ts +16 -2
  63. package/src/modules/catalog/api/products/bulk-create/route.ts +16 -2
  64. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +1 -0
  65. package/src/modules/catalog/components/prices/PriceScopeSelectors.tsx +2 -2
  66. package/src/modules/customer_accounts/AGENTS.md +1 -0
  67. package/src/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].ts +89 -0
  68. package/src/modules/customer_groups/api/customer-groups/price-kinds/route.ts +99 -0
  69. package/src/modules/customer_groups/backend/customer-groups/page.tsx +7 -1
  70. package/src/modules/customer_groups/components/CustomerGroupTermsPriceKindField.tsx +5 -4
  71. package/src/modules/customer_groups/components/CustomerGroupTermsSection.tsx +8 -4
  72. package/src/modules/customer_groups/lib/priceKindScope.ts +43 -0
  73. package/src/modules/customer_groups/widgets/injection/person-groups-explain-terms.tsx +2 -2
  74. package/src/modules/customers/commands/companies.ts +16 -1
  75. package/src/modules/dictionaries/components/DictionariesManager.tsx +8 -1
  76. package/src/modules/eudr/i18n/de.json +1 -0
  77. package/src/modules/eudr/i18n/en.json +1 -0
  78. package/src/modules/eudr/i18n/es.json +1 -0
  79. package/src/modules/eudr/i18n/ko.json +1 -0
  80. package/src/modules/eudr/i18n/pl.json +1 -0
  81. package/src/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.tsx +6 -5
  82. package/src/modules/forms/backend/forms/[id]/submissions/components/formSummary.ts +19 -0
  83. package/src/modules/forms/backend/forms/[id]/submissions/page.tsx +4 -16
  84. package/src/modules/forms/commands/distribution.ts +7 -3
  85. package/src/modules/forms/commands/form-version.ts +9 -4
  86. package/src/modules/forms/commands/form.ts +9 -4
  87. package/src/modules/forms/commands/invitation.ts +7 -3
  88. package/src/modules/forms/commands/submission.ts +13 -6
  89. package/src/modules/forms/i18n/de.json +21 -0
  90. package/src/modules/forms/i18n/en.json +21 -0
  91. package/src/modules/forms/i18n/es.json +21 -0
  92. package/src/modules/forms/i18n/ko.json +21 -0
  93. package/src/modules/forms/i18n/pl.json +21 -0
  94. package/src/modules/notifications/AGENTS.md +1 -1
  95. package/src/modules/push_notifications/i18n/de.json +1 -0
  96. package/src/modules/push_notifications/i18n/en.json +1 -0
  97. package/src/modules/push_notifications/i18n/es.json +1 -0
  98. package/src/modules/push_notifications/i18n/ko.json +1 -0
  99. package/src/modules/push_notifications/i18n/pl.json +1 -0
  100. package/src/modules/warranty_claims/i18n/de.json +1 -0
  101. package/src/modules/warranty_claims/i18n/en.json +1 -0
  102. package/src/modules/warranty_claims/i18n/es.json +1 -0
  103. package/src/modules/warranty_claims/i18n/ko.json +1 -0
  104. package/src/modules/warranty_claims/i18n/pl.json +1 -0
  105. package/src/modules/wms/i18n/de.json +1 -0
  106. package/src/modules/wms/i18n/en.json +1 -0
  107. package/src/modules/wms/i18n/es.json +1 -0
  108. package/src/modules/wms/i18n/ko.json +1 -0
  109. package/src/modules/wms/i18n/pl.json +1 -0
@@ -1,4 +1,4 @@
1
- [build:core] found 5540 entry points
1
+ [build:core] found 5548 entry points
2
2
  [build:core] built successfully
3
3
  [build:core:generated] found 248 entry points
4
4
  [build:core:generated] built successfully
@@ -7,7 +7,7 @@ import { organizationScopeRequiredResponse } from "@open-mercato/shared/lib/auth
7
7
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
8
8
  import { findAndCountWithDecryption } from "@open-mercato/shared/lib/encryption/find";
9
9
  import { availabilityPolicyCreateSchema, availabilityPolicyUpdateSchema } from "../../data/validators.js";
10
- import { resolveAvailabilityOrganizationId } from "../../lib/organizationScope.js";
10
+ import { resolveAvailabilityListOrganizationIds, scopeAvailabilityPolicyWriteInput } from "../../lib/organizationScope.js";
11
11
  import {
12
12
  createAvailabilityCrudOpenApi,
13
13
  createPagedListResponseSchema,
@@ -39,7 +39,7 @@ const crud = makeCrudRoute({
39
39
  create: {
40
40
  commandId: "availability.policies.create",
41
41
  schema: rawBodySchema,
42
- mapInput: ({ parsed }) => parsed,
42
+ mapInput: ({ parsed, ctx }) => scopeAvailabilityPolicyWriteInput(parsed, ctx),
43
43
  response: ({ result }) => ({ id: String(result.policyId) }),
44
44
  status: 201
45
45
  },
@@ -98,8 +98,8 @@ async function GET(req) {
98
98
  return NextResponse.json({ items: [], total: 0, page: 1, pageSize: 50, totalPages: 1 }, { status: 401 });
99
99
  }
100
100
  const container = await createRequestContainer();
101
- const organizationId = await resolveAvailabilityOrganizationId(container, auth, req);
102
- if (!organizationId && !auth.isSuperAdmin) return organizationScopeRequiredResponse();
101
+ const organizationIds = await resolveAvailabilityListOrganizationIds(container, auth, req);
102
+ if (organizationIds?.length === 0) return organizationScopeRequiredResponse();
103
103
  const url = new URL(req.url);
104
104
  const parsed = listQuerySchema.safeParse({
105
105
  id: url.searchParams.get("id") ?? void 0,
@@ -121,7 +121,7 @@ async function GET(req) {
121
121
  tenantId: auth.tenantId,
122
122
  deletedAt: null
123
123
  };
124
- if (organizationId) filter.organizationId = organizationId;
124
+ if (organizationIds) filter.organizationId = organizationIds.length === 1 ? organizationIds[0] : { $in: organizationIds };
125
125
  if (id) filter.id = id;
126
126
  if (storeId) filter.storeId = storeId;
127
127
  if (productId) filter.productId = productId;
@@ -136,7 +136,7 @@ async function GET(req) {
136
136
  AvailabilityPolicy,
137
137
  filter,
138
138
  { orderBy, limit: pageSize, offset },
139
- { tenantId: auth.tenantId, organizationId: organizationId ?? null }
139
+ { tenantId: auth.tenantId, organizationId: organizationIds?.length === 1 ? organizationIds[0] : null }
140
140
  );
141
141
  const items = rows.map(toRow);
142
142
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/availability/api/policies/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { AvailabilityPolicy } from '../../data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { FilterQuery } from '@mikro-orm/core'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { organizationScopeRequiredResponse } from '@open-mercato/shared/lib/auth/organizationScope'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findAndCountWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { availabilityPolicyCreateSchema, availabilityPolicyUpdateSchema } from '../../data/validators'\nimport { resolveAvailabilityOrganizationId } from '../../lib/organizationScope'\nimport {\n createAvailabilityCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['availability.policies.view'] },\n POST: { requireAuth: true, requireFeatures: ['availability.policies.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['availability.policies.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['availability.policies.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst rawBodySchema = z.object({}).loose()\ntype CrudInput = Record<string, unknown>\n\nconst crud = makeCrudRoute<CrudInput, CrudInput, Record<string, unknown>>({\n metadata: routeMetadata,\n orm: {\n entity: AvailabilityPolicy,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n events: {\n module: 'availability',\n entity: 'policy',\n persistent: true,\n },\n actions: {\n create: {\n commandId: 'availability.policies.create',\n schema: rawBodySchema,\n mapInput: ({ parsed }) => parsed,\n response: ({ result }) => ({ id: String(result.policyId) }),\n status: 201,\n },\n update: {\n commandId: 'availability.policies.update',\n schema: rawBodySchema,\n mapInput: ({ parsed }) => parsed,\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'availability.policies.delete',\n schema: rawBodySchema,\n mapInput: ({ raw, ctx }) => ({\n id: ((raw as Record<string, unknown>).query as Record<string, unknown> | undefined)?.id as string | undefined,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? undefined,\n tenantId: ctx.auth?.tenantId ?? undefined,\n }),\n response: () => ({ ok: true }),\n },\n },\n})\n\nconst listQuerySchema = z.object({\n id: z.uuid().optional(),\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n storeId: z.uuid().optional(),\n productId: z.uuid().optional(),\n variantId: z.uuid().optional(),\n isActive: z.enum(['true', 'false']).optional(),\n sortField: z.enum(['createdAt', 'updatedAt']).optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}).loose()\n\ntype AvailabilityPolicyRow = {\n id: string\n organizationId: string\n tenantId: string\n storeId: string | null\n productId: string | null\n variantId: string | null\n isStockManaged: boolean | null\n allowBackorder: boolean\n backorderLeadTimeDays: number | null\n preorderReleaseAt: string | null\n lowStockThreshold: number | null\n minOrderQuantity: number | null\n maxOrderQuantity: number | null\n quantityIncrement: number | null\n hideWhenOutOfStock: boolean\n isActive: boolean\n createdAt: string | null\n updatedAt: string | null\n}\n\nconst toRow = (policy: AvailabilityPolicy): AvailabilityPolicyRow => ({\n id: String(policy.id),\n organizationId: String(policy.organizationId),\n tenantId: String(policy.tenantId),\n storeId: policy.storeId ?? null,\n productId: policy.productId ?? null,\n variantId: policy.variantId ?? null,\n isStockManaged: policy.isStockManaged ?? null,\n allowBackorder: !!policy.allowBackorder,\n backorderLeadTimeDays: policy.backorderLeadTimeDays ?? null,\n preorderReleaseAt: policy.preorderReleaseAt ? policy.preorderReleaseAt.toISOString() : null,\n lowStockThreshold: policy.lowStockThreshold ?? null,\n minOrderQuantity: policy.minOrderQuantity ?? null,\n maxOrderQuantity: policy.maxOrderQuantity ?? null,\n quantityIncrement: policy.quantityIncrement ?? null,\n hideWhenOutOfStock: !!policy.hideWhenOutOfStock,\n isActive: !!policy.isActive,\n createdAt: policy.createdAt ? policy.createdAt.toISOString() : null,\n updatedAt: policy.updatedAt ? policy.updatedAt.toISOString() : null,\n})\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n return NextResponse.json({ items: [], total: 0, page: 1, pageSize: 50, totalPages: 1 }, { status: 401 })\n }\n const container = await createRequestContainer()\n const organizationId = await resolveAvailabilityOrganizationId(container, auth, req)\n // A superadmin with no organization selected legitimately sees every\n // organization in the tenant (om_selected_org=__all__); anyone else with\n // an unresolved scope gets the standard 400, never a 401 (that reads as an\n // expired session to the client and redirect-loops through session\n // refresh \u2014 see organizationScope.ts).\n if (!organizationId && !auth.isSuperAdmin) return organizationScopeRequiredResponse()\n\n const url = new URL(req.url)\n const parsed = listQuerySchema.safeParse({\n id: url.searchParams.get('id') ?? undefined,\n page: url.searchParams.get('page') ?? undefined,\n pageSize: url.searchParams.get('pageSize') ?? undefined,\n storeId: url.searchParams.get('storeId') ?? undefined,\n productId: url.searchParams.get('productId') ?? undefined,\n variantId: url.searchParams.get('variantId') ?? undefined,\n isActive: url.searchParams.get('isActive') ?? undefined,\n sortField: url.searchParams.get('sortField') ?? undefined,\n sortDir: url.searchParams.get('sortDir') ?? undefined,\n })\n if (!parsed.success) {\n return NextResponse.json({ items: [], total: 0, page: 1, pageSize: 50, totalPages: 1 }, { status: 400 })\n }\n\n const em = container.resolve('em') as EntityManager\n\n const { id, page, pageSize, storeId, productId, variantId, isActive, sortField, sortDir } = parsed.data\n const filter: FilterQuery<AvailabilityPolicy> = {\n tenantId: auth.tenantId,\n deletedAt: null,\n }\n if (organizationId) filter.organizationId = organizationId\n if (id) filter.id = id\n if (storeId) filter.storeId = storeId\n if (productId) filter.productId = productId\n if (variantId) filter.variantId = variantId\n if (isActive === 'true') filter.isActive = true\n if (isActive === 'false') filter.isActive = false\n\n const orderBy: Record<string, 'ASC' | 'DESC'> = {}\n orderBy[sortField ?? 'createdAt'] = sortDir === 'asc' ? 'ASC' : 'DESC'\n\n const offset = (page - 1) * pageSize\n const [rows, total] = await findAndCountWithDecryption(\n em,\n AvailabilityPolicy,\n filter,\n { orderBy, limit: pageSize, offset },\n { tenantId: auth.tenantId, organizationId: organizationId ?? null },\n )\n const items = rows.map(toRow)\n const totalPages = Math.max(1, Math.ceil(total / pageSize))\n\n return NextResponse.json({ items, total, page, pageSize, totalPages })\n}\n\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst availabilityPolicyListItemSchema = z.object({\n id: z.uuid(),\n organizationId: z.uuid(),\n tenantId: z.uuid(),\n storeId: z.uuid().nullable(),\n productId: z.uuid().nullable(),\n variantId: z.uuid().nullable(),\n isStockManaged: z.boolean().nullable(),\n allowBackorder: z.boolean(),\n backorderLeadTimeDays: z.number().nullable(),\n preorderReleaseAt: z.string().nullable(),\n lowStockThreshold: z.number().nullable(),\n minOrderQuantity: z.number().nullable(),\n maxOrderQuantity: z.number().nullable(),\n quantityIncrement: z.number().nullable(),\n hideWhenOutOfStock: z.boolean(),\n isActive: z.boolean(),\n createdAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n})\n\nconst policyDeleteQuerySchema = z.object({ id: z.uuid() })\n\nconst policyCrudOpenApi = createAvailabilityCrudOpenApi({\n resourceName: 'AvailabilityPolicy',\n pluralName: 'AvailabilityPolicies',\n querySchema: listQuerySchema,\n listResponseSchema: createPagedListResponseSchema(availabilityPolicyListItemSchema),\n create: {\n schema: availabilityPolicyCreateSchema,\n description: 'Creates a new availability policy.',\n },\n update: {\n schema: availabilityPolicyUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing availability policy by id.',\n },\n del: {\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes an availability policy identified by the `id` query parameter.',\n },\n})\n\nexport const openApi: OpenApiRouteDoc = {\n ...policyCrudOpenApi,\n methods: {\n ...policyCrudOpenApi.methods,\n ...(policyCrudOpenApi.methods.DELETE\n ? { DELETE: { ...policyCrudOpenApi.methods.DELETE, query: policyDeleteQuerySchema } }\n : {}),\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { AvailabilityPolicy } from '../../data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { FilterQuery } from '@mikro-orm/core'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { organizationScopeRequiredResponse } from '@open-mercato/shared/lib/auth/organizationScope'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findAndCountWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { availabilityPolicyCreateSchema, availabilityPolicyUpdateSchema } from '../../data/validators'\nimport { resolveAvailabilityListOrganizationIds, scopeAvailabilityPolicyWriteInput } from '../../lib/organizationScope'\nimport {\n createAvailabilityCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['availability.policies.view'] },\n POST: { requireAuth: true, requireFeatures: ['availability.policies.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['availability.policies.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['availability.policies.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst rawBodySchema = z.object({}).loose()\ntype CrudInput = Record<string, unknown>\n\nconst crud = makeCrudRoute<CrudInput, CrudInput, Record<string, unknown>>({\n metadata: routeMetadata,\n orm: {\n entity: AvailabilityPolicy,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n events: {\n module: 'availability',\n entity: 'policy',\n persistent: true,\n },\n actions: {\n create: {\n commandId: 'availability.policies.create',\n schema: rawBodySchema,\n mapInput: ({ parsed, ctx }) => scopeAvailabilityPolicyWriteInput(parsed, ctx),\n response: ({ result }) => ({ id: String(result.policyId) }),\n status: 201,\n },\n update: {\n commandId: 'availability.policies.update',\n schema: rawBodySchema,\n mapInput: ({ parsed }) => parsed,\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'availability.policies.delete',\n schema: rawBodySchema,\n mapInput: ({ raw, ctx }) => ({\n id: ((raw as Record<string, unknown>).query as Record<string, unknown> | undefined)?.id as string | undefined,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? undefined,\n tenantId: ctx.auth?.tenantId ?? undefined,\n }),\n response: () => ({ ok: true }),\n },\n },\n})\n\nconst listQuerySchema = z.object({\n id: z.uuid().optional(),\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n storeId: z.uuid().optional(),\n productId: z.uuid().optional(),\n variantId: z.uuid().optional(),\n isActive: z.enum(['true', 'false']).optional(),\n sortField: z.enum(['createdAt', 'updatedAt']).optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}).loose()\n\ntype AvailabilityPolicyRow = {\n id: string\n organizationId: string\n tenantId: string\n storeId: string | null\n productId: string | null\n variantId: string | null\n isStockManaged: boolean | null\n allowBackorder: boolean\n backorderLeadTimeDays: number | null\n preorderReleaseAt: string | null\n lowStockThreshold: number | null\n minOrderQuantity: number | null\n maxOrderQuantity: number | null\n quantityIncrement: number | null\n hideWhenOutOfStock: boolean\n isActive: boolean\n createdAt: string | null\n updatedAt: string | null\n}\n\nconst toRow = (policy: AvailabilityPolicy): AvailabilityPolicyRow => ({\n id: String(policy.id),\n organizationId: String(policy.organizationId),\n tenantId: String(policy.tenantId),\n storeId: policy.storeId ?? null,\n productId: policy.productId ?? null,\n variantId: policy.variantId ?? null,\n isStockManaged: policy.isStockManaged ?? null,\n allowBackorder: !!policy.allowBackorder,\n backorderLeadTimeDays: policy.backorderLeadTimeDays ?? null,\n preorderReleaseAt: policy.preorderReleaseAt ? policy.preorderReleaseAt.toISOString() : null,\n lowStockThreshold: policy.lowStockThreshold ?? null,\n minOrderQuantity: policy.minOrderQuantity ?? null,\n maxOrderQuantity: policy.maxOrderQuantity ?? null,\n quantityIncrement: policy.quantityIncrement ?? null,\n hideWhenOutOfStock: !!policy.hideWhenOutOfStock,\n isActive: !!policy.isActive,\n createdAt: policy.createdAt ? policy.createdAt.toISOString() : null,\n updatedAt: policy.updatedAt ? policy.updatedAt.toISOString() : null,\n})\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n return NextResponse.json({ items: [], total: 0, page: 1, pageSize: 50, totalPages: 1 }, { status: 401 })\n }\n const container = await createRequestContainer()\n const organizationIds = await resolveAvailabilityListOrganizationIds(container, auth, req)\n // \"All organizations\" (om_selected_org=__all__) lists every organization the\n // caller may access; a caller with no organization in scope gets the standard\n // 400, never a 401 (that reads as an expired session to the client and\n // redirect-loops through session refresh \u2014 see organizationScope.ts).\n if (organizationIds?.length === 0) return organizationScopeRequiredResponse()\n\n const url = new URL(req.url)\n const parsed = listQuerySchema.safeParse({\n id: url.searchParams.get('id') ?? undefined,\n page: url.searchParams.get('page') ?? undefined,\n pageSize: url.searchParams.get('pageSize') ?? undefined,\n storeId: url.searchParams.get('storeId') ?? undefined,\n productId: url.searchParams.get('productId') ?? undefined,\n variantId: url.searchParams.get('variantId') ?? undefined,\n isActive: url.searchParams.get('isActive') ?? undefined,\n sortField: url.searchParams.get('sortField') ?? undefined,\n sortDir: url.searchParams.get('sortDir') ?? undefined,\n })\n if (!parsed.success) {\n return NextResponse.json({ items: [], total: 0, page: 1, pageSize: 50, totalPages: 1 }, { status: 400 })\n }\n\n const em = container.resolve('em') as EntityManager\n\n const { id, page, pageSize, storeId, productId, variantId, isActive, sortField, sortDir } = parsed.data\n const filter: FilterQuery<AvailabilityPolicy> = {\n tenantId: auth.tenantId,\n deletedAt: null,\n }\n if (organizationIds) filter.organizationId = organizationIds.length === 1 ? organizationIds[0] : { $in: organizationIds }\n if (id) filter.id = id\n if (storeId) filter.storeId = storeId\n if (productId) filter.productId = productId\n if (variantId) filter.variantId = variantId\n if (isActive === 'true') filter.isActive = true\n if (isActive === 'false') filter.isActive = false\n\n const orderBy: Record<string, 'ASC' | 'DESC'> = {}\n orderBy[sortField ?? 'createdAt'] = sortDir === 'asc' ? 'ASC' : 'DESC'\n\n const offset = (page - 1) * pageSize\n const [rows, total] = await findAndCountWithDecryption(\n em,\n AvailabilityPolicy,\n filter,\n { orderBy, limit: pageSize, offset },\n { tenantId: auth.tenantId, organizationId: organizationIds?.length === 1 ? organizationIds[0] : null },\n )\n const items = rows.map(toRow)\n const totalPages = Math.max(1, Math.ceil(total / pageSize))\n\n return NextResponse.json({ items, total, page, pageSize, totalPages })\n}\n\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst availabilityPolicyListItemSchema = z.object({\n id: z.uuid(),\n organizationId: z.uuid(),\n tenantId: z.uuid(),\n storeId: z.uuid().nullable(),\n productId: z.uuid().nullable(),\n variantId: z.uuid().nullable(),\n isStockManaged: z.boolean().nullable(),\n allowBackorder: z.boolean(),\n backorderLeadTimeDays: z.number().nullable(),\n preorderReleaseAt: z.string().nullable(),\n lowStockThreshold: z.number().nullable(),\n minOrderQuantity: z.number().nullable(),\n maxOrderQuantity: z.number().nullable(),\n quantityIncrement: z.number().nullable(),\n hideWhenOutOfStock: z.boolean(),\n isActive: z.boolean(),\n createdAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n})\n\nconst policyDeleteQuerySchema = z.object({ id: z.uuid() })\n\nconst policyCrudOpenApi = createAvailabilityCrudOpenApi({\n resourceName: 'AvailabilityPolicy',\n pluralName: 'AvailabilityPolicies',\n querySchema: listQuerySchema,\n listResponseSchema: createPagedListResponseSchema(availabilityPolicyListItemSchema),\n create: {\n schema: availabilityPolicyCreateSchema,\n description: 'Creates a new availability policy.',\n },\n update: {\n schema: availabilityPolicyUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing availability policy by id.',\n },\n del: {\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes an availability policy identified by the `id` query parameter.',\n },\n})\n\nexport const openApi: OpenApiRouteDoc = {\n ...policyCrudOpenApi,\n methods: {\n ...policyCrudOpenApi.methods,\n ...(policyCrudOpenApi.methods.DELETE\n ? { DELETE: { ...policyCrudOpenApi.methods.DELETE, query: policyDeleteQuerySchema } }\n : {}),\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,qBAAqB;AAC9B,SAAS,0BAA0B;AAGnC,SAAS,0BAA0B;AACnC,SAAS,yCAAyC;AAClD,SAAS,8BAA8B;AAEvC,SAAS,kCAAkC;AAC3C,SAAS,gCAAgC,sCAAsC;AAC/E,SAAS,wCAAwC,yCAAyC;AAC1F;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,gBAAgB;AAAA,EACpB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,4BAA4B,EAAE;AAAA,EAC1E,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,8BAA8B,EAAE;AAAA,EAC7E,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,8BAA8B,EAAE;AAAA,EAC5E,QAAQ,EAAE,aAAa,MAAM,iBAAiB,CAAC,8BAA8B,EAAE;AACjF;AAEO,MAAM,WAAW;AAExB,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,MAAM;AAGzC,MAAM,OAAO,cAA6D;AAAA,EACxE,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,YAAY;AAAA,EACd;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,CAAC,EAAE,QAAQ,IAAI,MAAM,kCAAkC,QAAQ,GAAG;AAAA,MAC5E,UAAU,CAAC,EAAE,OAAO,OAAO,EAAE,IAAI,OAAO,OAAO,QAAQ,EAAE;AAAA,MACzD,QAAQ;AAAA,IACV;AAAA,IACA,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,CAAC,EAAE,OAAO,MAAM;AAAA,MAC1B,UAAU,OAAO,EAAE,IAAI,KAAK;AAAA,IAC9B;AAAA,IACA,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,CAAC,EAAE,KAAK,IAAI,OAAO;AAAA,QAC3B,IAAM,IAAgC,OAA+C;AAAA,QACrF,gBAAgB,IAAI,0BAA0B,IAAI,MAAM,SAAS;AAAA,QACjE,UAAU,IAAI,MAAM,YAAY;AAAA,MAClC;AAAA,MACA,UAAU,OAAO,EAAE,IAAI,KAAK;AAAA,IAC9B;AAAA,EACF;AACF,CAAC;AAED,MAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,IAAI,EAAE,KAAK,EAAE,SAAS;AAAA,EACtB,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,EACxC,UAAU,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EACtD,SAAS,EAAE,KAAK,EAAE,SAAS;AAAA,EAC3B,WAAW,EAAE,KAAK,EAAE,SAAS;AAAA,EAC7B,WAAW,EAAE,KAAK,EAAE,SAAS;AAAA,EAC7B,UAAU,EAAE,KAAK,CAAC,QAAQ,OAAO,CAAC,EAAE,SAAS;AAAA,EAC7C,WAAW,EAAE,KAAK,CAAC,aAAa,WAAW,CAAC,EAAE,SAAS;AAAA,EACvD,SAAS,EAAE,KAAK,CAAC,OAAO,MAAM,CAAC,EAAE,SAAS;AAC5C,CAAC,EAAE,MAAM;AAuBT,MAAM,QAAQ,CAAC,YAAuD;AAAA,EACpE,IAAI,OAAO,OAAO,EAAE;AAAA,EACpB,gBAAgB,OAAO,OAAO,cAAc;AAAA,EAC5C,UAAU,OAAO,OAAO,QAAQ;AAAA,EAChC,SAAS,OAAO,WAAW;AAAA,EAC3B,WAAW,OAAO,aAAa;AAAA,EAC/B,WAAW,OAAO,aAAa;AAAA,EAC/B,gBAAgB,OAAO,kBAAkB;AAAA,EACzC,gBAAgB,CAAC,CAAC,OAAO;AAAA,EACzB,uBAAuB,OAAO,yBAAyB;AAAA,EACvD,mBAAmB,OAAO,oBAAoB,OAAO,kBAAkB,YAAY,IAAI;AAAA,EACvF,mBAAmB,OAAO,qBAAqB;AAAA,EAC/C,kBAAkB,OAAO,oBAAoB;AAAA,EAC7C,kBAAkB,OAAO,oBAAoB;AAAA,EAC7C,mBAAmB,OAAO,qBAAqB;AAAA,EAC/C,oBAAoB,CAAC,CAAC,OAAO;AAAA,EAC7B,UAAU,CAAC,CAAC,OAAO;AAAA,EACnB,WAAW,OAAO,YAAY,OAAO,UAAU,YAAY,IAAI;AAAA,EAC/D,WAAW,OAAO,YAAY,OAAO,UAAU,YAAY,IAAI;AACjE;AAEA,eAAsB,IAAI,KAAc;AACtC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,QAAQ,CAAC,KAAK,UAAU;AAC3B,WAAO,aAAa,KAAK,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,IAAI,YAAY,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACzG;AACA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,kBAAkB,MAAM,uCAAuC,WAAW,MAAM,GAAG;AAKzF,MAAI,iBAAiB,WAAW,EAAG,QAAO,kCAAkC;AAE5E,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,QAAM,SAAS,gBAAgB,UAAU;AAAA,IACvC,IAAI,IAAI,aAAa,IAAI,IAAI,KAAK;AAAA,IAClC,MAAM,IAAI,aAAa,IAAI,MAAM,KAAK;AAAA,IACtC,UAAU,IAAI,aAAa,IAAI,UAAU,KAAK;AAAA,IAC9C,SAAS,IAAI,aAAa,IAAI,SAAS,KAAK;AAAA,IAC5C,WAAW,IAAI,aAAa,IAAI,WAAW,KAAK;AAAA,IAChD,WAAW,IAAI,aAAa,IAAI,WAAW,KAAK;AAAA,IAChD,UAAU,IAAI,aAAa,IAAI,UAAU,KAAK;AAAA,IAC9C,WAAW,IAAI,aAAa,IAAI,WAAW,KAAK;AAAA,IAChD,SAAS,IAAI,aAAa,IAAI,SAAS,KAAK;AAAA,EAC9C,CAAC;AACD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,aAAa,KAAK,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,IAAI,YAAY,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACzG;AAEA,QAAM,KAAK,UAAU,QAAQ,IAAI;AAEjC,QAAM,EAAE,IAAI,MAAM,UAAU,SAAS,WAAW,WAAW,UAAU,WAAW,QAAQ,IAAI,OAAO;AACnG,QAAM,SAA0C;AAAA,IAC9C,UAAU,KAAK;AAAA,IACf,WAAW;AAAA,EACb;AACA,MAAI,gBAAiB,QAAO,iBAAiB,gBAAgB,WAAW,IAAI,gBAAgB,CAAC,IAAI,EAAE,KAAK,gBAAgB;AACxH,MAAI,GAAI,QAAO,KAAK;AACpB,MAAI,QAAS,QAAO,UAAU;AAC9B,MAAI,UAAW,QAAO,YAAY;AAClC,MAAI,UAAW,QAAO,YAAY;AAClC,MAAI,aAAa,OAAQ,QAAO,WAAW;AAC3C,MAAI,aAAa,QAAS,QAAO,WAAW;AAE5C,QAAM,UAA0C,CAAC;AACjD,UAAQ,aAAa,WAAW,IAAI,YAAY,QAAQ,QAAQ;AAEhE,QAAM,UAAU,OAAO,KAAK;AAC5B,QAAM,CAAC,MAAM,KAAK,IAAI,MAAM;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,SAAS,OAAO,UAAU,OAAO;AAAA,IACnC,EAAE,UAAU,KAAK,UAAU,gBAAgB,iBAAiB,WAAW,IAAI,gBAAgB,CAAC,IAAI,KAAK;AAAA,EACvG;AACA,QAAM,QAAQ,KAAK,IAAI,KAAK;AAC5B,QAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,QAAQ,CAAC;AAE1D,SAAO,aAAa,KAAK,EAAE,OAAO,OAAO,MAAM,UAAU,WAAW,CAAC;AACvE;AAEO,MAAM,OAAO,KAAK;AAClB,MAAM,MAAM,KAAK;AACjB,MAAM,SAAS,KAAK;AAE3B,MAAM,mCAAmC,EAAE,OAAO;AAAA,EAChD,IAAI,EAAE,KAAK;AAAA,EACX,gBAAgB,EAAE,KAAK;AAAA,EACvB,UAAU,EAAE,KAAK;AAAA,EACjB,SAAS,EAAE,KAAK,EAAE,SAAS;AAAA,EAC3B,WAAW,EAAE,KAAK,EAAE,SAAS;AAAA,EAC7B,WAAW,EAAE,KAAK,EAAE,SAAS;AAAA,EAC7B,gBAAgB,EAAE,QAAQ,EAAE,SAAS;AAAA,EACrC,gBAAgB,EAAE,QAAQ;AAAA,EAC1B,uBAAuB,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3C,mBAAmB,EAAE,OAAO,EAAE,SAAS;AAAA,EACvC,mBAAmB,EAAE,OAAO,EAAE,SAAS;AAAA,EACvC,kBAAkB,EAAE,OAAO,EAAE,SAAS;AAAA,EACtC,kBAAkB,EAAE,OAAO,EAAE,SAAS;AAAA,EACtC,mBAAmB,EAAE,OAAO,EAAE,SAAS;AAAA,EACvC,oBAAoB,EAAE,QAAQ;AAAA,EAC9B,UAAU,EAAE,QAAQ;AAAA,EACpB,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,WAAW,EAAE,OAAO,EAAE,SAAS;AACjC,CAAC;AAED,MAAM,0BAA0B,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAEzD,MAAM,oBAAoB,8BAA8B;AAAA,EACtD,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,oBAAoB,8BAA8B,gCAAgC;AAAA,EAClF,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,gBAAgB;AAAA,IAChB,aAAa;AAAA,EACf;AACF,CAAC;AAEM,MAAM,UAA2B;AAAA,EACtC,GAAG;AAAA,EACH,SAAS;AAAA,IACP,GAAG,kBAAkB;AAAA,IACrB,GAAI,kBAAkB,QAAQ,SAC1B,EAAE,QAAQ,EAAE,GAAG,kBAAkB,QAAQ,QAAQ,OAAO,wBAAwB,EAAE,IAClF,CAAC;AAAA,EACP;AACF;",
6
6
  "names": []
7
7
  }
@@ -7,6 +7,7 @@ import { Label } from "@open-mercato/ui/primitives/label";
7
7
  import { Button } from "@open-mercato/ui/primitives/button";
8
8
  import { StatusBadge } from "@open-mercato/ui/primitives/status-badge";
9
9
  import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
10
+ import { ErrorMessage } from "@open-mercato/ui/backend/detail";
10
11
  import { useT } from "@open-mercato/shared/lib/i18n/context";
11
12
  const STATE_VARIANTS = {
12
13
  in_stock: "success",
@@ -126,8 +127,8 @@ function AvailabilityCheckPage() {
126
127
  ] })
127
128
  ] }),
128
129
  /* @__PURE__ */ jsx(Button, { onClick: () => void runCheck(), disabled: isRunning, children: isRunning ? t("availability.check.action.running") : t("availability.check.action.run") }),
129
- error && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 p-4 text-sm text-destructive", "data-testid": "availability-check-error", children: error }),
130
- availability && /* @__PURE__ */ jsxs("div", { className: "space-y-4 rounded-md border p-4", "data-testid": "availability-check-result", children: [
130
+ error && /* @__PURE__ */ jsx("div", { "data-testid": "availability-check-error", children: /* @__PURE__ */ jsx(ErrorMessage, { label: error }) }),
131
+ /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", "data-testid": "availability-check-result-region", children: availability && /* @__PURE__ */ jsxs("div", { className: "space-y-4 rounded-md border p-4", "data-testid": "availability-check-result", children: [
131
132
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
132
133
  /* @__PURE__ */ jsx(StatusBadge, { variant: STATE_VARIANTS[availability.state], children: t(`availability.states.${availability.state}`) }),
133
134
  !availability.isAuthoritative && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("availability.check.advisoryNote") })
@@ -155,7 +156,7 @@ function AvailabilityCheckPage() {
155
156
  ] })
156
157
  ] }),
157
158
  availability.state === "not_tracked" && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("availability.check.notTrackedExplanation") })
158
- ] }),
159
+ ] }) }),
159
160
  policyTrace && /* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-muted p-4", "data-testid": "availability-check-policy-trace", children: [
160
161
  /* @__PURE__ */ jsx("div", { className: "mb-2 text-sm font-medium", children: t("availability.policies.form.preview.title") }),
161
162
  /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: TRACE_FIELDS.map((key) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/availability/backend/availability/check/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { StatusBadge, type StatusBadgeVariant } from '@open-mercato/ui/primitives/status-badge'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype AvailabilityState = 'in_stock' | 'low_stock' | 'out_of_stock' | 'backorder' | 'preorder' | 'not_tracked'\n\ntype AvailabilityItemResult = {\n state: AvailabilityState\n availableQuantity: number | null\n canFulfil: boolean\n leadTimeDays: number | null\n releaseAt: string | null\n isAuthoritative: boolean\n policySourceId: string | null\n}\n\ntype FieldTrace = { value: unknown; policySourceId: string | null }\ntype PolicyTrace = Record<string, FieldTrace>\n\ntype CheckResponse = {\n availability?: AvailabilityItemResult | null\n policyTrace?: PolicyTrace | null\n error?: string\n}\n\nconst STATE_VARIANTS: Record<AvailabilityState, StatusBadgeVariant> = {\n in_stock: 'success',\n low_stock: 'warning',\n out_of_stock: 'error',\n backorder: 'info',\n preorder: 'info',\n not_tracked: 'neutral',\n}\n\nconst TRACE_FIELDS = [\n 'isStockManaged',\n 'allowBackorder',\n 'backorderLeadTimeDays',\n 'preorderReleaseAt',\n 'lowStockThreshold',\n 'minOrderQuantity',\n 'maxOrderQuantity',\n 'quantityIncrement',\n 'hideWhenOutOfStock',\n 'isActive',\n]\n\nfunction formatTraceValue(value: unknown, t: (key: string) => string): string {\n if (value === null || value === undefined) return t('availability.policies.form.preview.notSet')\n if (typeof value === 'boolean') return value ? t('availability.common.yes') : t('availability.common.no')\n return String(value)\n}\n\nexport default function AvailabilityCheckPage() {\n const t = useT()\n const [productId, setProductId] = React.useState('')\n const [variantId, setVariantId] = React.useState('')\n const [storeId, setStoreId] = React.useState('')\n const [quantity, setQuantity] = React.useState('1')\n const [isRunning, setIsRunning] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [result, setResult] = React.useState<CheckResponse | null>(null)\n\n const runCheck = React.useCallback(async () => {\n if (!productId.trim()) {\n setError(t('availability.check.errors.productRequired'))\n return\n }\n setIsRunning(true)\n setError(null)\n setResult(null)\n try {\n const call = await apiCall<CheckResponse>(\n '/api/availability/check',\n {\n method: 'POST',\n body: JSON.stringify({\n productId: productId.trim(),\n variantId: variantId.trim() || null,\n storeId: storeId.trim() || null,\n quantity: Number(quantity) > 0 ? Number(quantity) : 1,\n }),\n },\n { fallback: null },\n )\n if (!call.ok) {\n const errorPayload = call.result as { error?: string } | undefined\n setError(typeof errorPayload?.error === 'string' ? errorPayload.error : t('availability.check.errors.failed'))\n return\n }\n setResult(call.result ?? null)\n } catch (e) {\n setError(e instanceof Error ? e.message : t('availability.check.errors.failed'))\n } finally {\n setIsRunning(false)\n }\n }, [productId, variantId, storeId, quantity, t])\n\n const availability = result?.availability ?? null\n const policyTrace = result?.policyTrace ?? null\n\n return (\n <Page>\n <PageBody>\n <div\n className=\"space-y-6\"\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void runCheck()\n }\n }}\n >\n <h1 className=\"text-xl font-semibold\">{t('availability.check.title')}</h1>\n <div className=\"grid grid-cols-1 gap-4 rounded-md border p-4 sm:grid-cols-4\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"availability-check-product-id\">{t('availability.policies.form.field.productId')}</Label>\n <Input\n id=\"availability-check-product-id\"\n value={productId}\n onChange={(e) => setProductId(e.target.value)}\n autoFocus\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"availability-check-variant-id\">{t('availability.policies.form.field.variantId')}</Label>\n <Input id=\"availability-check-variant-id\" value={variantId} onChange={(e) => setVariantId(e.target.value)} />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"availability-check-store-id\">{t('availability.policies.form.field.storeId')}</Label>\n <Input id=\"availability-check-store-id\" value={storeId} onChange={(e) => setStoreId(e.target.value)} />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"availability-check-quantity\">{t('availability.check.field.quantity')}</Label>\n <Input\n id=\"availability-check-quantity\"\n type=\"number\"\n min={1}\n value={quantity}\n onChange={(e) => setQuantity(e.target.value)}\n />\n </div>\n </div>\n <Button onClick={() => void runCheck()} disabled={isRunning}>\n {isRunning ? t('availability.check.action.running') : t('availability.check.action.run')}\n </Button>\n\n {error && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-4 text-sm text-destructive\" data-testid=\"availability-check-error\">\n {error}\n </div>\n )}\n\n {availability && (\n <div className=\"space-y-4 rounded-md border p-4\" data-testid=\"availability-check-result\">\n <div className=\"flex items-center gap-3\">\n <StatusBadge variant={STATE_VARIANTS[availability.state]}>{t(`availability.states.${availability.state}`)}</StatusBadge>\n {!availability.isAuthoritative && (\n <span className=\"text-xs text-muted-foreground\">{t('availability.check.advisoryNote')}</span>\n )}\n </div>\n <dl className=\"grid grid-cols-1 gap-2 sm:grid-cols-3\">\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.check.result.availableQuantity')}</dt>\n <dd className=\"text-sm\">{availability.availableQuantity ?? t('availability.policies.form.preview.notSet')}</dd>\n </div>\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.check.result.canFulfil')}</dt>\n <dd className=\"text-sm\">{availability.canFulfil ? t('availability.common.yes') : t('availability.common.no')}</dd>\n </div>\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.check.result.policySourceId')}</dt>\n <dd className=\"text-sm\">{availability.policySourceId ?? t('availability.policies.form.preview.moduleDefault')}</dd>\n </div>\n {availability.leadTimeDays != null && (\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.policies.form.field.backorderLeadTimeDays')}</dt>\n <dd className=\"text-sm\">{availability.leadTimeDays}</dd>\n </div>\n )}\n {availability.releaseAt && (\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.policies.form.field.preorderReleaseAt')}</dt>\n <dd className=\"text-sm\">{availability.releaseAt}</dd>\n </div>\n )}\n </dl>\n {availability.state === 'not_tracked' && (\n <p className=\"text-xs text-muted-foreground\">{t('availability.check.notTrackedExplanation')}</p>\n )}\n </div>\n )}\n\n {policyTrace && (\n <div className=\"rounded-md border bg-muted p-4\" data-testid=\"availability-check-policy-trace\">\n <div className=\"mb-2 text-sm font-medium\">{t('availability.policies.form.preview.title')}</div>\n <dl className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n {TRACE_FIELDS.map((key) => {\n const field = policyTrace[key]\n const source = field?.policySourceId ?? t('availability.policies.form.preview.moduleDefault')\n return (\n <div key={key}>\n <dt className=\"text-xs text-muted-foreground\">{t(`availability.policies.form.field.${key}`)}</dt>\n <dd className=\"text-xs\">\n {formatTraceValue(field?.value, t)} <span className=\"text-muted-foreground\">({source})</span>\n </dd>\n </div>\n )\n })}\n </dl>\n </div>\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { StatusBadge, type StatusBadgeVariant } from '@open-mercato/ui/primitives/status-badge'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype AvailabilityState = 'in_stock' | 'low_stock' | 'out_of_stock' | 'backorder' | 'preorder' | 'not_tracked'\n\ntype AvailabilityItemResult = {\n state: AvailabilityState\n availableQuantity: number | null\n canFulfil: boolean\n leadTimeDays: number | null\n releaseAt: string | null\n isAuthoritative: boolean\n policySourceId: string | null\n}\n\ntype FieldTrace = { value: unknown; policySourceId: string | null }\ntype PolicyTrace = Record<string, FieldTrace>\n\ntype CheckResponse = {\n availability?: AvailabilityItemResult | null\n policyTrace?: PolicyTrace | null\n error?: string\n}\n\nconst STATE_VARIANTS: Record<AvailabilityState, StatusBadgeVariant> = {\n in_stock: 'success',\n low_stock: 'warning',\n out_of_stock: 'error',\n backorder: 'info',\n preorder: 'info',\n not_tracked: 'neutral',\n}\n\nconst TRACE_FIELDS = [\n 'isStockManaged',\n 'allowBackorder',\n 'backorderLeadTimeDays',\n 'preorderReleaseAt',\n 'lowStockThreshold',\n 'minOrderQuantity',\n 'maxOrderQuantity',\n 'quantityIncrement',\n 'hideWhenOutOfStock',\n 'isActive',\n]\n\nfunction formatTraceValue(value: unknown, t: (key: string) => string): string {\n if (value === null || value === undefined) return t('availability.policies.form.preview.notSet')\n if (typeof value === 'boolean') return value ? t('availability.common.yes') : t('availability.common.no')\n return String(value)\n}\n\nexport default function AvailabilityCheckPage() {\n const t = useT()\n const [productId, setProductId] = React.useState('')\n const [variantId, setVariantId] = React.useState('')\n const [storeId, setStoreId] = React.useState('')\n const [quantity, setQuantity] = React.useState('1')\n const [isRunning, setIsRunning] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [result, setResult] = React.useState<CheckResponse | null>(null)\n\n const runCheck = React.useCallback(async () => {\n if (!productId.trim()) {\n setError(t('availability.check.errors.productRequired'))\n return\n }\n setIsRunning(true)\n setError(null)\n setResult(null)\n try {\n const call = await apiCall<CheckResponse>(\n '/api/availability/check',\n {\n method: 'POST',\n body: JSON.stringify({\n productId: productId.trim(),\n variantId: variantId.trim() || null,\n storeId: storeId.trim() || null,\n quantity: Number(quantity) > 0 ? Number(quantity) : 1,\n }),\n },\n { fallback: null },\n )\n if (!call.ok) {\n const errorPayload = call.result as { error?: string } | undefined\n setError(typeof errorPayload?.error === 'string' ? errorPayload.error : t('availability.check.errors.failed'))\n return\n }\n setResult(call.result ?? null)\n } catch (e) {\n setError(e instanceof Error ? e.message : t('availability.check.errors.failed'))\n } finally {\n setIsRunning(false)\n }\n }, [productId, variantId, storeId, quantity, t])\n\n const availability = result?.availability ?? null\n const policyTrace = result?.policyTrace ?? null\n\n return (\n <Page>\n <PageBody>\n <div\n className=\"space-y-6\"\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void runCheck()\n }\n }}\n >\n <h1 className=\"text-xl font-semibold\">{t('availability.check.title')}</h1>\n <div className=\"grid grid-cols-1 gap-4 rounded-md border p-4 sm:grid-cols-4\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"availability-check-product-id\">{t('availability.policies.form.field.productId')}</Label>\n <Input\n id=\"availability-check-product-id\"\n value={productId}\n onChange={(e) => setProductId(e.target.value)}\n autoFocus\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"availability-check-variant-id\">{t('availability.policies.form.field.variantId')}</Label>\n <Input id=\"availability-check-variant-id\" value={variantId} onChange={(e) => setVariantId(e.target.value)} />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"availability-check-store-id\">{t('availability.policies.form.field.storeId')}</Label>\n <Input id=\"availability-check-store-id\" value={storeId} onChange={(e) => setStoreId(e.target.value)} />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"availability-check-quantity\">{t('availability.check.field.quantity')}</Label>\n <Input\n id=\"availability-check-quantity\"\n type=\"number\"\n min={1}\n value={quantity}\n onChange={(e) => setQuantity(e.target.value)}\n />\n </div>\n </div>\n <Button onClick={() => void runCheck()} disabled={isRunning}>\n {isRunning ? t('availability.check.action.running') : t('availability.check.action.run')}\n </Button>\n\n {error && (\n <div data-testid=\"availability-check-error\">\n <ErrorMessage label={error} />\n </div>\n )}\n\n <div role=\"status\" aria-live=\"polite\" data-testid=\"availability-check-result-region\">\n {availability && (\n <div className=\"space-y-4 rounded-md border p-4\" data-testid=\"availability-check-result\">\n <div className=\"flex items-center gap-3\">\n <StatusBadge variant={STATE_VARIANTS[availability.state]}>{t(`availability.states.${availability.state}`)}</StatusBadge>\n {!availability.isAuthoritative && (\n <span className=\"text-xs text-muted-foreground\">{t('availability.check.advisoryNote')}</span>\n )}\n </div>\n <dl className=\"grid grid-cols-1 gap-2 sm:grid-cols-3\">\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.check.result.availableQuantity')}</dt>\n <dd className=\"text-sm\">{availability.availableQuantity ?? t('availability.policies.form.preview.notSet')}</dd>\n </div>\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.check.result.canFulfil')}</dt>\n <dd className=\"text-sm\">{availability.canFulfil ? t('availability.common.yes') : t('availability.common.no')}</dd>\n </div>\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.check.result.policySourceId')}</dt>\n <dd className=\"text-sm\">{availability.policySourceId ?? t('availability.policies.form.preview.moduleDefault')}</dd>\n </div>\n {availability.leadTimeDays != null && (\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.policies.form.field.backorderLeadTimeDays')}</dt>\n <dd className=\"text-sm\">{availability.leadTimeDays}</dd>\n </div>\n )}\n {availability.releaseAt && (\n <div>\n <dt className=\"text-xs text-muted-foreground\">{t('availability.policies.form.field.preorderReleaseAt')}</dt>\n <dd className=\"text-sm\">{availability.releaseAt}</dd>\n </div>\n )}\n </dl>\n {availability.state === 'not_tracked' && (\n <p className=\"text-xs text-muted-foreground\">{t('availability.check.notTrackedExplanation')}</p>\n )}\n </div>\n )}\n </div>\n\n {policyTrace && (\n <div className=\"rounded-md border bg-muted p-4\" data-testid=\"availability-check-policy-trace\">\n <div className=\"mb-2 text-sm font-medium\">{t('availability.policies.form.preview.title')}</div>\n <dl className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n {TRACE_FIELDS.map((key) => {\n const field = policyTrace[key]\n const source = field?.policySourceId ?? t('availability.policies.form.preview.moduleDefault')\n return (\n <div key={key}>\n <dt className=\"text-xs text-muted-foreground\">{t(`availability.policies.form.field.${key}`)}</dt>\n <dd className=\"text-xs\">\n {formatTraceValue(field?.value, t)} <span className=\"text-muted-foreground\">({source})</span>\n </dd>\n </div>\n )\n })}\n </dl>\n </div>\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -56,6 +56,9 @@ function AvailabilityPolicyCreatePage() {
56
56
  )
57
57
  ] }),
58
58
  onSubmit: async (values) => {
59
+ if (!organizationId) {
60
+ throw createCrudFormError(t("availability.policies.errors.organizationRequired"));
61
+ }
59
62
  if (scope.variantId && !scope.productId) {
60
63
  throw createCrudFormError(
61
64
  t("availability.policies.errors.variantRequiresProduct"),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/availability/backend/availability/policies/create/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { ScopeFields, type PolicyScope } from '../ScopeFields'\nimport { ResolutionPreviewPanel, type PolicyTrace } from '../ResolutionPreviewPanel'\nimport { buildPolicyFieldGroups } from '../formGroups'\nimport { findIntegerFieldAboveMax, toIsoDateTimeOrNull } from '../policyPayload'\nimport { STOCK_MANAGED_INHERIT, fromStockManagedChoice } from '../StockManagedField'\n\ntype FormValues = {\n isStockManaged?: string | null\n allowBackorder?: boolean\n backorderLeadTimeDays?: number | string | null\n preorderReleaseAt?: string | null\n lowStockThreshold?: number | string | null\n minOrderQuantity?: number | string | null\n maxOrderQuantity?: number | string | null\n quantityIncrement?: number | string | null\n hideWhenOutOfStock?: boolean\n isActive?: boolean\n}\n\nfunction toNullableInt(value: number | string | null | undefined): number | null {\n if (value === null || value === undefined || value === '') return null\n const parsed = typeof value === 'number' ? value : parseInt(value, 10)\n return Number.isFinite(parsed) ? parsed : null\n}\n\nexport default function AvailabilityPolicyCreatePage() {\n const t = useT()\n const router = useRouter()\n const { organizationId, tenantId } = useOrganizationScopeDetail()\n const [scope, setScope] = React.useState<PolicyScope>({ productId: '', variantId: '', storeId: '' })\n\n const [resolvedStockManaged, setResolvedStockManaged] = React.useState<boolean | null>(null)\n\n const groups = React.useMemo(\n () => buildPolicyFieldGroups(t, { resolvedStockManaged }),\n [resolvedStockManaged, t],\n )\n const handleTraceChange = React.useCallback((trace: PolicyTrace | null) => {\n const value = trace?.isStockManaged?.value\n setResolvedStockManaged(typeof value === 'boolean' ? value : null)\n }, [])\n\n return (\n <CrudForm<FormValues>\n title={t('availability.policies.create.title')}\n titleHeadingLevel={1}\n backHref=\"/backend/availability/policies\"\n fields={[]}\n groups={groups}\n initialValues={{ isActive: true, isStockManaged: STOCK_MANAGED_INHERIT }}\n submitLabel={t('availability.policies.form.action.create')}\n cancelHref=\"/backend/availability/policies\"\n contentHeader={(\n <div className=\"space-y-4\">\n <ScopeFields value={scope} onChange={setScope} />\n <ResolutionPreviewPanel\n productId={scope.productId}\n variantId={scope.variantId || null}\n storeId={scope.storeId || null}\n onTraceChange={handleTraceChange}\n />\n </div>\n )}\n onSubmit={async (values) => {\n if (scope.variantId && !scope.productId) {\n throw createCrudFormError(\n t('availability.policies.errors.variantRequiresProduct'),\n { productId: t('availability.policies.errors.variantRequiresProduct') },\n )\n }\n if (values.allowBackorder && toNullableInt(values.backorderLeadTimeDays) == null) {\n throw createCrudFormError(\n t('availability.policies.errors.backorderRequiresLeadTime'),\n { backorderLeadTimeDays: t('availability.policies.errors.backorderRequiresLeadTime') },\n )\n }\n const min = toNullableInt(values.minOrderQuantity)\n const max = toNullableInt(values.maxOrderQuantity)\n const integerFieldAboveMax = findIntegerFieldAboveMax({\n backorderLeadTimeDays: toNullableInt(values.backorderLeadTimeDays),\n lowStockThreshold: toNullableInt(values.lowStockThreshold),\n minOrderQuantity: min,\n maxOrderQuantity: max,\n quantityIncrement: toNullableInt(values.quantityIncrement),\n })\n if (integerFieldAboveMax) {\n throw createCrudFormError(\n t('availability.policies.errors.integerTooLarge'),\n { [integerFieldAboveMax]: t('availability.policies.errors.integerTooLarge') },\n )\n }\n if (min != null && max != null && max < min) {\n throw createCrudFormError(\n t('availability.policies.errors.maxBelowMin'),\n { maxOrderQuantity: t('availability.policies.errors.maxBelowMin') },\n )\n }\n\n const payload = {\n organizationId,\n tenantId,\n productId: scope.productId || null,\n variantId: scope.variantId || null,\n storeId: scope.storeId || null,\n isStockManaged: fromStockManagedChoice(values.isStockManaged),\n allowBackorder: !!values.allowBackorder,\n backorderLeadTimeDays: toNullableInt(values.backorderLeadTimeDays),\n preorderReleaseAt: toIsoDateTimeOrNull(values.preorderReleaseAt),\n lowStockThreshold: toNullableInt(values.lowStockThreshold),\n minOrderQuantity: min,\n maxOrderQuantity: max,\n quantityIncrement: toNullableInt(values.quantityIncrement),\n hideWhenOutOfStock: !!values.hideWhenOutOfStock,\n isActive: values.isActive !== false,\n }\n await createCrud('availability/policies', payload)\n flash(t('availability.policies.flash.created'), 'success')\n router.push('/backend/availability/policies')\n }}\n />\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { ScopeFields, type PolicyScope } from '../ScopeFields'\nimport { ResolutionPreviewPanel, type PolicyTrace } from '../ResolutionPreviewPanel'\nimport { buildPolicyFieldGroups } from '../formGroups'\nimport { findIntegerFieldAboveMax, toIsoDateTimeOrNull } from '../policyPayload'\nimport { STOCK_MANAGED_INHERIT, fromStockManagedChoice } from '../StockManagedField'\n\ntype FormValues = {\n isStockManaged?: string | null\n allowBackorder?: boolean\n backorderLeadTimeDays?: number | string | null\n preorderReleaseAt?: string | null\n lowStockThreshold?: number | string | null\n minOrderQuantity?: number | string | null\n maxOrderQuantity?: number | string | null\n quantityIncrement?: number | string | null\n hideWhenOutOfStock?: boolean\n isActive?: boolean\n}\n\nfunction toNullableInt(value: number | string | null | undefined): number | null {\n if (value === null || value === undefined || value === '') return null\n const parsed = typeof value === 'number' ? value : parseInt(value, 10)\n return Number.isFinite(parsed) ? parsed : null\n}\n\nexport default function AvailabilityPolicyCreatePage() {\n const t = useT()\n const router = useRouter()\n const { organizationId, tenantId } = useOrganizationScopeDetail()\n const [scope, setScope] = React.useState<PolicyScope>({ productId: '', variantId: '', storeId: '' })\n\n const [resolvedStockManaged, setResolvedStockManaged] = React.useState<boolean | null>(null)\n\n const groups = React.useMemo(\n () => buildPolicyFieldGroups(t, { resolvedStockManaged }),\n [resolvedStockManaged, t],\n )\n const handleTraceChange = React.useCallback((trace: PolicyTrace | null) => {\n const value = trace?.isStockManaged?.value\n setResolvedStockManaged(typeof value === 'boolean' ? value : null)\n }, [])\n\n return (\n <CrudForm<FormValues>\n title={t('availability.policies.create.title')}\n titleHeadingLevel={1}\n backHref=\"/backend/availability/policies\"\n fields={[]}\n groups={groups}\n initialValues={{ isActive: true, isStockManaged: STOCK_MANAGED_INHERIT }}\n submitLabel={t('availability.policies.form.action.create')}\n cancelHref=\"/backend/availability/policies\"\n contentHeader={(\n <div className=\"space-y-4\">\n <ScopeFields value={scope} onChange={setScope} />\n <ResolutionPreviewPanel\n productId={scope.productId}\n variantId={scope.variantId || null}\n storeId={scope.storeId || null}\n onTraceChange={handleTraceChange}\n />\n </div>\n )}\n onSubmit={async (values) => {\n if (!organizationId) {\n throw createCrudFormError(t('availability.policies.errors.organizationRequired'))\n }\n if (scope.variantId && !scope.productId) {\n throw createCrudFormError(\n t('availability.policies.errors.variantRequiresProduct'),\n { productId: t('availability.policies.errors.variantRequiresProduct') },\n )\n }\n if (values.allowBackorder && toNullableInt(values.backorderLeadTimeDays) == null) {\n throw createCrudFormError(\n t('availability.policies.errors.backorderRequiresLeadTime'),\n { backorderLeadTimeDays: t('availability.policies.errors.backorderRequiresLeadTime') },\n )\n }\n const min = toNullableInt(values.minOrderQuantity)\n const max = toNullableInt(values.maxOrderQuantity)\n const integerFieldAboveMax = findIntegerFieldAboveMax({\n backorderLeadTimeDays: toNullableInt(values.backorderLeadTimeDays),\n lowStockThreshold: toNullableInt(values.lowStockThreshold),\n minOrderQuantity: min,\n maxOrderQuantity: max,\n quantityIncrement: toNullableInt(values.quantityIncrement),\n })\n if (integerFieldAboveMax) {\n throw createCrudFormError(\n t('availability.policies.errors.integerTooLarge'),\n { [integerFieldAboveMax]: t('availability.policies.errors.integerTooLarge') },\n )\n }\n if (min != null && max != null && max < min) {\n throw createCrudFormError(\n t('availability.policies.errors.maxBelowMin'),\n { maxOrderQuantity: t('availability.policies.errors.maxBelowMin') },\n )\n }\n\n const payload = {\n organizationId,\n tenantId,\n productId: scope.productId || null,\n variantId: scope.variantId || null,\n storeId: scope.storeId || null,\n isStockManaged: fromStockManagedChoice(values.isStockManaged),\n allowBackorder: !!values.allowBackorder,\n backorderLeadTimeDays: toNullableInt(values.backorderLeadTimeDays),\n preorderReleaseAt: toIsoDateTimeOrNull(values.preorderReleaseAt),\n lowStockThreshold: toNullableInt(values.lowStockThreshold),\n minOrderQuantity: min,\n maxOrderQuantity: max,\n quantityIncrement: toNullableInt(values.quantityIncrement),\n hideWhenOutOfStock: !!values.hideWhenOutOfStock,\n isActive: values.isActive !== false,\n }\n await createCrud('availability/policies', payload)\n flash(t('availability.policies.flash.created'), 'success')\n router.push('/backend/availability/policies')\n }}\n />\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,10 +1,33 @@
1
1
  import { resolveActiveOrganizationId } from "@open-mercato/shared/lib/auth/organizationScope";
2
+ import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
3
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
2
4
  import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
5
+ const AVAILABILITY_POLICY_ORGANIZATION_REQUIRED_MESSAGE = {
6
+ key: "availability.policies.errors.organizationRequired",
7
+ fallback: "Select a specific organization in the header before creating a policy."
8
+ };
3
9
  async function resolveAvailabilityOrganizationId(container, auth, request) {
4
10
  const scope = await resolveOrganizationScopeForRequest({ container, auth, request }).catch(() => null);
5
11
  return scope?.selectedId ?? resolveActiveOrganizationId(auth);
6
12
  }
13
+ async function resolveAvailabilityListOrganizationIds(container, auth, request) {
14
+ const scope = await resolveOrganizationScopeForRequest({ container, auth, request }).catch(() => null);
15
+ if (scope?.selectedId) return [scope.selectedId];
16
+ if (scope?.tenantId) return scope.filterIds ?? null;
17
+ const fallbackOrganizationId = resolveActiveOrganizationId(auth);
18
+ if (fallbackOrganizationId) return [fallbackOrganizationId];
19
+ return auth?.isSuperAdmin ? null : [];
20
+ }
21
+ async function scopeAvailabilityPolicyWriteInput(input, ctx) {
22
+ const { translate } = await resolveTranslations();
23
+ return withScopedPayload(input, ctx, translate, {
24
+ messages: { organizationRequired: AVAILABILITY_POLICY_ORGANIZATION_REQUIRED_MESSAGE }
25
+ });
26
+ }
7
27
  export {
8
- resolveAvailabilityOrganizationId
28
+ AVAILABILITY_POLICY_ORGANIZATION_REQUIRED_MESSAGE,
29
+ resolveAvailabilityListOrganizationIds,
30
+ resolveAvailabilityOrganizationId,
31
+ scopeAvailabilityPolicyWriteInput
9
32
  };
10
33
  //# sourceMappingURL=organizationScope.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/availability/lib/organizationScope.ts"],
4
- "sourcesContent": ["import type { AwilixContainer } from 'awilix'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\n\n// Policy writes go through `makeCrudRoute`, which scopes them to the organization\n// selected in the header (`ctx.selectedOrganizationId`). `getAuthFromRequest` applies\n// that selection to `auth.orgId` for superadmins only, so the hand-written reads\n// resolve it the same way the CRUD factory does; otherwise a user working in a second\n// organization would write policies there and read them from the home organization.\nexport async function resolveAvailabilityOrganizationId(\n container: AwilixContainer,\n auth: AuthContext,\n request: Request,\n): Promise<string | null> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request }).catch(() => null)\n return scope?.selectedId ?? resolveActiveOrganizationId(auth)\n}\n"],
5
- "mappings": "AAEA,SAAS,mCAAmC;AAC5C,SAAS,0CAA0C;AAOnD,eAAsB,kCACpB,WACA,MACA,SACwB;AACxB,QAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,QAAQ,CAAC,EAAE,MAAM,MAAM,IAAI;AACrG,SAAO,OAAO,cAAc,4BAA4B,IAAI;AAC9D;",
4
+ "sourcesContent": ["import type { AwilixContainer } from 'awilix'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'\nimport { withScopedPayload, type ScopedContext } from '@open-mercato/shared/lib/api/scoped'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\n\nexport const AVAILABILITY_POLICY_ORGANIZATION_REQUIRED_MESSAGE = {\n key: 'availability.policies.errors.organizationRequired',\n fallback: 'Select a specific organization in the header before creating a policy.',\n}\n\n// Policy writes go through `makeCrudRoute`, which scopes them to the organization\n// selected in the header (`ctx.selectedOrganizationId`). `getAuthFromRequest` applies\n// that selection to `auth.orgId` for superadmins only, so the hand-written reads\n// resolve it the same way the CRUD factory does; otherwise a user working in a second\n// organization would write policies there and read them from the home organization.\nexport async function resolveAvailabilityOrganizationId(\n container: AwilixContainer,\n auth: AuthContext,\n request: Request,\n): Promise<string | null> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request }).catch(() => null)\n return scope?.selectedId ?? resolveActiveOrganizationId(auth)\n}\n\n// The policy list reads the organization selected in the header, or under \"All\n// organizations\" every organization the caller may access, as the `makeCrudRoute` lists do.\n// `null` means the whole tenant; an empty array means no organization is in scope.\nexport async function resolveAvailabilityListOrganizationIds(\n container: AwilixContainer,\n auth: AuthContext,\n request: Request,\n): Promise<string[] | null> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request }).catch(() => null)\n if (scope?.selectedId) return [scope.selectedId]\n if (scope?.tenantId) return scope.filterIds ?? null\n const fallbackOrganizationId = resolveActiveOrganizationId(auth)\n if (fallbackOrganizationId) return [fallbackOrganizationId]\n return auth?.isSuperAdmin ? null : []\n}\n\n// A policy belongs to exactly one organization. The create form sends the header\n// selection, which is `null` under \"All organizations\"; fill the scope from the request\n// context instead and, when no single organization is in scope, answer with a message\n// the form can show rather than a field error on a field it does not render.\nexport async function scopeAvailabilityPolicyWriteInput(\n input: Record<string, unknown>,\n ctx: ScopedContext,\n): Promise<Record<string, unknown>> {\n const { translate } = await resolveTranslations()\n return withScopedPayload(input, ctx, translate, {\n messages: { organizationRequired: AVAILABILITY_POLICY_ORGANIZATION_REQUIRED_MESSAGE },\n })\n}\n"],
5
+ "mappings": "AAEA,SAAS,mCAAmC;AAC5C,SAAS,yBAA6C;AACtD,SAAS,2BAA2B;AACpC,SAAS,0CAA0C;AAE5C,MAAM,oDAAoD;AAAA,EAC/D,KAAK;AAAA,EACL,UAAU;AACZ;AAOA,eAAsB,kCACpB,WACA,MACA,SACwB;AACxB,QAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,QAAQ,CAAC,EAAE,MAAM,MAAM,IAAI;AACrG,SAAO,OAAO,cAAc,4BAA4B,IAAI;AAC9D;AAKA,eAAsB,uCACpB,WACA,MACA,SAC0B;AAC1B,QAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,QAAQ,CAAC,EAAE,MAAM,MAAM,IAAI;AACrG,MAAI,OAAO,WAAY,QAAO,CAAC,MAAM,UAAU;AAC/C,MAAI,OAAO,SAAU,QAAO,MAAM,aAAa;AAC/C,QAAM,yBAAyB,4BAA4B,IAAI;AAC/D,MAAI,uBAAwB,QAAO,CAAC,sBAAsB;AAC1D,SAAO,MAAM,eAAe,OAAO,CAAC;AACtC;AAMA,eAAsB,kCACpB,OACA,KACkC;AAClC,QAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,SAAO,kBAAkB,OAAO,KAAK,WAAW;AAAA,IAC9C,UAAU,EAAE,sBAAsB,kDAAkD;AAAA,EACtF,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -30,7 +30,7 @@ const openApi = {
30
30
  };
31
31
  async function POST(req) {
32
32
  const auth = await getAuthFromRequest(req);
33
- if (!auth?.tenantId || !auth.orgId) {
33
+ if (!auth?.tenantId) {
34
34
  return NextResponse.json(responseSchema.parse({
35
35
  ok: false,
36
36
  progressJobId: null,
@@ -52,7 +52,21 @@ async function POST(req) {
52
52
  const items = parsed.data.items;
53
53
  const container = await createRequestContainer();
54
54
  const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
55
- const organizationId = scope.selectedId ?? auth.orgId;
55
+ if (scope.selectionRejected) {
56
+ return NextResponse.json(responseSchema.parse({
57
+ ok: false,
58
+ progressJobId: null,
59
+ message: "Your selected organization is no longer available. Please re-select an organization and try again."
60
+ }), { status: 422 });
61
+ }
62
+ const organizationId = scope.selectedId;
63
+ if (!organizationId) {
64
+ return NextResponse.json(responseSchema.parse({
65
+ ok: false,
66
+ progressJobId: null,
67
+ message: "Organization context is required"
68
+ }), { status: 400 });
69
+ }
56
70
  const guardDecision = await runBulkCreateMutationGuards({
57
71
  container,
58
72
  auth,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/catalog/api/categories/bulk-create/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport type { ProgressService } from '../../../../progress/lib/progressService'\nimport { categoriesBulkCreateSchema } from '../../../data/validators'\nimport { DEFAULT_CHECKPOINT_INTERVAL } from '../../../lib/bulkCreateCheckpoint'\nimport { runBulkCreateMutationGuards } from '../../../lib/bulkCreateMutationGuards'\nimport {\n CATALOG_CATEGORY_BULK_CREATE_QUEUE,\n getCatalogQueue,\n} from '../../../lib/bulkCreateCategories'\n\nconst MAX_REPORTED_ISSUES = 20\n\nconst responseSchema = z.object({\n ok: z.boolean(),\n progressJobId: z.string().uuid().nullable(),\n message: z.string(),\n // Additive: existing consumers that only read `ok`/`progressJobId`/`message` are unaffected.\n // A batch of up to several thousand structurally rich rows is impossible to debug from a bare\n // \"Invalid payload\", so the first failing paths are reported back.\n errors: z\n .array(z.object({ path: z.string(), message: z.string() }))\n .optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['catalog.categories.manage'] },\n}\n\nexport const openApi = {\n tags: ['Catalog'],\n summary: 'Start bulk creating catalog categories',\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Unauthorized',\n }), { status: 401 })\n }\n\n const parsed = categoriesBulkCreateSchema.safeParse(await readJsonSafe(req))\n if (!parsed.success) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Invalid payload',\n errors: parsed.error.issues.slice(0, MAX_REPORTED_ISSUES).map((issue) => ({\n path: issue.path.join('.'),\n message: issue.message,\n })),\n }), { status: 400 })\n }\n\n const items = parsed.data.items\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope.selectedId ?? auth.orgId\n\n const guardDecision = await runBulkCreateMutationGuards({\n container,\n auth,\n request: req,\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n resourceKind: 'catalog.category',\n itemCount: items.length,\n })\n if (!guardDecision.ok) {\n return NextResponse.json(guardDecision.body, { status: guardDecision.status })\n }\n\n const progressService = container.resolve('progressService') as ProgressService\n\n const progressJob = await progressService.createJob(\n {\n jobType: 'catalog.categories.bulk_create',\n name: 'Bulk create categories',\n description: `${items.length} catalog categories queued for creation`,\n totalCount: items.length,\n cancellable: true,\n meta: {\n source: 'catalog.bulk-create',\n checkpointInterval: DEFAULT_CHECKPOINT_INTERVAL,\n lastCompletedRowIndex: -1,\n },\n },\n {\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub,\n },\n )\n\n const queue = getCatalogQueue(CATALOG_CATEGORY_BULK_CREATE_QUEUE)\n await queue.enqueue({\n progressJobId: progressJob.id,\n items,\n scope: {\n organizationId,\n tenantId: auth.tenantId,\n userId: auth.sub,\n },\n })\n\n return NextResponse.json(responseSchema.parse({\n ok: true,\n progressJobId: progressJob.id,\n message: 'Bulk create started.',\n }), { status: 202 })\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport type { ProgressService } from '../../../../progress/lib/progressService'\nimport { categoriesBulkCreateSchema } from '../../../data/validators'\nimport { DEFAULT_CHECKPOINT_INTERVAL } from '../../../lib/bulkCreateCheckpoint'\nimport { runBulkCreateMutationGuards } from '../../../lib/bulkCreateMutationGuards'\nimport {\n CATALOG_CATEGORY_BULK_CREATE_QUEUE,\n getCatalogQueue,\n} from '../../../lib/bulkCreateCategories'\n\nconst MAX_REPORTED_ISSUES = 20\n\nconst responseSchema = z.object({\n ok: z.boolean(),\n progressJobId: z.string().uuid().nullable(),\n message: z.string(),\n // Additive: existing consumers that only read `ok`/`progressJobId`/`message` are unaffected.\n // A batch of up to several thousand structurally rich rows is impossible to debug from a bare\n // \"Invalid payload\", so the first failing paths are reported back.\n errors: z\n .array(z.object({ path: z.string(), message: z.string() }))\n .optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['catalog.categories.manage'] },\n}\n\nexport const openApi = {\n tags: ['Catalog'],\n summary: 'Start bulk creating catalog categories',\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Unauthorized',\n }), { status: 401 })\n }\n\n const parsed = categoriesBulkCreateSchema.safeParse(await readJsonSafe(req))\n if (!parsed.success) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Invalid payload',\n errors: parsed.error.issues.slice(0, MAX_REPORTED_ISSUES).map((issue) => ({\n path: issue.path.join('.'),\n message: issue.message,\n })),\n }), { status: 400 })\n }\n\n const items = parsed.data.items\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n if (scope.selectionRejected) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Your selected organization is no longer available. Please re-select an organization and try again.',\n }), { status: 422 })\n }\n const organizationId = scope.selectedId\n if (!organizationId) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Organization context is required',\n }), { status: 400 })\n }\n\n const guardDecision = await runBulkCreateMutationGuards({\n container,\n auth,\n request: req,\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n resourceKind: 'catalog.category',\n itemCount: items.length,\n })\n if (!guardDecision.ok) {\n return NextResponse.json(guardDecision.body, { status: guardDecision.status })\n }\n\n const progressService = container.resolve('progressService') as ProgressService\n\n const progressJob = await progressService.createJob(\n {\n jobType: 'catalog.categories.bulk_create',\n name: 'Bulk create categories',\n description: `${items.length} catalog categories queued for creation`,\n totalCount: items.length,\n cancellable: true,\n meta: {\n source: 'catalog.bulk-create',\n checkpointInterval: DEFAULT_CHECKPOINT_INTERVAL,\n lastCompletedRowIndex: -1,\n },\n },\n {\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub,\n },\n )\n\n const queue = getCatalogQueue(CATALOG_CATEGORY_BULK_CREATE_QUEUE)\n await queue.enqueue({\n progressJobId: progressJob.id,\n items,\n scope: {\n organizationId,\n tenantId: auth.tenantId,\n userId: auth.sub,\n },\n })\n\n return NextResponse.json(responseSchema.parse({\n ok: true,\n progressJobId: progressJob.id,\n message: 'Bulk create started.',\n }), { status: 202 })\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -30,7 +30,7 @@ const openApi = {
30
30
  };
31
31
  async function POST(req) {
32
32
  const auth = await getAuthFromRequest(req);
33
- if (!auth?.tenantId || !auth.orgId) {
33
+ if (!auth?.tenantId) {
34
34
  return NextResponse.json(responseSchema.parse({
35
35
  ok: false,
36
36
  progressJobId: null,
@@ -52,7 +52,21 @@ async function POST(req) {
52
52
  const items = parsed.data.items;
53
53
  const container = await createRequestContainer();
54
54
  const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
55
- const organizationId = scope.selectedId ?? auth.orgId;
55
+ if (scope.selectionRejected) {
56
+ return NextResponse.json(responseSchema.parse({
57
+ ok: false,
58
+ progressJobId: null,
59
+ message: "Your selected organization is no longer available. Please re-select an organization and try again."
60
+ }), { status: 422 });
61
+ }
62
+ const organizationId = scope.selectedId;
63
+ if (!organizationId) {
64
+ return NextResponse.json(responseSchema.parse({
65
+ ok: false,
66
+ progressJobId: null,
67
+ message: "Organization context is required"
68
+ }), { status: 400 });
69
+ }
56
70
  const guardDecision = await runBulkCreateMutationGuards({
57
71
  container,
58
72
  auth,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/catalog/api/products/bulk-create/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport type { ProgressService } from '../../../../progress/lib/progressService'\nimport { productsBulkCreateSchema } from '../../../data/validators'\nimport { DEFAULT_CHECKPOINT_INTERVAL } from '../../../lib/bulkCreateCheckpoint'\nimport { runBulkCreateMutationGuards } from '../../../lib/bulkCreateMutationGuards'\nimport {\n CATALOG_PRODUCT_BULK_CREATE_QUEUE,\n getCatalogQueue,\n} from '../../../lib/bulkCreateProducts'\n\nconst MAX_REPORTED_ISSUES = 20\n\nconst responseSchema = z.object({\n ok: z.boolean(),\n progressJobId: z.string().uuid().nullable(),\n message: z.string(),\n // Additive: existing consumers that only read `ok`/`progressJobId`/`message` are unaffected.\n // A batch of up to several thousand structurally rich rows is impossible to debug from a bare\n // \"Invalid payload\", so the first failing paths are reported back.\n errors: z\n .array(z.object({ path: z.string(), message: z.string() }))\n .optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['catalog.products.manage'] },\n}\n\nexport const openApi = {\n tags: ['Catalog'],\n summary: 'Start bulk creating catalog products',\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Unauthorized',\n }), { status: 401 })\n }\n\n const parsed = productsBulkCreateSchema.safeParse(await readJsonSafe(req))\n if (!parsed.success) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Invalid payload',\n errors: parsed.error.issues.slice(0, MAX_REPORTED_ISSUES).map((issue) => ({\n path: issue.path.join('.'),\n message: issue.message,\n })),\n }), { status: 400 })\n }\n\n const items = parsed.data.items\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope.selectedId ?? auth.orgId\n\n const guardDecision = await runBulkCreateMutationGuards({\n container,\n auth,\n request: req,\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n resourceKind: 'catalog.product',\n itemCount: items.length,\n })\n if (!guardDecision.ok) {\n return NextResponse.json(guardDecision.body, { status: guardDecision.status })\n }\n\n const progressService = container.resolve('progressService') as ProgressService\n\n const progressJob = await progressService.createJob(\n {\n jobType: 'catalog.products.bulk_create',\n name: 'Bulk create products',\n description: `${items.length} catalog products queued for creation`,\n totalCount: items.length,\n cancellable: true,\n meta: {\n source: 'catalog.bulk-create',\n checkpointInterval: DEFAULT_CHECKPOINT_INTERVAL,\n lastCompletedRowIndex: -1,\n },\n },\n {\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub,\n },\n )\n\n const queue = getCatalogQueue(CATALOG_PRODUCT_BULK_CREATE_QUEUE)\n await queue.enqueue({\n progressJobId: progressJob.id,\n items,\n scope: {\n organizationId,\n tenantId: auth.tenantId,\n userId: auth.sub,\n },\n })\n\n return NextResponse.json(responseSchema.parse({\n ok: true,\n progressJobId: progressJob.id,\n message: 'Bulk create started.',\n }), { status: 202 })\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport type { ProgressService } from '../../../../progress/lib/progressService'\nimport { productsBulkCreateSchema } from '../../../data/validators'\nimport { DEFAULT_CHECKPOINT_INTERVAL } from '../../../lib/bulkCreateCheckpoint'\nimport { runBulkCreateMutationGuards } from '../../../lib/bulkCreateMutationGuards'\nimport {\n CATALOG_PRODUCT_BULK_CREATE_QUEUE,\n getCatalogQueue,\n} from '../../../lib/bulkCreateProducts'\n\nconst MAX_REPORTED_ISSUES = 20\n\nconst responseSchema = z.object({\n ok: z.boolean(),\n progressJobId: z.string().uuid().nullable(),\n message: z.string(),\n // Additive: existing consumers that only read `ok`/`progressJobId`/`message` are unaffected.\n // A batch of up to several thousand structurally rich rows is impossible to debug from a bare\n // \"Invalid payload\", so the first failing paths are reported back.\n errors: z\n .array(z.object({ path: z.string(), message: z.string() }))\n .optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['catalog.products.manage'] },\n}\n\nexport const openApi = {\n tags: ['Catalog'],\n summary: 'Start bulk creating catalog products',\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Unauthorized',\n }), { status: 401 })\n }\n\n const parsed = productsBulkCreateSchema.safeParse(await readJsonSafe(req))\n if (!parsed.success) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Invalid payload',\n errors: parsed.error.issues.slice(0, MAX_REPORTED_ISSUES).map((issue) => ({\n path: issue.path.join('.'),\n message: issue.message,\n })),\n }), { status: 400 })\n }\n\n const items = parsed.data.items\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n if (scope.selectionRejected) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Your selected organization is no longer available. Please re-select an organization and try again.',\n }), { status: 422 })\n }\n const organizationId = scope.selectedId\n if (!organizationId) {\n return NextResponse.json(responseSchema.parse({\n ok: false,\n progressJobId: null,\n message: 'Organization context is required',\n }), { status: 400 })\n }\n\n const guardDecision = await runBulkCreateMutationGuards({\n container,\n auth,\n request: req,\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n resourceKind: 'catalog.product',\n itemCount: items.length,\n })\n if (!guardDecision.ok) {\n return NextResponse.json(guardDecision.body, { status: guardDecision.status })\n }\n\n const progressService = container.resolve('progressService') as ProgressService\n\n const progressJob = await progressService.createJob(\n {\n jobType: 'catalog.products.bulk_create',\n name: 'Bulk create products',\n description: `${items.length} catalog products queued for creation`,\n totalCount: items.length,\n cancellable: true,\n meta: {\n source: 'catalog.bulk-create',\n checkpointInterval: DEFAULT_CHECKPOINT_INTERVAL,\n lastCompletedRowIndex: -1,\n },\n },\n {\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub,\n },\n )\n\n const queue = getCatalogQueue(CATALOG_PRODUCT_BULK_CREATE_QUEUE)\n await queue.enqueue({\n progressJobId: progressJob.id,\n items,\n scope: {\n organizationId,\n tenantId: auth.tenantId,\n userId: auth.sub,\n },\n })\n\n return NextResponse.json(responseSchema.parse({\n ok: true,\n progressJobId: progressJob.id,\n message: 'Bulk create started.',\n }), { status: 202 })\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1208,6 +1208,7 @@ function EditCatalogProductPage({
1208
1208
  },
1209
1209
  initialValues: initialValues ?? void 0,
1210
1210
  isLoading: loading,
1211
+ disableInitialFocus: true,
1211
1212
  loadingMessage: t("catalog.products.edit.loading", "Loading product"),
1212
1213
  submitLabel: t("catalog.products.edit.save", "Save changes"),
1213
1214
  cancelHref: "/backend/catalog/products",