@open-mercato/core 0.4.6-develop-f7d3079656 → 0.4.6-develop-0861f05ea9

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 (107) hide show
  1. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +17 -154
  2. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +3 -3
  3. package/dist/modules/currencies/backend/exchange-rates/create/page.js +14 -152
  4. package/dist/modules/currencies/backend/exchange-rates/create/page.js.map +2 -2
  5. package/dist/modules/currencies/lib/exchangeRateFormConfig.js +167 -0
  6. package/dist/modules/currencies/lib/exchangeRateFormConfig.js.map +7 -0
  7. package/dist/modules/customers/api/dashboard/widgets/utils.js +1 -34
  8. package/dist/modules/customers/api/dashboard/widgets/utils.js.map +2 -2
  9. package/dist/modules/customers/commands/activities.js +3 -8
  10. package/dist/modules/customers/commands/activities.js.map +2 -2
  11. package/dist/modules/customers/commands/comments.js +2 -8
  12. package/dist/modules/customers/commands/comments.js.map +2 -2
  13. package/dist/modules/dashboards/lib/widgetScope.js +38 -0
  14. package/dist/modules/dashboards/lib/widgetScope.js.map +7 -0
  15. package/dist/modules/entities/lib/makeActivityRoute.js +265 -0
  16. package/dist/modules/entities/lib/makeActivityRoute.js.map +7 -0
  17. package/dist/modules/resources/api/activities.js +24 -232
  18. package/dist/modules/resources/api/activities.js.map +2 -2
  19. package/dist/modules/resources/commands/activities.js +3 -8
  20. package/dist/modules/resources/commands/activities.js.map +2 -2
  21. package/dist/modules/resources/commands/comments.js +2 -8
  22. package/dist/modules/resources/commands/comments.js.map +2 -2
  23. package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js +27 -182
  24. package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js.map +2 -2
  25. package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js +28 -183
  26. package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js.map +2 -2
  27. package/dist/modules/sales/api/order-line-statuses/route.js +15 -194
  28. package/dist/modules/sales/api/order-line-statuses/route.js.map +2 -2
  29. package/dist/modules/sales/api/order-lines/route.js +15 -281
  30. package/dist/modules/sales/api/order-lines/route.js.map +2 -2
  31. package/dist/modules/sales/api/order-statuses/route.js +15 -194
  32. package/dist/modules/sales/api/order-statuses/route.js.map +2 -2
  33. package/dist/modules/sales/api/payment-statuses/route.js +15 -194
  34. package/dist/modules/sales/api/payment-statuses/route.js.map +2 -2
  35. package/dist/modules/sales/api/quote-lines/route.js +15 -279
  36. package/dist/modules/sales/api/quote-lines/route.js.map +2 -2
  37. package/dist/modules/sales/api/shipment-statuses/route.js +15 -194
  38. package/dist/modules/sales/api/shipment-statuses/route.js.map +2 -2
  39. package/dist/modules/sales/components/PaymentMethodsSettings.js +3 -84
  40. package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
  41. package/dist/modules/sales/components/ProviderFieldInput.js +86 -0
  42. package/dist/modules/sales/components/ProviderFieldInput.js.map +7 -0
  43. package/dist/modules/sales/components/ShippingMethodsSettings.js +3 -82
  44. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
  45. package/dist/modules/sales/lib/makeSalesLineRoute.js +308 -0
  46. package/dist/modules/sales/lib/makeSalesLineRoute.js.map +7 -0
  47. package/dist/modules/sales/lib/makeStatusDictionaryRoute.js +206 -0
  48. package/dist/modules/sales/lib/makeStatusDictionaryRoute.js.map +7 -0
  49. package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js +178 -0
  50. package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js.map +7 -0
  51. package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js +1 -39
  52. package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js.map +2 -2
  53. package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js +1 -39
  54. package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js.map +2 -2
  55. package/dist/modules/sales/widgets/dashboard/shared.js +46 -0
  56. package/dist/modules/sales/widgets/dashboard/shared.js.map +7 -0
  57. package/dist/modules/staff/api/activities.js +24 -232
  58. package/dist/modules/staff/api/activities.js.map +2 -2
  59. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +14 -34
  60. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  61. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +15 -34
  62. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  63. package/dist/modules/staff/commands/activities.js +3 -8
  64. package/dist/modules/staff/commands/activities.js.map +2 -2
  65. package/dist/modules/staff/commands/comments.js +2 -8
  66. package/dist/modules/staff/commands/comments.js.map +2 -2
  67. package/dist/modules/staff/lib/leaveRequestHelpers.js +41 -0
  68. package/dist/modules/staff/lib/leaveRequestHelpers.js.map +7 -0
  69. package/package.json +2 -2
  70. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +20 -180
  71. package/src/modules/currencies/backend/exchange-rates/create/page.tsx +16 -175
  72. package/src/modules/currencies/lib/exchangeRateFormConfig.ts +200 -0
  73. package/src/modules/customers/api/dashboard/widgets/utils.ts +1 -53
  74. package/src/modules/customers/commands/activities.ts +2 -8
  75. package/src/modules/customers/commands/comments.ts +2 -8
  76. package/src/modules/dashboards/i18n/de.json +3 -0
  77. package/src/modules/dashboards/i18n/en.json +3 -0
  78. package/src/modules/dashboards/i18n/es.json +3 -0
  79. package/src/modules/dashboards/i18n/pl.json +3 -0
  80. package/src/modules/dashboards/lib/widgetScope.ts +53 -0
  81. package/src/modules/entities/lib/makeActivityRoute.ts +327 -0
  82. package/src/modules/resources/api/activities.ts +25 -269
  83. package/src/modules/resources/commands/activities.ts +2 -7
  84. package/src/modules/resources/commands/comments.ts +2 -8
  85. package/src/modules/sales/api/dashboard/widgets/new-orders/route.ts +29 -244
  86. package/src/modules/sales/api/dashboard/widgets/new-quotes/route.ts +30 -245
  87. package/src/modules/sales/api/order-line-statuses/route.ts +16 -209
  88. package/src/modules/sales/api/order-lines/route.ts +16 -300
  89. package/src/modules/sales/api/order-statuses/route.ts +16 -209
  90. package/src/modules/sales/api/payment-statuses/route.ts +16 -209
  91. package/src/modules/sales/api/quote-lines/route.ts +16 -298
  92. package/src/modules/sales/api/shipment-statuses/route.ts +16 -209
  93. package/src/modules/sales/components/PaymentMethodsSettings.tsx +3 -88
  94. package/src/modules/sales/components/ProviderFieldInput.tsx +85 -0
  95. package/src/modules/sales/components/ShippingMethodsSettings.tsx +3 -86
  96. package/src/modules/sales/lib/makeSalesLineRoute.ts +345 -0
  97. package/src/modules/sales/lib/makeStatusDictionaryRoute.ts +229 -0
  98. package/src/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.ts +247 -0
  99. package/src/modules/sales/widgets/dashboard/new-orders/widget.client.tsx +7 -50
  100. package/src/modules/sales/widgets/dashboard/new-quotes/widget.client.tsx +7 -49
  101. package/src/modules/sales/widgets/dashboard/shared.ts +44 -0
  102. package/src/modules/staff/api/activities.ts +25 -269
  103. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +15 -69
  104. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +16 -65
  105. package/src/modules/staff/commands/activities.ts +2 -7
  106. package/src/modules/staff/commands/comments.ts +2 -8
  107. package/src/modules/staff/lib/leaveRequestHelpers.ts +78 -0
@@ -1,307 +1,23 @@
1
- import { z } from "zod";
2
- import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
- import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
4
- import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
5
- import {
6
- buildCustomFieldFiltersFromQuery,
7
- extractAllCustomFieldEntries,
8
- } from "@open-mercato/shared/lib/crud/custom-fields";
9
1
  import { SalesOrderLine } from "../../data/entities";
10
2
  import { orderLineCreateSchema } from "../../data/validators";
11
- import {
12
- createPagedListResponseSchema,
13
- createSalesCrudOpenApi,
14
- defaultOkResponseSchema,
15
- } from "../openapi";
16
- import { withScopedPayload } from "../utils";
17
3
  import { E } from "#generated/entities.ids.generated";
18
4
  import * as F from "#generated/entities/sales_order_line";
19
- import { canonicalizeUnitCode, REFERENCE_UNIT_CODES } from "@open-mercato/shared/lib/units/unitCodes";
20
-
21
- const rawBodySchema = z.object({}).passthrough();
22
- const resolveRawBody = (raw: unknown): Record<string, unknown> => {
23
- if (!raw || typeof raw !== "object") return {};
24
- if ("body" in raw) {
25
- const payload = raw as { body?: unknown };
26
- if (payload.body && typeof payload.body === "object") {
27
- return payload.body as Record<string, unknown>;
28
- }
29
- }
30
- return raw as Record<string, unknown>;
31
- };
32
-
33
- const listSchema = z
34
- .object({
35
- page: z.coerce.number().min(1).default(1),
36
- pageSize: z.coerce.number().min(1).max(100).default(50),
37
- id: z.string().uuid().optional(),
38
- orderId: z.string().uuid().optional(),
39
- sortField: z.string().optional(),
40
- sortDir: z.enum(["asc", "desc"]).optional(),
41
- })
42
- .passthrough();
43
-
44
- const routeMetadata = {
45
- GET: { requireAuth: true, requireFeatures: ["sales.orders.view"] },
46
- POST: { requireAuth: true, requireFeatures: ["sales.orders.manage"] },
47
- PUT: { requireAuth: true, requireFeatures: ["sales.orders.manage"] },
48
- DELETE: { requireAuth: true, requireFeatures: ["sales.orders.manage"] },
49
- };
50
-
51
- const upsertSchema = orderLineCreateSchema.extend({
52
- id: z.string().uuid().optional(),
53
- });
54
- const deleteSchema = z.object({
55
- id: z.string().uuid(),
56
- orderId: z.string().uuid(),
57
- });
58
-
59
- const crud = makeCrudRoute({
60
- metadata: routeMetadata,
61
- orm: {
62
- entity: SalesOrderLine,
63
- idField: "id",
64
- orgField: "organizationId",
65
- tenantField: "tenantId",
66
- softDeleteField: "deletedAt",
67
- },
68
- indexer: {
69
- entityType: E.sales.sales_order_line,
70
- },
71
- list: {
72
- schema: listSchema,
73
- entityId: E.sales.sales_order_line,
74
- fields: [
75
- F.id,
76
- "order_id",
77
- F.line_number,
78
- F.kind,
79
- F.status_entry_id,
80
- F.status,
81
- F.product_id,
82
- F.product_variant_id,
83
- F.catalog_snapshot,
84
- F.name,
85
- F.description,
86
- F.comment,
87
- F.organization_id,
88
- F.tenant_id,
89
- F.quantity,
90
- F.quantity_unit,
91
- F.normalized_quantity,
92
- F.normalized_unit,
93
- F.uom_snapshot,
94
- F.currency_code,
95
- F.unit_price_net,
96
- F.unit_price_gross,
97
- F.discount_amount,
98
- F.discount_percent,
99
- F.tax_rate,
100
- F.tax_amount,
101
- F.total_net_amount,
102
- F.total_gross_amount,
103
- F.configuration,
104
- F.promotion_code,
105
- F.promotion_snapshot,
106
- F.metadata,
107
- F.custom_field_set_id,
108
- F.created_at,
109
- F.updated_at,
110
- ],
111
- sortFieldMap: {
112
- createdAt: F.created_at,
113
- updatedAt: F.updated_at,
114
- lineNumber: F.line_number,
115
- },
116
- buildFilters: async (query, ctx) => {
117
- const filters: Record<string, unknown> = {};
118
- if (query.id) filters.id = { $eq: query.id };
119
- if (query.orderId) filters.order_id = { $eq: query.orderId };
120
- try {
121
- const em = ctx.container.resolve("em");
122
- const cfFilters = await buildCustomFieldFiltersFromQuery({
123
- entityId: E.sales.sales_order_line,
124
- query,
125
- em,
126
- tenantId: ctx.auth?.tenantId ?? null,
127
- });
128
- Object.assign(filters, cfFilters);
129
- } catch {
130
- // ignore
131
- }
132
- return filters;
133
- },
134
- transformItem: (item: Record<string, unknown> | null | undefined) => {
135
- if (!item) return item;
136
- const normalized = { ...item };
137
- const cfEntries = extractAllCustomFieldEntries(item);
138
- for (const key of Object.keys(normalized)) {
139
- if (key.startsWith("cf:")) delete normalized[key];
140
- }
141
- const quantityUnit = canonicalizeUnitCode(
142
- normalized["quantity_unit"] ?? normalized["quantityUnit"],
143
- );
144
- const normalizedUnit =
145
- canonicalizeUnitCode(
146
- normalized["normalized_unit"] ?? normalized["normalizedUnit"],
147
- ) ?? quantityUnit;
148
- return {
149
- ...normalized,
150
- quantity_unit: quantityUnit,
151
- normalized_unit: normalizedUnit,
152
- ...cfEntries,
153
- };
154
- },
155
- },
156
- actions: {
157
- create: {
158
- commandId: "sales.orders.lines.upsert",
159
- schema: rawBodySchema,
160
- mapInput: async ({ raw, ctx }) => {
161
- const { translate } = await resolveTranslations();
162
- const payload = upsertSchema.parse(
163
- withScopedPayload(resolveRawBody(raw) ?? {}, ctx, translate),
164
- );
165
- return { body: payload };
166
- },
167
- response: ({ result }) => ({
168
- id: result?.lineId ?? null,
169
- orderId: result?.orderId ?? null,
170
- }),
171
- status: 201,
172
- },
173
- update: {
174
- commandId: "sales.orders.lines.upsert",
175
- schema: rawBodySchema,
176
- mapInput: async ({ raw, ctx }) => {
177
- const { translate } = await resolveTranslations();
178
- const payload = upsertSchema.parse(
179
- withScopedPayload(resolveRawBody(raw) ?? {}, ctx, translate),
180
- );
181
- return { body: payload };
182
- },
183
- response: ({ result }) => ({
184
- id: result?.lineId ?? null,
185
- orderId: result?.orderId ?? null,
186
- }),
187
- },
188
- delete: {
189
- commandId: "sales.orders.lines.delete",
190
- schema: rawBodySchema,
191
- mapInput: async ({ raw, ctx }) => {
192
- const { translate } = await resolveTranslations();
193
- const payload = deleteSchema.parse(
194
- withScopedPayload(resolveRawBody(raw) ?? {}, ctx, translate),
195
- );
196
- if (!payload.id || !payload.orderId) {
197
- throw new CrudHttpError(400, {
198
- error: translate(
199
- "sales.documents.detail.error",
200
- "Document not found or inaccessible.",
201
- ),
202
- });
203
- }
204
- return { body: payload };
205
- },
206
- response: () => ({ ok: true }),
207
- },
5
+ import { makeSalesLineRoute } from "../../lib/makeSalesLineRoute";
6
+
7
+ const route = makeSalesLineRoute({
8
+ entity: SalesOrderLine,
9
+ entityId: E.sales.sales_order_line,
10
+ fieldConstants: F,
11
+ parentFkColumn: "order_id",
12
+ parentFkParam: "orderId",
13
+ createSchema: orderLineCreateSchema,
14
+ features: { view: "sales.orders.view", manage: "sales.orders.manage" },
15
+ commandPrefix: "sales.orders.lines",
16
+ openApi: {
17
+ resourceName: "Order line",
18
+ description: "an order line and recalculates totals",
208
19
  },
209
20
  });
210
21
 
211
- const { GET, POST, PUT, DELETE } = crud;
212
-
213
- export { GET, POST, PUT, DELETE };
214
-
215
- const uomSnapshotOpenApiSchema = z
216
- .object({
217
- version: z.literal(1),
218
- productId: z.string().nullable(),
219
- productVariantId: z.string().nullable(),
220
- baseUnitCode: z.string().nullable(),
221
- enteredUnitCode: z.string().nullable(),
222
- enteredQuantity: z.string(),
223
- toBaseFactor: z.string(),
224
- normalizedQuantity: z.string(),
225
- rounding: z.object({
226
- mode: z.enum(["half_up", "down", "up"]),
227
- scale: z.number().int(),
228
- }),
229
- source: z.object({
230
- conversionId: z.string().nullable(),
231
- resolvedAt: z.string(),
232
- }),
233
- unitPriceReference: z
234
- .object({
235
- enabled: z.boolean(),
236
- referenceUnitCode: z.enum(REFERENCE_UNIT_CODES).nullable(),
237
- baseQuantity: z.string().nullable(),
238
- grossPerReference: z.string().nullable().optional(),
239
- netPerReference: z.string().nullable().optional(),
240
- })
241
- .optional(),
242
- })
243
- .nullable()
244
- .optional();
245
-
246
- const orderLineSchema = z.object({
247
- id: z.string().uuid(),
248
- order_id: z.string().uuid(),
249
- line_number: z.number(),
250
- kind: z.string(),
251
- status_entry_id: z.string().uuid().nullable().optional(),
252
- status: z.string().nullable().optional(),
253
- product_id: z.string().uuid().nullable().optional(),
254
- product_variant_id: z.string().uuid().nullable().optional(),
255
- catalog_snapshot: z.record(z.string(), z.unknown()).nullable().optional(),
256
- name: z.string().nullable().optional(),
257
- description: z.string().nullable().optional(),
258
- comment: z.string().nullable().optional(),
259
- quantity: z.number(),
260
- quantity_unit: z.string().nullable().optional(),
261
- normalized_quantity: z.number(),
262
- normalized_unit: z.string().nullable().optional(),
263
- uom_snapshot: uomSnapshotOpenApiSchema,
264
- currency_code: z.string(),
265
- unit_price_net: z.number(),
266
- unit_price_gross: z.number(),
267
- discount_amount: z.number(),
268
- discount_percent: z.number(),
269
- tax_rate: z.number(),
270
- tax_amount: z.number(),
271
- total_net_amount: z.number(),
272
- total_gross_amount: z.number(),
273
- configuration: z.record(z.string(), z.unknown()).nullable().optional(),
274
- promotion_code: z.string().nullable().optional(),
275
- promotion_snapshot: z.record(z.string(), z.unknown()).nullable().optional(),
276
- metadata: z.record(z.string(), z.unknown()).nullable().optional(),
277
- custom_field_set_id: z.string().uuid().nullable().optional(),
278
- created_at: z.string(),
279
- updated_at: z.string(),
280
- });
281
-
282
- export const openApi = createSalesCrudOpenApi({
283
- resourceName: "Order line",
284
- querySchema: listSchema,
285
- listResponseSchema: createPagedListResponseSchema(orderLineSchema),
286
- create: {
287
- schema: upsertSchema,
288
- responseSchema: z.object({
289
- id: z.string().uuid().nullable(),
290
- orderId: z.string().uuid().nullable(),
291
- }),
292
- description: "Creates an order line and recalculates totals.",
293
- },
294
- update: {
295
- schema: upsertSchema,
296
- responseSchema: z.object({
297
- id: z.string().uuid().nullable(),
298
- orderId: z.string().uuid().nullable(),
299
- }),
300
- description: "Updates an order line and recalculates totals.",
301
- },
302
- del: {
303
- schema: deleteSchema,
304
- responseSchema: defaultOkResponseSchema,
305
- description: "Deletes an order line and recalculates totals.",
306
- },
307
- });
22
+ export const { GET, POST, PUT, DELETE } = route;
23
+ export const openApi = route.openApi;
@@ -1,214 +1,21 @@
1
- import { z } from 'zod'
2
- import { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'
3
- import type { EntityManager } from '@mikro-orm/postgresql'
4
- import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
5
- import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
6
- import { Dictionary, DictionaryEntry } from '@open-mercato/core/modules/dictionaries/data/entities'
7
1
  import { E } from '#generated/entities.ids.generated'
8
2
  import * as F from '#generated/entities/dictionary_entry'
9
- import { statusDictionaryCreateSchema, statusDictionaryUpdateSchema } from '../../data/validators'
10
- import { getSalesDictionaryDefinition, ensureSalesDictionary, type SalesDictionaryKind } from '../../lib/dictionaries'
11
- import { parseScopedCommandInput, resolveCrudRecordId } from '../utils'
12
- import {
13
- createPagedListResponseSchema,
14
- createSalesCrudOpenApi,
15
- defaultDeleteRequestSchema,
16
- } from '../openapi'
17
- import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
18
-
19
- const rawBodySchema = z.object({}).passthrough()
20
-
21
- const listSchema = z
22
- .object({
23
- page: z.coerce.number().min(1).default(1),
24
- pageSize: z.coerce.number().min(1).max(100).default(50),
25
- search: z.string().optional(),
26
- sortField: z.string().optional(),
27
- sortDir: z.enum(['asc', 'desc']).optional(),
28
- })
29
- .passthrough()
30
-
31
- const kind: SalesDictionaryKind = 'order-status'
32
- const definition = getSalesDictionaryDefinition(kind)
33
-
34
- export const metadata = {
35
- GET: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },
36
- POST: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },
37
- PUT: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },
38
- DELETE: { requireAuth: true, requireFeatures: ['sales.settings.manage'] },
39
- }
40
-
41
- const dictionaryItemSchema = z.object({
42
- id: z.string().uuid(),
43
- value: z.string(),
44
- label: z.string().nullable(),
45
- color: z.string().nullable(),
46
- icon: z.string().nullable(),
47
- organizationId: z.string().uuid().nullable(),
48
- tenantId: z.string().uuid().nullable(),
49
- createdAt: z.string(),
50
- updatedAt: z.string(),
51
- })
52
-
53
- const dictionaryListResponseSchema = createPagedListResponseSchema(dictionaryItemSchema)
54
-
55
- const normalizeId = (value: unknown): string | null => {
56
- if (typeof value !== 'string') return null
57
- const trimmed = value.trim()
58
- return trimmed.length > 0 ? trimmed : null
59
- }
60
-
61
- async function resolveDictionaryContext(ctx: any): Promise<{ dictionaryId: string; organizationId: string | null }> {
62
- if (!ctx.auth || !ctx.auth.tenantId) {
63
- throw new CrudHttpError(401, { error: 'Tenant context is required.' })
64
- }
65
- const em = ctx.container.resolve('em') as EntityManager
66
- const tenantId: string = ctx.auth.tenantId
67
- const candidateOrgIds = new Set<string>()
68
- const pushCandidate = (value: unknown) => {
69
- const normalized = normalizeId(value)
70
- if (normalized) candidateOrgIds.add(normalized)
71
- }
72
- pushCandidate(ctx.selectedOrganizationId)
73
- pushCandidate(ctx.auth.orgId ?? null)
74
- const scope = ctx.organizationScope
75
- if (scope) {
76
- if (Array.isArray(scope.filterIds)) {
77
- for (const id of scope.filterIds) pushCandidate(id)
78
- }
79
- if (Array.isArray(scope.allowedIds)) {
80
- for (const id of scope.allowedIds) pushCandidate(id)
81
- }
82
- }
83
-
84
- for (const orgId of candidateOrgIds) {
85
- const dictionary = await ensureSalesDictionary({
86
- em,
87
- tenantId,
88
- organizationId: orgId,
89
- kind,
90
- })
91
- if (dictionary) {
92
- return { dictionaryId: dictionary.id, organizationId: orgId }
93
- }
94
- }
95
-
96
- const fallback = await em.findOne(
97
- Dictionary,
98
- {
99
- tenantId,
100
- key: definition.key,
101
- deletedAt: null,
102
- },
103
- { orderBy: { createdAt: 'asc' } },
104
- )
105
- if (fallback) {
106
- return { dictionaryId: fallback.id, organizationId: fallback.organizationId }
107
- }
108
- throw new CrudHttpError(400, { error: 'Organization context is required.' })
109
- }
110
-
111
- const crud = makeCrudRoute({
112
- metadata,
113
- orm: {
114
- entity: DictionaryEntry,
115
- idField: 'id',
116
- orgField: 'organizationId',
117
- tenantField: 'tenantId',
118
- softDeleteField: null,
3
+ import { makeStatusDictionaryRoute } from '../../lib/makeStatusDictionaryRoute'
4
+
5
+ const route = makeStatusDictionaryRoute({
6
+ kind: 'order-status',
7
+ entityId: E.dictionaries.dictionary_entry,
8
+ fieldConstants: F,
9
+ openApi: {
10
+ resourceName: 'Order status',
11
+ pluralName: 'Order statuses',
12
+ description: 'Manage the lifecycle states available for sales orders.',
119
13
  },
120
- list: {
121
- schema: listSchema,
122
- entityId: E.dictionaries.dictionary_entry,
123
- fields: [
124
- F.id,
125
- F.value,
126
- F.label,
127
- F.color,
128
- F.icon,
129
- F.organization_id,
130
- F.tenant_id,
131
- F.created_at,
132
- F.updated_at,
133
- ],
134
- sortFieldMap: {
135
- id: F.id,
136
- value: F.value,
137
- label: F.label,
138
- createdAt: F.created_at,
139
- updatedAt: F.updated_at,
140
- },
141
- buildFilters: async (query, ctx) => {
142
- const { dictionaryId } = await resolveDictionaryContext(ctx)
143
- const filters: Record<string, unknown> = {
144
- dictionary_id: dictionaryId,
145
- }
146
- if (query.search && query.search.trim().length > 0) {
147
- const term = `%${escapeLikePattern(query.search.trim())}%`
148
- filters.$or = [
149
- { [F.value]: { $ilike: term } },
150
- { [F.label]: { $ilike: term } },
151
- ]
152
- }
153
- return filters
154
- },
155
- transformItem: (item: any) => ({
156
- id: item.id,
157
- value: item.value,
158
- label: item.label,
159
- color: item.color ?? null,
160
- icon: item.icon ?? null,
161
- organizationId: item.organization_id ?? null,
162
- tenantId: item.tenant_id ?? null,
163
- createdAt: item.created_at,
164
- updatedAt: item.updated_at,
165
- }),
166
- },
167
- actions: {
168
- create: {
169
- commandId: `${definition.commandPrefix}.create`,
170
- schema: rawBodySchema,
171
- mapInput: async ({ raw, ctx }) => {
172
- const { translate } = await resolveTranslations()
173
- return parseScopedCommandInput(statusDictionaryCreateSchema, raw ?? {}, ctx, translate)
174
- },
175
- response: ({ result }) => ({ id: result?.entryId ?? null }),
176
- status: 201,
177
- },
178
- update: {
179
- commandId: `${definition.commandPrefix}.update`,
180
- schema: rawBodySchema,
181
- mapInput: async ({ raw, ctx }) => {
182
- const { translate } = await resolveTranslations()
183
- return parseScopedCommandInput(statusDictionaryUpdateSchema, raw ?? {}, ctx, translate)
184
- },
185
- response: () => ({ ok: true }),
186
- },
187
- delete: {
188
- commandId: `${definition.commandPrefix}.delete`,
189
- schema: rawBodySchema,
190
- mapInput: async ({ parsed, ctx }) => {
191
- const { translate } = await resolveTranslations()
192
- const id = resolveCrudRecordId(parsed, ctx, translate)
193
- return { id }
194
- },
195
- response: () => ({ ok: true }),
196
- },
197
- },
198
- })
199
-
200
- export const openApi = createSalesCrudOpenApi({
201
- resourceName: 'Order status',
202
- pluralName: 'Order statuses',
203
- description: 'Manage the lifecycle states available for sales orders.',
204
- querySchema: listSchema,
205
- listResponseSchema: dictionaryListResponseSchema,
206
- create: { schema: statusDictionaryCreateSchema },
207
- update: { schema: statusDictionaryUpdateSchema },
208
- del: { schema: defaultDeleteRequestSchema },
209
14
  })
210
15
 
211
- export const GET = crud.GET
212
- export const POST = crud.POST
213
- export const PUT = crud.PUT
214
- export const DELETE = crud.DELETE
16
+ export const metadata = route.metadata
17
+ export const openApi = route.openApi
18
+ export const GET = route.GET
19
+ export const POST = route.POST
20
+ export const PUT = route.PUT
21
+ export const DELETE = route.DELETE