@open-mercato/core 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +13 -1
- package/dist/helpers/integration/api.js +29 -16
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/auth.js +11 -6
- package/dist/helpers/integration/auth.js.map +3 -3
- package/dist/modules/auth/commands/roles.js +9 -12
- package/dist/modules/auth/commands/roles.js.map +2 -2
- package/dist/modules/catalog/ai-agents-context.js +147 -0
- package/dist/modules/catalog/ai-agents-context.js.map +7 -0
- package/dist/modules/catalog/ai-agents.js +383 -0
- package/dist/modules/catalog/ai-agents.js.map +7 -0
- package/dist/modules/catalog/ai-tools/_shared.js +318 -0
- package/dist/modules/catalog/ai-tools/_shared.js.map +7 -0
- package/dist/modules/catalog/ai-tools/authoring-pack.js +391 -0
- package/dist/modules/catalog/ai-tools/authoring-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/categories-pack.js +167 -0
- package/dist/modules/catalog/ai-tools/categories-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/configuration-pack.js +120 -0
- package/dist/modules/catalog/ai-tools/configuration-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/media-tags-pack.js +107 -0
- package/dist/modules/catalog/ai-tools/media-tags-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +429 -0
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/mutation-pack.js +576 -0
- package/dist/modules/catalog/ai-tools/mutation-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/prices-offers-pack.js +208 -0
- package/dist/modules/catalog/ai-tools/prices-offers-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/products-pack.js +298 -0
- package/dist/modules/catalog/ai-tools/products-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/stats-pack.js +57 -0
- package/dist/modules/catalog/ai-tools/stats-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/types.js +10 -0
- package/dist/modules/catalog/ai-tools/types.js.map +7 -0
- package/dist/modules/catalog/ai-tools/variants-pack.js +75 -0
- package/dist/modules/catalog/ai-tools/variants-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools.js +28 -0
- package/dist/modules/catalog/ai-tools.js.map +7 -0
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +466 -0
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +7 -0
- package/dist/modules/catalog/backend/catalog/products/page.js +7 -1
- package/dist/modules/catalog/backend/catalog/products/page.js.map +2 -2
- package/dist/modules/catalog/components/CatalogStatsCard.js +91 -0
- package/dist/modules/catalog/components/CatalogStatsCard.js.map +7 -0
- package/dist/modules/catalog/components/products/ProductsDataTable.js +23 -3
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/events.js +7 -4
- package/dist/modules/catalog/events.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +59 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js +17 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +1 -1
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
- package/dist/modules/catalog/widgets/injection-table.js +13 -1
- package/dist/modules/catalog/widgets/injection-table.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js +94 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js +17 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js +9 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
- package/dist/modules/customers/ai-agents-context.js +96 -0
- package/dist/modules/customers/ai-agents-context.js.map +7 -0
- package/dist/modules/customers/ai-agents.js +244 -0
- package/dist/modules/customers/ai-agents.js.map +7 -0
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js +1015 -0
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/addresses-tags-pack.js +134 -0
- package/dist/modules/customers/ai-tools/addresses-tags-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/companies-pack.js +249 -0
- package/dist/modules/customers/ai-tools/companies-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/deals-pack.js +348 -0
- package/dist/modules/customers/ai-tools/deals-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/people-pack.js +261 -0
- package/dist/modules/customers/ai-tools/people-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/settings-pack.js +102 -0
- package/dist/modules/customers/ai-tools/settings-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/types.js +10 -0
- package/dist/modules/customers/ai-tools/types.js.map +7 -0
- package/dist/modules/customers/ai-tools.js +20 -0
- package/dist/modules/customers/ai-tools.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +469 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js +17 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js +117 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js +17 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js.map +7 -0
- package/dist/modules/customers/widgets/injection-table.js +26 -0
- package/dist/modules/customers/widgets/injection-table.js.map +7 -0
- package/dist/modules/inbox_ops/ai-tools.js +4 -0
- package/dist/modules/inbox_ops/ai-tools.js.map +2 -2
- package/dist/modules/inbox_ops/lib/llmProvider.js +52 -7
- package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
- package/dist/modules/notifications/setup.js +13 -0
- package/dist/modules/notifications/setup.js.map +7 -0
- package/jest.config.cjs +1 -0
- package/jest.setup.ts +18 -0
- package/package.json +5 -3
- package/src/helpers/integration/api.ts +38 -16
- package/src/helpers/integration/auth.ts +13 -6
- package/src/modules/auth/commands/roles.ts +10 -12
- package/src/modules/catalog/AGENTS.md +11 -0
- package/src/modules/catalog/ai-agents-context.ts +239 -0
- package/src/modules/catalog/ai-agents.ts +525 -0
- package/src/modules/catalog/ai-tools/_shared.ts +487 -0
- package/src/modules/catalog/ai-tools/authoring-pack.ts +600 -0
- package/src/modules/catalog/ai-tools/categories-pack.ts +192 -0
- package/src/modules/catalog/ai-tools/configuration-pack.ts +218 -0
- package/src/modules/catalog/ai-tools/media-tags-pack.ts +127 -0
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +608 -0
- package/src/modules/catalog/ai-tools/mutation-pack.ts +761 -0
- package/src/modules/catalog/ai-tools/prices-offers-pack.ts +376 -0
- package/src/modules/catalog/ai-tools/products-pack.ts +387 -0
- package/src/modules/catalog/ai-tools/stats-pack.ts +84 -0
- package/src/modules/catalog/ai-tools/types.ts +81 -0
- package/src/modules/catalog/ai-tools/variants-pack.ts +147 -0
- package/src/modules/catalog/ai-tools.ts +78 -0
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +597 -0
- package/src/modules/catalog/backend/catalog/products/page.tsx +23 -2
- package/src/modules/catalog/components/CatalogStatsCard.tsx +118 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +54 -6
- package/src/modules/catalog/events.ts +7 -4
- package/src/modules/catalog/i18n/de.json +17 -0
- package/src/modules/catalog/i18n/en.json +17 -0
- package/src/modules/catalog/i18n/es.json +17 -0
- package/src/modules/catalog/i18n/pl.json +17 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +109 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.ts +29 -0
- package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +1 -1
- package/src/modules/catalog/widgets/injection-table.ts +12 -0
- package/src/modules/customer_accounts/i18n/de.json +5 -0
- package/src/modules/customer_accounts/i18n/en.json +5 -0
- package/src/modules/customer_accounts/i18n/es.json +5 -0
- package/src/modules/customer_accounts/i18n/pl.json +5 -0
- package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.tsx +136 -0
- package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.ts +43 -0
- package/src/modules/customer_accounts/widgets/injection-table.ts +9 -0
- package/src/modules/customers/AGENTS.md +13 -0
- package/src/modules/customers/ai-agents-context.ts +150 -0
- package/src/modules/customers/ai-agents.ts +355 -0
- package/src/modules/customers/ai-tools/activities-tasks-pack.ts +1248 -0
- package/src/modules/customers/ai-tools/addresses-tags-pack.ts +145 -0
- package/src/modules/customers/ai-tools/companies-pack.ts +362 -0
- package/src/modules/customers/ai-tools/deals-pack.ts +505 -0
- package/src/modules/customers/ai-tools/people-pack.ts +369 -0
- package/src/modules/customers/ai-tools/settings-pack.ts +121 -0
- package/src/modules/customers/ai-tools/types.ts +76 -0
- package/src/modules/customers/ai-tools.ts +34 -0
- package/src/modules/customers/i18n/de.json +25 -0
- package/src/modules/customers/i18n/en.json +25 -0
- package/src/modules/customers/i18n/es.json +25 -0
- package/src/modules/customers/i18n/pl.json +25 -0
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +580 -0
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts +36 -0
- package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.tsx +191 -0
- package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.ts +37 -0
- package/src/modules/customers/widgets/injection-table.ts +41 -0
- package/src/modules/inbox_ops/ai-tools.ts +4 -0
- package/src/modules/inbox_ops/lib/llmProvider.ts +83 -7
- package/src/modules/notifications/setup.ts +11 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findOneWithDecryption,
|
|
3
|
+
findWithDecryption
|
|
4
|
+
} from "@open-mercato/shared/lib/encryption/find";
|
|
5
|
+
import {
|
|
6
|
+
loadCustomFieldDefinitionIndex,
|
|
7
|
+
loadCustomFieldValues
|
|
8
|
+
} from "@open-mercato/shared/lib/crud/custom-fields";
|
|
9
|
+
import { E } from "../../../generated/entities.ids.generated.js";
|
|
10
|
+
import { Attachment } from "@open-mercato/core/modules/attachments/data/entities";
|
|
11
|
+
import {
|
|
12
|
+
CatalogPriceKind,
|
|
13
|
+
CatalogProduct,
|
|
14
|
+
CatalogProductCategoryAssignment,
|
|
15
|
+
CatalogProductPrice,
|
|
16
|
+
CatalogProductTagAssignment,
|
|
17
|
+
CatalogProductUnitConversion,
|
|
18
|
+
CatalogProductVariant
|
|
19
|
+
} from "../data/entities.js";
|
|
20
|
+
function resolveEm(ctx) {
|
|
21
|
+
return ctx.container.resolve("em");
|
|
22
|
+
}
|
|
23
|
+
function buildScope(ctx, tenantId) {
|
|
24
|
+
return { tenantId, organizationId: ctx.organizationId };
|
|
25
|
+
}
|
|
26
|
+
async function listPriceKindsCore(ctx, input, tenantId) {
|
|
27
|
+
const em = resolveEm(ctx);
|
|
28
|
+
const limit = input.limit ?? 50;
|
|
29
|
+
const offset = input.offset ?? 0;
|
|
30
|
+
const where = { tenantId, deletedAt: null };
|
|
31
|
+
if (ctx.organizationId) {
|
|
32
|
+
where.$or = [{ organizationId: ctx.organizationId }, { organizationId: null }];
|
|
33
|
+
}
|
|
34
|
+
const [rows, total] = await Promise.all([
|
|
35
|
+
findWithDecryption(
|
|
36
|
+
em,
|
|
37
|
+
CatalogPriceKind,
|
|
38
|
+
where,
|
|
39
|
+
{ limit, offset, orderBy: { code: "asc" } },
|
|
40
|
+
buildScope(ctx, tenantId)
|
|
41
|
+
),
|
|
42
|
+
em.count(CatalogPriceKind, where)
|
|
43
|
+
]);
|
|
44
|
+
const filtered = rows.filter((row) => row.tenantId === tenantId);
|
|
45
|
+
return {
|
|
46
|
+
items: filtered.map((row) => ({
|
|
47
|
+
id: row.id,
|
|
48
|
+
code: row.code,
|
|
49
|
+
title: row.title,
|
|
50
|
+
displayMode: row.displayMode,
|
|
51
|
+
currencyCode: row.currencyCode ?? null,
|
|
52
|
+
isPromotion: !!row.isPromotion,
|
|
53
|
+
isActive: !!row.isActive,
|
|
54
|
+
organizationId: row.organizationId ?? null,
|
|
55
|
+
tenantId: row.tenantId ?? null,
|
|
56
|
+
createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,
|
|
57
|
+
updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null
|
|
58
|
+
})),
|
|
59
|
+
total,
|
|
60
|
+
limit,
|
|
61
|
+
offset
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function toProductSummary(row) {
|
|
65
|
+
return {
|
|
66
|
+
id: row.id,
|
|
67
|
+
title: row.title,
|
|
68
|
+
subtitle: row.subtitle ?? null,
|
|
69
|
+
sku: row.sku ?? null,
|
|
70
|
+
handle: row.handle ?? null,
|
|
71
|
+
productType: row.productType,
|
|
72
|
+
statusEntryId: row.statusEntryId ?? null,
|
|
73
|
+
primaryCurrencyCode: row.primaryCurrencyCode ?? null,
|
|
74
|
+
defaultMediaId: row.defaultMediaId ?? null,
|
|
75
|
+
defaultMediaUrl: row.defaultMediaUrl ?? null,
|
|
76
|
+
imageUrl: row.defaultMediaUrl ?? null,
|
|
77
|
+
isActive: !!row.isActive,
|
|
78
|
+
isConfigurable: !!row.isConfigurable,
|
|
79
|
+
organizationId: row.organizationId ?? null,
|
|
80
|
+
tenantId: row.tenantId ?? null,
|
|
81
|
+
createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,
|
|
82
|
+
updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,
|
|
83
|
+
// `description` is a product field used by D18 authoring tools to seed
|
|
84
|
+
// extract-attributes-from-description; falls back to null when absent.
|
|
85
|
+
description: row.description ?? null
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function toPriceNumeric(value) {
|
|
89
|
+
if (value === null || value === void 0) return null;
|
|
90
|
+
const parsed = Number(value);
|
|
91
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
92
|
+
}
|
|
93
|
+
function summarizeDefinitionAsField(summary, scope) {
|
|
94
|
+
return {
|
|
95
|
+
key: summary.key,
|
|
96
|
+
label: summary.label ?? null,
|
|
97
|
+
type: summary.kind ?? null,
|
|
98
|
+
required: false,
|
|
99
|
+
options: null,
|
|
100
|
+
scope
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function resolveAttributeSchema(ctx, tenantId, productId, categoryId) {
|
|
104
|
+
const em = resolveEm(ctx);
|
|
105
|
+
const organizationIds = ctx.organizationId ? [ctx.organizationId] : [];
|
|
106
|
+
const moduleDefs = await loadCustomFieldDefinitionIndex({
|
|
107
|
+
em,
|
|
108
|
+
entityIds: [E.catalog.catalog_product, E.catalog.catalog_product_category],
|
|
109
|
+
tenantId,
|
|
110
|
+
organizationIds
|
|
111
|
+
});
|
|
112
|
+
const fields = [];
|
|
113
|
+
moduleDefs.forEach((entries) => {
|
|
114
|
+
const pick = entries[0];
|
|
115
|
+
if (!pick) return;
|
|
116
|
+
const scope = pick.organizationId ? "product" : "module";
|
|
117
|
+
fields.push(summarizeDefinitionAsField(pick, scope));
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
fields,
|
|
121
|
+
resolvedFor: {
|
|
122
|
+
...productId ? { productId } : {},
|
|
123
|
+
...categoryId ? { categoryId } : {}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function resolvePricingService(ctx) {
|
|
128
|
+
try {
|
|
129
|
+
return ctx.container.resolve("catalogPricingService");
|
|
130
|
+
} catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function buildProductBundle(em, ctx, tenantId, productId) {
|
|
135
|
+
const where = {
|
|
136
|
+
id: productId,
|
|
137
|
+
tenantId,
|
|
138
|
+
deletedAt: null
|
|
139
|
+
};
|
|
140
|
+
if (ctx.organizationId) where.organizationId = ctx.organizationId;
|
|
141
|
+
const product = await findOneWithDecryption(
|
|
142
|
+
em,
|
|
143
|
+
CatalogProduct,
|
|
144
|
+
where,
|
|
145
|
+
void 0,
|
|
146
|
+
buildScope(ctx, tenantId)
|
|
147
|
+
);
|
|
148
|
+
if (!product || product.tenantId !== tenantId) {
|
|
149
|
+
return { found: false, productId };
|
|
150
|
+
}
|
|
151
|
+
const scope = buildScope(ctx, tenantId);
|
|
152
|
+
const [
|
|
153
|
+
categoryAssignments,
|
|
154
|
+
tagAssignments,
|
|
155
|
+
variants,
|
|
156
|
+
prices,
|
|
157
|
+
mediaAttachments,
|
|
158
|
+
unitConversions,
|
|
159
|
+
customFieldValues,
|
|
160
|
+
attributeSchema
|
|
161
|
+
] = await Promise.all([
|
|
162
|
+
findWithDecryption(
|
|
163
|
+
em,
|
|
164
|
+
CatalogProductCategoryAssignment,
|
|
165
|
+
{ tenantId, product: product.id },
|
|
166
|
+
{ limit: 100, populate: ["category"] },
|
|
167
|
+
scope
|
|
168
|
+
),
|
|
169
|
+
findWithDecryption(
|
|
170
|
+
em,
|
|
171
|
+
CatalogProductTagAssignment,
|
|
172
|
+
{ tenantId, product: product.id },
|
|
173
|
+
{ limit: 100, populate: ["tag"] },
|
|
174
|
+
scope
|
|
175
|
+
),
|
|
176
|
+
findWithDecryption(
|
|
177
|
+
em,
|
|
178
|
+
CatalogProductVariant,
|
|
179
|
+
{ tenantId, product: product.id, deletedAt: null },
|
|
180
|
+
{ limit: 100, orderBy: { createdAt: "asc" } },
|
|
181
|
+
scope
|
|
182
|
+
),
|
|
183
|
+
findWithDecryption(
|
|
184
|
+
em,
|
|
185
|
+
CatalogProductPrice,
|
|
186
|
+
{ tenantId, product: product.id },
|
|
187
|
+
{ limit: 100, orderBy: { createdAt: "asc" } },
|
|
188
|
+
scope
|
|
189
|
+
),
|
|
190
|
+
findWithDecryption(
|
|
191
|
+
em,
|
|
192
|
+
Attachment,
|
|
193
|
+
{ tenantId, entityId: E.catalog.catalog_product, recordId: product.id },
|
|
194
|
+
{ limit: 100, orderBy: { createdAt: "asc" } },
|
|
195
|
+
scope
|
|
196
|
+
),
|
|
197
|
+
findWithDecryption(
|
|
198
|
+
em,
|
|
199
|
+
CatalogProductUnitConversion,
|
|
200
|
+
{ tenantId, product: product.id, deletedAt: null },
|
|
201
|
+
{ limit: 100, orderBy: { sortOrder: "asc", createdAt: "asc" } },
|
|
202
|
+
scope
|
|
203
|
+
),
|
|
204
|
+
loadCustomFieldValues({
|
|
205
|
+
em,
|
|
206
|
+
entityId: E.catalog.catalog_product,
|
|
207
|
+
recordIds: [product.id],
|
|
208
|
+
tenantIdByRecord: { [product.id]: product.tenantId ?? null },
|
|
209
|
+
organizationIdByRecord: { [product.id]: product.organizationId ?? null },
|
|
210
|
+
tenantFallbacks: [product.tenantId ?? tenantId].filter((value) => !!value)
|
|
211
|
+
}),
|
|
212
|
+
resolveAttributeSchema(ctx, tenantId, product.id, void 0)
|
|
213
|
+
]);
|
|
214
|
+
const categories = categoryAssignments.map((assignment) => {
|
|
215
|
+
const category = assignment.category;
|
|
216
|
+
if (!category || typeof category === "string") {
|
|
217
|
+
const fallbackId = typeof category === "string" ? category : null;
|
|
218
|
+
return fallbackId ? { id: fallbackId, name: null, slug: null, path: null } : null;
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
id: category.id,
|
|
222
|
+
name: category.name ?? null,
|
|
223
|
+
slug: category.slug ?? null,
|
|
224
|
+
path: category.treePath ?? null
|
|
225
|
+
};
|
|
226
|
+
}).filter((value) => value !== null);
|
|
227
|
+
const tags = tagAssignments.map((assignment) => {
|
|
228
|
+
const tag = assignment.tag;
|
|
229
|
+
if (!tag || typeof tag === "string") return null;
|
|
230
|
+
return { id: tag.id, label: tag.label, slug: tag.slug };
|
|
231
|
+
}).filter((value) => value !== null);
|
|
232
|
+
const priceRows = prices.map((row) => ({
|
|
233
|
+
id: row.id,
|
|
234
|
+
priceKindId: row.priceKind && typeof row.priceKind === "object" ? row.priceKind.id : row.priceKind ?? null,
|
|
235
|
+
currencyCode: row.currencyCode,
|
|
236
|
+
kind: row.kind,
|
|
237
|
+
minQuantity: row.minQuantity,
|
|
238
|
+
maxQuantity: row.maxQuantity ?? null,
|
|
239
|
+
unitPriceNet: row.unitPriceNet ?? null,
|
|
240
|
+
unitPriceGross: row.unitPriceGross ?? null,
|
|
241
|
+
taxRate: row.taxRate ?? null,
|
|
242
|
+
taxAmount: row.taxAmount ?? null,
|
|
243
|
+
channelId: row.channelId ?? null,
|
|
244
|
+
offerId: row.offer && typeof row.offer === "object" ? row.offer.id : row.offer ?? null,
|
|
245
|
+
variantId: row.variant && typeof row.variant === "object" ? row.variant.id : row.variant ?? null,
|
|
246
|
+
startsAt: row.startsAt ? new Date(row.startsAt).toISOString() : null,
|
|
247
|
+
endsAt: row.endsAt ? new Date(row.endsAt).toISOString() : null
|
|
248
|
+
}));
|
|
249
|
+
let bestPrice = null;
|
|
250
|
+
const pricingService = resolvePricingService(ctx);
|
|
251
|
+
if (pricingService && prices.length > 0) {
|
|
252
|
+
const pricingContext = {
|
|
253
|
+
quantity: 1,
|
|
254
|
+
date: /* @__PURE__ */ new Date()
|
|
255
|
+
};
|
|
256
|
+
try {
|
|
257
|
+
const resolved = await pricingService.resolvePrice(prices, pricingContext);
|
|
258
|
+
if (resolved) {
|
|
259
|
+
bestPrice = {
|
|
260
|
+
id: resolved.id,
|
|
261
|
+
currencyCode: resolved.currencyCode,
|
|
262
|
+
kind: resolved.kind,
|
|
263
|
+
unitPriceNet: resolved.unitPriceNet ?? null,
|
|
264
|
+
unitPriceGross: resolved.unitPriceGross ?? null
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.warn("[catalog.get_product_bundle] resolvePrice failed, omitting best price", error);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
found: true,
|
|
273
|
+
id: product.id,
|
|
274
|
+
product: toProductSummary(product),
|
|
275
|
+
categories,
|
|
276
|
+
tags,
|
|
277
|
+
variants: variants.map((variant) => ({
|
|
278
|
+
id: variant.id,
|
|
279
|
+
name: variant.name ?? null,
|
|
280
|
+
sku: variant.sku ?? null,
|
|
281
|
+
barcode: variant.barcode ?? null,
|
|
282
|
+
optionValues: variant.optionValues ?? null,
|
|
283
|
+
defaultMediaId: variant.defaultMediaId ?? null,
|
|
284
|
+
defaultMediaUrl: variant.defaultMediaUrl ?? null,
|
|
285
|
+
isDefault: !!variant.isDefault,
|
|
286
|
+
isActive: !!variant.isActive
|
|
287
|
+
})),
|
|
288
|
+
prices: {
|
|
289
|
+
all: priceRows,
|
|
290
|
+
best: bestPrice
|
|
291
|
+
},
|
|
292
|
+
media: mediaAttachments.map((attachment) => ({
|
|
293
|
+
mediaId: attachment.id,
|
|
294
|
+
attachmentId: attachment.id,
|
|
295
|
+
fileName: attachment.fileName,
|
|
296
|
+
mediaType: attachment.mimeType,
|
|
297
|
+
size: attachment.fileSize,
|
|
298
|
+
altText: null,
|
|
299
|
+
sortOrder: 0
|
|
300
|
+
})),
|
|
301
|
+
customFields: customFieldValues[product.id] ?? {},
|
|
302
|
+
attributeSchema,
|
|
303
|
+
// No translation resolver exists for catalog (no `translations.ts` at
|
|
304
|
+
// module root yet); returning null is an explicit null-surface contract
|
|
305
|
+
// and a hint for Step 5+ to add the translations resolver.
|
|
306
|
+
translations: null
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
export {
|
|
310
|
+
buildProductBundle,
|
|
311
|
+
buildScope,
|
|
312
|
+
listPriceKindsCore,
|
|
313
|
+
resolveAttributeSchema,
|
|
314
|
+
resolveEm,
|
|
315
|
+
toPriceNumeric,
|
|
316
|
+
toProductSummary
|
|
317
|
+
};
|
|
318
|
+
//# sourceMappingURL=_shared.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/ai-tools/_shared.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared helpers for catalog AI tool packs (Phase 1 WS-C, Steps 3.10 / 3.11 / 3.12).\n *\n * Step 3.10/3.11 centralized the price-kind enumeration query used by both the\n * base tool (`catalog.list_price_kinds_base`) and the D18 spec-named tool\n * (`catalog.list_price_kinds`).\n *\n * Step 3.12 lifts the **product-bundle builder** (and the merged\n * attribute-schema resolver) here too, so the D18 AI-authoring tools\n * (`draft_description_from_attributes`, `extract_attributes_from_description`,\n * `draft_description_from_media`, `suggest_title_variants`,\n * `suggest_price_adjustment`) can reuse them verbatim without either\n * duplicating the logic or depending on an internal symbol in\n * `merchandising-pack.ts`. Both packs (`merchandising-pack.ts` and\n * `authoring-pack.ts`) consume these helpers; neither pack owns the bundle\n * loader any more.\n *\n * Keeping the shared pieces query-shaped (not tool-shaped) means each tool is\n * free to project its own output shape without leaking concerns between packs.\n */\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n findOneWithDecryption,\n findWithDecryption,\n} from '@open-mercato/shared/lib/encryption/find'\nimport {\n loadCustomFieldDefinitionIndex,\n loadCustomFieldValues,\n type CustomFieldDefinitionSummary,\n} from '@open-mercato/shared/lib/crud/custom-fields'\nimport { E } from '#generated/entities.ids.generated'\nimport { Attachment } from '@open-mercato/core/modules/attachments/data/entities'\nimport {\n CatalogPriceKind,\n CatalogProduct,\n CatalogProductCategoryAssignment,\n CatalogProductPrice,\n CatalogProductTag,\n CatalogProductTagAssignment,\n CatalogProductUnitConversion,\n CatalogProductVariant,\n} from '../data/entities'\nimport type { CatalogPricingService } from '../services/catalogPricingService'\nimport type { PriceRow, PricingContext } from '../lib/pricing'\nimport type { CatalogToolContext } from './types'\n\n/* -------------------------------------------------------------------------- */\n/* Price-kind enumeration shared core */\n/* -------------------------------------------------------------------------- */\n\nexport type ListPriceKindsCoreInput = {\n limit?: number\n offset?: number\n}\n\nexport type ListPriceKindsCoreRow = {\n id: string\n code: string\n title: string\n displayMode: string\n currencyCode: string | null\n isPromotion: boolean\n isActive: boolean\n organizationId: string | null\n tenantId: string | null\n createdAt: string | null\n updatedAt: string | null\n}\n\nexport type ListPriceKindsCoreResult = {\n items: ListPriceKindsCoreRow[]\n total: number\n limit: number\n offset: number\n}\n\nexport function resolveEm(ctx: CatalogToolContext): EntityManager {\n return ctx.container.resolve<EntityManager>('em')\n}\n\nexport function buildScope(ctx: CatalogToolContext, tenantId: string) {\n return { tenantId, organizationId: ctx.organizationId }\n}\n\n/**\n * Shared tenant-scoped enumeration of `CatalogPriceKind` rows.\n *\n * Uses `findWithDecryption` + post-filter. Price kinds are tenant-owned and\n * can be either organization-scoped (match `ctx.organizationId`) or\n * null-scoped (shared across the tenant); the `$or` below mirrors the\n * filter the base tool used pre-refactor so behavior stays identical.\n */\nexport async function listPriceKindsCore(\n ctx: CatalogToolContext,\n input: ListPriceKindsCoreInput,\n tenantId: string,\n): Promise<ListPriceKindsCoreResult> {\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId, deletedAt: null }\n if (ctx.organizationId) {\n where.$or = [{ organizationId: ctx.organizationId }, { organizationId: null }]\n }\n const [rows, total] = await Promise.all([\n findWithDecryption<CatalogPriceKind>(\n em,\n CatalogPriceKind,\n where as any,\n { limit, offset, orderBy: { code: 'asc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CatalogPriceKind, where as any),\n ])\n const filtered = rows.filter((row) => row.tenantId === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n code: row.code,\n title: row.title,\n displayMode: row.displayMode,\n currencyCode: row.currencyCode ?? null,\n isPromotion: !!row.isPromotion,\n isActive: !!row.isActive,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Product summary + bundle builder */\n/* -------------------------------------------------------------------------- */\n\nexport type ProductSummary = {\n id: string\n title: string\n subtitle: string | null\n sku: string | null\n handle: string | null\n productType: string\n statusEntryId: string | null\n primaryCurrencyCode: string | null\n defaultMediaId: string | null\n defaultMediaUrl: string | null\n /**\n * Alias of `defaultMediaUrl`. Surfaced under the same key the\n * `open-mercato:product` record card consumes so the model can pass it\n * straight through without renaming. Null when the product has no\n * default media.\n */\n imageUrl: string | null\n isActive: boolean\n isConfigurable: boolean\n organizationId: string | null\n tenantId: string | null\n createdAt: string | null\n updatedAt: string | null\n description: string | null\n}\n\nexport function toProductSummary(row: CatalogProduct): ProductSummary {\n return {\n id: row.id,\n title: row.title,\n subtitle: row.subtitle ?? null,\n sku: row.sku ?? null,\n handle: row.handle ?? null,\n productType: row.productType,\n statusEntryId: row.statusEntryId ?? null,\n primaryCurrencyCode: row.primaryCurrencyCode ?? null,\n defaultMediaId: row.defaultMediaId ?? null,\n defaultMediaUrl: row.defaultMediaUrl ?? null,\n imageUrl: row.defaultMediaUrl ?? null,\n isActive: !!row.isActive,\n isConfigurable: !!row.isConfigurable,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,\n // `description` is a product field used by D18 authoring tools to seed\n // extract-attributes-from-description; falls back to null when absent.\n description: (row as any).description ?? null,\n }\n}\n\nexport function toPriceNumeric(value: string | null | undefined): number | null {\n if (value === null || value === undefined) return null\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : null\n}\n\nexport type AttributeSchemaField = {\n key: string\n label: string | null\n type: string | null\n required: boolean\n options: unknown | null\n scope: 'module' | 'category' | 'product'\n}\n\nexport type AttributeSchemaResult = {\n fields: AttributeSchemaField[]\n resolvedFor: { productId?: string; categoryId?: string }\n}\n\nfunction summarizeDefinitionAsField(\n summary: CustomFieldDefinitionSummary,\n scope: AttributeSchemaField['scope'],\n): AttributeSchemaField {\n return {\n key: summary.key,\n label: summary.label ?? null,\n type: summary.kind ?? null,\n required: false,\n options: null,\n scope,\n }\n}\n\nexport async function resolveAttributeSchema(\n ctx: CatalogToolContext,\n tenantId: string,\n productId?: string,\n categoryId?: string,\n): Promise<AttributeSchemaResult> {\n const em = resolveEm(ctx)\n const organizationIds = ctx.organizationId ? [ctx.organizationId] : []\n const moduleDefs = await loadCustomFieldDefinitionIndex({\n em,\n entityIds: [E.catalog.catalog_product, E.catalog.catalog_product_category],\n tenantId,\n organizationIds,\n })\n const fields: AttributeSchemaField[] = []\n moduleDefs.forEach((entries) => {\n const pick = entries[0]\n if (!pick) return\n const scope: AttributeSchemaField['scope'] = pick.organizationId ? 'product' : 'module'\n fields.push(summarizeDefinitionAsField(pick, scope))\n })\n return {\n fields,\n resolvedFor: {\n ...(productId ? { productId } : {}),\n ...(categoryId ? { categoryId } : {}),\n },\n }\n}\n\nexport type ProductBundleMediaEntry = {\n mediaId: string\n attachmentId: string\n fileName: string\n mediaType: string | null\n size: number | null\n altText: string | null\n sortOrder: number\n}\n\nexport type ProductBundle = {\n found: true\n id: string\n product: ProductSummary\n categories: Array<{ id: string; name: string | null; slug: string | null; path: string | null }>\n tags: Array<{ id: string; label: string; slug: string }>\n variants: Array<Record<string, unknown>>\n prices: {\n all: Array<Record<string, unknown>>\n best: Record<string, unknown> | null\n }\n media: ProductBundleMediaEntry[]\n customFields: Record<string, unknown>\n attributeSchema: AttributeSchemaResult\n translations: null\n}\n\nexport type ProductBundleResult = ProductBundle | { found: false; productId: string }\n\nfunction resolvePricingService(ctx: CatalogToolContext): CatalogPricingService | null {\n try {\n return ctx.container.resolve<CatalogPricingService>('catalogPricingService')\n } catch {\n return null\n }\n}\n\nexport async function buildProductBundle(\n em: EntityManager,\n ctx: CatalogToolContext,\n tenantId: string,\n productId: string,\n): Promise<ProductBundleResult> {\n const where: Record<string, unknown> = {\n id: productId,\n tenantId,\n deletedAt: null,\n }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const product = await findOneWithDecryption<CatalogProduct>(\n em,\n CatalogProduct,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!product || product.tenantId !== tenantId) {\n return { found: false as const, productId }\n }\n const scope = buildScope(ctx, tenantId)\n const [\n categoryAssignments,\n tagAssignments,\n variants,\n prices,\n mediaAttachments,\n unitConversions,\n customFieldValues,\n attributeSchema,\n ] = await Promise.all([\n findWithDecryption<CatalogProductCategoryAssignment>(\n em,\n CatalogProductCategoryAssignment,\n { tenantId, product: product.id } as any,\n { limit: 100, populate: ['category'] as any } as any,\n scope,\n ),\n findWithDecryption<CatalogProductTagAssignment>(\n em,\n CatalogProductTagAssignment,\n { tenantId, product: product.id } as any,\n { limit: 100, populate: ['tag'] as any } as any,\n scope,\n ),\n findWithDecryption<CatalogProductVariant>(\n em,\n CatalogProductVariant,\n { tenantId, product: product.id, deletedAt: null } as any,\n { limit: 100, orderBy: { createdAt: 'asc' } as any } as any,\n scope,\n ),\n findWithDecryption<CatalogProductPrice>(\n em,\n CatalogProductPrice,\n { tenantId, product: product.id } as any,\n { limit: 100, orderBy: { createdAt: 'asc' } as any } as any,\n scope,\n ),\n findWithDecryption<Attachment>(\n em,\n Attachment,\n { tenantId, entityId: E.catalog.catalog_product, recordId: product.id } as any,\n { limit: 100, orderBy: { createdAt: 'asc' } as any } as any,\n scope,\n ),\n findWithDecryption<CatalogProductUnitConversion>(\n em,\n CatalogProductUnitConversion,\n { tenantId, product: product.id, deletedAt: null } as any,\n { limit: 100, orderBy: { sortOrder: 'asc', createdAt: 'asc' } as any } as any,\n scope,\n ),\n loadCustomFieldValues({\n em,\n entityId: E.catalog.catalog_product,\n recordIds: [product.id],\n tenantIdByRecord: { [product.id]: product.tenantId ?? null },\n organizationIdByRecord: { [product.id]: product.organizationId ?? null },\n tenantFallbacks: [product.tenantId ?? tenantId].filter((value): value is string => !!value),\n }),\n resolveAttributeSchema(ctx, tenantId, product.id, undefined),\n ])\n\n const categories = categoryAssignments\n .map((assignment) => {\n const category = (assignment as any).category\n if (!category || typeof category === 'string') {\n const fallbackId = typeof category === 'string' ? category : null\n return fallbackId ? { id: fallbackId, name: null, slug: null, path: null } : null\n }\n return {\n id: category.id,\n name: category.name ?? null,\n slug: category.slug ?? null,\n path: category.treePath ?? null,\n }\n })\n .filter((value): value is { id: string; name: string | null; slug: string | null; path: string | null } => value !== null)\n\n const tags = tagAssignments\n .map((assignment) => {\n const tag = (assignment as any).tag as CatalogProductTag | string | null\n if (!tag || typeof tag === 'string') return null\n return { id: tag.id, label: tag.label, slug: tag.slug }\n })\n .filter((value): value is { id: string; label: string; slug: string } => value !== null)\n\n const priceRows = prices.map((row) => ({\n id: row.id,\n priceKindId: (row as any).priceKind && typeof (row as any).priceKind === 'object'\n ? (row as any).priceKind.id\n : (row as any).priceKind ?? null,\n currencyCode: row.currencyCode,\n kind: row.kind,\n minQuantity: row.minQuantity,\n maxQuantity: row.maxQuantity ?? null,\n unitPriceNet: row.unitPriceNet ?? null,\n unitPriceGross: row.unitPriceGross ?? null,\n taxRate: row.taxRate ?? null,\n taxAmount: row.taxAmount ?? null,\n channelId: row.channelId ?? null,\n offerId: (row as any).offer && typeof (row as any).offer === 'object'\n ? (row as any).offer.id\n : (row as any).offer ?? null,\n variantId: (row as any).variant && typeof (row as any).variant === 'object'\n ? (row as any).variant.id\n : (row as any).variant ?? null,\n startsAt: row.startsAt ? new Date(row.startsAt).toISOString() : null,\n endsAt: row.endsAt ? new Date(row.endsAt).toISOString() : null,\n }))\n\n let bestPrice: Record<string, unknown> | null = null\n const pricingService = resolvePricingService(ctx)\n if (pricingService && prices.length > 0) {\n const pricingContext: PricingContext = {\n quantity: 1,\n date: new Date(),\n }\n try {\n const resolved = await pricingService.resolvePrice(prices as unknown as PriceRow[], pricingContext)\n if (resolved) {\n bestPrice = {\n id: (resolved as any).id,\n currencyCode: (resolved as any).currencyCode,\n kind: (resolved as any).kind,\n unitPriceNet: (resolved as any).unitPriceNet ?? null,\n unitPriceGross: (resolved as any).unitPriceGross ?? null,\n }\n }\n } catch (error) {\n console.warn('[catalog.get_product_bundle] resolvePrice failed, omitting best price', error)\n }\n }\n\n return {\n found: true,\n id: product.id,\n product: toProductSummary(product),\n categories,\n tags,\n variants: variants.map((variant) => ({\n id: variant.id,\n name: variant.name ?? null,\n sku: variant.sku ?? null,\n barcode: variant.barcode ?? null,\n optionValues: variant.optionValues ?? null,\n defaultMediaId: variant.defaultMediaId ?? null,\n defaultMediaUrl: variant.defaultMediaUrl ?? null,\n isDefault: !!variant.isDefault,\n isActive: !!variant.isActive,\n })),\n prices: {\n all: priceRows,\n best: bestPrice,\n },\n media: mediaAttachments.map((attachment) => ({\n mediaId: attachment.id,\n attachmentId: attachment.id,\n fileName: attachment.fileName,\n mediaType: attachment.mimeType,\n size: attachment.fileSize,\n altText: null,\n sortOrder: 0,\n })),\n customFields: customFieldValues[product.id] ?? {},\n attributeSchema,\n // No translation resolver exists for catalog (no `translations.ts` at\n // module root yet); returning null is an explicit null-surface contract\n // and a hint for Step 5+ to add the translations resolver.\n translations: null,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|