@open-mercato/core 0.8.1-develop.7266.1.8e520bbe03 → 0.8.1-develop.7268.1.033c0546d5

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 (128) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities.ids.generated.js +0 -4
  3. package/dist/generated/entities.ids.generated.js.map +2 -2
  4. package/dist/generated/entity-fields-registry.js +0 -21
  5. package/dist/generated/entity-fields-registry.js.map +2 -2
  6. package/dist/modules/customers/backend/customers/companies/create/page.js +5 -0
  7. package/dist/modules/customers/backend/customers/companies/create/page.js.map +2 -2
  8. package/dist/modules/wms/di.js +0 -3
  9. package/dist/modules/wms/di.js.map +2 -2
  10. package/generated/entities.ids.generated.ts +0 -4
  11. package/generated/entity-fields-registry.ts +0 -21
  12. package/package.json +7 -7
  13. package/src/modules/auth/i18n/de.json +0 -3
  14. package/src/modules/auth/i18n/en.json +0 -3
  15. package/src/modules/auth/i18n/es.json +0 -3
  16. package/src/modules/auth/i18n/ko.json +0 -3
  17. package/src/modules/auth/i18n/pl.json +0 -3
  18. package/src/modules/customer_accounts/AGENTS.md +1 -1
  19. package/src/modules/customers/backend/customers/companies/create/page.tsx +6 -0
  20. package/src/modules/wms/di.ts +0 -6
  21. package/dist/generated/entities/availability_policy/index.js +0 -41
  22. package/dist/generated/entities/availability_policy/index.js.map +0 -7
  23. package/dist/modules/availability/acl.js +0 -16
  24. package/dist/modules/availability/acl.js.map +0 -7
  25. package/dist/modules/availability/api/check/route.js +0 -95
  26. package/dist/modules/availability/api/check/route.js.map +0 -7
  27. package/dist/modules/availability/api/openapi.js +0 -27
  28. package/dist/modules/availability/api/openapi.js.map +0 -7
  29. package/dist/modules/availability/api/policies/resolve-preview/route.js +0 -58
  30. package/dist/modules/availability/api/policies/resolve-preview/route.js.map +0 -7
  31. package/dist/modules/availability/api/policies/route.js +0 -188
  32. package/dist/modules/availability/api/policies/route.js.map +0 -7
  33. package/dist/modules/availability/backend/availability/check/page.js +0 -185
  34. package/dist/modules/availability/backend/availability/check/page.js.map +0 -7
  35. package/dist/modules/availability/backend/availability/check/page.meta.js +0 -16
  36. package/dist/modules/availability/backend/availability/check/page.meta.js.map +0 -7
  37. package/dist/modules/availability/backend/availability/policies/ResolutionPreviewPanel.js +0 -79
  38. package/dist/modules/availability/backend/availability/policies/ResolutionPreviewPanel.js.map +0 -7
  39. package/dist/modules/availability/backend/availability/policies/ScopeFields.js +0 -53
  40. package/dist/modules/availability/backend/availability/policies/ScopeFields.js.map +0 -7
  41. package/dist/modules/availability/backend/availability/policies/[id]/page.js +0 -152
  42. package/dist/modules/availability/backend/availability/policies/[id]/page.js.map +0 -7
  43. package/dist/modules/availability/backend/availability/policies/[id]/page.meta.js +0 -12
  44. package/dist/modules/availability/backend/availability/policies/[id]/page.meta.js.map +0 -7
  45. package/dist/modules/availability/backend/availability/policies/create/page.js +0 -94
  46. package/dist/modules/availability/backend/availability/policies/create/page.js.map +0 -7
  47. package/dist/modules/availability/backend/availability/policies/create/page.meta.js +0 -12
  48. package/dist/modules/availability/backend/availability/policies/create/page.meta.js.map +0 -7
  49. package/dist/modules/availability/backend/availability/policies/formGroups.js +0 -75
  50. package/dist/modules/availability/backend/availability/policies/formGroups.js.map +0 -7
  51. package/dist/modules/availability/backend/availability/policies/page.js +0 -176
  52. package/dist/modules/availability/backend/availability/policies/page.js.map +0 -7
  53. package/dist/modules/availability/backend/availability/policies/page.meta.js +0 -16
  54. package/dist/modules/availability/backend/availability/policies/page.meta.js.map +0 -7
  55. package/dist/modules/availability/commands/policies.js +0 -312
  56. package/dist/modules/availability/commands/policies.js.map +0 -7
  57. package/dist/modules/availability/commands/scope.js +0 -19
  58. package/dist/modules/availability/commands/scope.js.map +0 -7
  59. package/dist/modules/availability/data/entities.js +0 -95
  60. package/dist/modules/availability/data/entities.js.map +0 -7
  61. package/dist/modules/availability/data/validators.js +0 -53
  62. package/dist/modules/availability/data/validators.js.map +0 -7
  63. package/dist/modules/availability/di.js +0 -41
  64. package/dist/modules/availability/di.js.map +0 -7
  65. package/dist/modules/availability/events.js +0 -18
  66. package/dist/modules/availability/events.js.map +0 -7
  67. package/dist/modules/availability/index.js +0 -15
  68. package/dist/modules/availability/index.js.map +0 -7
  69. package/dist/modules/availability/lib/policyResolution.js +0 -155
  70. package/dist/modules/availability/lib/policyResolution.js.map +0 -7
  71. package/dist/modules/availability/lib/tryResolve.js +0 -11
  72. package/dist/modules/availability/lib/tryResolve.js.map +0 -7
  73. package/dist/modules/availability/migrations/Migration20260922095844_availability.js +0 -16
  74. package/dist/modules/availability/migrations/Migration20260922095844_availability.js.map +0 -7
  75. package/dist/modules/availability/setup.js +0 -12
  76. package/dist/modules/availability/setup.js.map +0 -7
  77. package/dist/modules/wms/lib/availabilityCache.js +0 -85
  78. package/dist/modules/wms/lib/availabilityCache.js.map +0 -7
  79. package/dist/modules/wms/lib/availabilityCalculation.js +0 -178
  80. package/dist/modules/wms/lib/availabilityCalculation.js.map +0 -7
  81. package/dist/modules/wms/lib/availabilityProvider.js +0 -14
  82. package/dist/modules/wms/lib/availabilityProvider.js.map +0 -7
  83. package/dist/modules/wms/lib/sqlInClause.js +0 -9
  84. package/dist/modules/wms/lib/sqlInClause.js.map +0 -7
  85. package/dist/modules/wms/lib/tryResolve.js +0 -11
  86. package/dist/modules/wms/lib/tryResolve.js.map +0 -7
  87. package/dist/modules/wms/subscribers/invalidate-availability-cache.js +0 -16
  88. package/dist/modules/wms/subscribers/invalidate-availability-cache.js.map +0 -7
  89. package/generated/entities/availability_policy/index.ts +0 -19
  90. package/src/modules/availability/acl.ts +0 -12
  91. package/src/modules/availability/api/check/route.ts +0 -114
  92. package/src/modules/availability/api/openapi.ts +0 -28
  93. package/src/modules/availability/api/policies/resolve-preview/route.ts +0 -67
  94. package/src/modules/availability/api/policies/route.ts +0 -224
  95. package/src/modules/availability/backend/availability/check/page.meta.ts +0 -12
  96. package/src/modules/availability/backend/availability/check/page.tsx +0 -223
  97. package/src/modules/availability/backend/availability/policies/ResolutionPreviewPanel.tsx +0 -106
  98. package/src/modules/availability/backend/availability/policies/ScopeFields.tsx +0 -55
  99. package/src/modules/availability/backend/availability/policies/[id]/page.meta.ts +0 -8
  100. package/src/modules/availability/backend/availability/policies/[id]/page.tsx +0 -182
  101. package/src/modules/availability/backend/availability/policies/create/page.meta.ts +0 -8
  102. package/src/modules/availability/backend/availability/policies/create/page.tsx +0 -105
  103. package/src/modules/availability/backend/availability/policies/formGroups.ts +0 -77
  104. package/src/modules/availability/backend/availability/policies/page.meta.ts +0 -12
  105. package/src/modules/availability/backend/availability/policies/page.tsx +0 -196
  106. package/src/modules/availability/commands/policies.ts +0 -358
  107. package/src/modules/availability/commands/scope.ts +0 -26
  108. package/src/modules/availability/data/entities.ts +0 -92
  109. package/src/modules/availability/data/validators.ts +0 -70
  110. package/src/modules/availability/di.ts +0 -54
  111. package/src/modules/availability/events.ts +0 -17
  112. package/src/modules/availability/i18n/de.json +0 -81
  113. package/src/modules/availability/i18n/en.json +0 -81
  114. package/src/modules/availability/i18n/es.json +0 -81
  115. package/src/modules/availability/i18n/ko.json +0 -81
  116. package/src/modules/availability/i18n/pl.json +0 -81
  117. package/src/modules/availability/index.ts +0 -13
  118. package/src/modules/availability/lib/policyResolution.ts +0 -264
  119. package/src/modules/availability/lib/tryResolve.ts +0 -8
  120. package/src/modules/availability/migrations/.snapshot-open-mercato.json +0 -375
  121. package/src/modules/availability/migrations/Migration20260922095844_availability.ts +0 -13
  122. package/src/modules/availability/setup.ts +0 -10
  123. package/src/modules/wms/lib/availabilityCache.ts +0 -136
  124. package/src/modules/wms/lib/availabilityCalculation.ts +0 -289
  125. package/src/modules/wms/lib/availabilityProvider.ts +0 -29
  126. package/src/modules/wms/lib/sqlInClause.ts +0 -21
  127. package/src/modules/wms/lib/tryResolve.ts +0 -8
  128. package/src/modules/wms/subscribers/invalidate-availability-cache.ts +0 -30
@@ -1,188 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { z } from "zod";
3
- import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
4
- import { AvailabilityPolicy } from "../../data/entities.js";
5
- import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
6
- import { resolveActiveOrganizationId, organizationScopeRequiredResponse } from "@open-mercato/shared/lib/auth/organizationScope";
7
- import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
8
- import { availabilityPolicyCreateSchema, availabilityPolicyUpdateSchema } from "../../data/validators.js";
9
- import {
10
- createAvailabilityCrudOpenApi,
11
- createPagedListResponseSchema,
12
- defaultOkResponseSchema
13
- } from "../openapi.js";
14
- const routeMetadata = {
15
- GET: { requireAuth: true, requireFeatures: ["availability.policies.view"] },
16
- POST: { requireAuth: true, requireFeatures: ["availability.policies.manage"] },
17
- PUT: { requireAuth: true, requireFeatures: ["availability.policies.manage"] },
18
- DELETE: { requireAuth: true, requireFeatures: ["availability.policies.manage"] }
19
- };
20
- const metadata = routeMetadata;
21
- const rawBodySchema = z.object({}).loose();
22
- const crud = makeCrudRoute({
23
- metadata: routeMetadata,
24
- orm: {
25
- entity: AvailabilityPolicy,
26
- idField: "id",
27
- orgField: "organizationId",
28
- tenantField: "tenantId",
29
- softDeleteField: "deletedAt"
30
- },
31
- events: {
32
- module: "availability",
33
- entity: "policy",
34
- persistent: true
35
- },
36
- actions: {
37
- create: {
38
- commandId: "availability.policies.create",
39
- schema: rawBodySchema,
40
- mapInput: ({ parsed }) => parsed,
41
- response: ({ result }) => ({ id: String(result.policyId) }),
42
- status: 201
43
- },
44
- update: {
45
- commandId: "availability.policies.update",
46
- schema: rawBodySchema,
47
- mapInput: ({ parsed }) => parsed,
48
- response: () => ({ ok: true })
49
- },
50
- delete: {
51
- commandId: "availability.policies.delete",
52
- schema: rawBodySchema,
53
- mapInput: ({ raw, ctx }) => ({
54
- id: raw.query?.id,
55
- organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? void 0,
56
- tenantId: ctx.auth?.tenantId ?? void 0
57
- }),
58
- response: () => ({ ok: true })
59
- }
60
- }
61
- });
62
- const listQuerySchema = z.object({
63
- id: z.uuid().optional(),
64
- page: z.coerce.number().min(1).default(1),
65
- pageSize: z.coerce.number().min(1).max(100).default(50),
66
- storeId: z.uuid().optional(),
67
- productId: z.uuid().optional(),
68
- variantId: z.uuid().optional(),
69
- isActive: z.enum(["true", "false"]).optional(),
70
- sortField: z.enum(["createdAt", "updatedAt"]).optional(),
71
- sortDir: z.enum(["asc", "desc"]).optional()
72
- }).loose();
73
- const toRow = (policy) => ({
74
- id: String(policy.id),
75
- organizationId: String(policy.organizationId),
76
- tenantId: String(policy.tenantId),
77
- storeId: policy.storeId ?? null,
78
- productId: policy.productId ?? null,
79
- variantId: policy.variantId ?? null,
80
- isStockManaged: !!policy.isStockManaged,
81
- allowBackorder: !!policy.allowBackorder,
82
- backorderLeadTimeDays: policy.backorderLeadTimeDays ?? null,
83
- preorderReleaseAt: policy.preorderReleaseAt ? policy.preorderReleaseAt.toISOString() : null,
84
- lowStockThreshold: policy.lowStockThreshold ?? null,
85
- minOrderQuantity: policy.minOrderQuantity ?? null,
86
- maxOrderQuantity: policy.maxOrderQuantity ?? null,
87
- quantityIncrement: policy.quantityIncrement ?? null,
88
- hideWhenOutOfStock: !!policy.hideWhenOutOfStock,
89
- isActive: !!policy.isActive,
90
- createdAt: policy.createdAt ? policy.createdAt.toISOString() : null,
91
- updatedAt: policy.updatedAt ? policy.updatedAt.toISOString() : null
92
- });
93
- async function GET(req) {
94
- const auth = await getAuthFromRequest(req);
95
- if (!auth || !auth.tenantId) {
96
- return NextResponse.json({ items: [], total: 0, page: 1, pageSize: 50, totalPages: 1 }, { status: 401 });
97
- }
98
- const organizationId = resolveActiveOrganizationId(auth);
99
- if (!organizationId && !auth.isSuperAdmin) return organizationScopeRequiredResponse();
100
- const url = new URL(req.url);
101
- const parsed = listQuerySchema.safeParse({
102
- id: url.searchParams.get("id") ?? void 0,
103
- page: url.searchParams.get("page") ?? void 0,
104
- pageSize: url.searchParams.get("pageSize") ?? void 0,
105
- storeId: url.searchParams.get("storeId") ?? void 0,
106
- productId: url.searchParams.get("productId") ?? void 0,
107
- variantId: url.searchParams.get("variantId") ?? void 0,
108
- isActive: url.searchParams.get("isActive") ?? void 0,
109
- sortField: url.searchParams.get("sortField") ?? void 0,
110
- sortDir: url.searchParams.get("sortDir") ?? void 0
111
- });
112
- if (!parsed.success) {
113
- return NextResponse.json({ items: [], total: 0, page: 1, pageSize: 50, totalPages: 1 }, { status: 400 });
114
- }
115
- const container = await createRequestContainer();
116
- const em = container.resolve("em");
117
- const { id, page, pageSize, storeId, productId, variantId, isActive, sortField, sortDir } = parsed.data;
118
- const filter = {
119
- tenantId: auth.tenantId,
120
- deletedAt: null
121
- };
122
- if (organizationId) filter.organizationId = organizationId;
123
- if (id) filter.id = id;
124
- if (storeId) filter.storeId = storeId;
125
- if (productId) filter.productId = productId;
126
- if (variantId) filter.variantId = variantId;
127
- if (isActive === "true") filter.isActive = true;
128
- if (isActive === "false") filter.isActive = false;
129
- const orderBy = {};
130
- orderBy[sortField ?? "createdAt"] = sortDir === "asc" ? "ASC" : "DESC";
131
- const offset = (page - 1) * pageSize;
132
- const [rows, total] = await em.findAndCount(AvailabilityPolicy, filter, { orderBy, limit: pageSize, offset });
133
- const items = rows.map(toRow);
134
- const totalPages = Math.max(1, Math.ceil(total / pageSize));
135
- return NextResponse.json({ items, total, page, pageSize, totalPages });
136
- }
137
- const POST = crud.POST;
138
- const PUT = crud.PUT;
139
- const DELETE = crud.DELETE;
140
- const availabilityPolicyListItemSchema = z.object({
141
- id: z.uuid(),
142
- organizationId: z.uuid(),
143
- tenantId: z.uuid(),
144
- storeId: z.uuid().nullable(),
145
- productId: z.uuid().nullable(),
146
- variantId: z.uuid().nullable(),
147
- isStockManaged: z.boolean(),
148
- allowBackorder: z.boolean(),
149
- backorderLeadTimeDays: z.number().nullable(),
150
- preorderReleaseAt: z.string().nullable(),
151
- lowStockThreshold: z.number().nullable(),
152
- minOrderQuantity: z.number().nullable(),
153
- maxOrderQuantity: z.number().nullable(),
154
- quantityIncrement: z.number().nullable(),
155
- hideWhenOutOfStock: z.boolean(),
156
- isActive: z.boolean(),
157
- createdAt: z.string().nullable(),
158
- updatedAt: z.string().nullable()
159
- });
160
- const openApi = createAvailabilityCrudOpenApi({
161
- resourceName: "AvailabilityPolicy",
162
- pluralName: "AvailabilityPolicies",
163
- querySchema: listQuerySchema,
164
- listResponseSchema: createPagedListResponseSchema(availabilityPolicyListItemSchema),
165
- create: {
166
- schema: availabilityPolicyCreateSchema,
167
- description: "Creates a new availability policy."
168
- },
169
- update: {
170
- schema: availabilityPolicyUpdateSchema,
171
- responseSchema: defaultOkResponseSchema,
172
- description: "Updates an existing availability policy by id."
173
- },
174
- del: {
175
- schema: z.object({ id: z.string().uuid() }),
176
- responseSchema: defaultOkResponseSchema,
177
- description: "Deletes an availability policy by id."
178
- }
179
- });
180
- export {
181
- DELETE,
182
- GET,
183
- POST,
184
- PUT,
185
- metadata,
186
- openApi
187
- };
188
- //# sourceMappingURL=route.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 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 { resolveActiveOrganizationId, organizationScopeRequiredResponse } from '@open-mercato/shared/lib/auth/organizationScope'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { availabilityPolicyCreateSchema, availabilityPolicyUpdateSchema } from '../../data/validators'\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\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,\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 organizationId = resolveActiveOrganizationId(auth)\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 container = await createRequestContainer()\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 em.findAndCount(AvailabilityPolicy, filter, { orderBy, limit: pageSize, offset })\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(),\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\nexport const openApi = 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 schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes an availability policy by id.',\n },\n})\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,185 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { Page, PageBody } from "@open-mercato/ui/backend/Page";
5
- import { Input } from "@open-mercato/ui/primitives/input";
6
- import { Label } from "@open-mercato/ui/primitives/label";
7
- import { Button } from "@open-mercato/ui/primitives/button";
8
- import { StatusBadge } from "@open-mercato/ui/primitives/status-badge";
9
- import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
10
- import { useT } from "@open-mercato/shared/lib/i18n/context";
11
- const STATE_VARIANTS = {
12
- in_stock: "success",
13
- low_stock: "warning",
14
- out_of_stock: "error",
15
- backorder: "info",
16
- preorder: "info",
17
- not_tracked: "neutral"
18
- };
19
- const TRACE_FIELDS = [
20
- "isStockManaged",
21
- "allowBackorder",
22
- "backorderLeadTimeDays",
23
- "preorderReleaseAt",
24
- "lowStockThreshold",
25
- "minOrderQuantity",
26
- "maxOrderQuantity",
27
- "quantityIncrement",
28
- "hideWhenOutOfStock",
29
- "isActive"
30
- ];
31
- function formatTraceValue(value, t) {
32
- if (value === null || value === void 0) return t("availability.policies.form.preview.notSet");
33
- if (typeof value === "boolean") return value ? t("common.yes") : t("common.no");
34
- return String(value);
35
- }
36
- function AvailabilityCheckPage() {
37
- const t = useT();
38
- const [productId, setProductId] = React.useState("");
39
- const [variantId, setVariantId] = React.useState("");
40
- const [storeId, setStoreId] = React.useState("");
41
- const [quantity, setQuantity] = React.useState("1");
42
- const [isRunning, setIsRunning] = React.useState(false);
43
- const [error, setError] = React.useState(null);
44
- const [result, setResult] = React.useState(null);
45
- const runCheck = React.useCallback(async () => {
46
- if (!productId.trim()) {
47
- setError(t("availability.check.errors.productRequired"));
48
- return;
49
- }
50
- setIsRunning(true);
51
- setError(null);
52
- setResult(null);
53
- try {
54
- const call = await apiCall(
55
- "/api/availability/check",
56
- {
57
- method: "POST",
58
- body: JSON.stringify({
59
- productId: productId.trim(),
60
- variantId: variantId.trim() || null,
61
- storeId: storeId.trim() || null,
62
- quantity: Number(quantity) > 0 ? Number(quantity) : 1
63
- })
64
- },
65
- { fallback: null }
66
- );
67
- if (!call.ok) {
68
- const errorPayload = call.result;
69
- setError(typeof errorPayload?.error === "string" ? errorPayload.error : t("availability.check.errors.failed"));
70
- return;
71
- }
72
- setResult(call.result ?? null);
73
- } catch (e) {
74
- setError(e instanceof Error ? e.message : t("availability.check.errors.failed"));
75
- } finally {
76
- setIsRunning(false);
77
- }
78
- }, [productId, variantId, storeId, quantity, t]);
79
- const availability = result?.availability ?? null;
80
- const policyTrace = result?.policyTrace ?? null;
81
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsxs(
82
- "div",
83
- {
84
- className: "space-y-6",
85
- onKeyDown: (event) => {
86
- if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
87
- event.preventDefault();
88
- void runCheck();
89
- }
90
- },
91
- children: [
92
- /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: t("availability.check.title") }),
93
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 rounded-md border p-4 sm:grid-cols-4", children: [
94
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
95
- /* @__PURE__ */ jsx(Label, { htmlFor: "availability-check-product-id", children: t("availability.policies.form.field.productId") }),
96
- /* @__PURE__ */ jsx(
97
- Input,
98
- {
99
- id: "availability-check-product-id",
100
- value: productId,
101
- onChange: (e) => setProductId(e.target.value),
102
- autoFocus: true
103
- }
104
- )
105
- ] }),
106
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
107
- /* @__PURE__ */ jsx(Label, { htmlFor: "availability-check-variant-id", children: t("availability.policies.form.field.variantId") }),
108
- /* @__PURE__ */ jsx(Input, { id: "availability-check-variant-id", value: variantId, onChange: (e) => setVariantId(e.target.value) })
109
- ] }),
110
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
111
- /* @__PURE__ */ jsx(Label, { htmlFor: "availability-check-store-id", children: t("availability.policies.form.field.storeId") }),
112
- /* @__PURE__ */ jsx(Input, { id: "availability-check-store-id", value: storeId, onChange: (e) => setStoreId(e.target.value) })
113
- ] }),
114
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
115
- /* @__PURE__ */ jsx(Label, { htmlFor: "availability-check-quantity", children: t("availability.check.field.quantity") }),
116
- /* @__PURE__ */ jsx(
117
- Input,
118
- {
119
- id: "availability-check-quantity",
120
- type: "number",
121
- min: 1,
122
- value: quantity,
123
- onChange: (e) => setQuantity(e.target.value)
124
- }
125
- )
126
- ] })
127
- ] }),
128
- /* @__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: [
131
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
132
- /* @__PURE__ */ jsx(StatusBadge, { variant: STATE_VARIANTS[availability.state], children: t(`availability.states.${availability.state}`) }),
133
- !availability.isAuthoritative && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("availability.check.advisoryNote") })
134
- ] }),
135
- /* @__PURE__ */ jsxs("dl", { className: "grid grid-cols-1 gap-2 sm:grid-cols-3", children: [
136
- /* @__PURE__ */ jsxs("div", { children: [
137
- /* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: t("availability.check.result.availableQuantity") }),
138
- /* @__PURE__ */ jsx("dd", { className: "text-sm", children: availability.availableQuantity ?? t("availability.policies.form.preview.notSet") })
139
- ] }),
140
- /* @__PURE__ */ jsxs("div", { children: [
141
- /* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: t("availability.check.result.canFulfil") }),
142
- /* @__PURE__ */ jsx("dd", { className: "text-sm", children: availability.canFulfil ? t("common.yes") : t("common.no") })
143
- ] }),
144
- /* @__PURE__ */ jsxs("div", { children: [
145
- /* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: t("availability.check.result.policySourceId") }),
146
- /* @__PURE__ */ jsx("dd", { className: "text-sm", children: availability.policySourceId ?? t("availability.policies.form.preview.moduleDefault") })
147
- ] }),
148
- availability.leadTimeDays != null && /* @__PURE__ */ jsxs("div", { children: [
149
- /* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: t("availability.policies.form.field.backorderLeadTimeDays") }),
150
- /* @__PURE__ */ jsx("dd", { className: "text-sm", children: availability.leadTimeDays })
151
- ] }),
152
- availability.releaseAt && /* @__PURE__ */ jsxs("div", { children: [
153
- /* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: t("availability.policies.form.field.preorderReleaseAt") }),
154
- /* @__PURE__ */ jsx("dd", { className: "text-sm", children: availability.releaseAt })
155
- ] })
156
- ] }),
157
- availability.state === "not_tracked" && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("availability.check.notTrackedExplanation") })
158
- ] }),
159
- policyTrace && /* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-muted p-4", "data-testid": "availability-check-policy-trace", children: [
160
- /* @__PURE__ */ jsx("div", { className: "mb-2 text-sm font-medium", children: t("availability.policies.form.preview.title") }),
161
- /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: TRACE_FIELDS.map((key) => {
162
- const field = policyTrace[key];
163
- const source = field?.policySourceId ?? t("availability.policies.form.preview.moduleDefault");
164
- return /* @__PURE__ */ jsxs("div", { children: [
165
- /* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: t(`availability.policies.form.field.${key}`) }),
166
- /* @__PURE__ */ jsxs("dd", { className: "text-xs", children: [
167
- formatTraceValue(field?.value, t),
168
- " ",
169
- /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
170
- "(",
171
- source,
172
- ")"
173
- ] })
174
- ] })
175
- ] }, key);
176
- }) })
177
- ] })
178
- ]
179
- }
180
- ) }) });
181
- }
182
- export {
183
- AvailabilityCheckPage as default
184
- };
185
- //# sourceMappingURL=page.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 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('common.yes') : t('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('common.yes') : t('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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",
6
- "names": []
7
- }
@@ -1,16 +0,0 @@
1
- const metadata = {
2
- requireAuth: true,
3
- requireFeatures: ["availability.check"],
4
- pageTitle: "Availability Check",
5
- pageTitleKey: "availability.check.nav.title",
6
- pageGroup: "Availability",
7
- pageGroupKey: "availability.nav.group",
8
- pageOrder: 20,
9
- pageContext: "settings",
10
- icon: "search",
11
- breadcrumb: [{ label: "Availability Check", labelKey: "availability.check.nav.title" }]
12
- };
13
- export {
14
- metadata
15
- };
16
- //# sourceMappingURL=page.meta.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../../src/modules/availability/backend/availability/check/page.meta.ts"],
4
- "sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['availability.check'],\n pageTitle: 'Availability Check',\n pageTitleKey: 'availability.check.nav.title',\n pageGroup: 'Availability',\n pageGroupKey: 'availability.nav.group',\n pageOrder: 20,\n pageContext: 'settings' as const,\n icon: 'search',\n breadcrumb: [{ label: 'Availability Check', labelKey: 'availability.check.nav.title' }],\n}\n"],
5
- "mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,oBAAoB;AAAA,EACtC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,aAAa;AAAA,EACb,MAAM;AAAA,EACN,YAAY,CAAC,EAAE,OAAO,sBAAsB,UAAU,+BAA+B,CAAC;AACxF;",
6
- "names": []
7
- }
@@ -1,79 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
5
- import { useT } from "@open-mercato/shared/lib/i18n/context";
6
- const TRACE_FIELDS = [
7
- { key: "isStockManaged", labelKey: "availability.policies.form.field.isStockManaged" },
8
- { key: "allowBackorder", labelKey: "availability.policies.form.field.allowBackorder" },
9
- { key: "backorderLeadTimeDays", labelKey: "availability.policies.form.field.backorderLeadTimeDays" },
10
- { key: "preorderReleaseAt", labelKey: "availability.policies.form.field.preorderReleaseAt" },
11
- { key: "lowStockThreshold", labelKey: "availability.policies.form.field.lowStockThreshold" },
12
- { key: "minOrderQuantity", labelKey: "availability.policies.form.field.minOrderQuantity" },
13
- { key: "maxOrderQuantity", labelKey: "availability.policies.form.field.maxOrderQuantity" },
14
- { key: "quantityIncrement", labelKey: "availability.policies.form.field.quantityIncrement" },
15
- { key: "hideWhenOutOfStock", labelKey: "availability.policies.form.field.hideWhenOutOfStock" },
16
- { key: "isActive", labelKey: "availability.policies.form.field.isActive" }
17
- ];
18
- function formatValue(value, t) {
19
- if (value === null || value === void 0) return t("availability.policies.form.preview.notSet");
20
- if (typeof value === "boolean") return value ? t("common.yes") : t("common.no");
21
- return String(value);
22
- }
23
- function ResolutionPreviewPanel({
24
- productId,
25
- variantId,
26
- storeId
27
- }) {
28
- const t = useT();
29
- const [trace, setTrace] = React.useState(null);
30
- const [isLoading, setIsLoading] = React.useState(false);
31
- React.useEffect(() => {
32
- if (!productId) {
33
- setTrace(null);
34
- return;
35
- }
36
- let cancelled = false;
37
- const handle = setTimeout(() => {
38
- setIsLoading(true);
39
- const params = new URLSearchParams({ productId });
40
- if (variantId) params.set("variantId", variantId);
41
- if (storeId) params.set("storeId", storeId);
42
- apiCall(`/api/availability/policies/resolve-preview?${params.toString()}`, void 0, { fallback: null }).then((call) => {
43
- if (!cancelled && call.ok) setTrace(call.result?.policyTrace ?? null);
44
- }).finally(() => {
45
- if (!cancelled) setIsLoading(false);
46
- });
47
- }, 300);
48
- return () => {
49
- cancelled = true;
50
- clearTimeout(handle);
51
- };
52
- }, [productId, variantId, storeId]);
53
- if (!productId) {
54
- return /* @__PURE__ */ jsx("div", { className: "rounded-md border bg-muted p-4 text-sm text-muted-foreground", "data-testid": "availability-resolution-preview", children: t("availability.policies.form.preview.enterProduct") });
55
- }
56
- return /* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-muted p-4 text-sm", "data-testid": "availability-resolution-preview", children: [
57
- /* @__PURE__ */ jsx("div", { className: "mb-2 font-medium", children: t("availability.policies.form.preview.title") }),
58
- isLoading && !trace ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: t("common.loading") }) : /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: TRACE_FIELDS.map(({ key, labelKey }) => {
59
- const field = trace?.[key];
60
- const source = field?.policySourceId ?? t("availability.policies.form.preview.moduleDefault");
61
- return /* @__PURE__ */ jsxs("div", { children: [
62
- /* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: t(labelKey) }),
63
- /* @__PURE__ */ jsxs("dd", { className: "text-xs", children: [
64
- formatValue(field?.value, t),
65
- " ",
66
- /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
67
- "(",
68
- source,
69
- ")"
70
- ] })
71
- ] })
72
- ] }, key);
73
- }) })
74
- ] });
75
- }
76
- export {
77
- ResolutionPreviewPanel
78
- };
79
- //# sourceMappingURL=ResolutionPreviewPanel.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../../src/modules/availability/backend/availability/policies/ResolutionPreviewPanel.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype FieldTrace = { value: unknown; policySourceId: string | null }\ntype PolicyTrace = Record<string, FieldTrace>\n\ntype ResponsePayload = { policyTrace?: PolicyTrace }\n\nconst TRACE_FIELDS: Array<{ key: string; labelKey: string }> = [\n { key: 'isStockManaged', labelKey: 'availability.policies.form.field.isStockManaged' },\n { key: 'allowBackorder', labelKey: 'availability.policies.form.field.allowBackorder' },\n { key: 'backorderLeadTimeDays', labelKey: 'availability.policies.form.field.backorderLeadTimeDays' },\n { key: 'preorderReleaseAt', labelKey: 'availability.policies.form.field.preorderReleaseAt' },\n { key: 'lowStockThreshold', labelKey: 'availability.policies.form.field.lowStockThreshold' },\n { key: 'minOrderQuantity', labelKey: 'availability.policies.form.field.minOrderQuantity' },\n { key: 'maxOrderQuantity', labelKey: 'availability.policies.form.field.maxOrderQuantity' },\n { key: 'quantityIncrement', labelKey: 'availability.policies.form.field.quantityIncrement' },\n { key: 'hideWhenOutOfStock', labelKey: 'availability.policies.form.field.hideWhenOutOfStock' },\n { key: 'isActive', labelKey: 'availability.policies.form.field.isActive' },\n]\n\nfunction formatValue(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('common.yes') : t('common.no')\n return String(value)\n}\n\n/**\n * Live \"resolution-chain preview\" \u2014 US-A2. Shows the currently PERSISTED\n * resolution for the (product, variant, store) target the admin is editing,\n * refetched (debounced) whenever the target changes. Does not simulate the\n * in-progress, unsaved field edits \u2014 see PLAN.md \u00A7 Key design decisions.\n */\nexport function ResolutionPreviewPanel({\n productId,\n variantId,\n storeId,\n}: {\n productId: string\n variantId: string | null\n storeId: string | null\n}) {\n const t = useT()\n const [trace, setTrace] = React.useState<PolicyTrace | null>(null)\n const [isLoading, setIsLoading] = React.useState(false)\n\n React.useEffect(() => {\n if (!productId) {\n setTrace(null)\n return\n }\n let cancelled = false\n const handle = setTimeout(() => {\n setIsLoading(true)\n const params = new URLSearchParams({ productId })\n if (variantId) params.set('variantId', variantId)\n if (storeId) params.set('storeId', storeId)\n apiCall<ResponsePayload>(`/api/availability/policies/resolve-preview?${params.toString()}`, undefined, { fallback: null })\n .then((call) => {\n if (!cancelled && call.ok) setTrace(call.result?.policyTrace ?? null)\n })\n .finally(() => {\n if (!cancelled) setIsLoading(false)\n })\n }, 300)\n return () => {\n cancelled = true\n clearTimeout(handle)\n }\n }, [productId, variantId, storeId])\n\n if (!productId) {\n return (\n <div className=\"rounded-md border bg-muted p-4 text-sm text-muted-foreground\" data-testid=\"availability-resolution-preview\">\n {t('availability.policies.form.preview.enterProduct')}\n </div>\n )\n }\n\n return (\n <div className=\"rounded-md border bg-muted p-4 text-sm\" data-testid=\"availability-resolution-preview\">\n <div className=\"mb-2 font-medium\">{t('availability.policies.form.preview.title')}</div>\n {isLoading && !trace ? (\n <div className=\"text-muted-foreground\">{t('common.loading')}</div>\n ) : (\n <dl className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n {TRACE_FIELDS.map(({ key, labelKey }) => {\n const field = trace?.[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(labelKey)}</dt>\n <dd className=\"text-xs\">\n {formatValue(field?.value, t)}{' '}\n <span className=\"text-muted-foreground\">({source})</span>\n </dd>\n </div>\n )\n })}\n </dl>\n )}\n </div>\n )\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,53 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { Input } from "@open-mercato/ui/primitives/input";
4
- import { Label } from "@open-mercato/ui/primitives/label";
5
- import { useT } from "@open-mercato/shared/lib/i18n/context";
6
- function ScopeFields({ value, onChange, disabled }) {
7
- const t = useT();
8
- return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 rounded-md border p-4 sm:grid-cols-3", children: [
9
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
10
- /* @__PURE__ */ jsx(Label, { htmlFor: "availability-policy-product-id", children: t("availability.policies.form.field.productId") }),
11
- /* @__PURE__ */ jsx(
12
- Input,
13
- {
14
- id: "availability-policy-product-id",
15
- value: value.productId,
16
- disabled,
17
- onChange: (e) => onChange({ ...value, productId: e.target.value.trim() }),
18
- placeholder: t("availability.policies.form.field.productId.placeholder")
19
- }
20
- )
21
- ] }),
22
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
23
- /* @__PURE__ */ jsx(Label, { htmlFor: "availability-policy-variant-id", children: t("availability.policies.form.field.variantId") }),
24
- /* @__PURE__ */ jsx(
25
- Input,
26
- {
27
- id: "availability-policy-variant-id",
28
- value: value.variantId,
29
- disabled,
30
- onChange: (e) => onChange({ ...value, variantId: e.target.value.trim() }),
31
- placeholder: t("availability.policies.form.field.variantId.placeholder")
32
- }
33
- )
34
- ] }),
35
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
36
- /* @__PURE__ */ jsx(Label, { htmlFor: "availability-policy-store-id", children: t("availability.policies.form.field.storeId") }),
37
- /* @__PURE__ */ jsx(
38
- Input,
39
- {
40
- id: "availability-policy-store-id",
41
- value: value.storeId,
42
- disabled,
43
- onChange: (e) => onChange({ ...value, storeId: e.target.value.trim() }),
44
- placeholder: t("availability.policies.form.field.storeId.placeholder")
45
- }
46
- )
47
- ] })
48
- ] });
49
- }
50
- export {
51
- ScopeFields
52
- };
53
- //# sourceMappingURL=ScopeFields.js.map