@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.
Files changed (443) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/dist/admin/components/PackagingUnitsEditor.d.ts +12 -0
  4. package/dist/admin/components/PackagingUnitsEditor.d.ts.map +1 -0
  5. package/dist/admin/components/PackagingUnitsEditor.js +99 -0
  6. package/dist/admin/components/PackagingUnitsEditor.js.map +1 -0
  7. package/dist/admin/components/ProductAttributesTab.d.ts +13 -0
  8. package/dist/admin/components/ProductAttributesTab.d.ts.map +1 -0
  9. package/dist/admin/components/ProductAttributesTab.js +140 -0
  10. package/dist/admin/components/ProductAttributesTab.js.map +1 -0
  11. package/dist/admin/components/ProductInventoryTab.d.ts +14 -0
  12. package/dist/admin/components/ProductInventoryTab.d.ts.map +1 -0
  13. package/dist/admin/components/ProductInventoryTab.js +284 -0
  14. package/dist/admin/components/ProductInventoryTab.js.map +1 -0
  15. package/dist/admin/components/ProductScopeEditor.d.ts +94 -0
  16. package/dist/admin/components/ProductScopeEditor.d.ts.map +1 -0
  17. package/dist/admin/components/ProductScopeEditor.js +395 -0
  18. package/dist/admin/components/ProductScopeEditor.js.map +1 -0
  19. package/dist/admin/components/ProductsBulkEditDialog.d.ts +11 -0
  20. package/dist/admin/components/ProductsBulkEditDialog.d.ts.map +1 -0
  21. package/dist/admin/components/ProductsBulkEditDialog.js +304 -0
  22. package/dist/admin/components/ProductsBulkEditDialog.js.map +1 -0
  23. package/dist/admin/index.d.ts +45 -0
  24. package/dist/admin/index.d.ts.map +1 -0
  25. package/dist/admin/index.js +184 -0
  26. package/dist/admin/index.js.map +1 -0
  27. package/dist/admin/lib/resolve-product-selection.d.ts +21 -0
  28. package/dist/admin/lib/resolve-product-selection.d.ts.map +1 -0
  29. package/dist/admin/lib/resolve-product-selection.js +25 -0
  30. package/dist/admin/lib/resolve-product-selection.js.map +1 -0
  31. package/dist/admin/pages/AttachmentTypesPage.d.ts +18 -0
  32. package/dist/admin/pages/AttachmentTypesPage.d.ts.map +1 -0
  33. package/dist/admin/pages/AttachmentTypesPage.js +92 -0
  34. package/dist/admin/pages/AttachmentTypesPage.js.map +1 -0
  35. package/dist/admin/pages/AttributeSetsPage.d.ts +21 -0
  36. package/dist/admin/pages/AttributeSetsPage.d.ts.map +1 -0
  37. package/dist/admin/pages/AttributeSetsPage.js +158 -0
  38. package/dist/admin/pages/AttributeSetsPage.js.map +1 -0
  39. package/dist/admin/pages/AttributesManager.d.ts +9 -0
  40. package/dist/admin/pages/AttributesManager.d.ts.map +1 -0
  41. package/dist/admin/pages/AttributesManager.js +305 -0
  42. package/dist/admin/pages/AttributesManager.js.map +1 -0
  43. package/dist/admin/pages/BulkOperationDetailPage.d.ts +9 -0
  44. package/dist/admin/pages/BulkOperationDetailPage.d.ts.map +1 -0
  45. package/dist/admin/pages/BulkOperationDetailPage.js +187 -0
  46. package/dist/admin/pages/BulkOperationDetailPage.js.map +1 -0
  47. package/dist/admin/pages/BulkOperationsPage.d.ts +9 -0
  48. package/dist/admin/pages/BulkOperationsPage.d.ts.map +1 -0
  49. package/dist/admin/pages/BulkOperationsPage.js +98 -0
  50. package/dist/admin/pages/BulkOperationsPage.js.map +1 -0
  51. package/dist/admin/pages/CategoriesTree.d.ts +9 -0
  52. package/dist/admin/pages/CategoriesTree.d.ts.map +1 -0
  53. package/dist/admin/pages/CategoriesTree.js +176 -0
  54. package/dist/admin/pages/CategoriesTree.js.map +1 -0
  55. package/dist/admin/pages/ProductEditor.d.ts +13 -0
  56. package/dist/admin/pages/ProductEditor.d.ts.map +1 -0
  57. package/dist/admin/pages/ProductEditor.js +1050 -0
  58. package/dist/admin/pages/ProductEditor.js.map +1 -0
  59. package/dist/admin/pages/ProductsList.d.ts +9 -0
  60. package/dist/admin/pages/ProductsList.d.ts.map +1 -0
  61. package/dist/admin/pages/ProductsList.js +399 -0
  62. package/dist/admin/pages/ProductsList.js.map +1 -0
  63. package/dist/backend/commands/attribute-commands.d.ts +111 -0
  64. package/dist/backend/commands/attribute-commands.d.ts.map +1 -0
  65. package/dist/backend/commands/attribute-commands.js +482 -0
  66. package/dist/backend/commands/attribute-commands.js.map +1 -0
  67. package/dist/backend/demo/reset.d.ts +23 -0
  68. package/dist/backend/demo/reset.d.ts.map +1 -0
  69. package/dist/backend/demo/reset.js +41 -0
  70. package/dist/backend/demo/reset.js.map +1 -0
  71. package/dist/backend/demo/rows.d.ts +103 -0
  72. package/dist/backend/demo/rows.d.ts.map +1 -0
  73. package/dist/backend/demo/rows.js +162 -0
  74. package/dist/backend/demo/rows.js.map +1 -0
  75. package/dist/backend/demo/seed.d.ts +35 -0
  76. package/dist/backend/demo/seed.d.ts.map +1 -0
  77. package/dist/backend/demo/seed.js +177 -0
  78. package/dist/backend/demo/seed.js.map +1 -0
  79. package/dist/backend/entities/attachment-type.entity.d.ts +16 -0
  80. package/dist/backend/entities/attachment-type.entity.d.ts.map +1 -0
  81. package/dist/backend/entities/attachment-type.entity.js +57 -0
  82. package/dist/backend/entities/attachment-type.entity.js.map +1 -0
  83. package/dist/backend/entities/attribute-set-attribute.entity.d.ts +26 -0
  84. package/dist/backend/entities/attribute-set-attribute.entity.d.ts.map +1 -0
  85. package/dist/backend/entities/attribute-set-attribute.entity.js +55 -0
  86. package/dist/backend/entities/attribute-set-attribute.entity.js.map +1 -0
  87. package/dist/backend/entities/attribute-set.entity.d.ts +22 -0
  88. package/dist/backend/entities/attribute-set.entity.d.ts.map +1 -0
  89. package/dist/backend/entities/attribute-set.entity.js +67 -0
  90. package/dist/backend/entities/attribute-set.entity.js.map +1 -0
  91. package/dist/backend/entities/bulk-operation.entity.d.ts +78 -0
  92. package/dist/backend/entities/bulk-operation.entity.d.ts.map +1 -0
  93. package/dist/backend/entities/bulk-operation.entity.js +138 -0
  94. package/dist/backend/entities/bulk-operation.entity.js.map +1 -0
  95. package/dist/backend/entities/bundle-slot-option.entity.d.ts +23 -0
  96. package/dist/backend/entities/bundle-slot-option.entity.d.ts.map +1 -0
  97. package/dist/backend/entities/bundle-slot-option.entity.js +68 -0
  98. package/dist/backend/entities/bundle-slot-option.entity.js.map +1 -0
  99. package/dist/backend/entities/bundle-slot.entity.d.ts +25 -0
  100. package/dist/backend/entities/bundle-slot.entity.d.ts.map +1 -0
  101. package/dist/backend/entities/bundle-slot.entity.js +74 -0
  102. package/dist/backend/entities/bundle-slot.entity.js.map +1 -0
  103. package/dist/backend/entities/category.entity.d.ts +26 -0
  104. package/dist/backend/entities/category.entity.d.ts.map +1 -0
  105. package/dist/backend/entities/category.entity.js +119 -0
  106. package/dist/backend/entities/category.entity.js.map +1 -0
  107. package/dist/backend/entities/gallery-item-label.entity.d.ts +22 -0
  108. package/dist/backend/entities/gallery-item-label.entity.d.ts.map +1 -0
  109. package/dist/backend/entities/gallery-item-label.entity.js +50 -0
  110. package/dist/backend/entities/gallery-item-label.entity.js.map +1 -0
  111. package/dist/backend/entities/gallery-item.entity.d.ts +17 -0
  112. package/dist/backend/entities/gallery-item.entity.d.ts.map +1 -0
  113. package/dist/backend/entities/gallery-item.entity.js +58 -0
  114. package/dist/backend/entities/gallery-item.entity.js.map +1 -0
  115. package/dist/backend/entities/grouped-item.entity.d.ts +23 -0
  116. package/dist/backend/entities/grouped-item.entity.d.ts.map +1 -0
  117. package/dist/backend/entities/grouped-item.entity.js +68 -0
  118. package/dist/backend/entities/grouped-item.entity.js.map +1 -0
  119. package/dist/backend/entities/product-attachment.entity.d.ts +23 -0
  120. package/dist/backend/entities/product-attachment.entity.d.ts.map +1 -0
  121. package/dist/backend/entities/product-attachment.entity.js +77 -0
  122. package/dist/backend/entities/product-attachment.entity.js.map +1 -0
  123. package/dist/backend/entities/product-attribute.entity.d.ts +72 -0
  124. package/dist/backend/entities/product-attribute.entity.d.ts.map +1 -0
  125. package/dist/backend/entities/product-attribute.entity.js +161 -0
  126. package/dist/backend/entities/product-attribute.entity.js.map +1 -0
  127. package/dist/backend/entities/product-editor-preference.entity.d.ts +28 -0
  128. package/dist/backend/entities/product-editor-preference.entity.d.ts.map +1 -0
  129. package/dist/backend/entities/product-editor-preference.entity.js +63 -0
  130. package/dist/backend/entities/product-editor-preference.entity.js.map +1 -0
  131. package/dist/backend/entities/product-link.entity.d.ts +25 -0
  132. package/dist/backend/entities/product-link.entity.d.ts.map +1 -0
  133. package/dist/backend/entities/product-link.entity.js +70 -0
  134. package/dist/backend/entities/product-link.entity.js.map +1 -0
  135. package/dist/backend/entities/product-packaging-unit.entity.d.ts +26 -0
  136. package/dist/backend/entities/product-packaging-unit.entity.d.ts.map +1 -0
  137. package/dist/backend/entities/product-packaging-unit.entity.js +76 -0
  138. package/dist/backend/entities/product-packaging-unit.entity.js.map +1 -0
  139. package/dist/backend/entities/product-value-override.entity.d.ts +43 -0
  140. package/dist/backend/entities/product-value-override.entity.d.ts.map +1 -0
  141. package/dist/backend/entities/product-value-override.entity.js +90 -0
  142. package/dist/backend/entities/product-value-override.entity.js.map +1 -0
  143. package/dist/backend/entities/product-variant.entity.d.ts +18 -0
  144. package/dist/backend/entities/product-variant.entity.d.ts.map +1 -0
  145. package/dist/backend/entities/product-variant.entity.js +68 -0
  146. package/dist/backend/entities/product-variant.entity.js.map +1 -0
  147. package/dist/backend/entities/product.entity.d.ts +108 -0
  148. package/dist/backend/entities/product.entity.d.ts.map +1 -0
  149. package/dist/backend/entities/product.entity.js +230 -0
  150. package/dist/backend/entities/product.entity.js.map +1 -0
  151. package/dist/backend/index.d.ts +262 -0
  152. package/dist/backend/index.d.ts.map +1 -0
  153. package/dist/backend/index.js +642 -0
  154. package/dist/backend/index.js.map +1 -0
  155. package/dist/backend/plugin.d.ts +216 -0
  156. package/dist/backend/plugin.d.ts.map +1 -0
  157. package/dist/backend/plugin.js +223 -0
  158. package/dist/backend/plugin.js.map +1 -0
  159. package/dist/backend/prompt-tools.d.ts +47 -0
  160. package/dist/backend/prompt-tools.d.ts.map +1 -0
  161. package/dist/backend/prompt-tools.js +284 -0
  162. package/dist/backend/prompt-tools.js.map +1 -0
  163. package/dist/backend/routes.admin.d.ts +105 -0
  164. package/dist/backend/routes.admin.d.ts.map +1 -0
  165. package/dist/backend/routes.admin.js +1162 -0
  166. package/dist/backend/routes.admin.js.map +1 -0
  167. package/dist/backend/routes.api-key.d.ts +33 -0
  168. package/dist/backend/routes.api-key.d.ts.map +1 -0
  169. package/dist/backend/routes.api-key.js +43 -0
  170. package/dist/backend/routes.api-key.js.map +1 -0
  171. package/dist/backend/routes.external.d.ts +32 -0
  172. package/dist/backend/routes.external.d.ts.map +1 -0
  173. package/dist/backend/routes.external.js +115 -0
  174. package/dist/backend/routes.external.js.map +1 -0
  175. package/dist/backend/routes.public.d.ts +46 -0
  176. package/dist/backend/routes.public.d.ts.map +1 -0
  177. package/dist/backend/routes.public.js +318 -0
  178. package/dist/backend/routes.public.js.map +1 -0
  179. package/dist/backend/services/asset-references.d.ts +4 -0
  180. package/dist/backend/services/asset-references.d.ts.map +1 -0
  181. package/dist/backend/services/asset-references.js +104 -0
  182. package/dist/backend/services/asset-references.js.map +1 -0
  183. package/dist/backend/services/attachment.service.d.ts +45 -0
  184. package/dist/backend/services/attachment.service.d.ts.map +1 -0
  185. package/dist/backend/services/attachment.service.js +268 -0
  186. package/dist/backend/services/attachment.service.js.map +1 -0
  187. package/dist/backend/services/attribute-option-validator.d.ts +47 -0
  188. package/dist/backend/services/attribute-option-validator.d.ts.map +1 -0
  189. package/dist/backend/services/attribute-option-validator.js +69 -0
  190. package/dist/backend/services/attribute-option-validator.js.map +1 -0
  191. package/dist/backend/services/attribute-set-validations.d.ts +65 -0
  192. package/dist/backend/services/attribute-set-validations.d.ts.map +1 -0
  193. package/dist/backend/services/attribute-set-validations.js +89 -0
  194. package/dist/backend/services/attribute-set-validations.js.map +1 -0
  195. package/dist/backend/services/attribute-set.service.d.ts +50 -0
  196. package/dist/backend/services/attribute-set.service.d.ts.map +1 -0
  197. package/dist/backend/services/attribute-set.service.js +401 -0
  198. package/dist/backend/services/attribute-set.service.js.map +1 -0
  199. package/dist/backend/services/attribute-type-mapping.d.ts +66 -0
  200. package/dist/backend/services/attribute-type-mapping.d.ts.map +1 -0
  201. package/dist/backend/services/attribute-type-mapping.js +121 -0
  202. package/dist/backend/services/attribute-type-mapping.js.map +1 -0
  203. package/dist/backend/services/attribute-value-key.service.d.ts +48 -0
  204. package/dist/backend/services/attribute-value-key.service.d.ts.map +1 -0
  205. package/dist/backend/services/attribute-value-key.service.js +118 -0
  206. package/dist/backend/services/attribute-value-key.service.js.map +1 -0
  207. package/dist/backend/services/audit-references.d.ts +13 -0
  208. package/dist/backend/services/audit-references.d.ts.map +1 -0
  209. package/dist/backend/services/audit-references.js +51 -0
  210. package/dist/backend/services/audit-references.js.map +1 -0
  211. package/dist/backend/services/bulk-operation-queue.d.ts +26 -0
  212. package/dist/backend/services/bulk-operation-queue.d.ts.map +1 -0
  213. package/dist/backend/services/bulk-operation-queue.js +34 -0
  214. package/dist/backend/services/bulk-operation-queue.js.map +1 -0
  215. package/dist/backend/services/bulk-operation.service.d.ts +195 -0
  216. package/dist/backend/services/bulk-operation.service.d.ts.map +1 -0
  217. package/dist/backend/services/bulk-operation.service.js +510 -0
  218. package/dist/backend/services/bulk-operation.service.js.map +1 -0
  219. package/dist/backend/services/bundle.service.d.ts +87 -0
  220. package/dist/backend/services/bundle.service.d.ts.map +1 -0
  221. package/dist/backend/services/bundle.service.js +286 -0
  222. package/dist/backend/services/bundle.service.js.map +1 -0
  223. package/dist/backend/services/catalog-admin.service.d.ts +398 -0
  224. package/dist/backend/services/catalog-admin.service.d.ts.map +1 -0
  225. package/dist/backend/services/catalog-admin.service.js +1516 -0
  226. package/dist/backend/services/catalog-admin.service.js.map +1 -0
  227. package/dist/backend/services/catalog-attribute-read.service.d.ts +78 -0
  228. package/dist/backend/services/catalog-attribute-read.service.d.ts.map +1 -0
  229. package/dist/backend/services/catalog-attribute-read.service.js +216 -0
  230. package/dist/backend/services/catalog-attribute-read.service.js.map +1 -0
  231. package/dist/backend/services/catalog-bulk-import.service.d.ts +30 -0
  232. package/dist/backend/services/catalog-bulk-import.service.d.ts.map +1 -0
  233. package/dist/backend/services/catalog-bulk-import.service.js +136 -0
  234. package/dist/backend/services/catalog-bulk-import.service.js.map +1 -0
  235. package/dist/backend/services/catalog-bulk-update.service.d.ts +91 -0
  236. package/dist/backend/services/catalog-bulk-update.service.d.ts.map +1 -0
  237. package/dist/backend/services/catalog-bulk-update.service.js +330 -0
  238. package/dist/backend/services/catalog-bulk-update.service.js.map +1 -0
  239. package/dist/backend/services/catalog-category-read.service.d.ts +66 -0
  240. package/dist/backend/services/catalog-category-read.service.d.ts.map +1 -0
  241. package/dist/backend/services/catalog-category-read.service.js +248 -0
  242. package/dist/backend/services/catalog-category-read.service.js.map +1 -0
  243. package/dist/backend/services/catalog-org-price-decorator.d.ts +90 -0
  244. package/dist/backend/services/catalog-org-price-decorator.d.ts.map +1 -0
  245. package/dist/backend/services/catalog-org-price-decorator.js +184 -0
  246. package/dist/backend/services/catalog-org-price-decorator.js.map +1 -0
  247. package/dist/backend/services/catalog-product-filter.service.d.ts +82 -0
  248. package/dist/backend/services/catalog-product-filter.service.d.ts.map +1 -0
  249. package/dist/backend/services/catalog-product-filter.service.js +275 -0
  250. package/dist/backend/services/catalog-product-filter.service.js.map +1 -0
  251. package/dist/backend/services/catalog-product-read.service.d.ts +46 -0
  252. package/dist/backend/services/catalog-product-read.service.d.ts.map +1 -0
  253. package/dist/backend/services/catalog-product-read.service.js +197 -0
  254. package/dist/backend/services/catalog-product-read.service.js.map +1 -0
  255. package/dist/backend/services/catalog-query.service.d.ts +444 -0
  256. package/dist/backend/services/catalog-query.service.d.ts.map +1 -0
  257. package/dist/backend/services/catalog-query.service.js +1633 -0
  258. package/dist/backend/services/catalog-query.service.js.map +1 -0
  259. package/dist/backend/services/catalog-quick-search.service.d.ts +78 -0
  260. package/dist/backend/services/catalog-quick-search.service.d.ts.map +1 -0
  261. package/dist/backend/services/catalog-quick-search.service.js +159 -0
  262. package/dist/backend/services/catalog-quick-search.service.js.map +1 -0
  263. package/dist/backend/services/catalog-write-ports.d.ts +25 -0
  264. package/dist/backend/services/catalog-write-ports.d.ts.map +1 -0
  265. package/dist/backend/services/catalog-write-ports.js +63 -0
  266. package/dist/backend/services/catalog-write-ports.js.map +1 -0
  267. package/dist/backend/services/category-admin.service.d.ts +102 -0
  268. package/dist/backend/services/category-admin.service.d.ts.map +1 -0
  269. package/dist/backend/services/category-admin.service.js +271 -0
  270. package/dist/backend/services/category-admin.service.js.map +1 -0
  271. package/dist/backend/services/gallery.service.d.ts +85 -0
  272. package/dist/backend/services/gallery.service.d.ts.map +1 -0
  273. package/dist/backend/services/gallery.service.js +326 -0
  274. package/dist/backend/services/gallery.service.js.map +1 -0
  275. package/dist/backend/services/grouped.service.d.ts +39 -0
  276. package/dist/backend/services/grouped.service.d.ts.map +1 -0
  277. package/dist/backend/services/grouped.service.js +136 -0
  278. package/dist/backend/services/grouped.service.js.map +1 -0
  279. package/dist/backend/services/label-resolver.d.ts +16 -0
  280. package/dist/backend/services/label-resolver.d.ts.map +1 -0
  281. package/dist/backend/services/label-resolver.js +43 -0
  282. package/dist/backend/services/label-resolver.js.map +1 -0
  283. package/dist/backend/services/packaging-unit.service.d.ts +28 -0
  284. package/dist/backend/services/packaging-unit.service.d.ts.map +1 -0
  285. package/dist/backend/services/packaging-unit.service.js +197 -0
  286. package/dist/backend/services/packaging-unit.service.js.map +1 -0
  287. package/dist/backend/services/primary-asset-url.d.ts +4 -0
  288. package/dist/backend/services/primary-asset-url.d.ts.map +1 -0
  289. package/dist/backend/services/primary-asset-url.js +55 -0
  290. package/dist/backend/services/primary-asset-url.js.map +1 -0
  291. package/dist/backend/services/product-editor-preferences.service.d.ts +20 -0
  292. package/dist/backend/services/product-editor-preferences.service.d.ts.map +1 -0
  293. package/dist/backend/services/product-editor-preferences.service.js +44 -0
  294. package/dist/backend/services/product-editor-preferences.service.js.map +1 -0
  295. package/dist/backend/services/product-link.service.d.ts +169 -0
  296. package/dist/backend/services/product-link.service.d.ts.map +1 -0
  297. package/dist/backend/services/product-link.service.js +297 -0
  298. package/dist/backend/services/product-link.service.js.map +1 -0
  299. package/dist/backend/services/product-overrides.service.d.ts +77 -0
  300. package/dist/backend/services/product-overrides.service.d.ts.map +1 -0
  301. package/dist/backend/services/product-overrides.service.js +204 -0
  302. package/dist/backend/services/product-overrides.service.js.map +1 -0
  303. package/dist/backend/services/product-scope-context.service.d.ts +36 -0
  304. package/dist/backend/services/product-scope-context.service.d.ts.map +1 -0
  305. package/dist/backend/services/product-scope-context.service.js +106 -0
  306. package/dist/backend/services/product-scope-context.service.js.map +1 -0
  307. package/dist/backend/services/product-type-validations.d.ts +42 -0
  308. package/dist/backend/services/product-type-validations.d.ts.map +1 -0
  309. package/dist/backend/services/product-type-validations.js +55 -0
  310. package/dist/backend/services/product-type-validations.js.map +1 -0
  311. package/dist/backend/services/product-value-resolver.service.d.ts +59 -0
  312. package/dist/backend/services/product-value-resolver.service.d.ts.map +1 -0
  313. package/dist/backend/services/product-value-resolver.service.js +111 -0
  314. package/dist/backend/services/product-value-resolver.service.js.map +1 -0
  315. package/dist/backend/services/system-attribute-scopes.d.ts +18 -0
  316. package/dist/backend/services/system-attribute-scopes.d.ts.map +1 -0
  317. package/dist/backend/services/system-attribute-scopes.js +18 -0
  318. package/dist/backend/services/system-attribute-scopes.js.map +1 -0
  319. package/dist/backend/services/viewer-organization.d.ts +25 -0
  320. package/dist/backend/services/viewer-organization.d.ts.map +1 -0
  321. package/dist/backend/services/viewer-organization.js +31 -0
  322. package/dist/backend/services/viewer-organization.js.map +1 -0
  323. package/dist/manifest.d.ts +204 -0
  324. package/dist/manifest.d.ts.map +1 -0
  325. package/dist/manifest.js +686 -0
  326. package/dist/manifest.js.map +1 -0
  327. package/dist/migrations/20260429T064146_catalog_attribute_sets_init.d.ts +33 -0
  328. package/dist/migrations/20260429T064146_catalog_attribute_sets_init.d.ts.map +1 -0
  329. package/dist/migrations/20260429T064146_catalog_attribute_sets_init.js +118 -0
  330. package/dist/migrations/20260429T064146_catalog_attribute_sets_init.js.map +1 -0
  331. package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.d.ts +24 -0
  332. package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.d.ts.map +1 -0
  333. package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.js +31 -0
  334. package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.js.map +1 -0
  335. package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.d.ts +32 -0
  336. package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.d.ts.map +1 -0
  337. package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.js +58 -0
  338. package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.js.map +1 -0
  339. package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.d.ts +22 -0
  340. package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.d.ts.map +1 -0
  341. package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.js +66 -0
  342. package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.js.map +1 -0
  343. package/dist/migrations/20260429T112543_catalog_product_attachments.d.ts +18 -0
  344. package/dist/migrations/20260429T112543_catalog_product_attachments.d.ts.map +1 -0
  345. package/dist/migrations/20260429T112543_catalog_product_attachments.js +73 -0
  346. package/dist/migrations/20260429T112543_catalog_product_attachments.js.map +1 -0
  347. package/dist/migrations/20260429T123726_catalog_product_links.d.ts +21 -0
  348. package/dist/migrations/20260429T123726_catalog_product_links.d.ts.map +1 -0
  349. package/dist/migrations/20260429T123726_catalog_product_links.js +48 -0
  350. package/dist/migrations/20260429T123726_catalog_product_links.js.map +1 -0
  351. package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.d.ts +23 -0
  352. package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.d.ts.map +1 -0
  353. package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.js +94 -0
  354. package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.js.map +1 -0
  355. package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.d.ts +24 -0
  356. package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.d.ts.map +1 -0
  357. package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.js +31 -0
  358. package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.js.map +1 -0
  359. package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.d.ts +31 -0
  360. package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.d.ts.map +1 -0
  361. package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.js +133 -0
  362. package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.js.map +1 -0
  363. package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.d.ts +16 -0
  364. package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.d.ts.map +1 -0
  365. package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.js +23 -0
  366. package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.js.map +1 -0
  367. package/dist/migrations/20260526T124736_catalog_product_status_inactive.d.ts +10 -0
  368. package/dist/migrations/20260526T124736_catalog_product_status_inactive.d.ts.map +1 -0
  369. package/dist/migrations/20260526T124736_catalog_product_status_inactive.js +22 -0
  370. package/dist/migrations/20260526T124736_catalog_product_status_inactive.js.map +1 -0
  371. package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.d.ts +38 -0
  372. package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.d.ts.map +1 -0
  373. package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.js +98 -0
  374. package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.js.map +1 -0
  375. package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.d.ts +13 -0
  376. package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.d.ts.map +1 -0
  377. package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.js +17 -0
  378. package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.js.map +1 -0
  379. package/dist/migrations/20260611T140407_catalog_bulk_operations.d.ts +16 -0
  380. package/dist/migrations/20260611T140407_catalog_bulk_operations.d.ts.map +1 -0
  381. package/dist/migrations/20260611T140407_catalog_bulk_operations.js +42 -0
  382. package/dist/migrations/20260611T140407_catalog_bulk_operations.js.map +1 -0
  383. package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.d.ts +14 -0
  384. package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.d.ts.map +1 -0
  385. package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.js +18 -0
  386. package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.js.map +1 -0
  387. package/dist/migrations/20260611T140412_catalog_product_packaging_units.d.ts +11 -0
  388. package/dist/migrations/20260611T140412_catalog_product_packaging_units.d.ts.map +1 -0
  389. package/dist/migrations/20260611T140412_catalog_product_packaging_units.js +29 -0
  390. package/dist/migrations/20260611T140412_catalog_product_packaging_units.js.map +1 -0
  391. package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.d.ts +23 -0
  392. package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.d.ts.map +1 -0
  393. package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.js +35 -0
  394. package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.js.map +1 -0
  395. package/dist/migrations/20260718T200343_catalog_category_custom_field_values.d.ts +12 -0
  396. package/dist/migrations/20260718T200343_catalog_category_custom_field_values.d.ts.map +1 -0
  397. package/dist/migrations/20260718T200343_catalog_category_custom_field_values.js +16 -0
  398. package/dist/migrations/20260718T200343_catalog_category_custom_field_values.js.map +1 -0
  399. package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.d.ts +32 -0
  400. package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.d.ts.map +1 -0
  401. package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.js +286 -0
  402. package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.js.map +1 -0
  403. package/dist/migrations/20260804T152604_catalog_widen_product_sku.d.ts +36 -0
  404. package/dist/migrations/20260804T152604_catalog_widen_product_sku.d.ts.map +1 -0
  405. package/dist/migrations/20260804T152604_catalog_widen_product_sku.js +63 -0
  406. package/dist/migrations/20260804T152604_catalog_widen_product_sku.js.map +1 -0
  407. package/dist/migrations/20260804T160244_catalog_category_activation.d.ts +18 -0
  408. package/dist/migrations/20260804T160244_catalog_category_activation.d.ts.map +1 -0
  409. package/dist/migrations/20260804T160244_catalog_category_activation.js +22 -0
  410. package/dist/migrations/20260804T160244_catalog_category_activation.js.map +1 -0
  411. package/dist/migrations/20260912T094557_catalog_sales_channel_products.d.ts +27 -0
  412. package/dist/migrations/20260912T094557_catalog_sales_channel_products.d.ts.map +1 -0
  413. package/dist/migrations/20260912T094557_catalog_sales_channel_products.js +44 -0
  414. package/dist/migrations/20260912T094557_catalog_sales_channel_products.js.map +1 -0
  415. package/dist/migrations/20260912T094623_catalog_sales_channel_categories.d.ts +27 -0
  416. package/dist/migrations/20260912T094623_catalog_sales_channel_categories.d.ts.map +1 -0
  417. package/dist/migrations/20260912T094623_catalog_sales_channel_categories.js +44 -0
  418. package/dist/migrations/20260912T094623_catalog_sales_channel_categories.js.map +1 -0
  419. package/dist/migrations/20260925T125527_catalog_inventory_columns.d.ts +36 -0
  420. package/dist/migrations/20260925T125527_catalog_inventory_columns.d.ts.map +1 -0
  421. package/dist/migrations/20260925T125527_catalog_inventory_columns.js +87 -0
  422. package/dist/migrations/20260925T125527_catalog_inventory_columns.js.map +1 -0
  423. package/dist/migrations/index.d.ts +55 -0
  424. package/dist/migrations/index.d.ts.map +1 -0
  425. package/dist/migrations/index.js +80 -0
  426. package/dist/migrations/index.js.map +1 -0
  427. package/dist/ports/index.d.ts +96 -0
  428. package/dist/ports/index.d.ts.map +1 -0
  429. package/dist/ports/index.js +2 -0
  430. package/dist/ports/index.js.map +1 -0
  431. package/docs/catalog/attachments.md +69 -0
  432. package/docs/catalog/attribute-sets.md +63 -0
  433. package/docs/catalog/attributes.md +244 -0
  434. package/docs/catalog/composite-products.md +115 -0
  435. package/docs/catalog/gallery-and-labels.md +73 -0
  436. package/docs/catalog/packaging-units.md +67 -0
  437. package/docs/catalog/per-channel-per-language-overrides.md +234 -0
  438. package/docs/catalog/product-links.md +79 -0
  439. package/docs/catalog.md +207 -0
  440. package/i18n/en.json +649 -0
  441. package/i18n/pl.json +649 -0
  442. package/package.json +109 -0
  443. 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"}