@endora-commerce/mod-catalog 0.100.0
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/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/admin/components/PackagingUnitsEditor.d.ts +12 -0
- package/dist/admin/components/PackagingUnitsEditor.d.ts.map +1 -0
- package/dist/admin/components/PackagingUnitsEditor.js +99 -0
- package/dist/admin/components/PackagingUnitsEditor.js.map +1 -0
- package/dist/admin/components/ProductAttributesTab.d.ts +13 -0
- package/dist/admin/components/ProductAttributesTab.d.ts.map +1 -0
- package/dist/admin/components/ProductAttributesTab.js +140 -0
- package/dist/admin/components/ProductAttributesTab.js.map +1 -0
- package/dist/admin/components/ProductInventoryTab.d.ts +14 -0
- package/dist/admin/components/ProductInventoryTab.d.ts.map +1 -0
- package/dist/admin/components/ProductInventoryTab.js +284 -0
- package/dist/admin/components/ProductInventoryTab.js.map +1 -0
- package/dist/admin/components/ProductScopeEditor.d.ts +94 -0
- package/dist/admin/components/ProductScopeEditor.d.ts.map +1 -0
- package/dist/admin/components/ProductScopeEditor.js +395 -0
- package/dist/admin/components/ProductScopeEditor.js.map +1 -0
- package/dist/admin/components/ProductsBulkEditDialog.d.ts +11 -0
- package/dist/admin/components/ProductsBulkEditDialog.d.ts.map +1 -0
- package/dist/admin/components/ProductsBulkEditDialog.js +304 -0
- package/dist/admin/components/ProductsBulkEditDialog.js.map +1 -0
- package/dist/admin/index.d.ts +45 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +184 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/lib/resolve-product-selection.d.ts +21 -0
- package/dist/admin/lib/resolve-product-selection.d.ts.map +1 -0
- package/dist/admin/lib/resolve-product-selection.js +25 -0
- package/dist/admin/lib/resolve-product-selection.js.map +1 -0
- package/dist/admin/pages/AttachmentTypesPage.d.ts +18 -0
- package/dist/admin/pages/AttachmentTypesPage.d.ts.map +1 -0
- package/dist/admin/pages/AttachmentTypesPage.js +92 -0
- package/dist/admin/pages/AttachmentTypesPage.js.map +1 -0
- package/dist/admin/pages/AttributeSetsPage.d.ts +21 -0
- package/dist/admin/pages/AttributeSetsPage.d.ts.map +1 -0
- package/dist/admin/pages/AttributeSetsPage.js +158 -0
- package/dist/admin/pages/AttributeSetsPage.js.map +1 -0
- package/dist/admin/pages/AttributesManager.d.ts +9 -0
- package/dist/admin/pages/AttributesManager.d.ts.map +1 -0
- package/dist/admin/pages/AttributesManager.js +305 -0
- package/dist/admin/pages/AttributesManager.js.map +1 -0
- package/dist/admin/pages/BulkOperationDetailPage.d.ts +9 -0
- package/dist/admin/pages/BulkOperationDetailPage.d.ts.map +1 -0
- package/dist/admin/pages/BulkOperationDetailPage.js +187 -0
- package/dist/admin/pages/BulkOperationDetailPage.js.map +1 -0
- package/dist/admin/pages/BulkOperationsPage.d.ts +9 -0
- package/dist/admin/pages/BulkOperationsPage.d.ts.map +1 -0
- package/dist/admin/pages/BulkOperationsPage.js +98 -0
- package/dist/admin/pages/BulkOperationsPage.js.map +1 -0
- package/dist/admin/pages/CategoriesTree.d.ts +9 -0
- package/dist/admin/pages/CategoriesTree.d.ts.map +1 -0
- package/dist/admin/pages/CategoriesTree.js +176 -0
- package/dist/admin/pages/CategoriesTree.js.map +1 -0
- package/dist/admin/pages/ProductEditor.d.ts +13 -0
- package/dist/admin/pages/ProductEditor.d.ts.map +1 -0
- package/dist/admin/pages/ProductEditor.js +1050 -0
- package/dist/admin/pages/ProductEditor.js.map +1 -0
- package/dist/admin/pages/ProductsList.d.ts +9 -0
- package/dist/admin/pages/ProductsList.d.ts.map +1 -0
- package/dist/admin/pages/ProductsList.js +399 -0
- package/dist/admin/pages/ProductsList.js.map +1 -0
- package/dist/backend/commands/attribute-commands.d.ts +111 -0
- package/dist/backend/commands/attribute-commands.d.ts.map +1 -0
- package/dist/backend/commands/attribute-commands.js +482 -0
- package/dist/backend/commands/attribute-commands.js.map +1 -0
- package/dist/backend/demo/reset.d.ts +23 -0
- package/dist/backend/demo/reset.d.ts.map +1 -0
- package/dist/backend/demo/reset.js +41 -0
- package/dist/backend/demo/reset.js.map +1 -0
- package/dist/backend/demo/rows.d.ts +103 -0
- package/dist/backend/demo/rows.d.ts.map +1 -0
- package/dist/backend/demo/rows.js +162 -0
- package/dist/backend/demo/rows.js.map +1 -0
- package/dist/backend/demo/seed.d.ts +35 -0
- package/dist/backend/demo/seed.d.ts.map +1 -0
- package/dist/backend/demo/seed.js +177 -0
- package/dist/backend/demo/seed.js.map +1 -0
- package/dist/backend/entities/attachment-type.entity.d.ts +16 -0
- package/dist/backend/entities/attachment-type.entity.d.ts.map +1 -0
- package/dist/backend/entities/attachment-type.entity.js +57 -0
- package/dist/backend/entities/attachment-type.entity.js.map +1 -0
- package/dist/backend/entities/attribute-set-attribute.entity.d.ts +26 -0
- package/dist/backend/entities/attribute-set-attribute.entity.d.ts.map +1 -0
- package/dist/backend/entities/attribute-set-attribute.entity.js +55 -0
- package/dist/backend/entities/attribute-set-attribute.entity.js.map +1 -0
- package/dist/backend/entities/attribute-set.entity.d.ts +22 -0
- package/dist/backend/entities/attribute-set.entity.d.ts.map +1 -0
- package/dist/backend/entities/attribute-set.entity.js +67 -0
- package/dist/backend/entities/attribute-set.entity.js.map +1 -0
- package/dist/backend/entities/bulk-operation.entity.d.ts +78 -0
- package/dist/backend/entities/bulk-operation.entity.d.ts.map +1 -0
- package/dist/backend/entities/bulk-operation.entity.js +138 -0
- package/dist/backend/entities/bulk-operation.entity.js.map +1 -0
- package/dist/backend/entities/bundle-slot-option.entity.d.ts +23 -0
- package/dist/backend/entities/bundle-slot-option.entity.d.ts.map +1 -0
- package/dist/backend/entities/bundle-slot-option.entity.js +68 -0
- package/dist/backend/entities/bundle-slot-option.entity.js.map +1 -0
- package/dist/backend/entities/bundle-slot.entity.d.ts +25 -0
- package/dist/backend/entities/bundle-slot.entity.d.ts.map +1 -0
- package/dist/backend/entities/bundle-slot.entity.js +74 -0
- package/dist/backend/entities/bundle-slot.entity.js.map +1 -0
- package/dist/backend/entities/category.entity.d.ts +26 -0
- package/dist/backend/entities/category.entity.d.ts.map +1 -0
- package/dist/backend/entities/category.entity.js +119 -0
- package/dist/backend/entities/category.entity.js.map +1 -0
- package/dist/backend/entities/gallery-item-label.entity.d.ts +22 -0
- package/dist/backend/entities/gallery-item-label.entity.d.ts.map +1 -0
- package/dist/backend/entities/gallery-item-label.entity.js +50 -0
- package/dist/backend/entities/gallery-item-label.entity.js.map +1 -0
- package/dist/backend/entities/gallery-item.entity.d.ts +17 -0
- package/dist/backend/entities/gallery-item.entity.d.ts.map +1 -0
- package/dist/backend/entities/gallery-item.entity.js +58 -0
- package/dist/backend/entities/gallery-item.entity.js.map +1 -0
- package/dist/backend/entities/grouped-item.entity.d.ts +23 -0
- package/dist/backend/entities/grouped-item.entity.d.ts.map +1 -0
- package/dist/backend/entities/grouped-item.entity.js +68 -0
- package/dist/backend/entities/grouped-item.entity.js.map +1 -0
- package/dist/backend/entities/product-attachment.entity.d.ts +23 -0
- package/dist/backend/entities/product-attachment.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-attachment.entity.js +77 -0
- package/dist/backend/entities/product-attachment.entity.js.map +1 -0
- package/dist/backend/entities/product-attribute.entity.d.ts +72 -0
- package/dist/backend/entities/product-attribute.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-attribute.entity.js +161 -0
- package/dist/backend/entities/product-attribute.entity.js.map +1 -0
- package/dist/backend/entities/product-editor-preference.entity.d.ts +28 -0
- package/dist/backend/entities/product-editor-preference.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-editor-preference.entity.js +63 -0
- package/dist/backend/entities/product-editor-preference.entity.js.map +1 -0
- package/dist/backend/entities/product-link.entity.d.ts +25 -0
- package/dist/backend/entities/product-link.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-link.entity.js +70 -0
- package/dist/backend/entities/product-link.entity.js.map +1 -0
- package/dist/backend/entities/product-packaging-unit.entity.d.ts +26 -0
- package/dist/backend/entities/product-packaging-unit.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-packaging-unit.entity.js +76 -0
- package/dist/backend/entities/product-packaging-unit.entity.js.map +1 -0
- package/dist/backend/entities/product-value-override.entity.d.ts +43 -0
- package/dist/backend/entities/product-value-override.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-value-override.entity.js +90 -0
- package/dist/backend/entities/product-value-override.entity.js.map +1 -0
- package/dist/backend/entities/product-variant.entity.d.ts +18 -0
- package/dist/backend/entities/product-variant.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-variant.entity.js +68 -0
- package/dist/backend/entities/product-variant.entity.js.map +1 -0
- package/dist/backend/entities/product.entity.d.ts +108 -0
- package/dist/backend/entities/product.entity.d.ts.map +1 -0
- package/dist/backend/entities/product.entity.js +230 -0
- package/dist/backend/entities/product.entity.js.map +1 -0
- package/dist/backend/index.d.ts +262 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +642 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +216 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +223 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/prompt-tools.d.ts +47 -0
- package/dist/backend/prompt-tools.d.ts.map +1 -0
- package/dist/backend/prompt-tools.js +284 -0
- package/dist/backend/prompt-tools.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +105 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +1162 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.api-key.d.ts +33 -0
- package/dist/backend/routes.api-key.d.ts.map +1 -0
- package/dist/backend/routes.api-key.js +43 -0
- package/dist/backend/routes.api-key.js.map +1 -0
- package/dist/backend/routes.external.d.ts +32 -0
- package/dist/backend/routes.external.d.ts.map +1 -0
- package/dist/backend/routes.external.js +115 -0
- package/dist/backend/routes.external.js.map +1 -0
- package/dist/backend/routes.public.d.ts +46 -0
- package/dist/backend/routes.public.d.ts.map +1 -0
- package/dist/backend/routes.public.js +318 -0
- package/dist/backend/routes.public.js.map +1 -0
- package/dist/backend/services/asset-references.d.ts +4 -0
- package/dist/backend/services/asset-references.d.ts.map +1 -0
- package/dist/backend/services/asset-references.js +104 -0
- package/dist/backend/services/asset-references.js.map +1 -0
- package/dist/backend/services/attachment.service.d.ts +45 -0
- package/dist/backend/services/attachment.service.d.ts.map +1 -0
- package/dist/backend/services/attachment.service.js +268 -0
- package/dist/backend/services/attachment.service.js.map +1 -0
- package/dist/backend/services/attribute-option-validator.d.ts +47 -0
- package/dist/backend/services/attribute-option-validator.d.ts.map +1 -0
- package/dist/backend/services/attribute-option-validator.js +69 -0
- package/dist/backend/services/attribute-option-validator.js.map +1 -0
- package/dist/backend/services/attribute-set-validations.d.ts +65 -0
- package/dist/backend/services/attribute-set-validations.d.ts.map +1 -0
- package/dist/backend/services/attribute-set-validations.js +89 -0
- package/dist/backend/services/attribute-set-validations.js.map +1 -0
- package/dist/backend/services/attribute-set.service.d.ts +50 -0
- package/dist/backend/services/attribute-set.service.d.ts.map +1 -0
- package/dist/backend/services/attribute-set.service.js +401 -0
- package/dist/backend/services/attribute-set.service.js.map +1 -0
- package/dist/backend/services/attribute-type-mapping.d.ts +66 -0
- package/dist/backend/services/attribute-type-mapping.d.ts.map +1 -0
- package/dist/backend/services/attribute-type-mapping.js +121 -0
- package/dist/backend/services/attribute-type-mapping.js.map +1 -0
- package/dist/backend/services/attribute-value-key.service.d.ts +48 -0
- package/dist/backend/services/attribute-value-key.service.d.ts.map +1 -0
- package/dist/backend/services/attribute-value-key.service.js +118 -0
- package/dist/backend/services/attribute-value-key.service.js.map +1 -0
- package/dist/backend/services/audit-references.d.ts +13 -0
- package/dist/backend/services/audit-references.d.ts.map +1 -0
- package/dist/backend/services/audit-references.js +51 -0
- package/dist/backend/services/audit-references.js.map +1 -0
- package/dist/backend/services/bulk-operation-queue.d.ts +26 -0
- package/dist/backend/services/bulk-operation-queue.d.ts.map +1 -0
- package/dist/backend/services/bulk-operation-queue.js +34 -0
- package/dist/backend/services/bulk-operation-queue.js.map +1 -0
- package/dist/backend/services/bulk-operation.service.d.ts +195 -0
- package/dist/backend/services/bulk-operation.service.d.ts.map +1 -0
- package/dist/backend/services/bulk-operation.service.js +510 -0
- package/dist/backend/services/bulk-operation.service.js.map +1 -0
- package/dist/backend/services/bundle.service.d.ts +87 -0
- package/dist/backend/services/bundle.service.d.ts.map +1 -0
- package/dist/backend/services/bundle.service.js +286 -0
- package/dist/backend/services/bundle.service.js.map +1 -0
- package/dist/backend/services/catalog-admin.service.d.ts +398 -0
- package/dist/backend/services/catalog-admin.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-admin.service.js +1516 -0
- package/dist/backend/services/catalog-admin.service.js.map +1 -0
- package/dist/backend/services/catalog-attribute-read.service.d.ts +78 -0
- package/dist/backend/services/catalog-attribute-read.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-attribute-read.service.js +216 -0
- package/dist/backend/services/catalog-attribute-read.service.js.map +1 -0
- package/dist/backend/services/catalog-bulk-import.service.d.ts +30 -0
- package/dist/backend/services/catalog-bulk-import.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-bulk-import.service.js +136 -0
- package/dist/backend/services/catalog-bulk-import.service.js.map +1 -0
- package/dist/backend/services/catalog-bulk-update.service.d.ts +91 -0
- package/dist/backend/services/catalog-bulk-update.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-bulk-update.service.js +330 -0
- package/dist/backend/services/catalog-bulk-update.service.js.map +1 -0
- package/dist/backend/services/catalog-category-read.service.d.ts +66 -0
- package/dist/backend/services/catalog-category-read.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-category-read.service.js +248 -0
- package/dist/backend/services/catalog-category-read.service.js.map +1 -0
- package/dist/backend/services/catalog-org-price-decorator.d.ts +90 -0
- package/dist/backend/services/catalog-org-price-decorator.d.ts.map +1 -0
- package/dist/backend/services/catalog-org-price-decorator.js +184 -0
- package/dist/backend/services/catalog-org-price-decorator.js.map +1 -0
- package/dist/backend/services/catalog-product-filter.service.d.ts +82 -0
- package/dist/backend/services/catalog-product-filter.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-product-filter.service.js +275 -0
- package/dist/backend/services/catalog-product-filter.service.js.map +1 -0
- package/dist/backend/services/catalog-product-read.service.d.ts +46 -0
- package/dist/backend/services/catalog-product-read.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-product-read.service.js +197 -0
- package/dist/backend/services/catalog-product-read.service.js.map +1 -0
- package/dist/backend/services/catalog-query.service.d.ts +444 -0
- package/dist/backend/services/catalog-query.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-query.service.js +1633 -0
- package/dist/backend/services/catalog-query.service.js.map +1 -0
- package/dist/backend/services/catalog-quick-search.service.d.ts +78 -0
- package/dist/backend/services/catalog-quick-search.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-quick-search.service.js +159 -0
- package/dist/backend/services/catalog-quick-search.service.js.map +1 -0
- package/dist/backend/services/catalog-write-ports.d.ts +25 -0
- package/dist/backend/services/catalog-write-ports.d.ts.map +1 -0
- package/dist/backend/services/catalog-write-ports.js +63 -0
- package/dist/backend/services/catalog-write-ports.js.map +1 -0
- package/dist/backend/services/category-admin.service.d.ts +102 -0
- package/dist/backend/services/category-admin.service.d.ts.map +1 -0
- package/dist/backend/services/category-admin.service.js +271 -0
- package/dist/backend/services/category-admin.service.js.map +1 -0
- package/dist/backend/services/gallery.service.d.ts +85 -0
- package/dist/backend/services/gallery.service.d.ts.map +1 -0
- package/dist/backend/services/gallery.service.js +326 -0
- package/dist/backend/services/gallery.service.js.map +1 -0
- package/dist/backend/services/grouped.service.d.ts +39 -0
- package/dist/backend/services/grouped.service.d.ts.map +1 -0
- package/dist/backend/services/grouped.service.js +136 -0
- package/dist/backend/services/grouped.service.js.map +1 -0
- package/dist/backend/services/label-resolver.d.ts +16 -0
- package/dist/backend/services/label-resolver.d.ts.map +1 -0
- package/dist/backend/services/label-resolver.js +43 -0
- package/dist/backend/services/label-resolver.js.map +1 -0
- package/dist/backend/services/packaging-unit.service.d.ts +28 -0
- package/dist/backend/services/packaging-unit.service.d.ts.map +1 -0
- package/dist/backend/services/packaging-unit.service.js +197 -0
- package/dist/backend/services/packaging-unit.service.js.map +1 -0
- package/dist/backend/services/primary-asset-url.d.ts +4 -0
- package/dist/backend/services/primary-asset-url.d.ts.map +1 -0
- package/dist/backend/services/primary-asset-url.js +55 -0
- package/dist/backend/services/primary-asset-url.js.map +1 -0
- package/dist/backend/services/product-editor-preferences.service.d.ts +20 -0
- package/dist/backend/services/product-editor-preferences.service.d.ts.map +1 -0
- package/dist/backend/services/product-editor-preferences.service.js +44 -0
- package/dist/backend/services/product-editor-preferences.service.js.map +1 -0
- package/dist/backend/services/product-link.service.d.ts +169 -0
- package/dist/backend/services/product-link.service.d.ts.map +1 -0
- package/dist/backend/services/product-link.service.js +297 -0
- package/dist/backend/services/product-link.service.js.map +1 -0
- package/dist/backend/services/product-overrides.service.d.ts +77 -0
- package/dist/backend/services/product-overrides.service.d.ts.map +1 -0
- package/dist/backend/services/product-overrides.service.js +204 -0
- package/dist/backend/services/product-overrides.service.js.map +1 -0
- package/dist/backend/services/product-scope-context.service.d.ts +36 -0
- package/dist/backend/services/product-scope-context.service.d.ts.map +1 -0
- package/dist/backend/services/product-scope-context.service.js +106 -0
- package/dist/backend/services/product-scope-context.service.js.map +1 -0
- package/dist/backend/services/product-type-validations.d.ts +42 -0
- package/dist/backend/services/product-type-validations.d.ts.map +1 -0
- package/dist/backend/services/product-type-validations.js +55 -0
- package/dist/backend/services/product-type-validations.js.map +1 -0
- package/dist/backend/services/product-value-resolver.service.d.ts +59 -0
- package/dist/backend/services/product-value-resolver.service.d.ts.map +1 -0
- package/dist/backend/services/product-value-resolver.service.js +111 -0
- package/dist/backend/services/product-value-resolver.service.js.map +1 -0
- package/dist/backend/services/system-attribute-scopes.d.ts +18 -0
- package/dist/backend/services/system-attribute-scopes.d.ts.map +1 -0
- package/dist/backend/services/system-attribute-scopes.js +18 -0
- package/dist/backend/services/system-attribute-scopes.js.map +1 -0
- package/dist/backend/services/viewer-organization.d.ts +25 -0
- package/dist/backend/services/viewer-organization.d.ts.map +1 -0
- package/dist/backend/services/viewer-organization.js +31 -0
- package/dist/backend/services/viewer-organization.js.map +1 -0
- package/dist/manifest.d.ts +204 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +686 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260429T064146_catalog_attribute_sets_init.d.ts +33 -0
- package/dist/migrations/20260429T064146_catalog_attribute_sets_init.d.ts.map +1 -0
- package/dist/migrations/20260429T064146_catalog_attribute_sets_init.js +118 -0
- package/dist/migrations/20260429T064146_catalog_attribute_sets_init.js.map +1 -0
- package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.d.ts +24 -0
- package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.d.ts.map +1 -0
- package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.js +31 -0
- package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.js.map +1 -0
- package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.d.ts +32 -0
- package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.d.ts.map +1 -0
- package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.js +58 -0
- package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.js.map +1 -0
- package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.d.ts +22 -0
- package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.d.ts.map +1 -0
- package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.js +66 -0
- package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.js.map +1 -0
- package/dist/migrations/20260429T112543_catalog_product_attachments.d.ts +18 -0
- package/dist/migrations/20260429T112543_catalog_product_attachments.d.ts.map +1 -0
- package/dist/migrations/20260429T112543_catalog_product_attachments.js +73 -0
- package/dist/migrations/20260429T112543_catalog_product_attachments.js.map +1 -0
- package/dist/migrations/20260429T123726_catalog_product_links.d.ts +21 -0
- package/dist/migrations/20260429T123726_catalog_product_links.d.ts.map +1 -0
- package/dist/migrations/20260429T123726_catalog_product_links.js +48 -0
- package/dist/migrations/20260429T123726_catalog_product_links.js.map +1 -0
- package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.d.ts +23 -0
- package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.d.ts.map +1 -0
- package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.js +94 -0
- package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.js.map +1 -0
- package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.d.ts +24 -0
- package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.d.ts.map +1 -0
- package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.js +31 -0
- package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.js.map +1 -0
- package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.d.ts +31 -0
- package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.d.ts.map +1 -0
- package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.js +133 -0
- package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.js.map +1 -0
- package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.d.ts +16 -0
- package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.d.ts.map +1 -0
- package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.js +23 -0
- package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.js.map +1 -0
- package/dist/migrations/20260526T124736_catalog_product_status_inactive.d.ts +10 -0
- package/dist/migrations/20260526T124736_catalog_product_status_inactive.d.ts.map +1 -0
- package/dist/migrations/20260526T124736_catalog_product_status_inactive.js +22 -0
- package/dist/migrations/20260526T124736_catalog_product_status_inactive.js.map +1 -0
- package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.d.ts +38 -0
- package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.d.ts.map +1 -0
- package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.js +98 -0
- package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.js.map +1 -0
- package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.d.ts +13 -0
- package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.d.ts.map +1 -0
- package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.js +17 -0
- package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.js.map +1 -0
- package/dist/migrations/20260611T140407_catalog_bulk_operations.d.ts +16 -0
- package/dist/migrations/20260611T140407_catalog_bulk_operations.d.ts.map +1 -0
- package/dist/migrations/20260611T140407_catalog_bulk_operations.js +42 -0
- package/dist/migrations/20260611T140407_catalog_bulk_operations.js.map +1 -0
- package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.d.ts +14 -0
- package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.d.ts.map +1 -0
- package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.js +18 -0
- package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.js.map +1 -0
- package/dist/migrations/20260611T140412_catalog_product_packaging_units.d.ts +11 -0
- package/dist/migrations/20260611T140412_catalog_product_packaging_units.d.ts.map +1 -0
- package/dist/migrations/20260611T140412_catalog_product_packaging_units.js +29 -0
- package/dist/migrations/20260611T140412_catalog_product_packaging_units.js.map +1 -0
- package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.d.ts +23 -0
- package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.d.ts.map +1 -0
- package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.js +35 -0
- package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.js.map +1 -0
- package/dist/migrations/20260718T200343_catalog_category_custom_field_values.d.ts +12 -0
- package/dist/migrations/20260718T200343_catalog_category_custom_field_values.d.ts.map +1 -0
- package/dist/migrations/20260718T200343_catalog_category_custom_field_values.js +16 -0
- package/dist/migrations/20260718T200343_catalog_category_custom_field_values.js.map +1 -0
- package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.d.ts +32 -0
- package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.d.ts.map +1 -0
- package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.js +286 -0
- package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.js.map +1 -0
- package/dist/migrations/20260804T152604_catalog_widen_product_sku.d.ts +36 -0
- package/dist/migrations/20260804T152604_catalog_widen_product_sku.d.ts.map +1 -0
- package/dist/migrations/20260804T152604_catalog_widen_product_sku.js +63 -0
- package/dist/migrations/20260804T152604_catalog_widen_product_sku.js.map +1 -0
- package/dist/migrations/20260804T160244_catalog_category_activation.d.ts +18 -0
- package/dist/migrations/20260804T160244_catalog_category_activation.d.ts.map +1 -0
- package/dist/migrations/20260804T160244_catalog_category_activation.js +22 -0
- package/dist/migrations/20260804T160244_catalog_category_activation.js.map +1 -0
- package/dist/migrations/20260912T094557_catalog_sales_channel_products.d.ts +27 -0
- package/dist/migrations/20260912T094557_catalog_sales_channel_products.d.ts.map +1 -0
- package/dist/migrations/20260912T094557_catalog_sales_channel_products.js +44 -0
- package/dist/migrations/20260912T094557_catalog_sales_channel_products.js.map +1 -0
- package/dist/migrations/20260912T094623_catalog_sales_channel_categories.d.ts +27 -0
- package/dist/migrations/20260912T094623_catalog_sales_channel_categories.d.ts.map +1 -0
- package/dist/migrations/20260912T094623_catalog_sales_channel_categories.js +44 -0
- package/dist/migrations/20260912T094623_catalog_sales_channel_categories.js.map +1 -0
- package/dist/migrations/20260925T125527_catalog_inventory_columns.d.ts +36 -0
- package/dist/migrations/20260925T125527_catalog_inventory_columns.d.ts.map +1 -0
- package/dist/migrations/20260925T125527_catalog_inventory_columns.js +87 -0
- package/dist/migrations/20260925T125527_catalog_inventory_columns.js.map +1 -0
- package/dist/migrations/index.d.ts +55 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +80 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/ports/index.d.ts +96 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +2 -0
- package/dist/ports/index.js.map +1 -0
- package/docs/catalog/attachments.md +69 -0
- package/docs/catalog/attribute-sets.md +63 -0
- package/docs/catalog/attributes.md +244 -0
- package/docs/catalog/composite-products.md +115 -0
- package/docs/catalog/gallery-and-labels.md +73 -0
- package/docs/catalog/packaging-units.md +67 -0
- package/docs/catalog/per-channel-per-language-overrides.md +234 -0
- package/docs/catalog/product-links.md +79 -0
- package/docs/catalog.md +207 -0
- package/i18n/en.json +649 -0
- package/i18n/pl.json +649 -0
- package/package.json +109 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PackagingUnitService — admin CRUD for product packaging units (feature 043).
|
|
3
|
+
*
|
|
4
|
+
* A packaging unit is a named ordering unit on a product (e.g. "Paleta" = 480
|
|
5
|
+
* pieces). Units apply only to physical, purchasable product types
|
|
6
|
+
* (simple / configurable). At most one unit per product is the default
|
|
7
|
+
* presented on the storefront; setting a new default clears the previous one
|
|
8
|
+
* (last write wins). Names are unique within a product. Hard delete is safe
|
|
9
|
+
* because cart/order/RFQ lines snapshot their own copy.
|
|
10
|
+
*/
|
|
11
|
+
import { randomUUID } from 'node:crypto';
|
|
12
|
+
import { UniqueConstraintViolationException } from '@mikro-orm/core';
|
|
13
|
+
import { ERROR_CODES, } from '@endora-commerce/contracts';
|
|
14
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
15
|
+
import { Product } from '../entities/product.entity.js';
|
|
16
|
+
import { ProductPackagingUnit } from '../entities/product-packaging-unit.entity.js';
|
|
17
|
+
const ELIGIBLE_TYPES = new Set(['simple', 'configurable']);
|
|
18
|
+
export class PackagingUnitService {
|
|
19
|
+
emFactory;
|
|
20
|
+
commandBus;
|
|
21
|
+
constructor(emFactory,
|
|
22
|
+
/** Feature 054 — audits packaging-unit writes co-transactionally when provided. */
|
|
23
|
+
commandBus) {
|
|
24
|
+
this.emFactory = emFactory;
|
|
25
|
+
this.commandBus = commandBus;
|
|
26
|
+
}
|
|
27
|
+
/** Feature 054 — run a write through the Command Bus (co-transactional audit). */
|
|
28
|
+
async #audited(action, objectId, write) {
|
|
29
|
+
if (this.commandBus) {
|
|
30
|
+
return this.commandBus.run({
|
|
31
|
+
action,
|
|
32
|
+
objectType: 'packaging_unit',
|
|
33
|
+
objectId,
|
|
34
|
+
run: async ({ em }) => {
|
|
35
|
+
const w = await write(em);
|
|
36
|
+
return { result: w.result, before: w.before, after: w.after };
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const em = this.emFactory();
|
|
41
|
+
const w = await write(em);
|
|
42
|
+
await em.flush();
|
|
43
|
+
return w.result;
|
|
44
|
+
}
|
|
45
|
+
async list(productId) {
|
|
46
|
+
const em = this.emFactory();
|
|
47
|
+
await this.#assertProductExists(em, productId);
|
|
48
|
+
const items = await em.find(ProductPackagingUnit, { productId }, { orderBy: { position: 'asc', name: 'asc' } });
|
|
49
|
+
return items.map((i) => this.#dto(i));
|
|
50
|
+
}
|
|
51
|
+
async create(productId, req) {
|
|
52
|
+
const id = randomUUID();
|
|
53
|
+
const unit = await this.#audited('packaging_unit.create', id, async (em) => {
|
|
54
|
+
await this.#assertProductEligible(em, productId);
|
|
55
|
+
const position = req.position ?? (await this.#nextPosition(em, productId));
|
|
56
|
+
const u = em.create(ProductPackagingUnit, {
|
|
57
|
+
id,
|
|
58
|
+
productId,
|
|
59
|
+
name: req.name.trim(),
|
|
60
|
+
baseQuantity: req.baseQuantity,
|
|
61
|
+
position,
|
|
62
|
+
isDefault: req.isDefault ?? false,
|
|
63
|
+
});
|
|
64
|
+
try {
|
|
65
|
+
await em.flush();
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
throw this.#mapUniqueViolation(err, u.name);
|
|
69
|
+
}
|
|
70
|
+
if (u.isDefault)
|
|
71
|
+
await this.#clearOtherDefaults(em, productId, u.id);
|
|
72
|
+
return {
|
|
73
|
+
result: u,
|
|
74
|
+
before: null,
|
|
75
|
+
after: { productId, name: u.name, baseQuantity: u.baseQuantity, isDefault: u.isDefault },
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
return this.#dto(unit);
|
|
79
|
+
}
|
|
80
|
+
async update(productId, unitId, req) {
|
|
81
|
+
const unit = await this.#audited('packaging_unit.update', unitId, async (em) => {
|
|
82
|
+
const u = await this.#findOwned(em, productId, unitId);
|
|
83
|
+
const before = { name: u.name, baseQuantity: u.baseQuantity, isDefault: u.isDefault };
|
|
84
|
+
if (req.name !== undefined)
|
|
85
|
+
u.name = req.name.trim();
|
|
86
|
+
if (req.baseQuantity !== undefined)
|
|
87
|
+
u.baseQuantity = req.baseQuantity;
|
|
88
|
+
if (req.position !== undefined)
|
|
89
|
+
u.position = req.position;
|
|
90
|
+
if (req.isDefault !== undefined)
|
|
91
|
+
u.isDefault = req.isDefault;
|
|
92
|
+
try {
|
|
93
|
+
await em.flush();
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
throw this.#mapUniqueViolation(err, u.name);
|
|
97
|
+
}
|
|
98
|
+
if (req.isDefault === true)
|
|
99
|
+
await this.#clearOtherDefaults(em, productId, u.id);
|
|
100
|
+
return {
|
|
101
|
+
result: u,
|
|
102
|
+
before,
|
|
103
|
+
after: { name: u.name, baseQuantity: u.baseQuantity, isDefault: u.isDefault },
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
return this.#dto(unit);
|
|
107
|
+
}
|
|
108
|
+
async delete(productId, unitId) {
|
|
109
|
+
await this.#audited('packaging_unit.delete', unitId, async (em) => {
|
|
110
|
+
const unit = await this.#findOwned(em, productId, unitId);
|
|
111
|
+
const before = { productId, name: unit.name };
|
|
112
|
+
em.remove(unit);
|
|
113
|
+
return { result: undefined, before, after: null };
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async reorder(productId, req) {
|
|
117
|
+
await this.#audited('packaging_unit.reorder', productId, async (em) => {
|
|
118
|
+
await this.#assertProductExists(em, productId);
|
|
119
|
+
const items = await em.find(ProductPackagingUnit, { productId });
|
|
120
|
+
const byId = new Map(items.map((i) => [i.id, i]));
|
|
121
|
+
let position = 0;
|
|
122
|
+
for (const id of req.orderedIds) {
|
|
123
|
+
const unit = byId.get(id);
|
|
124
|
+
if (!unit) {
|
|
125
|
+
throw new HttpError(404, ERROR_CODES.PACKAGING_UNIT_NOT_FOUND, `Packaging unit ${id} not found under Product ${productId}.`);
|
|
126
|
+
}
|
|
127
|
+
unit.position = position++;
|
|
128
|
+
}
|
|
129
|
+
return { result: undefined, before: null, after: { productId, count: req.orderedIds.length } };
|
|
130
|
+
});
|
|
131
|
+
return this.list(productId);
|
|
132
|
+
}
|
|
133
|
+
// -- INTERNALS ------------------------------------------------------------
|
|
134
|
+
async #assertProductExists(em, productId) {
|
|
135
|
+
const product = await em.findOne(Product, { id: productId });
|
|
136
|
+
if (!product) {
|
|
137
|
+
throw new HttpError(404, ERROR_CODES.PRODUCT_NOT_FOUND, `Product ${productId} not found.`);
|
|
138
|
+
}
|
|
139
|
+
return product;
|
|
140
|
+
}
|
|
141
|
+
async #assertProductEligible(em, productId) {
|
|
142
|
+
const product = await this.#assertProductExists(em, productId);
|
|
143
|
+
if (!ELIGIBLE_TYPES.has(product.type)) {
|
|
144
|
+
throw new HttpError(422, ERROR_CODES.PACKAGING_UNIT_NOT_SUPPORTED_FOR_TYPE, `Packaging units are only supported for simple or configurable products; got "${product.type}".`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async #findOwned(em, productId, unitId) {
|
|
148
|
+
const unit = await em.findOne(ProductPackagingUnit, { id: unitId, productId });
|
|
149
|
+
if (!unit) {
|
|
150
|
+
throw new HttpError(404, ERROR_CODES.PACKAGING_UNIT_NOT_FOUND, `Packaging unit ${unitId} not found under Product ${productId}.`);
|
|
151
|
+
}
|
|
152
|
+
return unit;
|
|
153
|
+
}
|
|
154
|
+
/** Clear `isDefault` on every other unit of the product (last write wins). */
|
|
155
|
+
async #clearOtherDefaults(em, productId, keepId) {
|
|
156
|
+
const others = await em.find(ProductPackagingUnit, {
|
|
157
|
+
productId,
|
|
158
|
+
isDefault: true,
|
|
159
|
+
id: { $ne: keepId },
|
|
160
|
+
});
|
|
161
|
+
if (others.length === 0)
|
|
162
|
+
return;
|
|
163
|
+
// No flush here — the enclosing #audited command (or its bus-less fallback)
|
|
164
|
+
// commits these together with the create/update.
|
|
165
|
+
for (const o of others)
|
|
166
|
+
o.isDefault = false;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* `em.execute`, not `em.getConnection().execute`: `create` calls this on the
|
|
170
|
+
* Command's `em`, so the next free position is computed from the rows that
|
|
171
|
+
* transaction can see rather than from a pooled connection's older view
|
|
172
|
+
* (issue #207).
|
|
173
|
+
*/
|
|
174
|
+
async #nextPosition(em, productId) {
|
|
175
|
+
const rows = (await em.execute(`select coalesce(max(position), -1) + 1 as next_position from product_packaging_units where product_id = ?`, [productId]));
|
|
176
|
+
return rows[0]?.next_position ?? 0;
|
|
177
|
+
}
|
|
178
|
+
#mapUniqueViolation(err, name) {
|
|
179
|
+
if (err instanceof UniqueConstraintViolationException) {
|
|
180
|
+
return new HttpError(409, ERROR_CODES.PACKAGING_UNIT_NAME_CONFLICT, `A packaging unit named "${name}" already exists for this product.`);
|
|
181
|
+
}
|
|
182
|
+
return err;
|
|
183
|
+
}
|
|
184
|
+
#dto(u) {
|
|
185
|
+
return {
|
|
186
|
+
id: u.id,
|
|
187
|
+
productId: u.productId,
|
|
188
|
+
name: u.name,
|
|
189
|
+
baseQuantity: u.baseQuantity,
|
|
190
|
+
position: u.position,
|
|
191
|
+
isDefault: u.isDefault,
|
|
192
|
+
createdAt: u.createdAt.toISOString(),
|
|
193
|
+
updatedAt: u.updatedAt.toISOString(),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=packaging-unit.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packaging-unit.service.js","sourceRoot":"","sources":["../../../src/backend/services/packaging-unit.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { AssetReadPort } from '@endora-commerce/contracts';
|
|
3
|
+
export declare function resolvePrimaryAssetUrls(em: EntityManager, assets: AssetReadPort, productIds: readonly string[]): Promise<Map<string, string | null>>;
|
|
4
|
+
//# sourceMappingURL=primary-asset-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primary-asset-url.d.ts","sourceRoot":"","sources":["../../../src/backend/services/primary-asset-url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAqDhE,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,aAAa,EACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAuDrC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export async function resolvePrimaryAssetUrls(em, assets, productIds) {
|
|
2
|
+
const result = new Map();
|
|
3
|
+
for (const id of productIds)
|
|
4
|
+
result.set(id, null);
|
|
5
|
+
if (productIds.length === 0)
|
|
6
|
+
return result;
|
|
7
|
+
const ids = [...productIds];
|
|
8
|
+
const galleryRows = await em.execute(`select gi.product_id::text as product_id,
|
|
9
|
+
gi.asset_id::text as asset_id,
|
|
10
|
+
gil.label
|
|
11
|
+
from gallery_items gi
|
|
12
|
+
left join gallery_item_labels gil on gil.gallery_item_id = gi.id
|
|
13
|
+
where gi.product_id in (${ids.map(() => '?').join(',')})
|
|
14
|
+
order by gi.product_id, gi.position asc, gi.id asc`, ids);
|
|
15
|
+
// One call to the owner for every gallery candidate on the page.
|
|
16
|
+
// `assets_library` is a binding dependency of this module, so an absent owner
|
|
17
|
+
// fails closed here rather than quietly rendering an imageless catalogue.
|
|
18
|
+
const galleryUrls = await urlsFor(assets, galleryRows);
|
|
19
|
+
const galleryByProduct = new Map();
|
|
20
|
+
for (const row of galleryRows) {
|
|
21
|
+
if (!galleryUrls.has(row.asset_id))
|
|
22
|
+
continue;
|
|
23
|
+
const list = galleryByProduct.get(row.product_id) ?? [];
|
|
24
|
+
list.push(row);
|
|
25
|
+
galleryByProduct.set(row.product_id, list);
|
|
26
|
+
}
|
|
27
|
+
for (const [productId, rows] of galleryByProduct) {
|
|
28
|
+
const byLabel = (label) => galleryUrls.get(rows.find((r) => r.label === label)?.asset_id ?? '');
|
|
29
|
+
const first = rows[0] ? galleryUrls.get(rows[0].asset_id) : undefined;
|
|
30
|
+
result.set(productId, byLabel('thumbnail') ?? byLabel('base_image') ?? first ?? null);
|
|
31
|
+
}
|
|
32
|
+
const missing = ids.filter((id) => !galleryByProduct.has(id));
|
|
33
|
+
if (missing.length === 0)
|
|
34
|
+
return result;
|
|
35
|
+
const legacyRows = await em.execute(`select pa.product_id::text as product_id, pa.asset_id::text as asset_id, null::text as label
|
|
36
|
+
from product_assets pa
|
|
37
|
+
where pa.product_id in (${missing.map(() => '?').join(',')})
|
|
38
|
+
order by pa.product_id, pa.position asc`, missing);
|
|
39
|
+
const legacyUrls = await urlsFor(assets, legacyRows);
|
|
40
|
+
for (const row of legacyRows) {
|
|
41
|
+
if (result.get(row.product_id))
|
|
42
|
+
continue;
|
|
43
|
+
const url = legacyUrls.get(row.asset_id);
|
|
44
|
+
if (url !== undefined)
|
|
45
|
+
result.set(row.product_id, url);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
async function urlsFor(assets, rows) {
|
|
50
|
+
const ids = [...new Set(rows.map((r) => r.asset_id))];
|
|
51
|
+
if (ids.length === 0)
|
|
52
|
+
return new Map();
|
|
53
|
+
return new Map((await assets.findByIds(ids)).map((asset) => [asset.id, asset.storageUrl]));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=primary-asset-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primary-asset-url.js","sourceRoot":"","sources":["../../../src/backend/services/primary-asset-url.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { ProductEditorPreference } from '../entities/product-editor-preference.entity.js';
|
|
3
|
+
/**
|
|
4
|
+
* Feature 022 — per-(admin user, product) memory of the last
|
|
5
|
+
* Sales Channel + Language the editor selected on the product edit
|
|
6
|
+
* page. Read on page load to seed the switchers; upserted on
|
|
7
|
+
* switcher change.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ProductEditorPreferencesService {
|
|
10
|
+
private readonly emFactory;
|
|
11
|
+
constructor(emFactory: () => EntityManager);
|
|
12
|
+
/** Fetch the editor's last-selected context for this product. */
|
|
13
|
+
find(adminUserId: string, productId: string): Promise<ProductEditorPreference | null>;
|
|
14
|
+
/** Idempotent upsert. Returns the post-write row. */
|
|
15
|
+
upsert(adminUserId: string, productId: string, fields: {
|
|
16
|
+
lastChannelId: string | null;
|
|
17
|
+
lastLanguageCode: string | null;
|
|
18
|
+
}): Promise<ProductEditorPreference>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=product-editor-preferences.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-editor-preferences.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/product-editor-preferences.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAE1F;;;;;GAKG;AACH,qBAAa,+BAA+B;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAE3D,iEAAiE;IAC3D,IAAI,CACR,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC;IAK1C,qDAAqD;IAC/C,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;QACN,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,GACA,OAAO,CAAC,uBAAuB,CAAC;CAwBpC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ProductEditorPreference } from '../entities/product-editor-preference.entity.js';
|
|
2
|
+
/**
|
|
3
|
+
* Feature 022 — per-(admin user, product) memory of the last
|
|
4
|
+
* Sales Channel + Language the editor selected on the product edit
|
|
5
|
+
* page. Read on page load to seed the switchers; upserted on
|
|
6
|
+
* switcher change.
|
|
7
|
+
*/
|
|
8
|
+
export class ProductEditorPreferencesService {
|
|
9
|
+
emFactory;
|
|
10
|
+
constructor(emFactory) {
|
|
11
|
+
this.emFactory = emFactory;
|
|
12
|
+
}
|
|
13
|
+
/** Fetch the editor's last-selected context for this product. */
|
|
14
|
+
async find(adminUserId, productId) {
|
|
15
|
+
const em = this.emFactory();
|
|
16
|
+
return em.findOne(ProductEditorPreference, { adminUserId, productId });
|
|
17
|
+
}
|
|
18
|
+
/** Idempotent upsert. Returns the post-write row. */
|
|
19
|
+
async upsert(adminUserId, productId, fields) {
|
|
20
|
+
// command-coverage-ignore: per-admin UI editor state (last-selected channel +
|
|
21
|
+
// language on the product edit page) — a personal preference, not a catalog
|
|
22
|
+
// domain mutation, so it is not an admin-audit target.
|
|
23
|
+
const em = this.emFactory();
|
|
24
|
+
const existing = await em.findOne(ProductEditorPreference, {
|
|
25
|
+
adminUserId,
|
|
26
|
+
productId,
|
|
27
|
+
});
|
|
28
|
+
if (existing) {
|
|
29
|
+
existing.lastChannelId = fields.lastChannelId;
|
|
30
|
+
existing.lastLanguageCode = fields.lastLanguageCode;
|
|
31
|
+
await em.flush();
|
|
32
|
+
return existing;
|
|
33
|
+
}
|
|
34
|
+
const row = em.create(ProductEditorPreference, {
|
|
35
|
+
adminUserId,
|
|
36
|
+
productId,
|
|
37
|
+
lastChannelId: fields.lastChannelId,
|
|
38
|
+
lastLanguageCode: fields.lastLanguageCode,
|
|
39
|
+
});
|
|
40
|
+
await em.persistAndFlush(row);
|
|
41
|
+
return row;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=product-editor-preferences.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-editor-preferences.service.js","sourceRoot":"","sources":["../../../src/backend/services/product-editor-preferences.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,OAAO,+BAA+B;IACb;IAA7B,YAA6B,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAE/D,iEAAiE;IACjE,KAAK,CAAC,IAAI,CACR,WAAmB,EACnB,SAAiB;QAEjB,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,qDAAqD;IACrD,KAAK,CAAC,MAAM,CACV,WAAmB,EACnB,SAAiB,EACjB,MAGC;QAED,8EAA8E;QAC9E,4EAA4E;QAC5E,uDAAuD;QACvD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE;YACzD,WAAW;YACX,SAAS;SACV,CAAC,CAAC;QACH,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;YAC9C,QAAQ,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;YACpD,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,uBAAuB,EAAE;YAC7C,WAAW;YACX,SAAS;YACT,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;SAC1C,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { type AssetReadPort, type ListingPricePort, type OrganizationDetailsPort, type ProductAudience } from '@endora-commerce/contracts';
|
|
3
|
+
import type { SalesChannelMembershipPort } from '@endora-commerce/platform/kernel';
|
|
4
|
+
import type { CommandBus } from '@endora-commerce/platform/commands';
|
|
5
|
+
import { type ProductLinkKind } from '../entities/product-link.entity.js';
|
|
6
|
+
interface StorefrontContext {
|
|
7
|
+
/**
|
|
8
|
+
* The request's resolved sales channel (feature 053 / FR-002). Always
|
|
9
|
+
* present — the canonical resolver guarantees a concrete channel — so
|
|
10
|
+
* cross/up-sell filtering is unconditional and fails closed (Principle XII).
|
|
11
|
+
* `isPublic` is the price-visibility flag, and `defaultCurrency` is the
|
|
12
|
+
* currency the link tiles quote in — it used to be the literal `'PLN'`, which
|
|
13
|
+
* mislabelled every amount on a channel trading in anything else.
|
|
14
|
+
*/
|
|
15
|
+
resolvedChannel: {
|
|
16
|
+
id: string;
|
|
17
|
+
code: string;
|
|
18
|
+
isPublic: boolean;
|
|
19
|
+
defaultCurrency: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Who is asking. A cross-sell tile is a card with an Add-to-cart on it, and
|
|
23
|
+
* the cart line it leads to is priced for the buyer's organisation — so a
|
|
24
|
+
* strip quoting the channel price beside a listing quoting the buyer's would
|
|
25
|
+
* put two prices for two products on one page, arrived at two different ways.
|
|
26
|
+
*
|
|
27
|
+
* **Required, not defaulted**, for the reason `CatalogQueryContext` states:
|
|
28
|
+
* the safe default is the anonymous audience, and a caller that forgot to
|
|
29
|
+
* resolve its viewer would then quietly quote every buyer the channel price
|
|
30
|
+
* — a defect that reads as "the negotiated list does not work" and is found
|
|
31
|
+
* by nobody. Both call sites pass it; `tsc` names a third.
|
|
32
|
+
*
|
|
33
|
+
* It is read for the **price** and not, today, for the tile's visibility:
|
|
34
|
+
* `listForStorefront` filters by status and channel membership and has never
|
|
35
|
+
* applied `isProductVisibleTo`, which is issue #227 residue this change does
|
|
36
|
+
* not close. Do not read the presence of this field as the entitlement
|
|
37
|
+
* question having been answered here.
|
|
38
|
+
*/
|
|
39
|
+
audience: ProductAudience;
|
|
40
|
+
preferredLanguage?: string | undefined;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* ProductLinkService — admin CRUD + storefront read for related/up-sell/
|
|
44
|
+
* cross-sell pairings (feature 002 US4, T104).
|
|
45
|
+
*
|
|
46
|
+
* The service lives between the routes and the DB: routes pass parsed
|
|
47
|
+
* payloads, the service enforces business invariants (no self-link, no
|
|
48
|
+
* dup, target must exist), and surfaces typed errors with the matching
|
|
49
|
+
* ERROR_CODES so route handlers can map them to HTTP responses without
|
|
50
|
+
* sniffing message strings.
|
|
51
|
+
*
|
|
52
|
+
* `bulkCreate` is all-or-nothing: a single bad entry rolls back the whole
|
|
53
|
+
* batch (research §US4: admins curate links in the UI in chunks; partial
|
|
54
|
+
* inserts would surprise them).
|
|
55
|
+
*
|
|
56
|
+
* `listForStorefront` filters out targets whose product is not active,
|
|
57
|
+
* which is what the PDP/cart actually wants — admins should see archived
|
|
58
|
+
* targets in the admin list (so they can clean them up), the storefront
|
|
59
|
+
* shouldn't.
|
|
60
|
+
*/
|
|
61
|
+
export interface CreateLinkInput {
|
|
62
|
+
targetProductId: string;
|
|
63
|
+
kind: ProductLinkKind;
|
|
64
|
+
position?: number | undefined;
|
|
65
|
+
}
|
|
66
|
+
export interface ProductLinkRow {
|
|
67
|
+
id: string;
|
|
68
|
+
sourceProductId: string;
|
|
69
|
+
targetProductId: string;
|
|
70
|
+
kind: ProductLinkKind;
|
|
71
|
+
position: number;
|
|
72
|
+
}
|
|
73
|
+
export interface StorefrontLinkSummary {
|
|
74
|
+
id: string;
|
|
75
|
+
kind: ProductLinkKind;
|
|
76
|
+
position: number;
|
|
77
|
+
product: {
|
|
78
|
+
id: string;
|
|
79
|
+
sku: string;
|
|
80
|
+
slug: string;
|
|
81
|
+
name: string;
|
|
82
|
+
primaryAssetUrl: string | null;
|
|
83
|
+
price: {
|
|
84
|
+
amount: number;
|
|
85
|
+
currency: string;
|
|
86
|
+
} | null;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export declare class ProductLinkService {
|
|
90
|
+
#private;
|
|
91
|
+
private readonly emFactory;
|
|
92
|
+
/** Feature 054 — audits product-link writes co-transactionally when provided. */
|
|
93
|
+
private readonly commandBus?;
|
|
94
|
+
/**
|
|
95
|
+
* Issue #132 — the pricing engine, through the `pricingService` port. A
|
|
96
|
+
* related-product tile is a listing: it prices through the same chain as the
|
|
97
|
+
* catalogue grid, not off the catalogue's legacy default-price attribute.
|
|
98
|
+
*/
|
|
99
|
+
private readonly listingPrices?;
|
|
100
|
+
/**
|
|
101
|
+
* Feature 075 — `assets_library`'s read port. The two `join assets` clauses
|
|
102
|
+
* this service used to write are gone; the tile's image is resolved by the
|
|
103
|
+
* shared `resolvePrimaryAssetUrls` helper, which asks the owner for the
|
|
104
|
+
* asset row and keeps the bridge query on this module's own tables.
|
|
105
|
+
*/
|
|
106
|
+
private readonly assets?;
|
|
107
|
+
/**
|
|
108
|
+
* Issue #185 — the kernel's channel-membership accessor. The storefront
|
|
109
|
+
* link read below asked `sales_channel_products` in raw SQL, which crosses
|
|
110
|
+
* the boundary while naming no import specifier and is the read
|
|
111
|
+
* Constitution XII reserves to this service.
|
|
112
|
+
*
|
|
113
|
+
* Optional only in the signature, like the two above; a link read that
|
|
114
|
+
* reaches it unwired fails loudly rather than quietly answering the
|
|
115
|
+
* cross-channel set.
|
|
116
|
+
*/
|
|
117
|
+
private readonly channelMembership?;
|
|
118
|
+
/**
|
|
119
|
+
* `organizations`' read model — the customer group a group-targeted price
|
|
120
|
+
* list is selected by, which lives on the organisation row. Optional only
|
|
121
|
+
* in the signature, and never reached by an anonymous strip.
|
|
122
|
+
*/
|
|
123
|
+
private readonly organizationDetails?;
|
|
124
|
+
constructor(emFactory: () => EntityManager,
|
|
125
|
+
/** Feature 054 — audits product-link writes co-transactionally when provided. */
|
|
126
|
+
commandBus?: CommandBus | undefined,
|
|
127
|
+
/**
|
|
128
|
+
* Issue #132 — the pricing engine, through the `pricingService` port. A
|
|
129
|
+
* related-product tile is a listing: it prices through the same chain as the
|
|
130
|
+
* catalogue grid, not off the catalogue's legacy default-price attribute.
|
|
131
|
+
*/
|
|
132
|
+
listingPrices?: ListingPricePort | undefined,
|
|
133
|
+
/**
|
|
134
|
+
* Feature 075 — `assets_library`'s read port. The two `join assets` clauses
|
|
135
|
+
* this service used to write are gone; the tile's image is resolved by the
|
|
136
|
+
* shared `resolvePrimaryAssetUrls` helper, which asks the owner for the
|
|
137
|
+
* asset row and keeps the bridge query on this module's own tables.
|
|
138
|
+
*/
|
|
139
|
+
assets?: AssetReadPort | undefined,
|
|
140
|
+
/**
|
|
141
|
+
* Issue #185 — the kernel's channel-membership accessor. The storefront
|
|
142
|
+
* link read below asked `sales_channel_products` in raw SQL, which crosses
|
|
143
|
+
* the boundary while naming no import specifier and is the read
|
|
144
|
+
* Constitution XII reserves to this service.
|
|
145
|
+
*
|
|
146
|
+
* Optional only in the signature, like the two above; a link read that
|
|
147
|
+
* reaches it unwired fails loudly rather than quietly answering the
|
|
148
|
+
* cross-channel set.
|
|
149
|
+
*/
|
|
150
|
+
channelMembership?: SalesChannelMembershipPort | undefined,
|
|
151
|
+
/**
|
|
152
|
+
* `organizations`' read model — the customer group a group-targeted price
|
|
153
|
+
* list is selected by, which lives on the organisation row. Optional only
|
|
154
|
+
* in the signature, and never reached by an anonymous strip.
|
|
155
|
+
*/
|
|
156
|
+
organizationDetails?: OrganizationDetailsPort | undefined);
|
|
157
|
+
listForAdmin(sourceProductId: string, kind?: ProductLinkKind): Promise<ProductLinkRow[]>;
|
|
158
|
+
bulkCreate(sourceProductId: string, inputs: CreateLinkInput[]): Promise<ProductLinkRow[]>;
|
|
159
|
+
removeLink(sourceProductId: string, linkId: string): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Storefront read — drops links whose target product is not active or
|
|
162
|
+
* not visible in the requested sales channel; localizes name to the
|
|
163
|
+
* caller's preferred language.
|
|
164
|
+
*/
|
|
165
|
+
listForStorefront(sourceProductId: string, ctx: StorefrontContext, kind?: ProductLinkKind): Promise<StorefrontLinkSummary[]>;
|
|
166
|
+
reorderForKind(sourceProductId: string, kind: ProductLinkKind, linkIds: string[]): Promise<void>;
|
|
167
|
+
}
|
|
168
|
+
export {};
|
|
169
|
+
//# sourceMappingURL=product-link.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-link.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/product-link.service.ts"],"names":[],"mappings":"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"}
|