@open-mercato/core 0.4.6-develop-9ff1d4a9a2 → 0.4.6-develop-219dae16c5
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/dist/modules/currencies/backend/exchange-rates/[id]/page.js +17 -154
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +3 -3
- package/dist/modules/currencies/backend/exchange-rates/create/page.js +14 -152
- package/dist/modules/currencies/backend/exchange-rates/create/page.js.map +2 -2
- package/dist/modules/currencies/lib/exchangeRateFormConfig.js +167 -0
- package/dist/modules/currencies/lib/exchangeRateFormConfig.js.map +7 -0
- package/dist/modules/customers/api/dashboard/widgets/utils.js +1 -34
- package/dist/modules/customers/api/dashboard/widgets/utils.js.map +2 -2
- package/dist/modules/customers/commands/activities.js +3 -8
- package/dist/modules/customers/commands/activities.js.map +2 -2
- package/dist/modules/customers/commands/comments.js +2 -8
- package/dist/modules/customers/commands/comments.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetScope.js +38 -0
- package/dist/modules/dashboards/lib/widgetScope.js.map +7 -0
- package/dist/modules/entities/lib/makeActivityRoute.js +265 -0
- package/dist/modules/entities/lib/makeActivityRoute.js.map +7 -0
- package/dist/modules/resources/api/activities.js +24 -232
- package/dist/modules/resources/api/activities.js.map +2 -2
- package/dist/modules/resources/commands/activities.js +3 -8
- package/dist/modules/resources/commands/activities.js.map +2 -2
- package/dist/modules/resources/commands/comments.js +2 -8
- package/dist/modules/resources/commands/comments.js.map +2 -2
- package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js +27 -182
- package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js.map +2 -2
- package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js +28 -183
- package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js.map +2 -2
- package/dist/modules/sales/api/order-line-statuses/route.js +15 -194
- package/dist/modules/sales/api/order-line-statuses/route.js.map +2 -2
- package/dist/modules/sales/api/order-lines/route.js +15 -281
- package/dist/modules/sales/api/order-lines/route.js.map +2 -2
- package/dist/modules/sales/api/order-statuses/route.js +15 -194
- package/dist/modules/sales/api/order-statuses/route.js.map +2 -2
- package/dist/modules/sales/api/payment-statuses/route.js +15 -194
- package/dist/modules/sales/api/payment-statuses/route.js.map +2 -2
- package/dist/modules/sales/api/quote-lines/route.js +15 -279
- package/dist/modules/sales/api/quote-lines/route.js.map +2 -2
- package/dist/modules/sales/api/shipment-statuses/route.js +15 -194
- package/dist/modules/sales/api/shipment-statuses/route.js.map +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js +3 -84
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/ProviderFieldInput.js +86 -0
- package/dist/modules/sales/components/ProviderFieldInput.js.map +7 -0
- package/dist/modules/sales/components/ShippingMethodsSettings.js +3 -82
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
- package/dist/modules/sales/lib/makeSalesLineRoute.js +308 -0
- package/dist/modules/sales/lib/makeSalesLineRoute.js.map +7 -0
- package/dist/modules/sales/lib/makeStatusDictionaryRoute.js +206 -0
- package/dist/modules/sales/lib/makeStatusDictionaryRoute.js.map +7 -0
- package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js +178 -0
- package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js.map +7 -0
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js +1 -39
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js +1 -39
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/shared.js +46 -0
- package/dist/modules/sales/widgets/dashboard/shared.js.map +7 -0
- package/dist/modules/staff/api/activities.js +24 -232
- package/dist/modules/staff/api/activities.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +14 -34
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +15 -34
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/commands/activities.js +3 -8
- package/dist/modules/staff/commands/activities.js.map +2 -2
- package/dist/modules/staff/commands/comments.js +2 -8
- package/dist/modules/staff/commands/comments.js.map +2 -2
- package/dist/modules/staff/lib/leaveRequestHelpers.js +41 -0
- package/dist/modules/staff/lib/leaveRequestHelpers.js.map +7 -0
- package/package.json +2 -2
- package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +20 -180
- package/src/modules/currencies/backend/exchange-rates/create/page.tsx +16 -175
- package/src/modules/currencies/lib/exchangeRateFormConfig.ts +200 -0
- package/src/modules/customers/api/dashboard/widgets/utils.ts +1 -53
- package/src/modules/customers/commands/activities.ts +2 -8
- package/src/modules/customers/commands/comments.ts +2 -8
- package/src/modules/dashboards/i18n/de.json +3 -0
- package/src/modules/dashboards/i18n/en.json +3 -0
- package/src/modules/dashboards/i18n/es.json +3 -0
- package/src/modules/dashboards/i18n/pl.json +3 -0
- package/src/modules/dashboards/lib/widgetScope.ts +53 -0
- package/src/modules/entities/lib/makeActivityRoute.ts +327 -0
- package/src/modules/resources/api/activities.ts +25 -269
- package/src/modules/resources/commands/activities.ts +2 -7
- package/src/modules/resources/commands/comments.ts +2 -8
- package/src/modules/sales/api/dashboard/widgets/new-orders/route.ts +29 -244
- package/src/modules/sales/api/dashboard/widgets/new-quotes/route.ts +30 -245
- package/src/modules/sales/api/order-line-statuses/route.ts +16 -209
- package/src/modules/sales/api/order-lines/route.ts +16 -300
- package/src/modules/sales/api/order-statuses/route.ts +16 -209
- package/src/modules/sales/api/payment-statuses/route.ts +16 -209
- package/src/modules/sales/api/quote-lines/route.ts +16 -298
- package/src/modules/sales/api/shipment-statuses/route.ts +16 -209
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +3 -88
- package/src/modules/sales/components/ProviderFieldInput.tsx +85 -0
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +3 -86
- package/src/modules/sales/lib/makeSalesLineRoute.ts +345 -0
- package/src/modules/sales/lib/makeStatusDictionaryRoute.ts +229 -0
- package/src/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.ts +247 -0
- package/src/modules/sales/widgets/dashboard/new-orders/widget.client.tsx +7 -50
- package/src/modules/sales/widgets/dashboard/new-quotes/widget.client.tsx +7 -49
- package/src/modules/sales/widgets/dashboard/shared.ts +44 -0
- package/src/modules/staff/api/activities.ts +25 -269
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +15 -69
- package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +16 -65
- package/src/modules/staff/commands/activities.ts +2 -7
- package/src/modules/staff/commands/comments.ts +2 -8
- package/src/modules/staff/lib/leaveRequestHelpers.ts +78 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/sales/api/dashboard/widgets/new-orders/route.ts"],
|
|
4
|
-
"sourcesContent": ["import {
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\r\nimport { SalesOrder } from '../../../../data/entities'\r\nimport { extractCustomerName } from '../helpers'\r\nimport { makeDashboardWidgetRoute } from '../../../../widgets/dashboard/makeDashboardWidgetRoute'\r\n\r\nconst orderItemSchema = z.object({\r\n id: z.string().uuid(),\r\n orderNumber: z.string(),\r\n status: z.string().nullable(),\r\n fulfillmentStatus: z.string().nullable(),\r\n paymentStatus: z.string().nullable(),\r\n customerName: z.string().nullable(),\r\n customerEntityId: z.string().uuid().nullable(),\r\n netAmount: z.string(),\r\n grossAmount: z.string(),\r\n currency: z.string().nullable(),\r\n createdAt: z.string(),\r\n})\r\n\r\nconst { GET, metadata, openApi } = makeDashboardWidgetRoute({\r\n entity: SalesOrder,\r\n cacheId: 'sales:new-orders',\r\n cacheTags: ['widget-data:sales:orders'],\r\n feature: 'sales.widgets.new-orders',\r\n itemSchema: orderItemSchema,\r\n errorPrefix: 'sales.widgets.newOrders',\r\n openApi: {\r\n summary: 'New orders dashboard widget',\r\n description: 'Fetches recently created sales orders for the dashboard widget with a configurable date period.',\r\n getSummary: 'Fetch recently created sales orders',\r\n itemDescription: 'List of recent orders',\r\n errorFallback: 'Failed to load orders',\r\n },\r\n mapItem: (order) => ({\r\n id: order.id as string,\r\n orderNumber: order.orderNumber as string,\r\n status: (order.status as string) ?? null,\r\n fulfillmentStatus: (order.fulfillmentStatus as string) ?? null,\r\n paymentStatus: (order.paymentStatus as string) ?? null,\r\n customerName: extractCustomerName(order.customerSnapshot) ?? null,\r\n customerEntityId: (order.customerEntityId as string) ?? null,\r\n netAmount: (order.grandTotalNetAmount as string) ?? '0',\r\n grossAmount: (order.grandTotalGrossAmount as string) ?? '0',\r\n currency: (order.currencyCode as string) ?? null,\r\n createdAt: order.createdAt ? (order.createdAt as Date).toISOString() : new Date().toISOString(),\r\n }),\r\n})\r\n\r\nexport { GET, metadata, openApi }\r\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,kBAAkB;AAC3B,SAAS,2BAA2B;AACpC,SAAS,gCAAgC;AAEzC,MAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,aAAa,EAAE,OAAO;AAAA,EACtB,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,mBAAmB,EAAE,OAAO,EAAE,SAAS;AAAA,EACvC,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,kBAAkB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC7C,WAAW,EAAE,OAAO;AAAA,EACpB,aAAa,EAAE,OAAO;AAAA,EACtB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,WAAW,EAAE,OAAO;AACtB,CAAC;AAED,MAAM,EAAE,KAAK,UAAU,QAAQ,IAAI,yBAAyB;AAAA,EAC1D,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW,CAAC,0BAA0B;AAAA,EACtC,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,SAAS;AAAA,IACP,SAAS;AAAA,IACT,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA,SAAS,CAAC,WAAW;AAAA,IACnB,IAAI,MAAM;AAAA,IACV,aAAa,MAAM;AAAA,IACnB,QAAS,MAAM,UAAqB;AAAA,IACpC,mBAAoB,MAAM,qBAAgC;AAAA,IAC1D,eAAgB,MAAM,iBAA4B;AAAA,IAClD,cAAc,oBAAoB,MAAM,gBAAgB,KAAK;AAAA,IAC7D,kBAAmB,MAAM,oBAA+B;AAAA,IACxD,WAAY,MAAM,uBAAkC;AAAA,IACpD,aAAc,MAAM,yBAAoC;AAAA,IACxD,UAAW,MAAM,gBAA2B;AAAA,IAC5C,WAAW,MAAM,YAAa,MAAM,UAAmB,YAAY,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,EAChG;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,164 +1,7 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { NextResponse } from "next/server";
|
|
3
1
|
import { z } from "zod";
|
|
4
|
-
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
5
|
-
import { runWithCacheTenant } from "@open-mercato/cache";
|
|
6
|
-
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
7
|
-
import { findAndCountWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
8
|
-
import { resolveDateRange } from "@open-mercato/ui/backend/date-range";
|
|
9
2
|
import { SalesQuote } from "../../../../data/entities.js";
|
|
10
3
|
import { extractCustomerName } from "../helpers.js";
|
|
11
|
-
import {
|
|
12
|
-
const WIDGET_CACHE_TTL = 12e4;
|
|
13
|
-
const WIDGET_CACHE_SEGMENT_TTL = 864e5;
|
|
14
|
-
const WIDGET_CACHE_SEGMENT_KEY = "widget-data:__segment__";
|
|
15
|
-
const WIDGET_CACHE_TAGS = ["widget-data", "widget-data:sales:quotes"];
|
|
16
|
-
const WIDGET_CACHE_ID = "sales:new-quotes";
|
|
17
|
-
const querySchema = z.object({
|
|
18
|
-
limit: z.coerce.number().min(1).max(20).default(5),
|
|
19
|
-
datePeriod: z.enum(["last24h", "last7d", "last30d", "custom"]).default("last24h"),
|
|
20
|
-
customFrom: z.string().optional(),
|
|
21
|
-
customTo: z.string().optional(),
|
|
22
|
-
tenantId: z.string().uuid().optional(),
|
|
23
|
-
organizationId: z.string().uuid().optional()
|
|
24
|
-
});
|
|
25
|
-
const metadata = {
|
|
26
|
-
GET: { requireAuth: true, requireFeatures: ["dashboards.view", "sales.widgets.new-quotes"] }
|
|
27
|
-
};
|
|
28
|
-
function normalizeOrganizationIds(organizationIds) {
|
|
29
|
-
if (organizationIds === null) return null;
|
|
30
|
-
const set = new Set(organizationIds);
|
|
31
|
-
return Array.from(set).sort((a, b) => a.localeCompare(b));
|
|
32
|
-
}
|
|
33
|
-
function buildCacheKey(params) {
|
|
34
|
-
const hash = createHash("sha256");
|
|
35
|
-
hash.update(
|
|
36
|
-
JSON.stringify({
|
|
37
|
-
widget: WIDGET_CACHE_ID,
|
|
38
|
-
...params,
|
|
39
|
-
organizationIds: normalizeOrganizationIds(params.organizationIds)
|
|
40
|
-
})
|
|
41
|
-
);
|
|
42
|
-
return `widget-data:${hash.digest("hex").slice(0, 16)}`;
|
|
43
|
-
}
|
|
44
|
-
async function resolveContext(req, translate) {
|
|
45
|
-
const url = new URL(req.url);
|
|
46
|
-
const rawQuery = {};
|
|
47
|
-
for (const [key, value] of url.searchParams.entries()) rawQuery[key] = value;
|
|
48
|
-
const parsed = querySchema.safeParse(rawQuery);
|
|
49
|
-
if (!parsed.success) {
|
|
50
|
-
throw new CrudHttpError(400, { error: translate("sales.errors.invalid_query", "Invalid query parameters") });
|
|
51
|
-
}
|
|
52
|
-
const { container, em, tenantId, organizationIds } = await resolveWidgetScope(req, translate, {
|
|
53
|
-
tenantId: parsed.data.tenantId ?? null,
|
|
54
|
-
organizationId: parsed.data.organizationId ?? null
|
|
55
|
-
});
|
|
56
|
-
return {
|
|
57
|
-
container,
|
|
58
|
-
em,
|
|
59
|
-
tenantId,
|
|
60
|
-
organizationIds,
|
|
61
|
-
limit: parsed.data.limit,
|
|
62
|
-
datePeriod: parsed.data.datePeriod,
|
|
63
|
-
customFrom: parsed.data.customFrom,
|
|
64
|
-
customTo: parsed.data.customTo
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
async function GET(req) {
|
|
68
|
-
const { translate } = await resolveTranslations();
|
|
69
|
-
try {
|
|
70
|
-
const { container, em, tenantId, organizationIds, limit, datePeriod, customFrom, customTo } = await resolveContext(
|
|
71
|
-
req,
|
|
72
|
-
translate
|
|
73
|
-
);
|
|
74
|
-
const range = (() => {
|
|
75
|
-
if (datePeriod === "custom") {
|
|
76
|
-
const from = customFrom ? new Date(customFrom) : /* @__PURE__ */ new Date(0);
|
|
77
|
-
const to = customTo ? new Date(customTo) : /* @__PURE__ */ new Date();
|
|
78
|
-
return { start: from, end: to };
|
|
79
|
-
}
|
|
80
|
-
const preset = datePeriod === "last7d" ? "last_7_days" : datePeriod === "last30d" ? "last_30_days" : "today";
|
|
81
|
-
return resolveDateRange(preset);
|
|
82
|
-
})();
|
|
83
|
-
let cache = null;
|
|
84
|
-
try {
|
|
85
|
-
cache = container.resolve("cache");
|
|
86
|
-
} catch {
|
|
87
|
-
cache = null;
|
|
88
|
-
}
|
|
89
|
-
const cacheKey = buildCacheKey({ tenantId, organizationIds, limit, datePeriod, customFrom, customTo });
|
|
90
|
-
const tenantScope = tenantId ?? null;
|
|
91
|
-
if (cache) {
|
|
92
|
-
try {
|
|
93
|
-
const cached = await runWithCacheTenant(tenantScope, () => cache.get(cacheKey));
|
|
94
|
-
if (cached && typeof cached === "object" && "items" in cached) {
|
|
95
|
-
return NextResponse.json(cached);
|
|
96
|
-
}
|
|
97
|
-
} catch {
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
const where = {
|
|
101
|
-
tenantId,
|
|
102
|
-
deletedAt: null,
|
|
103
|
-
createdAt: { $gte: range.start, $lte: range.end }
|
|
104
|
-
};
|
|
105
|
-
if (Array.isArray(organizationIds)) {
|
|
106
|
-
const unique = Array.from(new Set(organizationIds));
|
|
107
|
-
where.organizationId = unique.length === 1 ? unique[0] : { $in: unique };
|
|
108
|
-
}
|
|
109
|
-
const organizationIdScope = Array.isArray(organizationIds) && organizationIds.length === 1 ? organizationIds[0] : null;
|
|
110
|
-
const [quotes, total] = await findAndCountWithDecryption(
|
|
111
|
-
em,
|
|
112
|
-
SalesQuote,
|
|
113
|
-
where,
|
|
114
|
-
{
|
|
115
|
-
limit,
|
|
116
|
-
orderBy: { createdAt: "desc" }
|
|
117
|
-
},
|
|
118
|
-
{ tenantId, organizationId: organizationIdScope }
|
|
119
|
-
);
|
|
120
|
-
const items = quotes.map((quote) => ({
|
|
121
|
-
id: quote.id,
|
|
122
|
-
quoteNumber: quote.quoteNumber,
|
|
123
|
-
status: quote.status ?? null,
|
|
124
|
-
customerName: extractCustomerName(quote.customerSnapshot) ?? null,
|
|
125
|
-
customerEntityId: quote.customerEntityId ?? null,
|
|
126
|
-
validFrom: quote.validFrom ? quote.validFrom.toISOString() : null,
|
|
127
|
-
validUntil: quote.validUntil ? quote.validUntil.toISOString() : null,
|
|
128
|
-
netAmount: quote.grandTotalNetAmount ?? "0",
|
|
129
|
-
grossAmount: quote.grandTotalGrossAmount ?? "0",
|
|
130
|
-
currency: quote.currencyCode ?? null,
|
|
131
|
-
createdAt: quote.createdAt.toISOString(),
|
|
132
|
-
convertedOrderId: quote.convertedOrderId ?? null
|
|
133
|
-
}));
|
|
134
|
-
const response = {
|
|
135
|
-
items,
|
|
136
|
-
total,
|
|
137
|
-
dateRange: { from: range.start.toISOString(), to: range.end.toISOString() }
|
|
138
|
-
};
|
|
139
|
-
if (cache) {
|
|
140
|
-
try {
|
|
141
|
-
await runWithCacheTenant(tenantScope, () => cache.set(cacheKey, response, { ttl: WIDGET_CACHE_TTL, tags: WIDGET_CACHE_TAGS }));
|
|
142
|
-
await runWithCacheTenant(tenantScope, () => cache.set(
|
|
143
|
-
WIDGET_CACHE_SEGMENT_KEY,
|
|
144
|
-
{ updatedAt: response.dateRange.to },
|
|
145
|
-
{ ttl: WIDGET_CACHE_SEGMENT_TTL, tags: ["widget-data"] }
|
|
146
|
-
));
|
|
147
|
-
} catch {
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return NextResponse.json(response);
|
|
151
|
-
} catch (err) {
|
|
152
|
-
if (err instanceof CrudHttpError) {
|
|
153
|
-
return NextResponse.json(err.body, { status: err.status });
|
|
154
|
-
}
|
|
155
|
-
console.error("sales.widgets.newQuotes failed", err);
|
|
156
|
-
return NextResponse.json(
|
|
157
|
-
{ error: translate("sales.widgets.newQuotes.error", "Failed to load quotes") },
|
|
158
|
-
{ status: 500 }
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
4
|
+
import { makeDashboardWidgetRoute } from "../../../../widgets/dashboard/makeDashboardWidgetRoute.js";
|
|
162
5
|
const quoteItemSchema = z.object({
|
|
163
6
|
id: z.string().uuid(),
|
|
164
7
|
quoteNumber: z.string(),
|
|
@@ -173,33 +16,35 @@ const quoteItemSchema = z.object({
|
|
|
173
16
|
createdAt: z.string(),
|
|
174
17
|
convertedOrderId: z.string().uuid().nullable()
|
|
175
18
|
});
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
19
|
+
const { GET, metadata, openApi } = makeDashboardWidgetRoute({
|
|
20
|
+
entity: SalesQuote,
|
|
21
|
+
cacheId: "sales:new-quotes",
|
|
22
|
+
cacheTags: ["widget-data:sales:quotes"],
|
|
23
|
+
feature: "sales.widgets.new-quotes",
|
|
24
|
+
itemSchema: quoteItemSchema,
|
|
25
|
+
errorPrefix: "sales.widgets.newQuotes",
|
|
26
|
+
openApi: {
|
|
27
|
+
summary: "New quotes dashboard widget",
|
|
28
|
+
description: "Fetches recently created sales quotes for the dashboard widget with a configurable date period.",
|
|
29
|
+
getSummary: "Fetch recently created sales quotes",
|
|
30
|
+
itemDescription: "List of recent quotes",
|
|
31
|
+
errorFallback: "Failed to load quotes"
|
|
32
|
+
},
|
|
33
|
+
mapItem: (quote) => ({
|
|
34
|
+
id: quote.id,
|
|
35
|
+
quoteNumber: quote.quoteNumber,
|
|
36
|
+
status: quote.status ?? null,
|
|
37
|
+
customerName: extractCustomerName(quote.customerSnapshot) ?? null,
|
|
38
|
+
customerEntityId: quote.customerEntityId ?? null,
|
|
39
|
+
validFrom: quote.validFrom ? quote.validFrom.toISOString() : null,
|
|
40
|
+
validUntil: quote.validUntil ? quote.validUntil.toISOString() : null,
|
|
41
|
+
netAmount: quote.grandTotalNetAmount ?? "0",
|
|
42
|
+
grossAmount: quote.grandTotalGrossAmount ?? "0",
|
|
43
|
+
currency: quote.currencyCode ?? null,
|
|
44
|
+
createdAt: quote.createdAt ? quote.createdAt.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
|
|
45
|
+
convertedOrderId: quote.convertedOrderId ?? null
|
|
182
46
|
})
|
|
183
47
|
});
|
|
184
|
-
const widgetErrorSchema = z.object({ error: z.string() });
|
|
185
|
-
const openApi = {
|
|
186
|
-
tag: "Sales",
|
|
187
|
-
summary: "New quotes dashboard widget",
|
|
188
|
-
description: "Fetches recently created sales quotes for the dashboard widget with a configurable date period.",
|
|
189
|
-
methods: {
|
|
190
|
-
GET: {
|
|
191
|
-
summary: "Fetch recently created sales quotes",
|
|
192
|
-
query: querySchema,
|
|
193
|
-
responses: [{ status: 200, description: "List of recent quotes", schema: responseSchema }],
|
|
194
|
-
errors: [
|
|
195
|
-
{ status: 400, description: "Invalid query parameters", schema: widgetErrorSchema },
|
|
196
|
-
{ status: 401, description: "Unauthorized", schema: widgetErrorSchema },
|
|
197
|
-
{ status: 403, description: "Forbidden", schema: widgetErrorSchema },
|
|
198
|
-
{ status: 500, description: "Widget failed to load", schema: widgetErrorSchema }
|
|
199
|
-
]
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
48
|
export {
|
|
204
49
|
GET,
|
|
205
50
|
metadata,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/sales/api/dashboard/widgets/new-quotes/route.ts"],
|
|
4
|
-
"sourcesContent": ["import {
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\r\nimport { SalesQuote } from '../../../../data/entities'\r\nimport { extractCustomerName } from '../helpers'\r\nimport { makeDashboardWidgetRoute } from '../../../../widgets/dashboard/makeDashboardWidgetRoute'\r\n\r\nconst quoteItemSchema = z.object({\r\n id: z.string().uuid(),\r\n quoteNumber: z.string(),\r\n status: z.string().nullable(),\r\n customerName: z.string().nullable(),\r\n customerEntityId: z.string().uuid().nullable(),\r\n validFrom: z.string().nullable(),\r\n validUntil: z.string().nullable(),\r\n netAmount: z.string(),\r\n grossAmount: z.string(),\r\n currency: z.string().nullable(),\r\n createdAt: z.string(),\r\n convertedOrderId: z.string().uuid().nullable(),\r\n})\r\n\r\nconst { GET, metadata, openApi } = makeDashboardWidgetRoute({\r\n entity: SalesQuote,\r\n cacheId: 'sales:new-quotes',\r\n cacheTags: ['widget-data:sales:quotes'],\r\n feature: 'sales.widgets.new-quotes',\r\n itemSchema: quoteItemSchema,\r\n errorPrefix: 'sales.widgets.newQuotes',\r\n openApi: {\r\n summary: 'New quotes dashboard widget',\r\n description: 'Fetches recently created sales quotes for the dashboard widget with a configurable date period.',\r\n getSummary: 'Fetch recently created sales quotes',\r\n itemDescription: 'List of recent quotes',\r\n errorFallback: 'Failed to load quotes',\r\n },\r\n mapItem: (quote) => ({\r\n id: quote.id as string,\r\n quoteNumber: quote.quoteNumber as string,\r\n status: (quote.status as string) ?? null,\r\n customerName: extractCustomerName(quote.customerSnapshot) ?? null,\r\n customerEntityId: (quote.customerEntityId as string) ?? null,\r\n validFrom: quote.validFrom ? (quote.validFrom as Date).toISOString() : null,\r\n validUntil: quote.validUntil ? (quote.validUntil as Date).toISOString() : null,\r\n netAmount: (quote.grandTotalNetAmount as string) ?? '0',\r\n grossAmount: (quote.grandTotalGrossAmount as string) ?? '0',\r\n currency: (quote.currencyCode as string) ?? null,\r\n createdAt: quote.createdAt ? (quote.createdAt as Date).toISOString() : new Date().toISOString(),\r\n convertedOrderId: (quote.convertedOrderId as string) ?? null,\r\n }),\r\n})\r\n\r\nexport { GET, metadata, openApi }\r\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,kBAAkB;AAC3B,SAAS,2BAA2B;AACpC,SAAS,gCAAgC;AAEzC,MAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,aAAa,EAAE,OAAO;AAAA,EACtB,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,kBAAkB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC7C,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,WAAW,EAAE,OAAO;AAAA,EACpB,aAAa,EAAE,OAAO;AAAA,EACtB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,WAAW,EAAE,OAAO;AAAA,EACpB,kBAAkB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAC/C,CAAC;AAED,MAAM,EAAE,KAAK,UAAU,QAAQ,IAAI,yBAAyB;AAAA,EAC1D,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW,CAAC,0BAA0B;AAAA,EACtC,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,SAAS;AAAA,IACP,SAAS;AAAA,IACT,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA,SAAS,CAAC,WAAW;AAAA,IACnB,IAAI,MAAM;AAAA,IACV,aAAa,MAAM;AAAA,IACnB,QAAS,MAAM,UAAqB;AAAA,IACpC,cAAc,oBAAoB,MAAM,gBAAgB,KAAK;AAAA,IAC7D,kBAAmB,MAAM,oBAA+B;AAAA,IACxD,WAAW,MAAM,YAAa,MAAM,UAAmB,YAAY,IAAI;AAAA,IACvE,YAAY,MAAM,aAAc,MAAM,WAAoB,YAAY,IAAI;AAAA,IAC1E,WAAY,MAAM,uBAAkC;AAAA,IACpD,aAAc,MAAM,yBAAoC;AAAA,IACxD,UAAW,MAAM,gBAA2B;AAAA,IAC5C,WAAW,MAAM,YAAa,MAAM,UAAmB,YAAY,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC9F,kBAAmB,MAAM,oBAA+B;AAAA,EAC1D;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,201 +1,22 @@
|
|
|
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 { Dictionary, DictionaryEntry } from "@open-mercato/core/modules/dictionaries/data/entities";
|
|
6
1
|
import { E } from "../../../../generated/entities.ids.generated.js";
|
|
7
2
|
import * as F from "../../../../generated/entities/dictionary_entry/index.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const rawBodySchema = z.object({}).passthrough();
|
|
18
|
-
const listSchema = z.object({
|
|
19
|
-
page: z.coerce.number().min(1).default(1),
|
|
20
|
-
pageSize: z.coerce.number().min(1).max(100).default(50),
|
|
21
|
-
search: z.string().optional(),
|
|
22
|
-
sortField: z.string().optional(),
|
|
23
|
-
sortDir: z.enum(["asc", "desc"]).optional()
|
|
24
|
-
}).passthrough();
|
|
25
|
-
const kind = "order-line-status";
|
|
26
|
-
const definition = getSalesDictionaryDefinition(kind);
|
|
27
|
-
const metadata = {
|
|
28
|
-
GET: { requireAuth: true, requireFeatures: ["sales.settings.manage"] },
|
|
29
|
-
POST: { requireAuth: true, requireFeatures: ["sales.settings.manage"] },
|
|
30
|
-
PUT: { requireAuth: true, requireFeatures: ["sales.settings.manage"] },
|
|
31
|
-
DELETE: { requireAuth: true, requireFeatures: ["sales.settings.manage"] }
|
|
32
|
-
};
|
|
33
|
-
const dictionaryItemSchema = z.object({
|
|
34
|
-
id: z.string().uuid(),
|
|
35
|
-
value: z.string(),
|
|
36
|
-
label: z.string().nullable(),
|
|
37
|
-
color: z.string().nullable(),
|
|
38
|
-
icon: z.string().nullable(),
|
|
39
|
-
organizationId: z.string().uuid().nullable(),
|
|
40
|
-
tenantId: z.string().uuid().nullable(),
|
|
41
|
-
createdAt: z.string(),
|
|
42
|
-
updatedAt: z.string()
|
|
43
|
-
});
|
|
44
|
-
const dictionaryListResponseSchema = createPagedListResponseSchema(dictionaryItemSchema);
|
|
45
|
-
const normalizeId = (value) => {
|
|
46
|
-
if (typeof value !== "string") return null;
|
|
47
|
-
const trimmed = value.trim();
|
|
48
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
49
|
-
};
|
|
50
|
-
async function resolveDictionaryContext(ctx) {
|
|
51
|
-
if (!ctx.auth || !ctx.auth.tenantId) {
|
|
52
|
-
throw new CrudHttpError(401, { error: "Tenant context is required." });
|
|
53
|
-
}
|
|
54
|
-
const em = ctx.container.resolve("em");
|
|
55
|
-
const tenantId = ctx.auth.tenantId;
|
|
56
|
-
const candidateOrgIds = /* @__PURE__ */ new Set();
|
|
57
|
-
const pushCandidate = (value) => {
|
|
58
|
-
const normalized = normalizeId(value);
|
|
59
|
-
if (normalized) candidateOrgIds.add(normalized);
|
|
60
|
-
};
|
|
61
|
-
pushCandidate(ctx.selectedOrganizationId);
|
|
62
|
-
pushCandidate(ctx.auth.orgId ?? null);
|
|
63
|
-
const scope = ctx.organizationScope;
|
|
64
|
-
if (scope) {
|
|
65
|
-
if (Array.isArray(scope.filterIds)) {
|
|
66
|
-
for (const id of scope.filterIds) pushCandidate(id);
|
|
67
|
-
}
|
|
68
|
-
if (Array.isArray(scope.allowedIds)) {
|
|
69
|
-
for (const id of scope.allowedIds) pushCandidate(id);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
for (const orgId of candidateOrgIds) {
|
|
73
|
-
const dictionary = await ensureSalesDictionary({
|
|
74
|
-
em,
|
|
75
|
-
tenantId,
|
|
76
|
-
organizationId: orgId,
|
|
77
|
-
kind
|
|
78
|
-
});
|
|
79
|
-
if (dictionary) {
|
|
80
|
-
return { dictionaryId: dictionary.id, organizationId: orgId };
|
|
81
|
-
}
|
|
3
|
+
import { makeStatusDictionaryRoute } from "../../lib/makeStatusDictionaryRoute.js";
|
|
4
|
+
const route = makeStatusDictionaryRoute({
|
|
5
|
+
kind: "order-line-status",
|
|
6
|
+
entityId: E.dictionaries.dictionary_entry,
|
|
7
|
+
fieldConstants: F,
|
|
8
|
+
openApi: {
|
|
9
|
+
resourceName: "Order line status",
|
|
10
|
+
pluralName: "Order line statuses",
|
|
11
|
+
description: "Manage custom order line statuses available for sales documents."
|
|
82
12
|
}
|
|
83
|
-
const fallback = await em.findOne(
|
|
84
|
-
Dictionary,
|
|
85
|
-
{
|
|
86
|
-
tenantId,
|
|
87
|
-
key: definition.key,
|
|
88
|
-
deletedAt: null
|
|
89
|
-
},
|
|
90
|
-
{ orderBy: { createdAt: "asc" } }
|
|
91
|
-
);
|
|
92
|
-
if (fallback) {
|
|
93
|
-
return { dictionaryId: fallback.id, organizationId: fallback.organizationId };
|
|
94
|
-
}
|
|
95
|
-
throw new CrudHttpError(400, { error: "Organization context is required." });
|
|
96
|
-
}
|
|
97
|
-
const crud = makeCrudRoute({
|
|
98
|
-
metadata,
|
|
99
|
-
orm: {
|
|
100
|
-
entity: DictionaryEntry,
|
|
101
|
-
idField: "id",
|
|
102
|
-
orgField: "organizationId",
|
|
103
|
-
tenantField: "tenantId",
|
|
104
|
-
softDeleteField: null
|
|
105
|
-
},
|
|
106
|
-
list: {
|
|
107
|
-
schema: listSchema,
|
|
108
|
-
entityId: E.dictionaries.dictionary_entry,
|
|
109
|
-
fields: [
|
|
110
|
-
F.id,
|
|
111
|
-
F.value,
|
|
112
|
-
F.label,
|
|
113
|
-
F.color,
|
|
114
|
-
F.icon,
|
|
115
|
-
F.organization_id,
|
|
116
|
-
F.tenant_id,
|
|
117
|
-
F.created_at,
|
|
118
|
-
F.updated_at
|
|
119
|
-
],
|
|
120
|
-
sortFieldMap: {
|
|
121
|
-
id: F.id,
|
|
122
|
-
value: F.value,
|
|
123
|
-
label: F.label,
|
|
124
|
-
createdAt: F.created_at,
|
|
125
|
-
updatedAt: F.updated_at
|
|
126
|
-
},
|
|
127
|
-
buildFilters: async (query, ctx) => {
|
|
128
|
-
const { dictionaryId } = await resolveDictionaryContext(ctx);
|
|
129
|
-
const filters = {
|
|
130
|
-
dictionary_id: dictionaryId
|
|
131
|
-
};
|
|
132
|
-
if (query.search && query.search.trim().length > 0) {
|
|
133
|
-
const term = `%${escapeLikePattern(query.search.trim())}%`;
|
|
134
|
-
filters.$or = [
|
|
135
|
-
{ [F.value]: { $ilike: term } },
|
|
136
|
-
{ [F.label]: { $ilike: term } }
|
|
137
|
-
];
|
|
138
|
-
}
|
|
139
|
-
return filters;
|
|
140
|
-
},
|
|
141
|
-
transformItem: (item) => ({
|
|
142
|
-
id: item.id,
|
|
143
|
-
value: item.value,
|
|
144
|
-
label: item.label,
|
|
145
|
-
color: item.color ?? null,
|
|
146
|
-
icon: item.icon ?? null,
|
|
147
|
-
organizationId: item.organization_id ?? null,
|
|
148
|
-
tenantId: item.tenant_id ?? null,
|
|
149
|
-
createdAt: item.created_at,
|
|
150
|
-
updatedAt: item.updated_at
|
|
151
|
-
})
|
|
152
|
-
},
|
|
153
|
-
actions: {
|
|
154
|
-
create: {
|
|
155
|
-
commandId: `${definition.commandPrefix}.create`,
|
|
156
|
-
schema: rawBodySchema,
|
|
157
|
-
mapInput: async ({ raw, ctx }) => {
|
|
158
|
-
const { translate } = await resolveTranslations();
|
|
159
|
-
return parseScopedCommandInput(statusDictionaryCreateSchema, raw ?? {}, ctx, translate);
|
|
160
|
-
},
|
|
161
|
-
response: ({ result }) => ({ id: result?.entryId ?? null }),
|
|
162
|
-
status: 201
|
|
163
|
-
},
|
|
164
|
-
update: {
|
|
165
|
-
commandId: `${definition.commandPrefix}.update`,
|
|
166
|
-
schema: rawBodySchema,
|
|
167
|
-
mapInput: async ({ raw, ctx }) => {
|
|
168
|
-
const { translate } = await resolveTranslations();
|
|
169
|
-
return parseScopedCommandInput(statusDictionaryUpdateSchema, raw ?? {}, ctx, translate);
|
|
170
|
-
},
|
|
171
|
-
response: () => ({ ok: true })
|
|
172
|
-
},
|
|
173
|
-
delete: {
|
|
174
|
-
commandId: `${definition.commandPrefix}.delete`,
|
|
175
|
-
schema: rawBodySchema,
|
|
176
|
-
mapInput: async ({ parsed, ctx }) => {
|
|
177
|
-
const { translate } = await resolveTranslations();
|
|
178
|
-
const id = resolveCrudRecordId(parsed, ctx, translate);
|
|
179
|
-
return { id };
|
|
180
|
-
},
|
|
181
|
-
response: () => ({ ok: true })
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
const openApi = createSalesCrudOpenApi({
|
|
186
|
-
resourceName: "Order line status",
|
|
187
|
-
pluralName: "Order line statuses",
|
|
188
|
-
description: "Manage custom order line statuses available for sales documents.",
|
|
189
|
-
querySchema: listSchema,
|
|
190
|
-
listResponseSchema: dictionaryListResponseSchema,
|
|
191
|
-
create: { schema: statusDictionaryCreateSchema },
|
|
192
|
-
update: { schema: statusDictionaryUpdateSchema },
|
|
193
|
-
del: { schema: defaultDeleteRequestSchema }
|
|
194
13
|
});
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const
|
|
14
|
+
const metadata = route.metadata;
|
|
15
|
+
const openApi = route.openApi;
|
|
16
|
+
const GET = route.GET;
|
|
17
|
+
const POST = route.POST;
|
|
18
|
+
const PUT = route.PUT;
|
|
19
|
+
const DELETE = route.DELETE;
|
|
199
20
|
export {
|
|
200
21
|
DELETE,
|
|
201
22
|
GET,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/sales/api/order-line-statuses/route.ts"],
|
|
4
|
-
"sourcesContent": ["import {
|
|
5
|
-
"mappings": "AAAA,SAAS,SAAS;AAClB,
|
|
4
|
+
"sourcesContent": ["import { E } from '#generated/entities.ids.generated'\nimport * as F from '#generated/entities/dictionary_entry'\nimport { makeStatusDictionaryRoute } from '../../lib/makeStatusDictionaryRoute'\n\nconst route = makeStatusDictionaryRoute({\n kind: 'order-line-status',\n entityId: E.dictionaries.dictionary_entry,\n fieldConstants: F,\n openApi: {\n resourceName: 'Order line status',\n pluralName: 'Order line statuses',\n description: 'Manage custom order line statuses available for sales documents.',\n },\n})\n\nexport const metadata = route.metadata\nexport const openApi = route.openApi\nexport const GET = route.GET\nexport const POST = route.POST\nexport const PUT = route.PUT\nexport const DELETE = route.DELETE\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAClB,YAAY,OAAO;AACnB,SAAS,iCAAiC;AAE1C,MAAM,QAAQ,0BAA0B;AAAA,EACtC,MAAM;AAAA,EACN,UAAU,EAAE,aAAa;AAAA,EACzB,gBAAgB;AAAA,EAChB,SAAS;AAAA,IACP,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,aAAa;AAAA,EACf;AACF,CAAC;AAEM,MAAM,WAAW,MAAM;AACvB,MAAM,UAAU,MAAM;AACtB,MAAM,MAAM,MAAM;AAClB,MAAM,OAAO,MAAM;AACnB,MAAM,MAAM,MAAM;AAClB,MAAM,SAAS,MAAM;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|