@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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/availability/api/policies/route.js +6 -6
- package/dist/modules/availability/api/policies/route.js.map +2 -2
- package/dist/modules/availability/backend/availability/check/page.js +4 -3
- package/dist/modules/availability/backend/availability/check/page.js.map +2 -2
- package/dist/modules/availability/backend/availability/policies/create/page.js +3 -0
- package/dist/modules/availability/backend/availability/policies/create/page.js.map +2 -2
- package/dist/modules/availability/lib/organizationScope.js +24 -1
- package/dist/modules/availability/lib/organizationScope.js.map +2 -2
- package/dist/modules/catalog/api/categories/bulk-create/route.js +16 -2
- package/dist/modules/catalog/api/categories/bulk-create/route.js.map +2 -2
- package/dist/modules/catalog/api/products/bulk-create/route.js +16 -2
- package/dist/modules/catalog/api/products/bulk-create/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +1 -0
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/components/prices/PriceScopeSelectors.js +2 -2
- package/dist/modules/catalog/components/prices/PriceScopeSelectors.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].js +78 -0
- package/dist/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/price-kinds/route.js +90 -0
- package/dist/modules/customer_groups/api/customer-groups/price-kinds/route.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/page.js +5 -1
- package/dist/modules/customer_groups/backend/customer-groups/page.js.map +2 -2
- package/dist/modules/customer_groups/components/CustomerGroupTermsPriceKindField.js +2 -2
- package/dist/modules/customer_groups/components/CustomerGroupTermsPriceKindField.js.map +2 -2
- package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js +3 -1
- package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js.map +2 -2
- package/dist/modules/customer_groups/lib/priceKindScope.js +35 -1
- package/dist/modules/customer_groups/lib/priceKindScope.js.map +2 -2
- package/dist/modules/customer_groups/widgets/injection/person-groups-explain-terms.js +1 -1
- package/dist/modules/customer_groups/widgets/injection/person-groups-explain-terms.js.map +2 -2
- package/dist/modules/customers/commands/companies.js +14 -1
- package/dist/modules/customers/commands/companies.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +98 -87
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.js +3 -3
- package/dist/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.js.map +2 -2
- package/dist/modules/forms/backend/forms/[id]/submissions/components/formSummary.js +9 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/components/formSummary.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/page.js +3 -6
- package/dist/modules/forms/backend/forms/[id]/submissions/page.js.map +2 -2
- package/dist/modules/forms/commands/distribution.js +7 -3
- package/dist/modules/forms/commands/distribution.js.map +2 -2
- package/dist/modules/forms/commands/form-version.js +9 -4
- package/dist/modules/forms/commands/form-version.js.map +2 -2
- package/dist/modules/forms/commands/form.js +9 -4
- package/dist/modules/forms/commands/form.js.map +2 -2
- package/dist/modules/forms/commands/invitation.js +7 -3
- package/dist/modules/forms/commands/invitation.js.map +2 -2
- package/dist/modules/forms/commands/submission.js +13 -6
- package/dist/modules/forms/commands/submission.js.map +2 -2
- package/package.json +8 -8
- package/src/modules/availability/api/policies/route.ts +10 -11
- package/src/modules/availability/backend/availability/check/page.tsx +38 -35
- package/src/modules/availability/backend/availability/policies/create/page.tsx +3 -0
- package/src/modules/availability/i18n/de.json +1 -0
- package/src/modules/availability/i18n/en.json +1 -0
- package/src/modules/availability/i18n/es.json +1 -0
- package/src/modules/availability/i18n/ko.json +1 -0
- package/src/modules/availability/i18n/pl.json +1 -0
- package/src/modules/availability/lib/organizationScope.ts +37 -0
- package/src/modules/catalog/api/categories/bulk-create/route.ts +16 -2
- package/src/modules/catalog/api/products/bulk-create/route.ts +16 -2
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +1 -0
- package/src/modules/catalog/components/prices/PriceScopeSelectors.tsx +2 -2
- package/src/modules/customer_accounts/AGENTS.md +1 -0
- package/src/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].ts +89 -0
- package/src/modules/customer_groups/api/customer-groups/price-kinds/route.ts +99 -0
- package/src/modules/customer_groups/backend/customer-groups/page.tsx +7 -1
- package/src/modules/customer_groups/components/CustomerGroupTermsPriceKindField.tsx +5 -4
- package/src/modules/customer_groups/components/CustomerGroupTermsSection.tsx +8 -4
- package/src/modules/customer_groups/lib/priceKindScope.ts +43 -0
- package/src/modules/customer_groups/widgets/injection/person-groups-explain-terms.tsx +2 -2
- package/src/modules/customers/commands/companies.ts +16 -1
- package/src/modules/dictionaries/components/DictionariesManager.tsx +8 -1
- package/src/modules/eudr/i18n/de.json +1 -0
- package/src/modules/eudr/i18n/en.json +1 -0
- package/src/modules/eudr/i18n/es.json +1 -0
- package/src/modules/eudr/i18n/ko.json +1 -0
- package/src/modules/eudr/i18n/pl.json +1 -0
- package/src/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.tsx +6 -5
- package/src/modules/forms/backend/forms/[id]/submissions/components/formSummary.ts +19 -0
- package/src/modules/forms/backend/forms/[id]/submissions/page.tsx +4 -16
- package/src/modules/forms/commands/distribution.ts +7 -3
- package/src/modules/forms/commands/form-version.ts +9 -4
- package/src/modules/forms/commands/form.ts +9 -4
- package/src/modules/forms/commands/invitation.ts +7 -3
- package/src/modules/forms/commands/submission.ts +13 -6
- package/src/modules/forms/i18n/de.json +21 -0
- package/src/modules/forms/i18n/en.json +21 -0
- package/src/modules/forms/i18n/es.json +21 -0
- package/src/modules/forms/i18n/ko.json +21 -0
- package/src/modules/forms/i18n/pl.json +21 -0
- package/src/modules/notifications/AGENTS.md +1 -1
- package/src/modules/push_notifications/i18n/de.json +1 -0
- package/src/modules/push_notifications/i18n/en.json +1 -0
- package/src/modules/push_notifications/i18n/es.json +1 -0
- package/src/modules/push_notifications/i18n/ko.json +1 -0
- package/src/modules/push_notifications/i18n/pl.json +1 -0
- package/src/modules/warranty_claims/i18n/de.json +1 -0
- package/src/modules/warranty_claims/i18n/en.json +1 -0
- package/src/modules/warranty_claims/i18n/es.json +1 -0
- package/src/modules/warranty_claims/i18n/ko.json +1 -0
- package/src/modules/warranty_claims/i18n/pl.json +1 -0
- package/src/modules/wms/i18n/de.json +1 -0
- package/src/modules/wms/i18n/en.json +1 -0
- package/src/modules/wms/i18n/es.json +1 -0
- package/src/modules/wms/i18n/ko.json +1 -0
- package/src/modules/wms/i18n/pl.json +1 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -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 {
|
|
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
|
|
102
|
-
if (
|
|
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 (
|
|
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:
|
|
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 {
|
|
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,yCAAyC;
|
|
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": "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",
|
|
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", {
|
|
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
|
|
5
|
-
"mappings": ";
|
|
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
|
-
|
|
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;
|
|
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
|
|
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
|
-
|
|
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
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,0CAA0C;AACnD,SAAS,oBAAoB;AAE7B,SAAS,kCAAkC;AAC3C,SAAS,mCAAmC;AAC5C,SAAS,mCAAmC;AAC5C;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,MAAM,sBAAsB;AAE5B,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,QAAQ;AAAA,EACd,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC1C,SAAS,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,EAIlB,QAAQ,EACL,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,EACzD,SAAS;AACd,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,2BAA2B,EAAE;AAC5E;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,SAAS;AAAA,EAChB,SAAS;AACX;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,
|
|
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
|
|
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
|
-
|
|
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
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,0CAA0C;AACnD,SAAS,oBAAoB;AAE7B,SAAS,gCAAgC;AACzC,SAAS,mCAAmC;AAC5C,SAAS,mCAAmC;AAC5C;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,MAAM,sBAAsB;AAE5B,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,QAAQ;AAAA,EACd,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC1C,SAAS,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,EAIlB,QAAQ,EACL,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,EACzD,SAAS;AACd,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AAC1E;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,SAAS;AAAA,EAChB,SAAS;AACX;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,
|
|
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",
|