@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,91 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { type BulkUpdateProductsRequest } from '@endora-commerce/contracts';
|
|
3
|
+
import type { AuditPort } from '@endora-commerce/platform/kernel';
|
|
4
|
+
import type { SalesChannelMembershipPort } from '@endora-commerce/platform/kernel';
|
|
5
|
+
import type { CatalogAdminService } from './catalog-admin.service.js';
|
|
6
|
+
import { type AdminAuditContext } from './catalog-admin.service.js';
|
|
7
|
+
/**
|
|
8
|
+
* Feature 022 — Products Bulk Edit.
|
|
9
|
+
*
|
|
10
|
+
* Composes existing module-public services to apply a sparse field-patch
|
|
11
|
+
* to a selection of products and report a per-product outcome. Honours:
|
|
12
|
+
*
|
|
13
|
+
* - Per-product atomicity (each product writes inside its own transaction).
|
|
14
|
+
* - No batch abort: a single failure does NOT roll back other products.
|
|
15
|
+
* - One summary `audit_logs` row per bulk operation; per-product audit
|
|
16
|
+
* rows are emitted by `CatalogAdminService.updateProduct` as before.
|
|
17
|
+
*/
|
|
18
|
+
export interface BulkUpdateOutcome {
|
|
19
|
+
productId: string;
|
|
20
|
+
status: 'succeeded' | 'skipped' | 'failed';
|
|
21
|
+
reason?: 'attribute_not_in_set' | 'validation_failed' | 'permission_denied' | 'concurrent_modification' | 'product_not_found';
|
|
22
|
+
details?: {
|
|
23
|
+
code?: string;
|
|
24
|
+
message?: string;
|
|
25
|
+
attribute?: string;
|
|
26
|
+
};
|
|
27
|
+
changedFields?: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface BulkUpdateResult {
|
|
30
|
+
bulkOperationId: string;
|
|
31
|
+
summary: {
|
|
32
|
+
succeeded: number;
|
|
33
|
+
skipped: number;
|
|
34
|
+
failed: number;
|
|
35
|
+
total: number;
|
|
36
|
+
};
|
|
37
|
+
results: BulkUpdateOutcome[];
|
|
38
|
+
}
|
|
39
|
+
export interface BulkUpdateProgress {
|
|
40
|
+
processed: number;
|
|
41
|
+
total: number;
|
|
42
|
+
succeeded: number;
|
|
43
|
+
skipped: number;
|
|
44
|
+
failed: number;
|
|
45
|
+
}
|
|
46
|
+
export interface BulkUpdateOptions {
|
|
47
|
+
/**
|
|
48
|
+
* Skip the synchronous MAX_BATCH_SIZE guard. Set by the queued worker
|
|
49
|
+
* path, which is allowed to process arbitrarily large selections off
|
|
50
|
+
* the request thread.
|
|
51
|
+
*/
|
|
52
|
+
skipBatchLimit?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Invoked periodically (every {@link PROGRESS_REPORT_EVERY} products and
|
|
55
|
+
* once at the end) so the worker can persist live progress counters.
|
|
56
|
+
*/
|
|
57
|
+
onProgress?: (progress: BulkUpdateProgress) => Promise<void> | void;
|
|
58
|
+
}
|
|
59
|
+
export declare class CatalogBulkUpdateService {
|
|
60
|
+
private readonly emFactory;
|
|
61
|
+
private readonly catalogAdmin;
|
|
62
|
+
private readonly salesChannelMembership?;
|
|
63
|
+
private readonly auditLog?;
|
|
64
|
+
constructor(emFactory: () => EntityManager, catalogAdmin: CatalogAdminService, salesChannelMembership?: SalesChannelMembershipPort | undefined, auditLog?: AuditPort | undefined);
|
|
65
|
+
/**
|
|
66
|
+
* Apply `req.fields` to every product in `req.productIds`.
|
|
67
|
+
*
|
|
68
|
+
* Pre-flight (rejects whole request):
|
|
69
|
+
* - productIds.length > 200 → BULK_TOO_LARGE
|
|
70
|
+
* - attributeValues key not flagged → ATTRIBUTE_NOT_MASS_EDITABLE
|
|
71
|
+
* mass_editable=true
|
|
72
|
+
*
|
|
73
|
+
* Per-product outcomes:
|
|
74
|
+
* - succeeded → all touched fields applied
|
|
75
|
+
* - skipped, product_not_found → product id missing in DB
|
|
76
|
+
* - skipped, attribute_not_in_set → one of the requested
|
|
77
|
+
* attribute keys is not in
|
|
78
|
+
* the product's attribute set
|
|
79
|
+
* AND no other field changed
|
|
80
|
+
* - failed, validation_failed → any other write rejection
|
|
81
|
+
*/
|
|
82
|
+
bulkUpdate(req: BulkUpdateProductsRequest, auditCtx?: AdminAuditContext, opts?: BulkUpdateOptions): Promise<BulkUpdateResult>;
|
|
83
|
+
private assertAllAttributesAreMassEditable;
|
|
84
|
+
private applyToOneProduct;
|
|
85
|
+
private classifyPerProductError;
|
|
86
|
+
private readCurrentCategoryIds;
|
|
87
|
+
private readAllowedAttributeKeys;
|
|
88
|
+
private applySalesChannels;
|
|
89
|
+
private recordSummaryAudit;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=catalog-bulk-update.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-bulk-update.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/catalog-bulk-update.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAe,KAAK,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAGzF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAC,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAGpE;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3C,MAAM,CAAC,EACH,sBAAsB,GACtB,mBAAmB,GACnB,mBAAmB,GACnB,yBAAyB,GACzB,mBAAmB,CAAC;IACxB,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAOD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACrE;AAED,qBAAa,wBAAwB;IAEjC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAHT,SAAS,EAAE,MAAM,aAAa,EAC9B,YAAY,EAAE,mBAAmB,EACjC,sBAAsB,CAAC,EAAE,0BAA0B,YAAA,EACnD,QAAQ,CAAC,EAAE,SAAS,YAAA;IAGvC;;;;;;;;;;;;;;;;OAgBG;IACG,UAAU,CACd,GAAG,EAAE,yBAAyB,EAC9B,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,gBAAgB,CAAC;YA8Dd,kCAAkC;YAkBlC,iBAAiB;IA8I/B,OAAO,CAAC,uBAAuB;YA2BjB,sBAAsB;YAetB,wBAAwB;YAwBxB,kBAAkB;YAqClB,kBAAkB;CA+BjC"}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { ERROR_CODES } from '@endora-commerce/contracts';
|
|
3
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
4
|
+
import { rethrowIfModuleDisabled } from '@endora-commerce/platform/kernel';
|
|
5
|
+
import {} from './catalog-admin.service.js';
|
|
6
|
+
import { Product } from '../entities/product.entity.js';
|
|
7
|
+
const MAX_BATCH_SIZE = 200;
|
|
8
|
+
const RECOMMENDED_SPLIT_INTO = 100;
|
|
9
|
+
/** How often the async worker path is told how far the run has progressed. */
|
|
10
|
+
const PROGRESS_REPORT_EVERY = 25;
|
|
11
|
+
export class CatalogBulkUpdateService {
|
|
12
|
+
emFactory;
|
|
13
|
+
catalogAdmin;
|
|
14
|
+
salesChannelMembership;
|
|
15
|
+
auditLog;
|
|
16
|
+
constructor(emFactory, catalogAdmin, salesChannelMembership, auditLog) {
|
|
17
|
+
this.emFactory = emFactory;
|
|
18
|
+
this.catalogAdmin = catalogAdmin;
|
|
19
|
+
this.salesChannelMembership = salesChannelMembership;
|
|
20
|
+
this.auditLog = auditLog;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Apply `req.fields` to every product in `req.productIds`.
|
|
24
|
+
*
|
|
25
|
+
* Pre-flight (rejects whole request):
|
|
26
|
+
* - productIds.length > 200 → BULK_TOO_LARGE
|
|
27
|
+
* - attributeValues key not flagged → ATTRIBUTE_NOT_MASS_EDITABLE
|
|
28
|
+
* mass_editable=true
|
|
29
|
+
*
|
|
30
|
+
* Per-product outcomes:
|
|
31
|
+
* - succeeded → all touched fields applied
|
|
32
|
+
* - skipped, product_not_found → product id missing in DB
|
|
33
|
+
* - skipped, attribute_not_in_set → one of the requested
|
|
34
|
+
* attribute keys is not in
|
|
35
|
+
* the product's attribute set
|
|
36
|
+
* AND no other field changed
|
|
37
|
+
* - failed, validation_failed → any other write rejection
|
|
38
|
+
*/
|
|
39
|
+
async bulkUpdate(req, auditCtx, opts) {
|
|
40
|
+
// The synchronous request path caps the selection at MAX_BATCH_SIZE so a
|
|
41
|
+
// single HTTP call never blocks on thousands of writes. The asynchronous
|
|
42
|
+
// worker path (queued bulk operations) passes `skipBatchLimit` because it
|
|
43
|
+
// already chunks progress reporting and runs off the request thread.
|
|
44
|
+
if (!opts?.skipBatchLimit && req.productIds.length > MAX_BATCH_SIZE) {
|
|
45
|
+
throw new HttpError(400, ERROR_CODES.BULK_TOO_LARGE, `productIds.length=${req.productIds.length} exceeds maxBatchSize=${MAX_BATCH_SIZE}`, { maxBatchSize: MAX_BATCH_SIZE, recommendedSplitInto: RECOMMENDED_SPLIT_INTO });
|
|
46
|
+
}
|
|
47
|
+
// Pre-flight: every attributeValues key MUST be flagged mass_editable=true.
|
|
48
|
+
// This is a client-side bug (the dialog should never offer a non-flagged
|
|
49
|
+
// attribute), so the whole batch is rejected before any per-product write.
|
|
50
|
+
if (req.fields.attributeValues && Object.keys(req.fields.attributeValues).length > 0) {
|
|
51
|
+
await this.assertAllAttributesAreMassEditable(Object.keys(req.fields.attributeValues));
|
|
52
|
+
}
|
|
53
|
+
const bulkOperationId = randomUUID();
|
|
54
|
+
const results = [];
|
|
55
|
+
const total = req.productIds.length;
|
|
56
|
+
let processed = 0;
|
|
57
|
+
let succeeded = 0;
|
|
58
|
+
let skipped = 0;
|
|
59
|
+
let failed = 0;
|
|
60
|
+
for (const productId of req.productIds) {
|
|
61
|
+
const outcome = await this.applyToOneProduct(productId, req, auditCtx);
|
|
62
|
+
results.push(outcome);
|
|
63
|
+
processed += 1;
|
|
64
|
+
if (outcome.status === 'succeeded')
|
|
65
|
+
succeeded += 1;
|
|
66
|
+
else if (outcome.status === 'skipped')
|
|
67
|
+
skipped += 1;
|
|
68
|
+
else
|
|
69
|
+
failed += 1;
|
|
70
|
+
if (opts?.onProgress &&
|
|
71
|
+
(processed % PROGRESS_REPORT_EVERY === 0 || processed === total)) {
|
|
72
|
+
await opts.onProgress({ processed, total, succeeded, skipped, failed });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const summary = {
|
|
76
|
+
succeeded: results.filter((r) => r.status === 'succeeded').length,
|
|
77
|
+
skipped: results.filter((r) => r.status === 'skipped').length,
|
|
78
|
+
failed: results.filter((r) => r.status === 'failed').length,
|
|
79
|
+
total: results.length,
|
|
80
|
+
};
|
|
81
|
+
await this.recordSummaryAudit(bulkOperationId, req, results, summary, auditCtx);
|
|
82
|
+
return { bulkOperationId, summary, results };
|
|
83
|
+
}
|
|
84
|
+
// --------------------------------------------------------------------
|
|
85
|
+
// Internal helpers
|
|
86
|
+
// --------------------------------------------------------------------
|
|
87
|
+
async assertAllAttributesAreMassEditable(keys) {
|
|
88
|
+
// Feature 061 — the flag lives on the extension; the key on the definition.
|
|
89
|
+
// Read through the composed view (catalog's sanctioned attribute read).
|
|
90
|
+
const views = await this.catalogAdmin.listAttributes();
|
|
91
|
+
const byKey = new Map(views.map((v) => [v.key, v]));
|
|
92
|
+
for (const key of keys) {
|
|
93
|
+
const view = byKey.get(key);
|
|
94
|
+
if (!view || !view.massEditable) {
|
|
95
|
+
throw new HttpError(400, ERROR_CODES.ATTRIBUTE_NOT_MASS_EDITABLE, `attribute_not_mass_editable`, { attribute: key });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async applyToOneProduct(productId, req, auditCtx) {
|
|
100
|
+
const em = this.emFactory();
|
|
101
|
+
const product = await em.findOne(Product, { id: productId });
|
|
102
|
+
if (!product) {
|
|
103
|
+
return { productId, status: 'skipped', reason: 'product_not_found' };
|
|
104
|
+
}
|
|
105
|
+
// Partition attributeValues into those allowed for the product's set
|
|
106
|
+
// and those that must be skipped. Build the partial UpdateProductRequest.
|
|
107
|
+
const fields = req.fields;
|
|
108
|
+
const partial = {};
|
|
109
|
+
let touchedAny = false;
|
|
110
|
+
let attributeSkipReason = null;
|
|
111
|
+
if (fields.status !== undefined) {
|
|
112
|
+
partial.status = fields.status;
|
|
113
|
+
touchedAny = true;
|
|
114
|
+
}
|
|
115
|
+
if (fields.visibility !== undefined) {
|
|
116
|
+
partial.visibility = fields.visibility;
|
|
117
|
+
touchedAny = true;
|
|
118
|
+
}
|
|
119
|
+
// Attribute Set — assign (or clear, with null) on every selected product.
|
|
120
|
+
if (fields.attributeSetId !== undefined) {
|
|
121
|
+
partial.attributeSetId = fields.attributeSetId;
|
|
122
|
+
touchedAny = true;
|
|
123
|
+
}
|
|
124
|
+
// Categories — translate {mode, categoryIds} into the partial's
|
|
125
|
+
// categoryIds field (which the single-product PATCH treats as the
|
|
126
|
+
// canonical set when present). For `add` mode, union the target with
|
|
127
|
+
// current memberships before passing through.
|
|
128
|
+
if (fields.categories) {
|
|
129
|
+
if (fields.categories.mode === 'replace') {
|
|
130
|
+
partial.categoryIds = fields.categories.categoryIds;
|
|
131
|
+
}
|
|
132
|
+
else if (fields.categories.mode === 'remove') {
|
|
133
|
+
const current = await this.readCurrentCategoryIds(em, productId);
|
|
134
|
+
const toRemove = new Set(fields.categories.categoryIds);
|
|
135
|
+
partial.categoryIds = current.filter((id) => !toRemove.has(id));
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
const current = await this.readCurrentCategoryIds(em, productId);
|
|
139
|
+
const union = Array.from(new Set([...current, ...fields.categories.categoryIds]));
|
|
140
|
+
partial.categoryIds = union;
|
|
141
|
+
}
|
|
142
|
+
touchedAny = true;
|
|
143
|
+
}
|
|
144
|
+
// Attribute values — drop keys that are not in this product's set;
|
|
145
|
+
// surface a skip reason if NO other field is being touched and EVERY
|
|
146
|
+
// attribute write would be dropped.
|
|
147
|
+
if (fields.attributeValues && Object.keys(fields.attributeValues).length > 0) {
|
|
148
|
+
const allowedKeys = await this.readAllowedAttributeKeys(em, product.attributeSetId);
|
|
149
|
+
const allowed = {};
|
|
150
|
+
const dropped = [];
|
|
151
|
+
for (const [k, v] of Object.entries(fields.attributeValues)) {
|
|
152
|
+
if (allowedKeys.has(k)) {
|
|
153
|
+
allowed[k] = v;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
dropped.push(k);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (Object.keys(allowed).length > 0) {
|
|
160
|
+
partial.attributeValues = allowed;
|
|
161
|
+
touchedAny = true;
|
|
162
|
+
}
|
|
163
|
+
if (dropped.length > 0 &&
|
|
164
|
+
Object.keys(allowed).length === 0 &&
|
|
165
|
+
fields.status === undefined &&
|
|
166
|
+
fields.visibility === undefined &&
|
|
167
|
+
fields.categories === undefined &&
|
|
168
|
+
fields.salesChannels === undefined &&
|
|
169
|
+
fields.attributeSetId === undefined) {
|
|
170
|
+
// Nothing else to do for this product and at least one attribute
|
|
171
|
+
// was skipped — report skip with the first dropped key for
|
|
172
|
+
// visibility in the response.
|
|
173
|
+
attributeSkipReason = { attribute: dropped[0] };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Apply updateProduct (status / visibility / categories / attributeValues).
|
|
177
|
+
let changedFields = [];
|
|
178
|
+
if (touchedAny) {
|
|
179
|
+
try {
|
|
180
|
+
await this.catalogAdmin.updateProduct(productId, partial, auditCtx);
|
|
181
|
+
// The service tracks changedFields internally; from the caller's
|
|
182
|
+
// perspective we report the set of fields we *attempted* to write
|
|
183
|
+
// (the audit row has the canonical changedFields).
|
|
184
|
+
changedFields = Object.keys(partial);
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
return this.classifyPerProductError(productId, err);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Sales channels run AFTER updateProduct because they live on a
|
|
191
|
+
// different bridge table and use a dedicated service.
|
|
192
|
+
if (fields.salesChannels && this.salesChannelMembership) {
|
|
193
|
+
try {
|
|
194
|
+
const changed = await this.applySalesChannels(productId, fields.salesChannels.mode, fields.salesChannels.channelIds);
|
|
195
|
+
if (changed) {
|
|
196
|
+
changedFields = Array.from(new Set([...changedFields, 'salesChannels']));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
return this.classifyPerProductError(productId, err);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (changedFields.length === 0 && attributeSkipReason) {
|
|
204
|
+
return {
|
|
205
|
+
productId,
|
|
206
|
+
status: 'skipped',
|
|
207
|
+
reason: 'attribute_not_in_set',
|
|
208
|
+
details: attributeSkipReason,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
productId,
|
|
213
|
+
status: 'succeeded',
|
|
214
|
+
changedFields,
|
|
215
|
+
// Surface the skipped attribute when other fields *did* succeed —
|
|
216
|
+
// not strictly required by the contract but useful to the admin.
|
|
217
|
+
...(attributeSkipReason
|
|
218
|
+
? { details: { ...attributeSkipReason, message: 'attribute_not_in_set' } }
|
|
219
|
+
: {}),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
classifyPerProductError(productId, err) {
|
|
223
|
+
// The per-product tolerance is right — one product that fails validation
|
|
224
|
+
// must not abandon the other 4 999 — but a presence answer is not per
|
|
225
|
+
// product. `ModuleDisabledError` is an `HttpError`, so without this line it
|
|
226
|
+
// classified as `validation_failed` on every row, and the report read as a
|
|
227
|
+
// data problem in the catalogue rather than a module that is off. Placed
|
|
228
|
+
// here rather than at the two call sites so a third one inherits it.
|
|
229
|
+
rethrowIfModuleDisabled(err);
|
|
230
|
+
if (err instanceof HttpError) {
|
|
231
|
+
if (err.code === ERROR_CODES.PRODUCT_NOT_FOUND) {
|
|
232
|
+
return { productId, status: 'skipped', reason: 'product_not_found' };
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
productId,
|
|
236
|
+
status: 'failed',
|
|
237
|
+
reason: 'validation_failed',
|
|
238
|
+
details: { code: err.code, message: err.message },
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
productId,
|
|
243
|
+
status: 'failed',
|
|
244
|
+
reason: 'validation_failed',
|
|
245
|
+
details: { message: err instanceof Error ? err.message : String(err) },
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
async readCurrentCategoryIds(em, productId) {
|
|
249
|
+
const rows = await em
|
|
250
|
+
.getConnection()
|
|
251
|
+
.execute(`select category_id from product_categories where product_id = ?`, [productId], 'all', em.getTransactionContext());
|
|
252
|
+
return rows.map((r) => r.category_id);
|
|
253
|
+
}
|
|
254
|
+
async readAllowedAttributeKeys(em, attributeSetId) {
|
|
255
|
+
// Feature 061 — set membership is definition-keyed; keys come from the
|
|
256
|
+
// composed view.
|
|
257
|
+
const rows = await em
|
|
258
|
+
.getConnection()
|
|
259
|
+
.execute(`select custom_field_definition_id from attribute_set_attributes ` +
|
|
260
|
+
`where attribute_set_id = ?`, [attributeSetId], 'all', em.getTransactionContext());
|
|
261
|
+
const views = await this.catalogAdmin.listAttributes();
|
|
262
|
+
const keyByDefinitionId = new Map(views.map((v) => [v.customFieldDefinitionId, v.key]));
|
|
263
|
+
return new Set(rows
|
|
264
|
+
.map((r) => keyByDefinitionId.get(r.custom_field_definition_id))
|
|
265
|
+
.filter((k) => k !== undefined));
|
|
266
|
+
}
|
|
267
|
+
async applySalesChannels(productId, mode, targetChannelIds) {
|
|
268
|
+
const svc = this.salesChannelMembership;
|
|
269
|
+
const current = await svc.listChannelsForEntity('product', productId);
|
|
270
|
+
const currentIds = new Set(current.map((c) => c.id));
|
|
271
|
+
const targetSet = new Set(targetChannelIds);
|
|
272
|
+
let changed = false;
|
|
273
|
+
if (mode === 'add') {
|
|
274
|
+
for (const id of targetChannelIds) {
|
|
275
|
+
if (!currentIds.has(id)) {
|
|
276
|
+
const r = await svc.addToChannel(id, 'product', productId);
|
|
277
|
+
if (r.changed)
|
|
278
|
+
changed = true;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
// replace
|
|
284
|
+
for (const id of targetChannelIds) {
|
|
285
|
+
if (!currentIds.has(id)) {
|
|
286
|
+
const r = await svc.addToChannel(id, 'product', productId);
|
|
287
|
+
if (r.changed)
|
|
288
|
+
changed = true;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
for (const id of currentIds) {
|
|
292
|
+
if (!targetSet.has(id)) {
|
|
293
|
+
const r = await svc.removeFromChannel(id, 'product', productId, {
|
|
294
|
+
fallbackToDefault: true,
|
|
295
|
+
});
|
|
296
|
+
if (r.changed)
|
|
297
|
+
changed = true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return changed;
|
|
302
|
+
}
|
|
303
|
+
async recordSummaryAudit(bulkOperationId, req, results, summary, auditCtx) {
|
|
304
|
+
if (!this.auditLog || !auditCtx)
|
|
305
|
+
return;
|
|
306
|
+
await this.auditLog.record({
|
|
307
|
+
actorAdminUserId: auditCtx.actorAdminUserId,
|
|
308
|
+
...(auditCtx.impersonatedCustomerAccountId !== undefined
|
|
309
|
+
? { impersonatedCustomerAccountId: auditCtx.impersonatedCustomerAccountId }
|
|
310
|
+
: {}),
|
|
311
|
+
action: 'product.bulk_update',
|
|
312
|
+
objectType: 'bulk_operation',
|
|
313
|
+
objectId: bulkOperationId,
|
|
314
|
+
stateAfter: {
|
|
315
|
+
selectionIds: req.productIds,
|
|
316
|
+
touchedFields: Object.entries(req.fields)
|
|
317
|
+
.filter(([, v]) => v !== undefined)
|
|
318
|
+
.map(([k]) => k),
|
|
319
|
+
categoryMode: req.fields.categories?.mode ?? null,
|
|
320
|
+
salesChannelMode: req.fields.salesChannels?.mode ?? null,
|
|
321
|
+
resultsSummary: summary,
|
|
322
|
+
perProductOutcomes: results,
|
|
323
|
+
},
|
|
324
|
+
...(auditCtx.ipAddress !== undefined ? { ipAddress: auditCtx.ipAddress } : {}),
|
|
325
|
+
...(auditCtx.userAgent !== undefined ? { userAgent: auditCtx.userAgent } : {}),
|
|
326
|
+
...(auditCtx.requestId !== undefined ? { requestId: auditCtx.requestId } : {}),
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=catalog-bulk-update.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-bulk-update.service.js","sourceRoot":"","sources":["../../../src/backend/services/catalog-bulk-update.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { CatalogCategoryAssignmentRecord, CatalogCategoryProductCount, CatalogCategoryReadPort, CatalogCategoryRecord } from '@endora-commerce/contracts';
|
|
3
|
+
import { Category } from '../entities/category.entity.js';
|
|
4
|
+
export declare class CatalogCategoryReadService implements CatalogCategoryReadPort {
|
|
5
|
+
private readonly emFactory;
|
|
6
|
+
constructor(emFactory: () => EntityManager);
|
|
7
|
+
findById(id: string, options?: {
|
|
8
|
+
liveOnly?: boolean;
|
|
9
|
+
}): Promise<CatalogCategoryRecord | null>;
|
|
10
|
+
findByIds(ids: readonly string[], options?: {
|
|
11
|
+
liveOnly?: boolean;
|
|
12
|
+
}): Promise<CatalogCategoryRecord[]>;
|
|
13
|
+
findBySlug(slug: string): Promise<CatalogCategoryRecord | null>;
|
|
14
|
+
countByIds(ids: readonly string[]): Promise<number>;
|
|
15
|
+
listAll(options?: {
|
|
16
|
+
liveOnly?: boolean;
|
|
17
|
+
}): Promise<CatalogCategoryRecord[]>;
|
|
18
|
+
listWithInventoryThresholds(): Promise<CatalogCategoryRecord[]>;
|
|
19
|
+
ancestorsOf(categoryId: string): Promise<CatalogCategoryRecord[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Feature 075 / D-87 — the `product_categories` bridge, which has no entity
|
|
22
|
+
* class and was therefore joined in raw SQL by whoever needed it. `search`
|
|
23
|
+
* ran this statement three times from inside its indexer.
|
|
24
|
+
*
|
|
25
|
+
* `em.execute` rather than `getConnection().execute`: the two are the same
|
|
26
|
+
* outside a transaction and only the first joins one when the caller has it
|
|
27
|
+
* open (issue #200).
|
|
28
|
+
*/
|
|
29
|
+
listAssignmentsForProducts(productIds: readonly string[], options?: {
|
|
30
|
+
activeOnly?: boolean;
|
|
31
|
+
}): Promise<CatalogCategoryAssignmentRecord[]>;
|
|
32
|
+
/**
|
|
33
|
+
* One recursive query rather than a query per level: a subtree re-projection
|
|
34
|
+
* runs on every category write, and the depth of the tree is data.
|
|
35
|
+
*
|
|
36
|
+
* No `is_active` / `deleted_at` filter anywhere in the walk — see the port's
|
|
37
|
+
* contract. The caller re-projects *because* a category changed, and a
|
|
38
|
+
* deactivation is the change that matters most.
|
|
39
|
+
*/
|
|
40
|
+
listProductIdsInSubtree(categoryId: string): Promise<string[]>;
|
|
41
|
+
/**
|
|
42
|
+
* The selection walk — see the port's contract for why it is not a batched
|
|
43
|
+
* {@link listProductIdsInSubtree}. It skips soft-deleted categories and it
|
|
44
|
+
* tolerates a cycle; the structural read above does neither, deliberately.
|
|
45
|
+
*
|
|
46
|
+
* It was `CatalogQueryService.expandCategoryProductIds` until
|
|
47
|
+
* `specs/110-instance-repository/` T118c, reached by both composition roots
|
|
48
|
+
* over the unpublished `catalogQueryPort` name and by nothing else. It is a
|
|
49
|
+
* category read, so it belongs to the category read model; there is one copy.
|
|
50
|
+
*/
|
|
51
|
+
expandCategoryProductIds(categoryIds: readonly string[]): Promise<Map<string, Set<string>>>;
|
|
52
|
+
/**
|
|
53
|
+
* The one category, not its subtree — see the port's contract for why the two
|
|
54
|
+
* are separate methods. `pim_ergonode` wrote this statement itself before the
|
|
55
|
+
* port had it, to detach the products of a category the source tree dropped.
|
|
56
|
+
*/
|
|
57
|
+
listProductIdsInCategory(categoryId: string): Promise<string[]>;
|
|
58
|
+
/**
|
|
59
|
+
* One grouped query rather than a count per id: the caller renders a source
|
|
60
|
+
* hierarchy of a few hundred bound categories on one screen, so a count per
|
|
61
|
+
* row would be a few hundred round trips every time it loads.
|
|
62
|
+
*/
|
|
63
|
+
countLiveProductsByCategory(categoryIds: readonly string[]): Promise<CatalogCategoryProductCount[]>;
|
|
64
|
+
}
|
|
65
|
+
export declare function toCatalogCategoryRecord(category: Category): CatalogCategoryRecord;
|
|
66
|
+
//# sourceMappingURL=catalog-category-read.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-category-read.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/catalog-category-read.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EACV,+BAA+B,EAC/B,2BAA2B,EAC3B,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAiB1D,qBAAa,0BAA2B,YAAW,uBAAuB;IAC5D,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAErD,QAAQ,CACZ,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAC/B,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAQlC,SAAS,CACb,GAAG,EAAE,SAAS,MAAM,EAAE,EACtB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAC/B,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAS7B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAK/D,UAAU,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnD,OAAO,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAS3E,2BAA2B,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAW/D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAevE;;;;;;;;OAQG;IACG,0BAA0B,CAC9B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,GACjC,OAAO,CAAC,+BAA+B,EAAE,CAAC;IAoB7C;;;;;;;OAOG;IACG,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAepE;;;;;;;;;OASG;IACG,wBAAwB,CAC5B,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAsEpC;;;;OAIG;IACG,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAQrE;;;;OAIG;IACG,2BAA2B,CAC/B,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,OAAO,CAAC,2BAA2B,EAAE,CAAC;CAkB1C;AAMD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,qBAAqB,CAmBjF"}
|