@open-mercato/core 0.4.5-develop-3ce83a8b24 → 0.4.5-develop-539cff4960
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/generated/entities/catalog_product/index.js +16 -0
- package/dist/generated/entities/catalog_product/index.js.map +2 -2
- package/dist/generated/entities/catalog_product_unit_conversion/index.js +27 -0
- package/dist/generated/entities/catalog_product_unit_conversion/index.js.map +7 -0
- package/dist/generated/entities/sales_credit_memo_line/index.js +7 -1
- package/dist/generated/entities/sales_credit_memo_line/index.js.map +2 -2
- package/dist/generated/entities/sales_invoice_line/index.js +7 -1
- package/dist/generated/entities/sales_invoice_line/index.js.map +2 -2
- package/dist/generated/entities/sales_order_line/index.js +6 -0
- package/dist/generated/entities/sales_order_line/index.js.map +2 -2
- package/dist/generated/entities/sales_quote_line/index.js +6 -0
- package/dist/generated/entities/sales_quote_line/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +1 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/catalog/api/prices/route.js +123 -8
- package/dist/modules/catalog/api/prices/route.js.map +2 -2
- package/dist/modules/catalog/api/product-unit-conversions/route.js +194 -0
- package/dist/modules/catalog/api/product-unit-conversions/route.js.map +7 -0
- package/dist/modules/catalog/api/products/route.js +351 -201
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +1267 -497
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +733 -210
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/commands/index.js +1 -0
- package/dist/modules/catalog/commands/index.js.map +2 -2
- package/dist/modules/catalog/commands/productUnitConversions.js +503 -0
- package/dist/modules/catalog/commands/productUnitConversions.js.map +7 -0
- package/dist/modules/catalog/commands/products.js +355 -73
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/shared.js +18 -4
- package/dist/modules/catalog/commands/shared.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductUomSection.js +591 -0
- package/dist/modules/catalog/components/products/ProductUomSection.js.map +7 -0
- package/dist/modules/catalog/components/products/productForm.js +66 -5
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/catalog/components/products/productFormUtils.js +68 -0
- package/dist/modules/catalog/components/products/productFormUtils.js.map +7 -0
- package/dist/modules/catalog/data/entities.js +86 -0
- package/dist/modules/catalog/data/entities.js.map +2 -2
- package/dist/modules/catalog/data/validators.js +65 -3
- package/dist/modules/catalog/data/validators.js.map +2 -2
- package/dist/modules/catalog/events.js +3 -0
- package/dist/modules/catalog/events.js.map +2 -2
- package/dist/modules/catalog/lib/unitCodes.js +7 -0
- package/dist/modules/catalog/lib/unitCodes.js.map +7 -0
- package/dist/modules/catalog/lib/unitResolution.js +53 -0
- package/dist/modules/catalog/lib/unitResolution.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20260218225422.js +19 -0
- package/dist/modules/catalog/migrations/Migration20260218225422.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20260219084500.js +27 -0
- package/dist/modules/catalog/migrations/Migration20260219084500.js.map +7 -0
- package/dist/modules/catalog/search.js +69 -1
- package/dist/modules/catalog/search.js.map +2 -2
- package/dist/modules/catalog/seed/examples.js +91 -42
- package/dist/modules/catalog/seed/examples.js.map +2 -2
- package/dist/modules/dashboards/seed/analytics.js +3 -0
- package/dist/modules/dashboards/seed/analytics.js.map +2 -2
- package/dist/modules/sales/api/order-lines/route.js +98 -15
- package/dist/modules/sales/api/order-lines/route.js.map +2 -2
- package/dist/modules/sales/api/quote-lines/route.js +101 -14
- package/dist/modules/sales/api/quote-lines/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/public/[token]/route.js +87 -12
- package/dist/modules/sales/api/quotes/public/[token]/route.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +1424 -260
- package/dist/modules/sales/commands/documents.js.map +3 -3
- package/dist/modules/sales/commands/shared.js +6 -2
- package/dist/modules/sales/commands/shared.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +216 -86
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +913 -241
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +3 -3
- package/dist/modules/sales/components/documents/ShipmentsSection.js +15 -3
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/data/entities.js +59 -3
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/data/validators.js +35 -0
- package/dist/modules/sales/data/validators.js.map +2 -2
- package/dist/modules/sales/frontend/quote/[token]/page.js +15 -1
- package/dist/modules/sales/frontend/quote/[token]/page.js.map +2 -2
- package/dist/modules/sales/migrations/Migration20260218225423.js +31 -0
- package/dist/modules/sales/migrations/Migration20260218225423.js.map +7 -0
- package/dist/modules/sales/migrations/Migration20260219084501.js +71 -0
- package/dist/modules/sales/migrations/Migration20260219084501.js.map +7 -0
- package/dist/modules/sales/search.js +28 -0
- package/dist/modules/sales/search.js.map +2 -2
- package/dist/modules/sales/seed/examples.js +14 -1
- package/dist/modules/sales/seed/examples.js.map +2 -2
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js +1 -1
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +28 -15
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/translations.js +9 -0
- package/dist/modules/staff/translations.js.map +7 -0
- package/dist/modules/translations/components/TranslationDrawerAction.js +97 -0
- package/dist/modules/translations/components/TranslationDrawerAction.js.map +7 -0
- package/dist/modules/translations/lib/extract-record-id.js +31 -2
- package/dist/modules/translations/lib/extract-record-id.js.map +2 -2
- package/dist/modules/translations/lib/resolve-field-list.js +3 -0
- package/dist/modules/translations/lib/resolve-field-list.js.map +2 -2
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +105 -36
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +2 -2
- package/dist/modules/translations/widgets/injection-table.js +18 -29
- package/dist/modules/translations/widgets/injection-table.js.map +2 -2
- package/generated/entities/catalog_product/index.ts +8 -0
- package/generated/entities/catalog_product_unit_conversion/index.ts +12 -0
- package/generated/entities/sales_credit_memo_line/index.ts +3 -0
- package/generated/entities/sales_invoice_line/index.ts +3 -0
- package/generated/entities/sales_order_line/index.ts +3 -0
- package/generated/entities/sales_quote_line/index.ts +3 -0
- package/generated/entities.ids.generated.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +2 -2
- package/src/modules/auth/i18n/de.json +1 -1
- package/src/modules/auth/i18n/en.json +1 -1
- package/src/modules/auth/i18n/es.json +1 -1
- package/src/modules/auth/i18n/pl.json +1 -1
- package/src/modules/catalog/api/prices/route.ts +213 -81
- package/src/modules/catalog/api/product-unit-conversions/route.ts +195 -0
- package/src/modules/catalog/api/products/route.ts +638 -402
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +2085 -1072
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +1288 -593
- package/src/modules/catalog/commands/index.ts +1 -0
- package/src/modules/catalog/commands/productUnitConversions.ts +626 -0
- package/src/modules/catalog/commands/products.ts +1151 -693
- package/src/modules/catalog/commands/shared.ts +19 -5
- package/src/modules/catalog/components/products/ProductUomSection.tsx +745 -0
- package/src/modules/catalog/components/products/productForm.ts +369 -256
- package/src/modules/catalog/components/products/productFormUtils.ts +82 -0
- package/src/modules/catalog/data/entities.ts +82 -1
- package/src/modules/catalog/data/validators.ts +118 -34
- package/src/modules/catalog/events.ts +3 -0
- package/src/modules/catalog/i18n/de.json +56 -0
- package/src/modules/catalog/i18n/en.json +56 -0
- package/src/modules/catalog/i18n/es.json +56 -0
- package/src/modules/catalog/i18n/pl.json +56 -0
- package/src/modules/catalog/lib/unitCodes.ts +1 -0
- package/src/modules/catalog/lib/unitResolution.ts +62 -0
- package/src/modules/catalog/migrations/.snapshot-open-mercato.json +245 -0
- package/src/modules/catalog/migrations/Migration20260218225422.ts +21 -0
- package/src/modules/catalog/migrations/Migration20260219084500.ts +26 -0
- package/src/modules/catalog/search.ts +73 -1
- package/src/modules/catalog/seed/examples.ts +552 -479
- package/src/modules/dashboards/i18n/de.json +1 -1
- package/src/modules/dashboards/i18n/en.json +1 -1
- package/src/modules/dashboards/i18n/es.json +1 -1
- package/src/modules/dashboards/i18n/pl.json +1 -1
- package/src/modules/dashboards/seed/analytics.ts +3 -0
- package/src/modules/sales/api/order-lines/route.ts +158 -68
- package/src/modules/sales/api/quote-lines/route.ts +161 -67
- package/src/modules/sales/api/quotes/public/[token]/route.ts +122 -36
- package/src/modules/sales/commands/documents.ts +4250 -2424
- package/src/modules/sales/commands/shared.ts +7 -2
- package/src/modules/sales/components/documents/ItemsSection.tsx +580 -310
- package/src/modules/sales/components/documents/LineItemDialog.tsx +1988 -833
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +17 -3
- package/src/modules/sales/components/documents/lineItemTypes.ts +6 -0
- package/src/modules/sales/data/entities.ts +53 -0
- package/src/modules/sales/data/validators.ts +36 -0
- package/src/modules/sales/frontend/quote/[token]/page.tsx +25 -1
- package/src/modules/sales/i18n/de.json +23 -3
- package/src/modules/sales/i18n/en.json +23 -3
- package/src/modules/sales/i18n/es.json +23 -3
- package/src/modules/sales/i18n/pl.json +23 -3
- package/src/modules/sales/lib/types.ts +30 -0
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +172 -0
- package/src/modules/sales/migrations/Migration20260218225423.ts +37 -0
- package/src/modules/sales/migrations/Migration20260219084501.ts +73 -0
- package/src/modules/sales/search.ts +28 -0
- package/src/modules/sales/seed/examples.ts +20 -1
- package/src/modules/sales/widgets/injection/document-history/widget.client.tsx +1 -1
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +8 -0
- package/src/modules/staff/translations.ts +5 -0
- package/src/modules/translations/components/TranslationDrawerAction.tsx +107 -0
- package/src/modules/translations/lib/extract-record-id.ts +47 -3
- package/src/modules/translations/lib/resolve-field-list.ts +4 -0
- package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +108 -36
- package/src/modules/translations/widgets/injection-table.ts +19 -33
- package/src/modules/workflows/i18n/de.json +4 -4
- package/src/modules/workflows/i18n/en.json +4 -4
- package/src/modules/workflows/i18n/es.json +4 -4
- package/src/modules/workflows/i18n/pl.json +4 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/catalog/seed/examples.ts"],
|
|
4
|
-
"sourcesContent": ["import { randomUUID } from 'node:crypto'\nimport path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { AwilixContainer } from 'awilix'\nimport { SalesChannel } from '@open-mercato/core/modules/sales/data/entities'\nimport {\n CatalogOffer,\n CatalogPriceKind,\n CatalogProduct,\n CatalogProductCategory,\n CatalogProductCategoryAssignment,\n CatalogProductPrice,\n CatalogProductVariant,\n} from '../data/entities'\nimport { DefaultDataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { ensureCustomFieldDefinitions, type FieldSetInput } from '@open-mercato/core/modules/entities/lib/field-definitions'\nimport { CustomFieldEntityConfig } from '@open-mercato/core/modules/entities/data/entities'\nimport { rebuildCategoryHierarchyForOrganization } from '../lib/categoryHierarchy'\nimport { defineFields, cf } from '@open-mercato/shared/modules/dsl'\nimport { E } from '#generated/entities.ids.generated'\nimport { SalesTaxRate } from '@open-mercato/core/modules/sales/data/entities'\nimport { Attachment, AttachmentPartition } from '@open-mercato/core/modules/attachments/data/entities'\nimport { ensureDefaultPartitions, resolveDefaultPartitionCode } from '@open-mercato/core/modules/attachments/lib/partitions'\nimport { storePartitionFile } from '@open-mercato/core/modules/attachments/lib/storage'\nimport { mergeAttachmentMetadata } from '@open-mercato/core/modules/attachments/lib/metadata'\nimport { buildAttachmentFileUrl, buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\n\ntype SeedScope = { tenantId: string; organizationId: string }\n\nconst EXAMPLES_MEDIA_ROOT = path.join(process.cwd(), 'public', 'examples')\n\nfunction detectMimeType(fileName: string): string {\n const ext = fileName.toLowerCase().split('.').pop() || ''\n if (ext === 'png') return 'image/png'\n if (ext === 'jpg' || ext === 'jpeg') return 'image/jpeg'\n if (ext === 'webp') return 'image/webp'\n return 'application/octet-stream'\n}\n\nasync function ensureAttachmentPartition(\n em: EntityManager,\n code: string\n): Promise<AttachmentPartition> {\n let partition = await em.findOne(AttachmentPartition, { code })\n if (!partition) {\n await ensureDefaultPartitions(em)\n partition = await em.findOne(AttachmentPartition, { code })\n }\n if (!partition) {\n throw new Error(`Attachment partition \"${code}\" is not configured.`)\n }\n return partition\n}\n\nasync function attachMediaFromExamples(\n em: EntityManager,\n scope: SeedScope,\n entityId: string,\n recordId: string,\n mediaSeeds?: MediaSeed[]\n): Promise<Array<{ id: string; imageUrl: string }>> {\n if (!mediaSeeds?.length) return []\n const partitionCode = resolveDefaultPartitionCode(entityId)\n const partition = await ensureAttachmentPartition(em, partitionCode)\n const results: Array<{ id: string; imageUrl: string }> = []\n for (const media of mediaSeeds) {\n const sourcePath = path.join(EXAMPLES_MEDIA_ROOT, media.file)\n let buffer: Buffer\n try {\n buffer = await fs.readFile(sourcePath)\n } catch (error) {\n console.warn(`[catalog.seed] Example media missing: ${sourcePath}`)\n continue\n }\n const stored = await storePartitionFile({\n partitionCode: partition.code,\n orgId: scope.organizationId,\n tenantId: scope.tenantId,\n fileName: media.file,\n buffer,\n })\n const attachmentId = randomUUID()\n const slug = slugifyAttachmentFileName(media.file, 'media')\n const metadata = mergeAttachmentMetadata(null, {\n assignments: [{ type: entityId, id: recordId }],\n })\n const attachment = em.create(Attachment, {\n id: attachmentId,\n entityId,\n recordId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n partitionCode: partition.code,\n fileName: media.file,\n mimeType: detectMimeType(media.file),\n fileSize: buffer.length,\n storageDriver: partition.storageDriver || 'local',\n storagePath: stored.storagePath,\n storageMetadata: metadata,\n url: buildAttachmentFileUrl(attachmentId),\n })\n em.persist(attachment)\n results.push({\n id: attachmentId,\n imageUrl: buildAttachmentImageUrl(attachmentId, { slug }),\n })\n }\n return results\n}\n\nconst PRODUCT_FIELDSETS = [\n {\n code: 'fashion_mens_footwear',\n label: 'Fashion \u00B7 Men \u00B7 Footwear',\n icon: 'carbon:sneaker',\n description: 'Material, construction, and care metadata for men\u2019s performance footwear.',\n groups: [\n { code: 'identity', title: 'Identity' },\n { code: 'materials', title: 'Materials & Build' },\n { code: 'care', title: 'Care instructions' },\n ],\n },\n {\n code: 'fashion_womens_dresses',\n label: 'Fashion \u00B7 Women \u00B7 Dresses & Jumpsuits',\n icon: 'solar:dress-linear',\n description: 'Silhouette, fabric, and care metadata for womenswear.',\n groups: [\n { code: 'identity', title: 'Identity' },\n { code: 'materials', title: 'Materials' },\n { code: 'fit', title: 'Fit & Length' },\n { code: 'care', title: 'Care instructions' },\n ],\n },\n {\n code: 'service_schedule',\n label: 'Services \u00B7 Scheduling',\n icon: 'solar:calendar-linear',\n description: 'Scheduling, preparation, and delivery metadata for service offerings.',\n groups: [\n { code: 'identity', title: 'Identity' },\n { code: 'timing', title: 'Timing rules' },\n { code: 'resources', title: 'Resources & Delivery' },\n ],\n },\n] as const\n\nconst VARIANT_FIELDSETS = [\n {\n code: 'fashion_mens_footwear',\n label: 'Fashion \u00B7 Men \u00B7 Footwear',\n icon: 'carbon:sneaker',\n description: 'Variant-level sizing metadata for men\u2019s footwear.',\n groups: [\n { code: 'fit', title: 'Fit' },\n { code: 'finish', title: 'Finish' },\n ],\n },\n {\n code: 'fashion_womens_dresses',\n label: 'Fashion \u00B7 Women \u00B7 Dresses & Jumpsuits',\n icon: 'solar:dress-linear',\n description: 'Variant-level sizing metadata for womenswear.',\n groups: [\n { code: 'fit', title: 'Fit' },\n { code: 'finish', title: 'Finish' },\n ],\n },\n {\n code: 'service_schedule',\n label: 'Services \u00B7 Scheduling',\n icon: 'solar:calendar-linear',\n description: 'Provider, duration, and environment metadata for service slots.',\n groups: [\n { code: 'provider', title: 'Provider' },\n { code: 'environment', title: 'Environment' },\n ],\n },\n] as const\n\nconst CUSTOM_FIELD_SETS: FieldSetInput[] = [\n defineFields(E.catalog.catalog_product, [\n cf.text('style_code', {\n label: 'Style code',\n description: 'Reference code shared with merchandising teams.',\n filterable: true,\n fieldset: 'fashion_mens_footwear',\n group: { code: 'identity' },\n }),\n cf.select('upper_material', ['engineered_knit', 'full_grain_leather', 'recycled_mesh'], {\n label: 'Upper material',\n fieldset: 'fashion_mens_footwear',\n group: { code: 'materials' },\n filterable: true,\n }),\n cf.select('cushioning_profile', ['responsive', 'plush', 'stability'], {\n label: 'Cushioning profile',\n fieldset: 'fashion_mens_footwear',\n group: { code: 'materials' },\n }),\n cf.multiline('care_notes', {\n label: 'Care notes',\n editor: 'markdown',\n fieldset: 'fashion_mens_footwear',\n group: { code: 'care' },\n }),\n ]),\n defineFields(E.catalog.catalog_product, [\n cf.select('silhouette', ['wrap', 'column', 'fit_and_flare', 'jumpsuit'], {\n label: 'Silhouette',\n fieldset: 'fashion_womens_dresses',\n group: { code: 'identity' },\n filterable: true,\n }),\n cf.select('fabric_mix', ['silk_blend', 'recycled_poly', 'linen', 'cupro'], {\n label: 'Fabric mix',\n fieldset: 'fashion_womens_dresses',\n group: { code: 'materials' },\n }),\n cf.select('occasion_ready', ['daytime', 'evening', 'resort'], {\n label: 'Occasion',\n fieldset: 'fashion_womens_dresses',\n group: { code: 'fit' },\n }),\n cf.multiline('finishing_details', {\n label: 'Finishing details',\n editor: 'markdown',\n fieldset: 'fashion_womens_dresses',\n group: { code: 'care' },\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.integer('shoe_size', {\n label: 'US size',\n fieldset: 'fashion_mens_footwear',\n group: { code: 'fit' },\n filterable: true,\n }),\n cf.select('shoe_width', ['B', 'D', 'EE'], {\n label: 'Width',\n fieldset: 'fashion_mens_footwear',\n group: { code: 'fit' },\n }),\n cf.text('colorway', {\n label: 'Colorway',\n fieldset: 'fashion_mens_footwear',\n group: { code: 'finish' },\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.integer('numeric_size', {\n label: 'Numeric size',\n fieldset: 'fashion_womens_dresses',\n group: { code: 'fit' },\n }),\n cf.select('length_profile', ['mini', 'midi', 'maxi'], {\n label: 'Length',\n fieldset: 'fashion_womens_dresses',\n group: { code: 'fit' },\n }),\n cf.text('color_story', {\n label: 'Color story',\n fieldset: 'fashion_womens_dresses',\n group: { code: 'finish' },\n }),\n ]),\n defineFields(E.catalog.catalog_product, [\n cf.integer('service_duration_minutes', {\n label: 'Duration (minutes)',\n description: 'Length of a single service slot.',\n fieldset: 'service_schedule',\n group: { code: 'timing' },\n filterable: true,\n required: true,\n }),\n cf.integer('service_buffer_minutes', {\n label: 'Buffer between appointments',\n description: 'Minimum downtime between consecutive service slots (minutes).',\n fieldset: 'service_schedule',\n group: { code: 'timing' },\n }),\n cf.text('service_location', {\n label: 'Location / Room',\n description: 'Where the service is delivered.',\n fieldset: 'service_schedule',\n group: { code: 'identity' },\n }),\n cf.select('service_resources', ['stylist', 'therapist', 'treatment_room', 'wash_station', 'steam_room'], {\n label: 'Required resources',\n description: 'Staff or rooms required to perform the service.',\n fieldset: 'service_schedule',\n group: { code: 'resources' },\n multi: true,\n }),\n cf.boolean('service_remote_available', {\n label: 'Remote session available',\n description: 'Indicates whether the service can be performed remotely or virtually.',\n fieldset: 'service_schedule',\n group: { code: 'resources' },\n defaultValue: false,\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.select('provider_level', ['junior', 'senior', 'master'], {\n label: 'Provider level',\n description: 'Seniority of the assigned specialist.',\n fieldset: 'service_schedule',\n group: { code: 'provider' },\n filterable: true,\n }),\n cf.text('staff_member', {\n label: 'Staff member',\n description: 'Optional name of the staff member who usually delivers this variant.',\n fieldset: 'service_schedule',\n group: { code: 'provider' },\n }),\n cf.select('environment_type', ['studio', 'suite', 'on_site'], {\n label: 'Environment',\n description: 'Where the session is hosted.',\n fieldset: 'service_schedule',\n group: { code: 'environment' },\n }),\n ]),\n]\n\ntype CategorySeed = {\n slug: string\n name: string\n description?: string\n children?: CategorySeed[]\n}\n\nconst CATEGORY_TREE: CategorySeed[] = [\n {\n slug: 'fashion',\n name: 'Fashion',\n description: 'Seasonal assortments and vertical-specific collections.',\n children: [\n {\n slug: 'fashion-men',\n name: 'Men',\n children: [\n {\n slug: 'fashion-men-footwear',\n name: 'Footwear',\n description: 'Premium sneakers, boots, and sandals.',\n },\n ],\n },\n {\n slug: 'fashion-women',\n name: 'Women',\n children: [\n {\n slug: 'fashion-women-dresses-jumpsuits',\n name: 'Dresses & Jumpsuits',\n description: 'Occasion-ready dresses and tailored jumpsuits.',\n },\n ],\n },\n ],\n },\n {\n slug: 'services',\n name: 'Services',\n description: 'Bookable in-person and virtual experiences.',\n children: [\n {\n slug: 'services-hairdresser',\n name: 'Hairdresser',\n description: 'Salon services ranging from quick trims to signature looks.',\n },\n {\n slug: 'services-massage',\n name: 'Massage',\n description: 'Wellness treatments and bodywork sessions.',\n },\n ],\n },\n]\n\ntype MediaSeed = {\n file: string\n title?: string\n}\n\ntype VariantSeed = {\n name: string\n sku: string\n isDefault?: boolean\n optionValues?: Record<string, string>\n prices: {\n regular: number\n sale?: number\n }\n customFields?: Record<string, string | number | boolean | null>\n media?: MediaSeed[]\n}\n\ntype ProductSeed = {\n title: string\n handle: string\n sku?: string\n description: string\n categorySlug: string\n customFieldsetCode: string\n variantFieldsetCode: string\n unit: string\n metadata?: Record<string, unknown>\n customFields?: Record<string, string | number | boolean | null>\n media?: MediaSeed[]\n variants: VariantSeed[]\n}\n\nconst PRODUCT_SEEDS: ProductSeed[] = [\n {\n title: 'Atlas Runner Sneaker',\n handle: 'atlas-runner-sneaker',\n sku: 'ATLAS-RUNNER',\n description:\n 'Lightweight road sneaker engineered with a breathable knit upper, recycled TPU overlays, and a decoupled heel for smooth transitions.',\n categorySlug: 'fashion-men-footwear',\n customFieldsetCode: 'fashion_mens_footwear',\n variantFieldsetCode: 'fashion_mens_footwear',\n unit: 'pair',\n metadata: { division: 'RunLab', season: 'SS25' },\n customFields: {\n style_code: 'AR-2025',\n upper_material: 'engineered_knit',\n cushioning_profile: 'responsive',\n care_notes: 'Spot clean after each run and air dry. Avoid machine drying.',\n },\n media: [\n { file: 'atlas-runner-midnight-1.png' },\n ],\n variants: [\n {\n name: 'Midnight Navy \u00B7 US 8',\n sku: 'ATLAS-RUN-NAVY-8',\n isDefault: true,\n optionValues: { color: 'Midnight Navy', size: 'US 8' },\n prices: { regular: 168, sale: 148 },\n customFields: { shoe_size: 8, shoe_width: 'D', colorway: 'Midnight Navy' },\n media: [\n { file: 'atlas-runner-midnight-1.png' },\n { file: 'atlas-runner-midnight-2.png' },\n ],\n },\n {\n name: 'Glacier Grey \u00B7 US 10',\n sku: 'ATLAS-RUN-GLACIER-10',\n optionValues: { color: 'Glacier Grey', size: 'US 10' },\n prices: { regular: 168, sale: 138 },\n customFields: { shoe_size: 10, shoe_width: 'EE', colorway: 'Glacier Grey' },\n media: [\n { file: 'atlas-runner-glacier-1.png' },\n { file: 'atlas-runner-glacier-2.png' },\n ],\n },\n ],\n },\n {\n title: 'Aurora Wrap Dress',\n handle: 'aurora-wrap-dress',\n sku: 'AURORA-WRAP',\n description:\n 'Bias-cut wrap dress with blouson sleeves, matte silk blend, and hidden interior snaps so the placket stays put at events.',\n categorySlug: 'fashion-women-dresses-jumpsuits',\n customFieldsetCode: 'fashion_womens_dresses',\n variantFieldsetCode: 'fashion_womens_dresses',\n unit: 'unit',\n metadata: { capsule: 'Evening Atelier', season: 'Resort 25' },\n customFields: {\n silhouette: 'wrap',\n fabric_mix: 'silk_blend',\n occasion_ready: 'evening',\n finishing_details: 'Hand-finished hem with subtle tonal beading along the wrap edge.',\n },\n media: [\n { file: 'aurora-wrap-rosewood.png' },\n ],\n variants: [\n {\n name: 'Rosewood \u00B7 Medium',\n sku: 'AURORA-ROSE-M',\n isDefault: true,\n optionValues: { color: 'Rosewood', size: 'Medium' },\n prices: { regular: 248, sale: 212 },\n customFields: { numeric_size: 6, length_profile: 'midi', color_story: 'Rosewood' },\n media: [\n { file: 'aurora-wrap-rosewood.png' },\n ],\n },\n {\n name: 'Celestial \u00B7 Large',\n sku: 'AURORA-CELESTIAL-L',\n optionValues: { color: 'Celestial', size: 'Large' },\n prices: { regular: 248, sale: 198 },\n customFields: { numeric_size: 8, length_profile: 'maxi', color_story: 'Celestial blue' },\n media: [\n { file: 'aurora-wrap-celestial.png' },\n ],\n },\n ],\n },\n {\n title: 'Signature Haircut & Finish',\n handle: 'signature-haircut-service',\n sku: 'SERV-HAIR-60',\n description:\n 'Tailored haircut with relaxing wash, scalp massage, and styling finish. Designed for repeat visits in the demo portal.',\n categorySlug: 'services-hairdresser',\n customFieldsetCode: 'service_schedule',\n variantFieldsetCode: 'service_schedule',\n unit: 'hour',\n metadata: { channel: 'salon', serviceType: 'hairdresser' },\n customFields: {\n service_duration_minutes: 60,\n service_buffer_minutes: 15,\n service_location: 'Salon Studio 3',\n service_resources: 'stylist,wash_station',\n service_remote_available: false,\n },\n media: [{ file: 'hairdresser-service.png' }],\n variants: [\n {\n name: 'Senior Stylist \u00B7 60 min',\n sku: 'SERV-HAIR-60-SENIOR',\n isDefault: true,\n optionValues: { stylist: 'Senior', duration: '60' },\n prices: { regular: 95, sale: 85 },\n customFields: {\n provider_level: 'senior',\n staff_member: 'Amelia Hart',\n environment_type: 'studio',\n },\n media: [{ file: 'hairdresser-service.png' }],\n },\n ],\n },\n {\n title: 'Restorative Massage Session',\n handle: 'restorative-massage-service',\n sku: 'SERV-MASSAGE-90',\n description:\n 'Full-body massage with aromatherapy oils and guided breathing. Includes complimentary refreshments and studio amenities.',\n categorySlug: 'services-massage',\n customFieldsetCode: 'service_schedule',\n variantFieldsetCode: 'service_schedule',\n unit: 'hour',\n metadata: { channel: 'wellness', serviceType: 'massage' },\n customFields: {\n service_duration_minutes: 90,\n service_buffer_minutes: 20,\n service_location: 'Wellness Suite B',\n service_resources: 'therapist,treatment_room,steam_room',\n service_remote_available: false,\n },\n media: [{ file: 'massage-service.png' }],\n variants: [\n {\n name: 'Master Therapist \u00B7 90 min',\n sku: 'SERV-MASSAGE-90-MASTER',\n isDefault: true,\n optionValues: { therapist: 'Master', duration: '90' },\n prices: { regular: 140, sale: 120 },\n customFields: {\n provider_level: 'master',\n staff_member: 'Noah Li',\n environment_type: 'suite',\n },\n media: [{ file: 'massage-service.png' }],\n },\n ],\n },\n]\n\nconst CHANNEL_DEFINITION = {\n code: 'fashion-online',\n name: 'Mercato Fashion Online',\n description: 'Direct-to-consumer storefront showcasing premium demos.',\n websiteUrl: 'https://demo.open-mercato.com',\n contactEmail: 'store@open-mercato.com',\n}\n\nfunction formatMoney(value: number): string {\n return value.toFixed(2)\n}\n\nasync function resolveDefaultTaxRate(\n em: EntityManager,\n scope: SeedScope\n): Promise<SalesTaxRate | null> {\n const [rate] = await em.find(\n SalesTaxRate,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n },\n {\n limit: 1,\n orderBy: {\n isDefault: 'DESC',\n priority: 'ASC',\n rate: 'DESC',\n createdAt: 'ASC',\n },\n }\n )\n return rate ?? null\n}\n\nasync function ensureFieldsetConfig(\n em: EntityManager,\n scope: SeedScope,\n entityId: string,\n fieldsets: typeof PRODUCT_FIELDSETS | typeof VARIANT_FIELDSETS\n): Promise<void> {\n const now = new Date()\n let config = await em.findOne(CustomFieldEntityConfig, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!config) {\n config = em.create(CustomFieldEntityConfig, {\n id: randomUUID(),\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n })\n }\n config.configJson = {\n fieldsets,\n singleFieldsetPerRecord: true,\n }\n config.isActive = true\n config.updatedAt = now\n em.persist(config)\n}\n\nasync function ensureFieldsetsAndDefinitions(em: EntityManager, scope: SeedScope): Promise<void> {\n await ensureFieldsetConfig(em, scope, E.catalog.catalog_product, PRODUCT_FIELDSETS)\n await ensureFieldsetConfig(em, scope, E.catalog.catalog_product_variant, VARIANT_FIELDSETS)\n await ensureCustomFieldDefinitions(em, CUSTOM_FIELD_SETS, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n await em.flush()\n}\n\nasync function ensureCategories(\n em: EntityManager,\n scope: SeedScope\n): Promise<Map<string, CatalogProductCategory>> {\n const map = new Map<string, CatalogProductCategory>()\n const now = new Date()\n\n const upsert = async (seed: CategorySeed, parent: CatalogProductCategory | null) => {\n let record = await em.findOne(CatalogProductCategory, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n slug: seed.slug,\n })\n if (!record) {\n record = em.create(CatalogProductCategory, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: seed.name,\n slug: seed.slug,\n description: seed.description ?? null,\n parentId: parent ? parent.id : null,\n rootId: parent ? parent.rootId ?? parent.id : null,\n treePath: null,\n depth: parent ? (parent.depth ?? 0) + 1 : 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\n metadata: null,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n })\n em.persist(record)\n } else {\n record.name = seed.name\n record.description = seed.description ?? null\n record.parentId = parent ? parent.id : null\n record.isActive = true\n record.updatedAt = now\n }\n map.set(seed.slug, record)\n if (Array.isArray(seed.children)) {\n for (const child of seed.children) {\n await upsert(child, record)\n }\n }\n }\n\n for (const seed of CATEGORY_TREE) {\n await upsert(seed, null)\n }\n\n await em.flush()\n await rebuildCategoryHierarchyForOrganization(em, scope.organizationId, scope.tenantId)\n\n return map\n}\n\nasync function ensureChannel(em: EntityManager, scope: SeedScope): Promise<SalesChannel> {\n const now = new Date()\n let channel = await em.findOne(SalesChannel, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n code: CHANNEL_DEFINITION.code,\n deletedAt: null,\n })\n if (!channel) {\n channel = em.create(SalesChannel, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n code: CHANNEL_DEFINITION.code,\n name: CHANNEL_DEFINITION.name,\n description: CHANNEL_DEFINITION.description,\n websiteUrl: CHANNEL_DEFINITION.websiteUrl,\n contactEmail: CHANNEL_DEFINITION.contactEmail,\n status: 'active',\n isActive: true,\n metadata: { locale: 'en-US' },\n createdAt: now,\n updatedAt: now,\n })\n em.persist(channel)\n await em.flush()\n }\n return channel\n}\n\nasync function loadPriceKinds(\n em: EntityManager,\n scope: SeedScope\n): Promise<Map<string, CatalogPriceKind>> {\n const kinds = await em.find(CatalogPriceKind, {\n tenantId: scope.tenantId,\n code: { $in: ['regular', 'sale'] },\n deletedAt: null,\n })\n const map = new Map<string, CatalogPriceKind>()\n for (const kind of kinds) {\n map.set(kind.code.toLowerCase(), kind)\n }\n return map\n}\n\nexport async function seedCatalogExamples(\n em: EntityManager,\n container: AwilixContainer,\n scope: SeedScope\n): Promise<boolean> {\n await ensureFieldsetsAndDefinitions(em, scope)\n await ensureDefaultPartitions(em)\n\n const handles = PRODUCT_SEEDS.map((seed) => seed.handle)\n const existingProducts = await em.find(CatalogProduct, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n handle: { $in: handles as any },\n })\n const existingByHandle = new Map(existingProducts.map((product) => [product.handle?.toLowerCase(), product]))\n\n const categoryMap = await ensureCategories(em, scope)\n const channel = await ensureChannel(em, scope)\n const priceKinds = await loadPriceKinds(em, scope)\n const regularKind = priceKinds.get('regular')\n const saleKind = priceKinds.get('sale')\n const defaultTaxRate = await resolveDefaultTaxRate(em, scope)\n const defaultTaxRateId = defaultTaxRate?.id ?? null\n const defaultTaxRateValue = defaultTaxRate?.rate ?? null\n if (!regularKind || !saleKind) {\n throw new Error('Missing catalog price kinds; run `mercato catalog seed-price-kinds` first.')\n }\n\n const dataEngine = new DefaultDataEngine(em, container)\n const customFieldAssignments: Array<() => Promise<void>> = []\n let createdAny = false\n\n for (const productSeed of PRODUCT_SEEDS) {\n const existing = existingByHandle.get(productSeed.handle.toLowerCase())\n if (existing) {\n continue\n }\n createdAny = true\n const product = em.create(CatalogProduct, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: productSeed.title,\n description: productSeed.description,\n sku: productSeed.sku ?? null,\n handle: productSeed.handle,\n productType: 'configurable',\n primaryCurrencyCode: 'USD',\n defaultUnit: productSeed.unit,\n customFieldsetCode: productSeed.customFieldsetCode,\n metadata: productSeed.metadata ?? null,\n taxRateId: defaultTaxRateId,\n taxRate: defaultTaxRateValue,\n isConfigurable: true,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(product)\n\n const category = categoryMap.get(productSeed.categorySlug)\n if (category) {\n const assignment = em.create(CatalogProductCategoryAssignment, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n category,\n position: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(assignment)\n }\n\n const offer = em.create(CatalogOffer, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n channelId: channel.id,\n title: `${productSeed.title} \u00B7 Online`,\n description: 'Offer curated for the demo storefront channel.',\n metadata: { channelCode: CHANNEL_DEFINITION.code },\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(offer)\n\n if (productSeed.customFields && Object.keys(productSeed.customFields).length) {\n const payload = { ...productSeed.customFields }\n customFieldAssignments.push(() =>\n dataEngine.setCustomFields({\n entityId: E.catalog.catalog_product,\n recordId: product.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: payload,\n })\n )\n }\n\n const productMedia = await attachMediaFromExamples(\n em,\n scope,\n E.catalog.catalog_product,\n product.id,\n productSeed.media\n )\n if (productMedia.length) {\n const hero = productMedia[0]\n product.defaultMediaId = hero.id\n product.defaultMediaUrl = hero.imageUrl\n offer.defaultMediaId = hero.id\n offer.defaultMediaUrl = hero.imageUrl\n }\n\n for (const variantSeed of productSeed.variants) {\n const variant = em.create(CatalogProductVariant, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n name: variantSeed.name,\n sku: variantSeed.sku,\n isDefault: variantSeed.isDefault ?? false,\n optionValues: variantSeed.optionValues ?? null,\n customFieldsetCode: productSeed.variantFieldsetCode,\n metadata: null,\n taxRateId: defaultTaxRateId,\n taxRate: defaultTaxRateValue,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(variant)\n\n const variantMedia = await attachMediaFromExamples(\n em,\n scope,\n E.catalog.catalog_product_variant,\n variant.id,\n variantSeed.media\n )\n const variantCover = variantMedia[0] ?? productMedia[0]\n\n const regularPrice = em.create(CatalogProductPrice, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n variant,\n offer,\n priceKind: regularKind,\n currencyCode: 'USD',\n kind: regularKind.code,\n minQuantity: 1,\n taxRate: defaultTaxRateValue,\n unitPriceGross: formatMoney(variantSeed.prices.regular),\n unitPriceNet: formatMoney(variantSeed.prices.regular),\n channelId: channel.id,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(regularPrice)\n\n if (variantSeed.prices.sale !== undefined) {\n const salePrice = em.create(CatalogProductPrice, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n variant,\n offer,\n priceKind: saleKind,\n currencyCode: 'USD',\n kind: saleKind.code,\n minQuantity: 1,\n taxRate: defaultTaxRateValue,\n unitPriceGross: formatMoney(variantSeed.prices.sale),\n unitPriceNet: formatMoney(variantSeed.prices.sale),\n channelId: channel.id,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(salePrice)\n }\n\n if (variantSeed.customFields && Object.keys(variantSeed.customFields).length) {\n const payload = { ...variantSeed.customFields }\n customFieldAssignments.push(() =>\n dataEngine.setCustomFields({\n entityId: E.catalog.catalog_product_variant,\n recordId: variant.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: payload,\n })\n )\n }\n }\n }\n\n if (!createdAny) {\n return false\n }\n\n await em.flush()\n\n for (const assign of customFieldAssignments) {\n try {\n await assign()\n } catch (err) {\n console.warn('[catalog.seed] Failed to set example custom field values', err)\n }\n }\n\n return true\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport path from \"node:path\";\nimport { promises as fs } from \"node:fs\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport type { AwilixContainer } from \"awilix\";\nimport { SalesChannel } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n CatalogOffer,\n CatalogPriceKind,\n CatalogProduct,\n CatalogProductCategory,\n CatalogProductCategoryAssignment,\n CatalogProductPrice,\n CatalogProductVariant,\n} from \"../data/entities\";\nimport { DefaultDataEngine } from \"@open-mercato/shared/lib/data/engine\";\nimport {\n ensureCustomFieldDefinitions,\n type FieldSetInput,\n} from \"@open-mercato/core/modules/entities/lib/field-definitions\";\nimport { CustomFieldEntityConfig } from \"@open-mercato/core/modules/entities/data/entities\";\nimport { rebuildCategoryHierarchyForOrganization } from \"../lib/categoryHierarchy\";\nimport { defineFields, cf } from \"@open-mercato/shared/modules/dsl\";\nimport { E } from \"#generated/entities.ids.generated\";\nimport { SalesTaxRate } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n Attachment,\n AttachmentPartition,\n} from \"@open-mercato/core/modules/attachments/data/entities\";\nimport {\n ensureDefaultPartitions,\n resolveDefaultPartitionCode,\n} from \"@open-mercato/core/modules/attachments/lib/partitions\";\nimport { storePartitionFile } from \"@open-mercato/core/modules/attachments/lib/storage\";\nimport { mergeAttachmentMetadata } from \"@open-mercato/core/modules/attachments/lib/metadata\";\nimport {\n buildAttachmentFileUrl,\n buildAttachmentImageUrl,\n slugifyAttachmentFileName,\n} from \"@open-mercato/core/modules/attachments/lib/imageUrls\";\nimport { canonicalizeUnitCode } from \"../lib/unitCodes\";\n\ntype SeedScope = { tenantId: string; organizationId: string };\n\nconst EXAMPLES_MEDIA_ROOT = path.join(process.cwd(), \"public\", \"examples\");\n\nfunction detectMimeType(fileName: string): string {\n const ext = fileName.toLowerCase().split(\".\").pop() || \"\";\n if (ext === \"png\") return \"image/png\";\n if (ext === \"jpg\" || ext === \"jpeg\") return \"image/jpeg\";\n if (ext === \"webp\") return \"image/webp\";\n return \"application/octet-stream\";\n}\n\nasync function ensureAttachmentPartition(\n em: EntityManager,\n code: string,\n): Promise<AttachmentPartition> {\n let partition = await em.findOne(AttachmentPartition, { code });\n if (!partition) {\n await ensureDefaultPartitions(em);\n partition = await em.findOne(AttachmentPartition, { code });\n }\n if (!partition) {\n throw new Error(`Attachment partition \"${code}\" is not configured.`);\n }\n return partition;\n}\n\nasync function attachMediaFromExamples(\n em: EntityManager,\n scope: SeedScope,\n entityId: string,\n recordId: string,\n mediaSeeds?: MediaSeed[],\n): Promise<Array<{ id: string; imageUrl: string }>> {\n if (!mediaSeeds?.length) return [];\n const partitionCode = resolveDefaultPartitionCode(entityId);\n const partition = await ensureAttachmentPartition(em, partitionCode);\n const results: Array<{ id: string; imageUrl: string }> = [];\n for (const media of mediaSeeds) {\n const sourcePath = path.join(EXAMPLES_MEDIA_ROOT, media.file);\n let buffer: Buffer;\n try {\n buffer = await fs.readFile(sourcePath);\n } catch (error) {\n console.warn(`[catalog.seed] Example media missing: ${sourcePath}`);\n continue;\n }\n const stored = await storePartitionFile({\n partitionCode: partition.code,\n orgId: scope.organizationId,\n tenantId: scope.tenantId,\n fileName: media.file,\n buffer,\n });\n const attachmentId = randomUUID();\n const slug = slugifyAttachmentFileName(media.file, \"media\");\n const metadata = mergeAttachmentMetadata(null, {\n assignments: [{ type: entityId, id: recordId }],\n });\n const attachment = em.create(Attachment, {\n id: attachmentId,\n entityId,\n recordId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n partitionCode: partition.code,\n fileName: media.file,\n mimeType: detectMimeType(media.file),\n fileSize: buffer.length,\n storageDriver: partition.storageDriver || \"local\",\n storagePath: stored.storagePath,\n storageMetadata: metadata,\n url: buildAttachmentFileUrl(attachmentId),\n });\n em.persist(attachment);\n results.push({\n id: attachmentId,\n imageUrl: buildAttachmentImageUrl(attachmentId, { slug }),\n });\n }\n return results;\n}\n\nconst PRODUCT_FIELDSETS = [\n {\n code: \"fashion_mens_footwear\",\n label: \"Fashion \u00B7 Men \u00B7 Footwear\",\n icon: \"carbon:sneaker\",\n description:\n \"Material, construction, and care metadata for men\u2019s performance footwear.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"materials\", title: \"Materials & Build\" },\n { code: \"care\", title: \"Care instructions\" },\n ],\n },\n {\n code: \"fashion_womens_dresses\",\n label: \"Fashion \u00B7 Women \u00B7 Dresses & Jumpsuits\",\n icon: \"solar:dress-linear\",\n description: \"Silhouette, fabric, and care metadata for womenswear.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"materials\", title: \"Materials\" },\n { code: \"fit\", title: \"Fit & Length\" },\n { code: \"care\", title: \"Care instructions\" },\n ],\n },\n {\n code: \"service_schedule\",\n label: \"Services \u00B7 Scheduling\",\n icon: \"solar:calendar-linear\",\n description:\n \"Scheduling, preparation, and delivery metadata for service offerings.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"timing\", title: \"Timing rules\" },\n { code: \"resources\", title: \"Resources & Delivery\" },\n ],\n },\n] as const;\n\nconst VARIANT_FIELDSETS = [\n {\n code: \"fashion_mens_footwear\",\n label: \"Fashion \u00B7 Men \u00B7 Footwear\",\n icon: \"carbon:sneaker\",\n description: \"Variant-level sizing metadata for men\u2019s footwear.\",\n groups: [\n { code: \"fit\", title: \"Fit\" },\n { code: \"finish\", title: \"Finish\" },\n ],\n },\n {\n code: \"fashion_womens_dresses\",\n label: \"Fashion \u00B7 Women \u00B7 Dresses & Jumpsuits\",\n icon: \"solar:dress-linear\",\n description: \"Variant-level sizing metadata for womenswear.\",\n groups: [\n { code: \"fit\", title: \"Fit\" },\n { code: \"finish\", title: \"Finish\" },\n ],\n },\n {\n code: \"service_schedule\",\n label: \"Services \u00B7 Scheduling\",\n icon: \"solar:calendar-linear\",\n description:\n \"Provider, duration, and environment metadata for service slots.\",\n groups: [\n { code: \"provider\", title: \"Provider\" },\n { code: \"environment\", title: \"Environment\" },\n ],\n },\n] as const;\n\nconst CUSTOM_FIELD_SETS: FieldSetInput[] = [\n defineFields(E.catalog.catalog_product, [\n cf.text(\"style_code\", {\n label: \"Style code\",\n description: \"Reference code shared with merchandising teams.\",\n filterable: true,\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"identity\" },\n }),\n cf.select(\n \"upper_material\",\n [\"engineered_knit\", \"full_grain_leather\", \"recycled_mesh\"],\n {\n label: \"Upper material\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"materials\" },\n filterable: true,\n },\n ),\n cf.select(\"cushioning_profile\", [\"responsive\", \"plush\", \"stability\"], {\n label: \"Cushioning profile\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"materials\" },\n }),\n cf.multiline(\"care_notes\", {\n label: \"Care notes\",\n editor: \"markdown\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"care\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product, [\n cf.select(\"silhouette\", [\"wrap\", \"column\", \"fit_and_flare\", \"jumpsuit\"], {\n label: \"Silhouette\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"identity\" },\n filterable: true,\n }),\n cf.select(\"fabric_mix\", [\"silk_blend\", \"recycled_poly\", \"linen\", \"cupro\"], {\n label: \"Fabric mix\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"materials\" },\n }),\n cf.select(\"occasion_ready\", [\"daytime\", \"evening\", \"resort\"], {\n label: \"Occasion\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.multiline(\"finishing_details\", {\n label: \"Finishing details\",\n editor: \"markdown\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"care\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.integer(\"shoe_size\", {\n label: \"US size\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"fit\" },\n filterable: true,\n }),\n cf.select(\"shoe_width\", [\"B\", \"D\", \"EE\"], {\n label: \"Width\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"fit\" },\n }),\n cf.text(\"colorway\", {\n label: \"Colorway\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"finish\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.integer(\"numeric_size\", {\n label: \"Numeric size\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.select(\"length_profile\", [\"mini\", \"midi\", \"maxi\"], {\n label: \"Length\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.text(\"color_story\", {\n label: \"Color story\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"finish\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product, [\n cf.integer(\"service_duration_minutes\", {\n label: \"Duration (minutes)\",\n description: \"Length of a single service slot.\",\n fieldset: \"service_schedule\",\n group: { code: \"timing\" },\n filterable: true,\n required: true,\n }),\n cf.integer(\"service_buffer_minutes\", {\n label: \"Buffer between appointments\",\n description:\n \"Minimum downtime between consecutive service slots (minutes).\",\n fieldset: \"service_schedule\",\n group: { code: \"timing\" },\n }),\n cf.text(\"service_location\", {\n label: \"Location / Room\",\n description: \"Where the service is delivered.\",\n fieldset: \"service_schedule\",\n group: { code: \"identity\" },\n }),\n cf.select(\n \"service_resources\",\n [\"stylist\", \"therapist\", \"treatment_room\", \"wash_station\", \"steam_room\"],\n {\n label: \"Required resources\",\n description: \"Staff or rooms required to perform the service.\",\n fieldset: \"service_schedule\",\n group: { code: \"resources\" },\n multi: true,\n },\n ),\n cf.boolean(\"service_remote_available\", {\n label: \"Remote session available\",\n description:\n \"Indicates whether the service can be performed remotely or virtually.\",\n fieldset: \"service_schedule\",\n group: { code: \"resources\" },\n defaultValue: false,\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.select(\"provider_level\", [\"junior\", \"senior\", \"master\"], {\n label: \"Provider level\",\n description: \"Seniority of the assigned specialist.\",\n fieldset: \"service_schedule\",\n group: { code: \"provider\" },\n filterable: true,\n }),\n cf.text(\"staff_member\", {\n label: \"Staff member\",\n description:\n \"Optional name of the staff member who usually delivers this variant.\",\n fieldset: \"service_schedule\",\n group: { code: \"provider\" },\n }),\n cf.select(\"environment_type\", [\"studio\", \"suite\", \"on_site\"], {\n label: \"Environment\",\n description: \"Where the session is hosted.\",\n fieldset: \"service_schedule\",\n group: { code: \"environment\" },\n }),\n ]),\n];\n\ntype CategorySeed = {\n slug: string;\n name: string;\n description?: string;\n children?: CategorySeed[];\n};\n\nconst CATEGORY_TREE: CategorySeed[] = [\n {\n slug: \"fashion\",\n name: \"Fashion\",\n description: \"Seasonal assortments and vertical-specific collections.\",\n children: [\n {\n slug: \"fashion-men\",\n name: \"Men\",\n children: [\n {\n slug: \"fashion-men-footwear\",\n name: \"Footwear\",\n description: \"Premium sneakers, boots, and sandals.\",\n },\n ],\n },\n {\n slug: \"fashion-women\",\n name: \"Women\",\n children: [\n {\n slug: \"fashion-women-dresses-jumpsuits\",\n name: \"Dresses & Jumpsuits\",\n description: \"Occasion-ready dresses and tailored jumpsuits.\",\n },\n ],\n },\n ],\n },\n {\n slug: \"services\",\n name: \"Services\",\n description: \"Bookable in-person and virtual experiences.\",\n children: [\n {\n slug: \"services-hairdresser\",\n name: \"Hairdresser\",\n description:\n \"Salon services ranging from quick trims to signature looks.\",\n },\n {\n slug: \"services-massage\",\n name: \"Massage\",\n description: \"Wellness treatments and bodywork sessions.\",\n },\n ],\n },\n];\n\ntype MediaSeed = {\n file: string;\n title?: string;\n};\n\ntype VariantSeed = {\n name: string;\n sku: string;\n isDefault?: boolean;\n optionValues?: Record<string, string>;\n prices: {\n regular: number;\n sale?: number;\n };\n customFields?: Record<string, string | number | boolean | null>;\n media?: MediaSeed[];\n};\n\ntype ProductSeed = {\n title: string;\n handle: string;\n sku?: string;\n description: string;\n categorySlug: string;\n customFieldsetCode: string;\n variantFieldsetCode: string;\n unit: string;\n metadata?: Record<string, unknown>;\n customFields?: Record<string, string | number | boolean | null>;\n media?: MediaSeed[];\n variants: VariantSeed[];\n};\n\nconst PRODUCT_SEEDS: ProductSeed[] = [\n {\n title: \"Atlas Runner Sneaker\",\n handle: \"atlas-runner-sneaker\",\n sku: \"ATLAS-RUNNER\",\n description:\n \"Lightweight road sneaker engineered with a breathable knit upper, recycled TPU overlays, and a decoupled heel for smooth transitions.\",\n categorySlug: \"fashion-men-footwear\",\n customFieldsetCode: \"fashion_mens_footwear\",\n variantFieldsetCode: \"fashion_mens_footwear\",\n unit: \"pair\",\n metadata: { division: \"RunLab\", season: \"SS25\" },\n customFields: {\n style_code: \"AR-2025\",\n upper_material: \"engineered_knit\",\n cushioning_profile: \"responsive\",\n care_notes:\n \"Spot clean after each run and air dry. Avoid machine drying.\",\n },\n media: [{ file: \"atlas-runner-midnight-1.png\" }],\n variants: [\n {\n name: \"Midnight Navy \u00B7 US 8\",\n sku: \"ATLAS-RUN-NAVY-8\",\n isDefault: true,\n optionValues: { color: \"Midnight Navy\", size: \"US 8\" },\n prices: { regular: 168, sale: 148 },\n customFields: {\n shoe_size: 8,\n shoe_width: \"D\",\n colorway: \"Midnight Navy\",\n },\n media: [\n { file: \"atlas-runner-midnight-1.png\" },\n { file: \"atlas-runner-midnight-2.png\" },\n ],\n },\n {\n name: \"Glacier Grey \u00B7 US 10\",\n sku: \"ATLAS-RUN-GLACIER-10\",\n optionValues: { color: \"Glacier Grey\", size: \"US 10\" },\n prices: { regular: 168, sale: 138 },\n customFields: {\n shoe_size: 10,\n shoe_width: \"EE\",\n colorway: \"Glacier Grey\",\n },\n media: [\n { file: \"atlas-runner-glacier-1.png\" },\n { file: \"atlas-runner-glacier-2.png\" },\n ],\n },\n ],\n },\n {\n title: \"Aurora Wrap Dress\",\n handle: \"aurora-wrap-dress\",\n sku: \"AURORA-WRAP\",\n description:\n \"Bias-cut wrap dress with blouson sleeves, matte silk blend, and hidden interior snaps so the placket stays put at events.\",\n categorySlug: \"fashion-women-dresses-jumpsuits\",\n customFieldsetCode: \"fashion_womens_dresses\",\n variantFieldsetCode: \"fashion_womens_dresses\",\n unit: \"unit\",\n metadata: { capsule: \"Evening Atelier\", season: \"Resort 25\" },\n customFields: {\n silhouette: \"wrap\",\n fabric_mix: \"silk_blend\",\n occasion_ready: \"evening\",\n finishing_details:\n \"Hand-finished hem with subtle tonal beading along the wrap edge.\",\n },\n media: [{ file: \"aurora-wrap-rosewood.png\" }],\n variants: [\n {\n name: \"Rosewood \u00B7 Medium\",\n sku: \"AURORA-ROSE-M\",\n isDefault: true,\n optionValues: { color: \"Rosewood\", size: \"Medium\" },\n prices: { regular: 248, sale: 212 },\n customFields: {\n numeric_size: 6,\n length_profile: \"midi\",\n color_story: \"Rosewood\",\n },\n media: [{ file: \"aurora-wrap-rosewood.png\" }],\n },\n {\n name: \"Celestial \u00B7 Large\",\n sku: \"AURORA-CELESTIAL-L\",\n optionValues: { color: \"Celestial\", size: \"Large\" },\n prices: { regular: 248, sale: 198 },\n customFields: {\n numeric_size: 8,\n length_profile: \"maxi\",\n color_story: \"Celestial blue\",\n },\n media: [{ file: \"aurora-wrap-celestial.png\" }],\n },\n ],\n },\n {\n title: \"Signature Haircut & Finish\",\n handle: \"signature-haircut-service\",\n sku: \"SERV-HAIR-60\",\n description:\n \"Tailored haircut with relaxing wash, scalp massage, and styling finish. Designed for repeat visits in the demo portal.\",\n categorySlug: \"services-hairdresser\",\n customFieldsetCode: \"service_schedule\",\n variantFieldsetCode: \"service_schedule\",\n unit: \"hour\",\n metadata: { channel: \"salon\", serviceType: \"hairdresser\" },\n customFields: {\n service_duration_minutes: 60,\n service_buffer_minutes: 15,\n service_location: \"Salon Studio 3\",\n service_resources: \"stylist,wash_station\",\n service_remote_available: false,\n },\n media: [{ file: \"hairdresser-service.png\" }],\n variants: [\n {\n name: \"Senior Stylist \u00B7 60 min\",\n sku: \"SERV-HAIR-60-SENIOR\",\n isDefault: true,\n optionValues: { stylist: \"Senior\", duration: \"60\" },\n prices: { regular: 95, sale: 85 },\n customFields: {\n provider_level: \"senior\",\n staff_member: \"Amelia Hart\",\n environment_type: \"studio\",\n },\n media: [{ file: \"hairdresser-service.png\" }],\n },\n ],\n },\n {\n title: \"Restorative Massage Session\",\n handle: \"restorative-massage-service\",\n sku: \"SERV-MASSAGE-90\",\n description:\n \"Full-body massage with aromatherapy oils and guided breathing. Includes complimentary refreshments and studio amenities.\",\n categorySlug: \"services-massage\",\n customFieldsetCode: \"service_schedule\",\n variantFieldsetCode: \"service_schedule\",\n unit: \"hour\",\n metadata: { channel: \"wellness\", serviceType: \"massage\" },\n customFields: {\n service_duration_minutes: 90,\n service_buffer_minutes: 20,\n service_location: \"Wellness Suite B\",\n service_resources: \"therapist,treatment_room,steam_room\",\n service_remote_available: false,\n },\n media: [{ file: \"massage-service.png\" }],\n variants: [\n {\n name: \"Master Therapist \u00B7 90 min\",\n sku: \"SERV-MASSAGE-90-MASTER\",\n isDefault: true,\n optionValues: { therapist: \"Master\", duration: \"90\" },\n prices: { regular: 140, sale: 120 },\n customFields: {\n provider_level: \"master\",\n staff_member: \"Noah Li\",\n environment_type: \"suite\",\n },\n media: [{ file: \"massage-service.png\" }],\n },\n ],\n },\n];\n\nconst CHANNEL_DEFINITION = {\n code: \"fashion-online\",\n name: \"Mercato Fashion Online\",\n description: \"Direct-to-consumer storefront showcasing premium demos.\",\n websiteUrl: \"https://demo.open-mercato.com\",\n contactEmail: \"store@open-mercato.com\",\n};\n\nfunction formatMoney(value: number): string {\n return value.toFixed(2);\n}\n\nasync function resolveDefaultTaxRate(\n em: EntityManager,\n scope: SeedScope,\n): Promise<SalesTaxRate | null> {\n const [rate] = await em.find(\n SalesTaxRate,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n },\n {\n limit: 1,\n orderBy: {\n isDefault: \"DESC\",\n priority: \"ASC\",\n rate: \"DESC\",\n createdAt: \"ASC\",\n },\n },\n );\n return rate ?? null;\n}\n\nasync function ensureFieldsetConfig(\n em: EntityManager,\n scope: SeedScope,\n entityId: string,\n fieldsets: typeof PRODUCT_FIELDSETS | typeof VARIANT_FIELDSETS,\n): Promise<void> {\n const now = new Date();\n let config = await em.findOne(CustomFieldEntityConfig, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n });\n if (!config) {\n config = em.create(CustomFieldEntityConfig, {\n id: randomUUID(),\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n });\n }\n config.configJson = {\n fieldsets,\n singleFieldsetPerRecord: true,\n };\n config.isActive = true;\n config.updatedAt = now;\n em.persist(config);\n}\n\nasync function ensureFieldsetsAndDefinitions(\n em: EntityManager,\n scope: SeedScope,\n): Promise<void> {\n await ensureFieldsetConfig(\n em,\n scope,\n E.catalog.catalog_product,\n PRODUCT_FIELDSETS,\n );\n await ensureFieldsetConfig(\n em,\n scope,\n E.catalog.catalog_product_variant,\n VARIANT_FIELDSETS,\n );\n await ensureCustomFieldDefinitions(em, CUSTOM_FIELD_SETS, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n });\n await em.flush();\n}\n\nasync function ensureCategories(\n em: EntityManager,\n scope: SeedScope,\n): Promise<Map<string, CatalogProductCategory>> {\n const map = new Map<string, CatalogProductCategory>();\n const now = new Date();\n\n const upsert = async (\n seed: CategorySeed,\n parent: CatalogProductCategory | null,\n ) => {\n let record = await em.findOne(CatalogProductCategory, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n slug: seed.slug,\n });\n if (!record) {\n record = em.create(CatalogProductCategory, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: seed.name,\n slug: seed.slug,\n description: seed.description ?? null,\n parentId: parent ? parent.id : null,\n rootId: parent ? (parent.rootId ?? parent.id) : null,\n treePath: null,\n depth: parent ? (parent.depth ?? 0) + 1 : 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\n metadata: null,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n });\n em.persist(record);\n } else {\n record.name = seed.name;\n record.description = seed.description ?? null;\n record.parentId = parent ? parent.id : null;\n record.isActive = true;\n record.updatedAt = now;\n }\n map.set(seed.slug, record);\n if (Array.isArray(seed.children)) {\n for (const child of seed.children) {\n await upsert(child, record);\n }\n }\n };\n\n for (const seed of CATEGORY_TREE) {\n await upsert(seed, null);\n }\n\n await em.flush();\n await rebuildCategoryHierarchyForOrganization(\n em,\n scope.organizationId,\n scope.tenantId,\n );\n\n return map;\n}\n\nasync function ensureChannel(\n em: EntityManager,\n scope: SeedScope,\n): Promise<SalesChannel> {\n const now = new Date();\n let channel = await em.findOne(SalesChannel, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n code: CHANNEL_DEFINITION.code,\n deletedAt: null,\n });\n if (!channel) {\n channel = em.create(SalesChannel, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n code: CHANNEL_DEFINITION.code,\n name: CHANNEL_DEFINITION.name,\n description: CHANNEL_DEFINITION.description,\n websiteUrl: CHANNEL_DEFINITION.websiteUrl,\n contactEmail: CHANNEL_DEFINITION.contactEmail,\n status: \"active\",\n isActive: true,\n metadata: { locale: \"en-US\" },\n createdAt: now,\n updatedAt: now,\n });\n em.persist(channel);\n await em.flush();\n }\n return channel;\n}\n\nasync function loadPriceKinds(\n em: EntityManager,\n scope: SeedScope,\n): Promise<Map<string, CatalogPriceKind>> {\n const kinds = await em.find(CatalogPriceKind, {\n tenantId: scope.tenantId,\n code: { $in: [\"regular\", \"sale\"] },\n deletedAt: null,\n });\n const map = new Map<string, CatalogPriceKind>();\n for (const kind of kinds) {\n map.set(kind.code.toLowerCase(), kind);\n }\n return map;\n}\n\nexport async function seedCatalogExamples(\n em: EntityManager,\n container: AwilixContainer,\n scope: SeedScope,\n): Promise<boolean> {\n await ensureFieldsetsAndDefinitions(em, scope);\n await ensureDefaultPartitions(em);\n\n const handles = PRODUCT_SEEDS.map((seed) => seed.handle);\n const existingProducts = await em.find(CatalogProduct, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n handle: { $in: [...handles] },\n });\n const existingByHandle = new Map(\n existingProducts.map((product) => [product.handle?.toLowerCase(), product]),\n );\n\n const categoryMap = await ensureCategories(em, scope);\n const channel = await ensureChannel(em, scope);\n const priceKinds = await loadPriceKinds(em, scope);\n const regularKind = priceKinds.get(\"regular\");\n const saleKind = priceKinds.get(\"sale\");\n const defaultTaxRate = await resolveDefaultTaxRate(em, scope);\n const defaultTaxRateId = defaultTaxRate?.id ?? null;\n const defaultTaxRateValue = defaultTaxRate?.rate ?? null;\n if (!regularKind || !saleKind) {\n throw new Error(\n \"Missing catalog price kinds; run `mercato catalog seed-price-kinds` first.\",\n );\n }\n\n const dataEngine = new DefaultDataEngine(em, container);\n const customFieldAssignments: Array<() => Promise<void>> = [];\n let createdAny = false;\n\n for (const productSeed of PRODUCT_SEEDS) {\n const existing = existingByHandle.get(productSeed.handle.toLowerCase());\n if (existing) {\n continue;\n }\n createdAny = true;\n const product = em.create(CatalogProduct, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: productSeed.title,\n description: productSeed.description,\n sku: productSeed.sku ?? null,\n handle: productSeed.handle,\n productType: \"configurable\",\n primaryCurrencyCode: \"USD\",\n defaultUnit: canonicalizeUnitCode(productSeed.unit) ?? productSeed.unit,\n customFieldsetCode: productSeed.customFieldsetCode,\n metadata: productSeed.metadata ?? null,\n taxRateId: defaultTaxRateId,\n taxRate: defaultTaxRateValue,\n isConfigurable: true,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(product);\n\n const category = categoryMap.get(productSeed.categorySlug);\n if (category) {\n const assignment = em.create(CatalogProductCategoryAssignment, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n category,\n position: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(assignment);\n }\n\n const offer = em.create(CatalogOffer, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n channelId: channel.id,\n title: `${productSeed.title} \u00B7 Online`,\n description: \"Offer curated for the demo storefront channel.\",\n metadata: { channelCode: CHANNEL_DEFINITION.code },\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(offer);\n\n if (\n productSeed.customFields &&\n Object.keys(productSeed.customFields).length\n ) {\n const payload = { ...productSeed.customFields };\n customFieldAssignments.push(() =>\n dataEngine.setCustomFields({\n entityId: E.catalog.catalog_product,\n recordId: product.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: payload,\n }),\n );\n }\n\n const productMedia = await attachMediaFromExamples(\n em,\n scope,\n E.catalog.catalog_product,\n product.id,\n productSeed.media,\n );\n if (productMedia.length) {\n const hero = productMedia[0];\n product.defaultMediaId = hero.id;\n product.defaultMediaUrl = hero.imageUrl;\n offer.defaultMediaId = hero.id;\n offer.defaultMediaUrl = hero.imageUrl;\n }\n\n for (const variantSeed of productSeed.variants) {\n const variant = em.create(CatalogProductVariant, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n name: variantSeed.name,\n sku: variantSeed.sku,\n isDefault: variantSeed.isDefault ?? false,\n optionValues: variantSeed.optionValues ?? null,\n customFieldsetCode: productSeed.variantFieldsetCode,\n metadata: null,\n taxRateId: defaultTaxRateId,\n taxRate: defaultTaxRateValue,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(variant);\n\n const variantMedia = await attachMediaFromExamples(\n em,\n scope,\n E.catalog.catalog_product_variant,\n variant.id,\n variantSeed.media,\n );\n const regularPrice = em.create(CatalogProductPrice, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n variant,\n offer,\n priceKind: regularKind,\n currencyCode: \"USD\",\n kind: regularKind.code,\n minQuantity: 1,\n taxRate: defaultTaxRateValue,\n unitPriceGross: formatMoney(variantSeed.prices.regular),\n unitPriceNet: formatMoney(variantSeed.prices.regular),\n channelId: channel.id,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(regularPrice);\n\n if (variantSeed.prices.sale !== undefined) {\n const salePrice = em.create(CatalogProductPrice, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n variant,\n offer,\n priceKind: saleKind,\n currencyCode: \"USD\",\n kind: saleKind.code,\n minQuantity: 1,\n taxRate: defaultTaxRateValue,\n unitPriceGross: formatMoney(variantSeed.prices.sale),\n unitPriceNet: formatMoney(variantSeed.prices.sale),\n channelId: channel.id,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(salePrice);\n }\n\n if (\n variantSeed.customFields &&\n Object.keys(variantSeed.customFields).length\n ) {\n const payload = { ...variantSeed.customFields };\n customFieldAssignments.push(() =>\n dataEngine.setCustomFields({\n entityId: E.catalog.catalog_product_variant,\n recordId: variant.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: payload,\n }),\n );\n }\n }\n }\n\n if (!createdAny) {\n return false;\n }\n\n await em.flush();\n\n for (const assign of customFieldAssignments) {\n try {\n await assign();\n } catch (err) {\n console.warn(\n \"[catalog.seed] Failed to set example custom field values\",\n err,\n );\n }\n }\n\n return true;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -306,6 +306,9 @@ async function seedAnalyticsData(em, scope, options = {}) {
|
|
|
306
306
|
kind: "product",
|
|
307
307
|
name: lineData.product.title,
|
|
308
308
|
quantity: toAmount(lineData.quantity),
|
|
309
|
+
normalizedQuantity: toAmount(lineData.quantity),
|
|
310
|
+
normalizedUnit: null,
|
|
311
|
+
uomSnapshot: null,
|
|
309
312
|
currencyCode: "USD",
|
|
310
313
|
unitPriceNet: toAmount(lineData.unitPriceNet),
|
|
311
314
|
unitPriceGross: toAmount(lineData.unitPriceGross),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/dashboards/seed/analytics.ts"],
|
|
4
|
-
"sourcesContent": ["import { randomUUID } from 'crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n SalesOrder,\n SalesOrderLine,\n} from '@open-mercato/core/modules/sales/data/entities'\nimport {\n CustomerEntity,\n CustomerCompanyProfile,\n CustomerDeal,\n} from '@open-mercato/core/modules/customers/data/entities'\nimport {\n CatalogProduct,\n CatalogProductVariant,\n} from '@open-mercato/core/modules/catalog/data/entities'\n\nexport type AnalyticsSeedScope = {\n tenantId: string\n organizationId: string\n}\n\nexport type AnalyticsSeedOptions = {\n months?: number\n ordersPerMonth?: number\n customersCount?: number\n productsCount?: number\n dealsCount?: number\n}\n\nconst ORDER_STATUSES = ['draft', 'pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled'] as const\nconst FULFILLMENT_STATUSES = ['pending', 'in_fulfillment', 'partially_fulfilled', 'fulfilled'] as const\nconst PAYMENT_STATUSES = ['unpaid', 'partial', 'paid', 'refunded'] as const\nconst DEAL_PIPELINE_STAGES = ['lead', 'qualified', 'proposal', 'negotiation', 'closed_won', 'closed_lost'] as const\nconst COUNTRIES = ['US', 'GB', 'DE', 'FR', 'CA', 'AU', 'NL', 'ES', 'IT', 'PL'] as const\nconst REGIONS_BY_COUNTRY: Record<string, string[]> = {\n US: ['California', 'New York', 'Texas', 'Florida', 'Illinois', 'Washington', 'Massachusetts'],\n GB: ['England', 'Scotland', 'Wales'],\n DE: ['Bavaria', 'Berlin', 'Hamburg', 'Hessen'],\n FR: ['\u00CEle-de-France', 'Provence', 'Rh\u00F4ne-Alpes'],\n CA: ['Ontario', 'Quebec', 'British Columbia'],\n AU: ['New South Wales', 'Victoria', 'Queensland'],\n NL: ['North Holland', 'South Holland'],\n ES: ['Madrid', 'Catalonia', 'Andalusia'],\n IT: ['Lombardy', 'Lazio', 'Veneto'],\n PL: ['Mazovia', 'Lesser Poland', 'Silesia'],\n}\n\nconst COMPANY_NAMES = [\n 'Acme Corp', 'Global Industries', 'Tech Solutions', 'Prime Services',\n 'Northern Analytics', 'Blue Ocean Trading', 'Summit Enterprises', 'Horizon Dynamics',\n 'Vertex Systems', 'Atlas Logistics', 'Pinnacle Group', 'Quantum Labs',\n 'Stellar Innovations', 'Pacific Partners', 'Apex Manufacturing', 'Nexus Technologies',\n 'Eclipse Ventures', 'Titan Holdings', 'Vanguard Solutions', 'Momentum Corp',\n 'Crystal Clear Media', 'Silver Line Transport', 'Golden Gate Imports', 'Red Rock Mining',\n 'Green Valley Foods', 'Blue Sky Aviation', 'White Mountain Retail', 'Black Diamond Sports',\n]\n\nconst PRODUCT_NAMES = [\n 'Premium Widget', 'Standard Component', 'Professional Kit', 'Enterprise Module',\n 'Basic Starter Pack', 'Advanced System', 'Deluxe Bundle', 'Essential Tools',\n 'Pro Series Device', 'Ultra Performance Unit', 'Classic Edition', 'Limited Series',\n 'Industrial Grade Part', 'Consumer Package', 'Business Solution', 'Home Edition',\n]\n\nconst DEAL_TITLES = [\n 'Enterprise License Deal', 'Annual Subscription', 'Pilot Program', 'Strategic Partnership',\n 'Volume Purchase Agreement', 'Service Contract', 'Implementation Project', 'Expansion Deal',\n 'Renewal Opportunity', 'Upsell Initiative', 'Cross-sell Package', 'Custom Solution',\n]\n\nfunction randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\nfunction randomFloat(min: number, max: number, decimals = 2): number {\n const value = Math.random() * (max - min) + min\n return Number(value.toFixed(decimals))\n}\n\nfunction randomElement<T>(arr: readonly T[]): T {\n return arr[Math.floor(Math.random() * arr.length)]\n}\n\nfunction randomElements<T>(arr: readonly T[], count: number): T[] {\n const shuffled = [...arr].sort(() => Math.random() - 0.5)\n return shuffled.slice(0, Math.min(count, arr.length))\n}\n\nfunction toAmount(value: number): string {\n return value.toFixed(2)\n}\n\nfunction daysAgo(days: number): Date {\n const date = new Date()\n date.setDate(date.getDate() - days)\n return date\n}\n\nfunction randomDateInRange(startDaysAgo: number, endDaysAgo: number): Date {\n const daysOffset = randomInt(endDaysAgo, startDaysAgo)\n return daysAgo(daysOffset)\n}\n\nfunction generateOrderNumber(index: number): string {\n return `SO-ANALYTICS-${String(index).padStart(5, '0')}`\n}\n\nexport async function seedAnalyticsData(\n em: EntityManager,\n scope: AnalyticsSeedScope,\n options: AnalyticsSeedOptions = {}\n): Promise<{ orders: number; customers: number; products: number; deals: number }> {\n const {\n months = 6,\n ordersPerMonth = 50,\n customersCount = 25,\n productsCount = 15,\n dealsCount = 20,\n } = options\n\n const existingOrders = await em.count(SalesOrder, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n orderNumber: { $like: 'SO-ANALYTICS-%' },\n })\n\n if (existingOrders > 0) {\n return { orders: 0, customers: 0, products: 0, deals: 0 }\n }\n\n const customers: CustomerEntity[] = []\n const products: CatalogProduct[] = []\n const variants: CatalogProductVariant[] = []\n\n for (let i = 0; i < customersCount; i++) {\n const companyName = COMPANY_NAMES[i % COMPANY_NAMES.length]\n const customerCreatedAt = randomDateInRange(months * 30 + 60, 0)\n\n const customer = em.create(CustomerEntity, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n kind: 'company',\n displayName: `${companyName} #${i + 1}`,\n primaryEmail: `contact${i + 1}@${companyName.toLowerCase().replace(/\\s+/g, '')}.example.com`,\n status: 'active',\n lifecycleStage: randomElement(['lead', 'customer', 'opportunity']),\n isActive: true,\n createdAt: customerCreatedAt,\n updatedAt: customerCreatedAt,\n })\n em.persist(customer)\n customers.push(customer)\n\n const companyProfile = em.create(CustomerCompanyProfile, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n entity: customer,\n legalName: `${companyName} Inc.`,\n brandName: companyName,\n industry: randomElement(['Technology', 'Manufacturing', 'Retail', 'Services', 'Healthcare']),\n sizeBucket: randomElement(['small', 'medium', 'large', 'enterprise']),\n annualRevenue: toAmount(randomFloat(100000, 50000000)),\n createdAt: customerCreatedAt,\n updatedAt: customerCreatedAt,\n })\n em.persist(companyProfile)\n }\n\n for (let i = 0; i < productsCount; i++) {\n const productName = PRODUCT_NAMES[i % PRODUCT_NAMES.length]\n const productCreatedAt = daysAgo(months * 30 + randomInt(0, 30))\n\n const product = em.create(CatalogProduct, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: `${productName} ${i + 1}`,\n handle: `analytics-product-${i + 1}`,\n sku: `SKU-ANALYTICS-${String(i + 1).padStart(3, '0')}`,\n productType: 'simple',\n isConfigurable: false,\n isActive: true,\n createdAt: productCreatedAt,\n updatedAt: productCreatedAt,\n })\n em.persist(product)\n products.push(product)\n\n const variant = em.create(CatalogProductVariant, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n name: 'Default',\n sku: `${product.sku}-DEFAULT`,\n isDefault: true,\n isActive: true,\n createdAt: productCreatedAt,\n updatedAt: productCreatedAt,\n })\n em.persist(variant)\n variants.push(variant)\n }\n\n let orderIndex = 1\n const totalDays = months * 30\n const orders: SalesOrder[] = []\n\n for (let dayOffset = totalDays; dayOffset >= 0; dayOffset--) {\n const ordersToday = Math.round(ordersPerMonth / 30 * randomFloat(0.5, 1.5))\n\n for (let j = 0; j < ordersToday; j++) {\n const orderDate = daysAgo(dayOffset)\n const customer = randomElement(customers)\n const country = randomElement(COUNTRIES)\n const region = randomElement(REGIONS_BY_COUNTRY[country] || [''])\n\n const lineCount = randomInt(1, 5)\n const selectedProducts = randomElements(products, lineCount)\n\n let subtotalNet = 0\n let subtotalGross = 0\n let taxTotal = 0\n\n const orderLines: Array<{\n product: CatalogProduct\n variant: CatalogProductVariant\n quantity: number\n unitPriceNet: number\n unitPriceGross: number\n taxRate: number\n lineNetAmount: number\n lineGrossAmount: number\n lineTaxAmount: number\n }> = []\n\n for (let k = 0; k < selectedProducts.length; k++) {\n const product = selectedProducts[k]\n const variant = variants.find((v) => v.product.id === product.id) || variants[0]\n const quantity = randomInt(1, 10)\n const unitPriceNet = randomFloat(10, 500)\n const taxRate = randomElement([0, 5, 10, 20, 23])\n const unitPriceGross = unitPriceNet * (1 + taxRate / 100)\n const lineNetAmount = unitPriceNet * quantity\n const lineGrossAmount = unitPriceGross * quantity\n const lineTaxAmount = lineGrossAmount - lineNetAmount\n\n subtotalNet += lineNetAmount\n subtotalGross += lineGrossAmount\n taxTotal += lineTaxAmount\n\n orderLines.push({\n product,\n variant,\n quantity,\n unitPriceNet,\n unitPriceGross,\n taxRate,\n lineNetAmount,\n lineGrossAmount,\n lineTaxAmount,\n })\n }\n\n const order = em.create(SalesOrder, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderNumber: generateOrderNumber(orderIndex++),\n status: randomElement(ORDER_STATUSES),\n fulfillmentStatus: randomElement(FULFILLMENT_STATUSES),\n paymentStatus: randomElement(PAYMENT_STATUSES),\n customerEntityId: customer.id,\n customerSnapshot: {\n customer: {\n id: customer.id,\n kind: customer.kind,\n displayName: customer.displayName,\n },\n },\n currencyCode: 'USD',\n placedAt: orderDate,\n shippingAddressSnapshot: {\n country,\n region,\n city: `City ${randomInt(1, 100)}`,\n postalCode: String(randomInt(10000, 99999)),\n },\n billingAddressSnapshot: {\n country,\n region,\n city: `City ${randomInt(1, 100)}`,\n postalCode: String(randomInt(10000, 99999)),\n },\n subtotalNetAmount: toAmount(subtotalNet),\n subtotalGrossAmount: toAmount(subtotalGross),\n discountTotalAmount: '0.00',\n taxTotalAmount: toAmount(taxTotal),\n shippingNetAmount: '0.00',\n shippingGrossAmount: '0.00',\n surchargeTotalAmount: '0.00',\n grandTotalNetAmount: toAmount(subtotalNet),\n grandTotalGrossAmount: toAmount(subtotalGross),\n paidTotalAmount: '0.00',\n refundedTotalAmount: '0.00',\n outstandingAmount: toAmount(subtotalGross),\n lineItemCount: orderLines.length,\n metadata: { seed: 'dashboards.analytics' },\n createdAt: orderDate,\n updatedAt: orderDate,\n })\n em.persist(order)\n orders.push(order)\n\n for (let k = 0; k < orderLines.length; k++) {\n const lineData = orderLines[k]\n const line = em.create(SalesOrderLine, {\n id: randomUUID(),\n order,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: k + 1,\n kind: 'product',\n name: lineData.product.title,\n quantity: toAmount(lineData.quantity),\n currencyCode: 'USD',\n unitPriceNet: toAmount(lineData.unitPriceNet),\n unitPriceGross: toAmount(lineData.unitPriceGross),\n discountAmount: '0.00',\n discountPercent: '0.00',\n taxRate: toAmount(lineData.taxRate),\n taxAmount: toAmount(lineData.lineTaxAmount),\n totalNetAmount: toAmount(lineData.lineNetAmount),\n totalGrossAmount: toAmount(lineData.lineGrossAmount),\n reservedQuantity: '0',\n fulfilledQuantity: '0',\n invoicedQuantity: '0',\n returnedQuantity: '0',\n productId: lineData.product.id,\n productVariantId: lineData.variant?.id ?? null,\n catalogSnapshot: {\n product: {\n id: lineData.product.id,\n title: lineData.product.title,\n sku: lineData.product.sku,\n },\n variant: lineData.variant\n ? {\n id: lineData.variant.id,\n name: lineData.variant.name,\n sku: lineData.variant.sku,\n }\n : null,\n },\n createdAt: orderDate,\n updatedAt: orderDate,\n })\n em.persist(line)\n }\n }\n }\n\n for (let i = 0; i < dealsCount; i++) {\n const customer = randomElement(customers)\n const dealCreatedAt = randomDateInRange(months * 30, 0)\n const pipelineStage = randomElement(DEAL_PIPELINE_STAGES)\n\n const probabilityByStage: Record<string, number> = {\n lead: 10,\n qualified: 25,\n proposal: 50,\n negotiation: 75,\n closed_won: 100,\n closed_lost: 0,\n }\n\n const deal = em.create(CustomerDeal, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: `${randomElement(DEAL_TITLES)} - ${customer.displayName}`,\n status: pipelineStage === 'closed_won' || pipelineStage === 'closed_lost' ? 'closed' : 'open',\n pipelineStage,\n valueAmount: toAmount(randomFloat(5000, 500000)),\n valueCurrency: 'USD',\n probability: probabilityByStage[pipelineStage],\n expectedCloseAt: daysAgo(randomInt(-60, 90)),\n source: randomElement(['inbound', 'outbound', 'referral', 'partner']),\n createdAt: dealCreatedAt,\n updatedAt: dealCreatedAt,\n })\n em.persist(deal)\n }\n\n await em.flush()\n\n return {\n orders: orders.length,\n customers: customers.length,\n products: products.length,\n deals: dealsCount,\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { randomUUID } from 'crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n SalesOrder,\n SalesOrderLine,\n} from '@open-mercato/core/modules/sales/data/entities'\nimport {\n CustomerEntity,\n CustomerCompanyProfile,\n CustomerDeal,\n} from '@open-mercato/core/modules/customers/data/entities'\nimport {\n CatalogProduct,\n CatalogProductVariant,\n} from '@open-mercato/core/modules/catalog/data/entities'\n\nexport type AnalyticsSeedScope = {\n tenantId: string\n organizationId: string\n}\n\nexport type AnalyticsSeedOptions = {\n months?: number\n ordersPerMonth?: number\n customersCount?: number\n productsCount?: number\n dealsCount?: number\n}\n\nconst ORDER_STATUSES = ['draft', 'pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled'] as const\nconst FULFILLMENT_STATUSES = ['pending', 'in_fulfillment', 'partially_fulfilled', 'fulfilled'] as const\nconst PAYMENT_STATUSES = ['unpaid', 'partial', 'paid', 'refunded'] as const\nconst DEAL_PIPELINE_STAGES = ['lead', 'qualified', 'proposal', 'negotiation', 'closed_won', 'closed_lost'] as const\nconst COUNTRIES = ['US', 'GB', 'DE', 'FR', 'CA', 'AU', 'NL', 'ES', 'IT', 'PL'] as const\nconst REGIONS_BY_COUNTRY: Record<string, string[]> = {\n US: ['California', 'New York', 'Texas', 'Florida', 'Illinois', 'Washington', 'Massachusetts'],\n GB: ['England', 'Scotland', 'Wales'],\n DE: ['Bavaria', 'Berlin', 'Hamburg', 'Hessen'],\n FR: ['\u00CEle-de-France', 'Provence', 'Rh\u00F4ne-Alpes'],\n CA: ['Ontario', 'Quebec', 'British Columbia'],\n AU: ['New South Wales', 'Victoria', 'Queensland'],\n NL: ['North Holland', 'South Holland'],\n ES: ['Madrid', 'Catalonia', 'Andalusia'],\n IT: ['Lombardy', 'Lazio', 'Veneto'],\n PL: ['Mazovia', 'Lesser Poland', 'Silesia'],\n}\n\nconst COMPANY_NAMES = [\n 'Acme Corp', 'Global Industries', 'Tech Solutions', 'Prime Services',\n 'Northern Analytics', 'Blue Ocean Trading', 'Summit Enterprises', 'Horizon Dynamics',\n 'Vertex Systems', 'Atlas Logistics', 'Pinnacle Group', 'Quantum Labs',\n 'Stellar Innovations', 'Pacific Partners', 'Apex Manufacturing', 'Nexus Technologies',\n 'Eclipse Ventures', 'Titan Holdings', 'Vanguard Solutions', 'Momentum Corp',\n 'Crystal Clear Media', 'Silver Line Transport', 'Golden Gate Imports', 'Red Rock Mining',\n 'Green Valley Foods', 'Blue Sky Aviation', 'White Mountain Retail', 'Black Diamond Sports',\n]\n\nconst PRODUCT_NAMES = [\n 'Premium Widget', 'Standard Component', 'Professional Kit', 'Enterprise Module',\n 'Basic Starter Pack', 'Advanced System', 'Deluxe Bundle', 'Essential Tools',\n 'Pro Series Device', 'Ultra Performance Unit', 'Classic Edition', 'Limited Series',\n 'Industrial Grade Part', 'Consumer Package', 'Business Solution', 'Home Edition',\n]\n\nconst DEAL_TITLES = [\n 'Enterprise License Deal', 'Annual Subscription', 'Pilot Program', 'Strategic Partnership',\n 'Volume Purchase Agreement', 'Service Contract', 'Implementation Project', 'Expansion Deal',\n 'Renewal Opportunity', 'Upsell Initiative', 'Cross-sell Package', 'Custom Solution',\n]\n\nfunction randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\nfunction randomFloat(min: number, max: number, decimals = 2): number {\n const value = Math.random() * (max - min) + min\n return Number(value.toFixed(decimals))\n}\n\nfunction randomElement<T>(arr: readonly T[]): T {\n return arr[Math.floor(Math.random() * arr.length)]\n}\n\nfunction randomElements<T>(arr: readonly T[], count: number): T[] {\n const shuffled = [...arr].sort(() => Math.random() - 0.5)\n return shuffled.slice(0, Math.min(count, arr.length))\n}\n\nfunction toAmount(value: number): string {\n return value.toFixed(2)\n}\n\nfunction daysAgo(days: number): Date {\n const date = new Date()\n date.setDate(date.getDate() - days)\n return date\n}\n\nfunction randomDateInRange(startDaysAgo: number, endDaysAgo: number): Date {\n const daysOffset = randomInt(endDaysAgo, startDaysAgo)\n return daysAgo(daysOffset)\n}\n\nfunction generateOrderNumber(index: number): string {\n return `SO-ANALYTICS-${String(index).padStart(5, '0')}`\n}\n\nexport async function seedAnalyticsData(\n em: EntityManager,\n scope: AnalyticsSeedScope,\n options: AnalyticsSeedOptions = {}\n): Promise<{ orders: number; customers: number; products: number; deals: number }> {\n const {\n months = 6,\n ordersPerMonth = 50,\n customersCount = 25,\n productsCount = 15,\n dealsCount = 20,\n } = options\n\n const existingOrders = await em.count(SalesOrder, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n orderNumber: { $like: 'SO-ANALYTICS-%' },\n })\n\n if (existingOrders > 0) {\n return { orders: 0, customers: 0, products: 0, deals: 0 }\n }\n\n const customers: CustomerEntity[] = []\n const products: CatalogProduct[] = []\n const variants: CatalogProductVariant[] = []\n\n for (let i = 0; i < customersCount; i++) {\n const companyName = COMPANY_NAMES[i % COMPANY_NAMES.length]\n const customerCreatedAt = randomDateInRange(months * 30 + 60, 0)\n\n const customer = em.create(CustomerEntity, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n kind: 'company',\n displayName: `${companyName} #${i + 1}`,\n primaryEmail: `contact${i + 1}@${companyName.toLowerCase().replace(/\\s+/g, '')}.example.com`,\n status: 'active',\n lifecycleStage: randomElement(['lead', 'customer', 'opportunity']),\n isActive: true,\n createdAt: customerCreatedAt,\n updatedAt: customerCreatedAt,\n })\n em.persist(customer)\n customers.push(customer)\n\n const companyProfile = em.create(CustomerCompanyProfile, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n entity: customer,\n legalName: `${companyName} Inc.`,\n brandName: companyName,\n industry: randomElement(['Technology', 'Manufacturing', 'Retail', 'Services', 'Healthcare']),\n sizeBucket: randomElement(['small', 'medium', 'large', 'enterprise']),\n annualRevenue: toAmount(randomFloat(100000, 50000000)),\n createdAt: customerCreatedAt,\n updatedAt: customerCreatedAt,\n })\n em.persist(companyProfile)\n }\n\n for (let i = 0; i < productsCount; i++) {\n const productName = PRODUCT_NAMES[i % PRODUCT_NAMES.length]\n const productCreatedAt = daysAgo(months * 30 + randomInt(0, 30))\n\n const product = em.create(CatalogProduct, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: `${productName} ${i + 1}`,\n handle: `analytics-product-${i + 1}`,\n sku: `SKU-ANALYTICS-${String(i + 1).padStart(3, '0')}`,\n productType: 'simple',\n isConfigurable: false,\n isActive: true,\n createdAt: productCreatedAt,\n updatedAt: productCreatedAt,\n })\n em.persist(product)\n products.push(product)\n\n const variant = em.create(CatalogProductVariant, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n name: 'Default',\n sku: `${product.sku}-DEFAULT`,\n isDefault: true,\n isActive: true,\n createdAt: productCreatedAt,\n updatedAt: productCreatedAt,\n })\n em.persist(variant)\n variants.push(variant)\n }\n\n let orderIndex = 1\n const totalDays = months * 30\n const orders: SalesOrder[] = []\n\n for (let dayOffset = totalDays; dayOffset >= 0; dayOffset--) {\n const ordersToday = Math.round(ordersPerMonth / 30 * randomFloat(0.5, 1.5))\n\n for (let j = 0; j < ordersToday; j++) {\n const orderDate = daysAgo(dayOffset)\n const customer = randomElement(customers)\n const country = randomElement(COUNTRIES)\n const region = randomElement(REGIONS_BY_COUNTRY[country] || [''])\n\n const lineCount = randomInt(1, 5)\n const selectedProducts = randomElements(products, lineCount)\n\n let subtotalNet = 0\n let subtotalGross = 0\n let taxTotal = 0\n\n const orderLines: Array<{\n product: CatalogProduct\n variant: CatalogProductVariant\n quantity: number\n unitPriceNet: number\n unitPriceGross: number\n taxRate: number\n lineNetAmount: number\n lineGrossAmount: number\n lineTaxAmount: number\n }> = []\n\n for (let k = 0; k < selectedProducts.length; k++) {\n const product = selectedProducts[k]\n const variant = variants.find((v) => v.product.id === product.id) || variants[0]\n const quantity = randomInt(1, 10)\n const unitPriceNet = randomFloat(10, 500)\n const taxRate = randomElement([0, 5, 10, 20, 23])\n const unitPriceGross = unitPriceNet * (1 + taxRate / 100)\n const lineNetAmount = unitPriceNet * quantity\n const lineGrossAmount = unitPriceGross * quantity\n const lineTaxAmount = lineGrossAmount - lineNetAmount\n\n subtotalNet += lineNetAmount\n subtotalGross += lineGrossAmount\n taxTotal += lineTaxAmount\n\n orderLines.push({\n product,\n variant,\n quantity,\n unitPriceNet,\n unitPriceGross,\n taxRate,\n lineNetAmount,\n lineGrossAmount,\n lineTaxAmount,\n })\n }\n\n const order = em.create(SalesOrder, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderNumber: generateOrderNumber(orderIndex++),\n status: randomElement(ORDER_STATUSES),\n fulfillmentStatus: randomElement(FULFILLMENT_STATUSES),\n paymentStatus: randomElement(PAYMENT_STATUSES),\n customerEntityId: customer.id,\n customerSnapshot: {\n customer: {\n id: customer.id,\n kind: customer.kind,\n displayName: customer.displayName,\n },\n },\n currencyCode: 'USD',\n placedAt: orderDate,\n shippingAddressSnapshot: {\n country,\n region,\n city: `City ${randomInt(1, 100)}`,\n postalCode: String(randomInt(10000, 99999)),\n },\n billingAddressSnapshot: {\n country,\n region,\n city: `City ${randomInt(1, 100)}`,\n postalCode: String(randomInt(10000, 99999)),\n },\n subtotalNetAmount: toAmount(subtotalNet),\n subtotalGrossAmount: toAmount(subtotalGross),\n discountTotalAmount: '0.00',\n taxTotalAmount: toAmount(taxTotal),\n shippingNetAmount: '0.00',\n shippingGrossAmount: '0.00',\n surchargeTotalAmount: '0.00',\n grandTotalNetAmount: toAmount(subtotalNet),\n grandTotalGrossAmount: toAmount(subtotalGross),\n paidTotalAmount: '0.00',\n refundedTotalAmount: '0.00',\n outstandingAmount: toAmount(subtotalGross),\n lineItemCount: orderLines.length,\n metadata: { seed: 'dashboards.analytics' },\n createdAt: orderDate,\n updatedAt: orderDate,\n })\n em.persist(order)\n orders.push(order)\n\n for (let k = 0; k < orderLines.length; k++) {\n const lineData = orderLines[k]\n const line = em.create(SalesOrderLine, {\n id: randomUUID(),\n order,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: k + 1,\n kind: 'product',\n name: lineData.product.title,\n quantity: toAmount(lineData.quantity),\n normalizedQuantity: toAmount(lineData.quantity),\n normalizedUnit: null,\n uomSnapshot: null,\n currencyCode: 'USD',\n unitPriceNet: toAmount(lineData.unitPriceNet),\n unitPriceGross: toAmount(lineData.unitPriceGross),\n discountAmount: '0.00',\n discountPercent: '0.00',\n taxRate: toAmount(lineData.taxRate),\n taxAmount: toAmount(lineData.lineTaxAmount),\n totalNetAmount: toAmount(lineData.lineNetAmount),\n totalGrossAmount: toAmount(lineData.lineGrossAmount),\n reservedQuantity: '0',\n fulfilledQuantity: '0',\n invoicedQuantity: '0',\n returnedQuantity: '0',\n productId: lineData.product.id,\n productVariantId: lineData.variant?.id ?? null,\n catalogSnapshot: {\n product: {\n id: lineData.product.id,\n title: lineData.product.title,\n sku: lineData.product.sku,\n },\n variant: lineData.variant\n ? {\n id: lineData.variant.id,\n name: lineData.variant.name,\n sku: lineData.variant.sku,\n }\n : null,\n },\n createdAt: orderDate,\n updatedAt: orderDate,\n })\n em.persist(line)\n }\n }\n }\n\n for (let i = 0; i < dealsCount; i++) {\n const customer = randomElement(customers)\n const dealCreatedAt = randomDateInRange(months * 30, 0)\n const pipelineStage = randomElement(DEAL_PIPELINE_STAGES)\n\n const probabilityByStage: Record<string, number> = {\n lead: 10,\n qualified: 25,\n proposal: 50,\n negotiation: 75,\n closed_won: 100,\n closed_lost: 0,\n }\n\n const deal = em.create(CustomerDeal, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: `${randomElement(DEAL_TITLES)} - ${customer.displayName}`,\n status: pipelineStage === 'closed_won' || pipelineStage === 'closed_lost' ? 'closed' : 'open',\n pipelineStage,\n valueAmount: toAmount(randomFloat(5000, 500000)),\n valueCurrency: 'USD',\n probability: probabilityByStage[pipelineStage],\n expectedCloseAt: daysAgo(randomInt(-60, 90)),\n source: randomElement(['inbound', 'outbound', 'referral', 'partner']),\n createdAt: dealCreatedAt,\n updatedAt: dealCreatedAt,\n })\n em.persist(deal)\n }\n\n await em.flush()\n\n return {\n orders: orders.length,\n customers: customers.length,\n products: products.length,\n deals: dealsCount,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,18 +2,35 @@ import { z } from "zod";
|
|
|
2
2
|
import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
|
|
3
3
|
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
4
4
|
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
buildCustomFieldFiltersFromQuery,
|
|
7
|
+
extractAllCustomFieldEntries
|
|
8
|
+
} from "@open-mercato/shared/lib/crud/custom-fields";
|
|
6
9
|
import { SalesOrderLine } from "../../data/entities.js";
|
|
7
10
|
import { orderLineCreateSchema } from "../../data/validators.js";
|
|
8
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
createPagedListResponseSchema,
|
|
13
|
+
createSalesCrudOpenApi,
|
|
14
|
+
defaultOkResponseSchema
|
|
15
|
+
} from "../openapi.js";
|
|
9
16
|
import { withScopedPayload } from "../utils.js";
|
|
10
17
|
import { E } from "../../../../generated/entities.ids.generated.js";
|
|
11
18
|
import * as F from "../../../../generated/entities/sales_order_line/index.js";
|
|
19
|
+
import { canonicalizeUnitCode, REFERENCE_UNIT_CODES } from "@open-mercato/shared/lib/units/unitCodes";
|
|
12
20
|
const rawBodySchema = z.object({}).passthrough();
|
|
13
|
-
const resolveRawBody = (raw) =>
|
|
21
|
+
const resolveRawBody = (raw) => {
|
|
22
|
+
if (!raw || typeof raw !== "object") return {};
|
|
23
|
+
if ("body" in raw) {
|
|
24
|
+
const payload = raw;
|
|
25
|
+
if (payload.body && typeof payload.body === "object") {
|
|
26
|
+
return payload.body;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return raw;
|
|
30
|
+
};
|
|
14
31
|
const listSchema = z.object({
|
|
15
32
|
page: z.coerce.number().min(1).default(1),
|
|
16
|
-
pageSize: z.coerce.number().min(1).max(
|
|
33
|
+
pageSize: z.coerce.number().min(1).max(100).default(50),
|
|
17
34
|
id: z.string().uuid().optional(),
|
|
18
35
|
orderId: z.string().uuid().optional(),
|
|
19
36
|
sortField: z.string().optional(),
|
|
@@ -25,7 +42,9 @@ const routeMetadata = {
|
|
|
25
42
|
PUT: { requireAuth: true, requireFeatures: ["sales.orders.manage"] },
|
|
26
43
|
DELETE: { requireAuth: true, requireFeatures: ["sales.orders.manage"] }
|
|
27
44
|
};
|
|
28
|
-
const upsertSchema = orderLineCreateSchema.extend({
|
|
45
|
+
const upsertSchema = orderLineCreateSchema.extend({
|
|
46
|
+
id: z.string().uuid().optional()
|
|
47
|
+
});
|
|
29
48
|
const deleteSchema = z.object({
|
|
30
49
|
id: z.string().uuid(),
|
|
31
50
|
orderId: z.string().uuid()
|
|
@@ -62,6 +81,9 @@ const crud = makeCrudRoute({
|
|
|
62
81
|
F.tenant_id,
|
|
63
82
|
F.quantity,
|
|
64
83
|
F.quantity_unit,
|
|
84
|
+
F.normalized_quantity,
|
|
85
|
+
F.normalized_unit,
|
|
86
|
+
F.uom_snapshot,
|
|
65
87
|
F.currency_code,
|
|
66
88
|
F.unit_price_net,
|
|
67
89
|
F.unit_price_gross,
|
|
@@ -108,7 +130,18 @@ const crud = makeCrudRoute({
|
|
|
108
130
|
for (const key of Object.keys(normalized)) {
|
|
109
131
|
if (key.startsWith("cf:")) delete normalized[key];
|
|
110
132
|
}
|
|
111
|
-
|
|
133
|
+
const quantityUnit = canonicalizeUnitCode(
|
|
134
|
+
normalized["quantity_unit"] ?? normalized["quantityUnit"]
|
|
135
|
+
);
|
|
136
|
+
const normalizedUnit = canonicalizeUnitCode(
|
|
137
|
+
normalized["normalized_unit"] ?? normalized["normalizedUnit"]
|
|
138
|
+
) ?? quantityUnit;
|
|
139
|
+
return {
|
|
140
|
+
...normalized,
|
|
141
|
+
quantity_unit: quantityUnit,
|
|
142
|
+
normalized_unit: normalizedUnit,
|
|
143
|
+
...cfEntries
|
|
144
|
+
};
|
|
112
145
|
}
|
|
113
146
|
},
|
|
114
147
|
actions: {
|
|
@@ -116,12 +149,16 @@ const crud = makeCrudRoute({
|
|
|
116
149
|
commandId: "sales.orders.lines.upsert",
|
|
117
150
|
schema: rawBodySchema,
|
|
118
151
|
mapInput: async ({ raw, ctx }) => {
|
|
119
|
-
console.log("CREATE order line raw input:", raw);
|
|
120
152
|
const { translate } = await resolveTranslations();
|
|
121
|
-
const payload = upsertSchema.parse(
|
|
153
|
+
const payload = upsertSchema.parse(
|
|
154
|
+
withScopedPayload(resolveRawBody(raw) ?? {}, ctx, translate)
|
|
155
|
+
);
|
|
122
156
|
return { body: payload };
|
|
123
157
|
},
|
|
124
|
-
response: ({ result }) => ({
|
|
158
|
+
response: ({ result }) => ({
|
|
159
|
+
id: result?.lineId ?? null,
|
|
160
|
+
orderId: result?.orderId ?? null
|
|
161
|
+
}),
|
|
125
162
|
status: 201
|
|
126
163
|
},
|
|
127
164
|
update: {
|
|
@@ -129,19 +166,31 @@ const crud = makeCrudRoute({
|
|
|
129
166
|
schema: rawBodySchema,
|
|
130
167
|
mapInput: async ({ raw, ctx }) => {
|
|
131
168
|
const { translate } = await resolveTranslations();
|
|
132
|
-
const payload = upsertSchema.parse(
|
|
169
|
+
const payload = upsertSchema.parse(
|
|
170
|
+
withScopedPayload(resolveRawBody(raw) ?? {}, ctx, translate)
|
|
171
|
+
);
|
|
133
172
|
return { body: payload };
|
|
134
173
|
},
|
|
135
|
-
response: ({ result }) => ({
|
|
174
|
+
response: ({ result }) => ({
|
|
175
|
+
id: result?.lineId ?? null,
|
|
176
|
+
orderId: result?.orderId ?? null
|
|
177
|
+
})
|
|
136
178
|
},
|
|
137
179
|
delete: {
|
|
138
180
|
commandId: "sales.orders.lines.delete",
|
|
139
181
|
schema: rawBodySchema,
|
|
140
182
|
mapInput: async ({ raw, ctx }) => {
|
|
141
183
|
const { translate } = await resolveTranslations();
|
|
142
|
-
const payload = deleteSchema.parse(
|
|
184
|
+
const payload = deleteSchema.parse(
|
|
185
|
+
withScopedPayload(resolveRawBody(raw) ?? {}, ctx, translate)
|
|
186
|
+
);
|
|
143
187
|
if (!payload.id || !payload.orderId) {
|
|
144
|
-
throw new CrudHttpError(400, {
|
|
188
|
+
throw new CrudHttpError(400, {
|
|
189
|
+
error: translate(
|
|
190
|
+
"sales.documents.detail.error",
|
|
191
|
+
"Document not found or inaccessible."
|
|
192
|
+
)
|
|
193
|
+
});
|
|
145
194
|
}
|
|
146
195
|
return { body: payload };
|
|
147
196
|
},
|
|
@@ -150,6 +199,31 @@ const crud = makeCrudRoute({
|
|
|
150
199
|
}
|
|
151
200
|
});
|
|
152
201
|
const { GET, POST, PUT, DELETE } = crud;
|
|
202
|
+
const uomSnapshotOpenApiSchema = z.object({
|
|
203
|
+
version: z.literal(1),
|
|
204
|
+
productId: z.string().nullable(),
|
|
205
|
+
productVariantId: z.string().nullable(),
|
|
206
|
+
baseUnitCode: z.string().nullable(),
|
|
207
|
+
enteredUnitCode: z.string().nullable(),
|
|
208
|
+
enteredQuantity: z.string(),
|
|
209
|
+
toBaseFactor: z.string(),
|
|
210
|
+
normalizedQuantity: z.string(),
|
|
211
|
+
rounding: z.object({
|
|
212
|
+
mode: z.enum(["half_up", "down", "up"]),
|
|
213
|
+
scale: z.number().int()
|
|
214
|
+
}),
|
|
215
|
+
source: z.object({
|
|
216
|
+
conversionId: z.string().nullable(),
|
|
217
|
+
resolvedAt: z.string()
|
|
218
|
+
}),
|
|
219
|
+
unitPriceReference: z.object({
|
|
220
|
+
enabled: z.boolean(),
|
|
221
|
+
referenceUnitCode: z.enum(REFERENCE_UNIT_CODES).nullable(),
|
|
222
|
+
baseQuantity: z.string().nullable(),
|
|
223
|
+
grossPerReference: z.string().nullable().optional(),
|
|
224
|
+
netPerReference: z.string().nullable().optional()
|
|
225
|
+
}).optional()
|
|
226
|
+
}).nullable().optional();
|
|
153
227
|
const orderLineSchema = z.object({
|
|
154
228
|
id: z.string().uuid(),
|
|
155
229
|
order_id: z.string().uuid(),
|
|
@@ -165,6 +239,9 @@ const orderLineSchema = z.object({
|
|
|
165
239
|
comment: z.string().nullable().optional(),
|
|
166
240
|
quantity: z.number(),
|
|
167
241
|
quantity_unit: z.string().nullable().optional(),
|
|
242
|
+
normalized_quantity: z.number(),
|
|
243
|
+
normalized_unit: z.string().nullable().optional(),
|
|
244
|
+
uom_snapshot: uomSnapshotOpenApiSchema,
|
|
168
245
|
currency_code: z.string(),
|
|
169
246
|
unit_price_net: z.number(),
|
|
170
247
|
unit_price_gross: z.number(),
|
|
@@ -188,12 +265,18 @@ const openApi = createSalesCrudOpenApi({
|
|
|
188
265
|
listResponseSchema: createPagedListResponseSchema(orderLineSchema),
|
|
189
266
|
create: {
|
|
190
267
|
schema: upsertSchema,
|
|
191
|
-
responseSchema: z.object({
|
|
268
|
+
responseSchema: z.object({
|
|
269
|
+
id: z.string().uuid().nullable(),
|
|
270
|
+
orderId: z.string().uuid().nullable()
|
|
271
|
+
}),
|
|
192
272
|
description: "Creates an order line and recalculates totals."
|
|
193
273
|
},
|
|
194
274
|
update: {
|
|
195
275
|
schema: upsertSchema,
|
|
196
|
-
responseSchema: z.object({
|
|
276
|
+
responseSchema: z.object({
|
|
277
|
+
id: z.string().uuid().nullable(),
|
|
278
|
+
orderId: z.string().uuid().nullable()
|
|
279
|
+
}),
|
|
197
280
|
description: "Updates an order line and recalculates totals."
|
|
198
281
|
},
|
|
199
282
|
del: {
|