@yoryoboy/bi-mcp 1.10.0 → 1.13.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 (239) hide show
  1. package/README.md +4 -5
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +398 -8
  4. package/dist/index.js.map +2 -2
  5. package/dist/mcp-use.json +2 -2
  6. package/dist/src/config/__tests__/meta.test.js +35 -0
  7. package/dist/src/config/__tests__/meta.test.js.map +7 -0
  8. package/dist/src/config/mercadolibre-profile-store.js +25 -0
  9. package/dist/src/config/mercadolibre-profile-store.js.map +2 -2
  10. package/dist/src/config/meta-store.js +109 -0
  11. package/dist/src/config/meta-store.js.map +7 -0
  12. package/dist/src/config/meta.js +0 -2
  13. package/dist/src/config/meta.js.map +2 -2
  14. package/dist/src/meta/__tests__/meta-utils.test.js +155 -0
  15. package/dist/src/meta/__tests__/meta-utils.test.js.map +7 -0
  16. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js +265 -0
  17. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js.map +7 -0
  18. package/dist/src/services/mercadolibre/__tests__/mercadolibre-items.test.js +311 -0
  19. package/dist/src/services/mercadolibre/__tests__/mercadolibre-items.test.js.map +7 -0
  20. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js +220 -0
  21. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js.map +7 -0
  22. package/dist/src/services/meta/__tests__/meta-ads.test.js +126 -0
  23. package/dist/src/services/meta/__tests__/meta-ads.test.js.map +7 -0
  24. package/dist/src/services/meta/__tests__/meta-api.test.js +70 -0
  25. package/dist/src/services/meta/__tests__/meta-api.test.js.map +7 -0
  26. package/dist/src/services/meta/meta-ads.js +94 -40
  27. package/dist/src/services/meta/meta-ads.js.map +2 -2
  28. package/dist/src/services/meta/meta-api.js +8 -6
  29. package/dist/src/services/meta/meta-api.js.map +2 -2
  30. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js +165 -0
  31. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js.map +7 -0
  32. package/dist/src/services/vtex/__tests__/vtex-catalog-write-eans.test.js +92 -0
  33. package/dist/src/services/vtex/__tests__/vtex-catalog-write-eans.test.js.map +7 -0
  34. package/dist/src/services/vtex/__tests__/vtex-catalog-write-products.test.js +41 -0
  35. package/dist/src/services/vtex/__tests__/vtex-catalog-write-products.test.js.map +7 -0
  36. package/dist/src/services/vtex/__tests__/vtex-catalog.test.js +80 -0
  37. package/dist/src/services/vtex/__tests__/vtex-catalog.test.js.map +7 -0
  38. package/dist/src/services/vtex/__tests__/vtex-orders-write-http.test.js +85 -0
  39. package/dist/src/services/vtex/__tests__/vtex-orders-write-http.test.js.map +7 -0
  40. package/dist/src/services/vtex/__tests__/vtex-orders-write-state-validation.test.js +251 -0
  41. package/dist/src/services/vtex/__tests__/vtex-orders-write-state-validation.test.js.map +7 -0
  42. package/dist/src/services/vtex/__tests__/vtex-write.test.js +111 -0
  43. package/dist/src/services/vtex/__tests__/vtex-write.test.js.map +7 -0
  44. package/dist/src/services/vtex/vtex-catalog-write.js +194 -1
  45. package/dist/src/services/vtex/vtex-catalog-write.js.map +2 -2
  46. package/dist/src/services/vtex/vtex-catalog.js +118 -1
  47. package/dist/src/services/vtex/vtex-catalog.js.map +2 -2
  48. package/dist/src/services/vtex/vtex-pricing-write.js +5 -0
  49. package/dist/src/services/vtex/vtex-pricing-write.js.map +2 -2
  50. package/dist/src/services/vtex/vtex-write.js +67 -1
  51. package/dist/src/services/vtex/vtex-write.js.map +2 -2
  52. package/dist/src/tools/config/list-profiles.js +85 -11
  53. package/dist/src/tools/config/list-profiles.js.map +2 -2
  54. package/dist/src/tools/index.js.map +2 -2
  55. package/dist/src/tools/mercadolibre/__tests__/helpers.test.js +37 -0
  56. package/dist/src/tools/mercadolibre/__tests__/helpers.test.js.map +7 -0
  57. package/dist/src/tools/mercadolibre/__tests__/profile-resolution.test.js +30 -0
  58. package/dist/src/tools/mercadolibre/__tests__/profile-resolution.test.js.map +7 -0
  59. package/dist/src/tools/mercadolibre/profile-resolution.js +4 -50
  60. package/dist/src/tools/mercadolibre/profile-resolution.js.map +2 -2
  61. package/dist/src/tools/meta/__tests__/pagination.test.js +133 -0
  62. package/dist/src/tools/meta/__tests__/pagination.test.js.map +7 -0
  63. package/dist/src/tools/meta/__tests__/profile-access.test.js +262 -0
  64. package/dist/src/tools/meta/__tests__/profile-access.test.js.map +7 -0
  65. package/dist/src/tools/meta/__tests__/read-tools.test.js +722 -0
  66. package/dist/src/tools/meta/__tests__/read-tools.test.js.map +7 -0
  67. package/dist/src/tools/meta/__tests__/schemas.test.js +103 -0
  68. package/dist/src/tools/meta/__tests__/schemas.test.js.map +7 -0
  69. package/dist/src/tools/meta/account-overview.js +37 -19
  70. package/dist/src/tools/meta/account-overview.js.map +2 -2
  71. package/dist/src/tools/meta/ad-account-info.js +31 -6
  72. package/dist/src/tools/meta/ad-account-info.js.map +2 -2
  73. package/dist/src/tools/meta/ads-performance.js +35 -21
  74. package/dist/src/tools/meta/ads-performance.js.map +2 -2
  75. package/dist/src/tools/meta/campaign-performance.js +35 -18
  76. package/dist/src/tools/meta/campaign-performance.js.map +2 -2
  77. package/dist/src/tools/meta/list-accessible-ad-accounts.js +39 -10
  78. package/dist/src/tools/meta/list-accessible-ad-accounts.js.map +2 -2
  79. package/dist/src/tools/meta/list-accessible-businesses.js +37 -13
  80. package/dist/src/tools/meta/list-accessible-businesses.js.map +2 -2
  81. package/dist/src/tools/meta/placement-mix.js +37 -22
  82. package/dist/src/tools/meta/placement-mix.js.map +2 -2
  83. package/dist/src/tools/meta/profile-access.js +215 -0
  84. package/dist/src/tools/meta/profile-access.js.map +7 -0
  85. package/dist/src/tools/meta/schema-helpers.js +19 -0
  86. package/dist/src/tools/meta/schema-helpers.js.map +7 -0
  87. package/dist/src/tools/meta/time-series.js +40 -23
  88. package/dist/src/tools/meta/time-series.js.map +2 -2
  89. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js +233 -0
  90. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js.map +7 -0
  91. package/dist/src/tools/vtex/__tests__/catalog-admin-categories.test.js +649 -0
  92. package/dist/src/tools/vtex/__tests__/catalog-admin-categories.test.js.map +7 -0
  93. package/dist/src/tools/vtex/__tests__/catalog-admin-product-specifications.test.js +339 -0
  94. package/dist/src/tools/vtex/__tests__/catalog-admin-product-specifications.test.js.map +7 -0
  95. package/dist/src/tools/vtex/__tests__/catalog-admin-products-skus.test.js +235 -0
  96. package/dist/src/tools/vtex/__tests__/catalog-admin-products-skus.test.js.map +7 -0
  97. package/dist/src/tools/vtex/__tests__/catalog-navigation-reads.test.js +372 -0
  98. package/dist/src/tools/vtex/__tests__/catalog-navigation-reads.test.js.map +7 -0
  99. package/dist/src/tools/vtex/__tests__/catalog-navigation-surface.test.js +57 -0
  100. package/dist/src/tools/vtex/__tests__/catalog-navigation-surface.test.js.map +7 -0
  101. package/dist/src/tools/vtex/__tests__/write-helpers.test.js +97 -0
  102. package/dist/src/tools/vtex/__tests__/write-helpers.test.js.map +7 -0
  103. package/dist/src/tools/vtex/activate-sku.js +1 -48
  104. package/dist/src/tools/vtex/activate-sku.js.map +2 -2
  105. package/dist/src/tools/vtex/associate-specification.js +3 -54
  106. package/dist/src/tools/vtex/associate-specification.js.map +2 -2
  107. package/dist/src/tools/vtex/attach-catalog-image.js +3 -57
  108. package/dist/src/tools/vtex/attach-catalog-image.js.map +2 -2
  109. package/dist/src/tools/vtex/catalog-admin-batch.js +298 -0
  110. package/dist/src/tools/vtex/catalog-admin-batch.js.map +7 -0
  111. package/dist/src/tools/vtex/catalog-admin-categories.js +542 -0
  112. package/dist/src/tools/vtex/catalog-admin-categories.js.map +7 -0
  113. package/dist/src/tools/vtex/catalog-admin-product-specifications.js +275 -0
  114. package/dist/src/tools/vtex/catalog-admin-product-specifications.js.map +7 -0
  115. package/dist/src/tools/vtex/catalog-admin-products-skus.js +475 -0
  116. package/dist/src/tools/vtex/catalog-admin-products-skus.js.map +7 -0
  117. package/dist/src/tools/vtex/catalog-navigation-reads.js +430 -0
  118. package/dist/src/tools/vtex/catalog-navigation-reads.js.map +7 -0
  119. package/dist/src/tools/vtex/create-brand.js +1 -64
  120. package/dist/src/tools/vtex/create-brand.js.map +2 -2
  121. package/dist/src/tools/vtex/create-category.js +1 -76
  122. package/dist/src/tools/vtex/create-category.js.map +2 -2
  123. package/dist/src/tools/vtex/create-product-with-sku.js +3 -114
  124. package/dist/src/tools/vtex/create-product-with-sku.js.map +2 -2
  125. package/dist/src/tools/vtex/create-specification-value.js +3 -47
  126. package/dist/src/tools/vtex/create-specification-value.js.map +2 -2
  127. package/dist/src/tools/vtex/create-specification.js +1 -80
  128. package/dist/src/tools/vtex/create-specification.js.map +2 -2
  129. package/dist/src/tools/vtex/deactivate-sku.js +1 -48
  130. package/dist/src/tools/vtex/deactivate-sku.js.map +2 -2
  131. package/dist/src/tools/vtex/delete-all-product-specifications.js +9 -0
  132. package/dist/src/tools/vtex/delete-all-product-specifications.js.map +7 -0
  133. package/dist/src/tools/vtex/delete-all-sku-specifications.js +9 -0
  134. package/dist/src/tools/vtex/delete-all-sku-specifications.js.map +7 -0
  135. package/dist/src/tools/vtex/delete-brand.js +9 -0
  136. package/dist/src/tools/vtex/delete-brand.js.map +7 -0
  137. package/dist/src/tools/vtex/delete-catalog-image.js +9 -0
  138. package/dist/src/tools/vtex/delete-catalog-image.js.map +7 -0
  139. package/dist/src/tools/vtex/delete-product-specification.js +9 -0
  140. package/dist/src/tools/vtex/delete-product-specification.js.map +7 -0
  141. package/dist/src/tools/vtex/delete-sku-price.js +55 -0
  142. package/dist/src/tools/vtex/delete-sku-price.js.map +7 -0
  143. package/dist/src/tools/vtex/delete-sku-specification.js +9 -0
  144. package/dist/src/tools/vtex/delete-sku-specification.js.map +7 -0
  145. package/dist/src/tools/vtex/get-brand.js +6 -0
  146. package/dist/src/tools/vtex/get-brand.js.map +7 -0
  147. package/dist/src/tools/vtex/get-category-tree.js +6 -0
  148. package/dist/src/tools/vtex/get-category-tree.js.map +7 -0
  149. package/dist/src/tools/vtex/get-category.js +6 -0
  150. package/dist/src/tools/vtex/get-category.js.map +7 -0
  151. package/dist/src/tools/vtex/get-product-specifications.js +9 -0
  152. package/dist/src/tools/vtex/get-product-specifications.js.map +7 -0
  153. package/dist/src/tools/vtex/get-product.js +6 -0
  154. package/dist/src/tools/vtex/get-product.js.map +7 -0
  155. package/dist/src/tools/vtex/get-sku.js +6 -0
  156. package/dist/src/tools/vtex/get-sku.js.map +7 -0
  157. package/dist/src/tools/vtex/index.js +23 -1
  158. package/dist/src/tools/vtex/index.js.map +2 -2
  159. package/dist/src/tools/vtex/list-brands.js +6 -0
  160. package/dist/src/tools/vtex/list-brands.js.map +7 -0
  161. package/dist/src/tools/vtex/list-categories.js +6 -0
  162. package/dist/src/tools/vtex/list-categories.js.map +7 -0
  163. package/dist/src/tools/vtex/list-products-by-category.js +6 -0
  164. package/dist/src/tools/vtex/list-products-by-category.js.map +7 -0
  165. package/dist/src/tools/vtex/list-products.js +6 -0
  166. package/dist/src/tools/vtex/list-products.js.map +7 -0
  167. package/dist/src/tools/vtex/list-skus-by-product.js +6 -0
  168. package/dist/src/tools/vtex/list-skus-by-product.js.map +7 -0
  169. package/dist/src/tools/vtex/list-specification-groups.js +9 -0
  170. package/dist/src/tools/vtex/list-specification-groups.js.map +7 -0
  171. package/dist/src/tools/vtex/move-category.js +6 -0
  172. package/dist/src/tools/vtex/move-category.js.map +7 -0
  173. package/dist/src/tools/vtex/profile-resolution.js +4 -51
  174. package/dist/src/tools/vtex/profile-resolution.js.map +2 -2
  175. package/dist/src/tools/vtex/update-brand.js +6 -0
  176. package/dist/src/tools/vtex/update-brand.js.map +7 -0
  177. package/dist/src/tools/vtex/update-category.js +6 -0
  178. package/dist/src/tools/vtex/update-category.js.map +7 -0
  179. package/dist/src/tools/vtex/update-product-basic-fields.js +3 -65
  180. package/dist/src/tools/vtex/update-product-basic-fields.js.map +2 -2
  181. package/dist/src/tools/vtex/update-sku-basic-fields.js +1 -87
  182. package/dist/src/tools/vtex/update-sku-basic-fields.js.map +2 -2
  183. package/dist/src/tools/vtex/update-sku-price.js +21 -1
  184. package/dist/src/tools/vtex/update-sku-price.js.map +2 -2
  185. package/dist/src/tools/vtex/write-helpers.js +104 -14
  186. package/dist/src/tools/vtex/write-helpers.js.map +2 -2
  187. package/dist/src/utils/provider-profile-selection.js +117 -0
  188. package/dist/src/utils/provider-profile-selection.js.map +7 -0
  189. package/dist/tests/meli/mercadolibre-tool-handlers-medium-batch4.test.js +678 -0
  190. package/dist/tests/meli/mercadolibre-tool-handlers-medium-batch4.test.js.map +7 -0
  191. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch5.test.js +564 -0
  192. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch5.test.js.map +7 -0
  193. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch6.test.js +387 -0
  194. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch6.test.js.map +7 -0
  195. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch7.test.js +368 -0
  196. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch7.test.js.map +7 -0
  197. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js +626 -0
  198. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js.map +7 -0
  199. package/dist/tests/meli/mercadolibre-tool-handlers-write-batch8.test.js +480 -0
  200. package/dist/tests/meli/mercadolibre-tool-handlers-write-batch8.test.js.map +7 -0
  201. package/dist/tests/setup.js +2 -0
  202. package/dist/tests/setup.js.map +7 -0
  203. package/dist/tests/smoke/test-harness.test.js +7 -0
  204. package/dist/tests/smoke/test-harness.test.js.map +7 -0
  205. package/dist/tests/vtex/read-only-utils.test.js +161 -0
  206. package/dist/tests/vtex/read-only-utils.test.js.map +7 -0
  207. package/dist/tests/vtex/vtex-catalog-admin-docs.test.js +24 -0
  208. package/dist/tests/vtex/vtex-catalog-admin-docs.test.js.map +7 -0
  209. package/dist/tests/vtex/vtex-catalog-admin-surface.test.js +30 -0
  210. package/dist/tests/vtex/vtex-catalog-admin-surface.test.js.map +7 -0
  211. package/dist/tests/vtex/vtex-catalog-write-tools.test.js +712 -0
  212. package/dist/tests/vtex/vtex-catalog-write-tools.test.js.map +7 -0
  213. package/dist/tests/vtex/vtex-catalog.service.test.js +51 -0
  214. package/dist/tests/vtex/vtex-catalog.service.test.js.map +7 -0
  215. package/dist/tests/vtex/vtex-inventory-tools.test.js +201 -0
  216. package/dist/tests/vtex/vtex-inventory-tools.test.js.map +7 -0
  217. package/dist/tests/vtex/vtex-logistics.service.test.js +134 -0
  218. package/dist/tests/vtex/vtex-logistics.service.test.js.map +7 -0
  219. package/dist/tests/vtex/vtex-order-details.tool.test.js +141 -0
  220. package/dist/tests/vtex/vtex-order-details.tool.test.js.map +7 -0
  221. package/dist/tests/vtex/vtex-order-write-tools.test.js +483 -0
  222. package/dist/tests/vtex/vtex-order-write-tools.test.js.map +7 -0
  223. package/dist/tests/vtex/vtex-orders-summary.tool.test.js +185 -0
  224. package/dist/tests/vtex/vtex-orders-summary.tool.test.js.map +7 -0
  225. package/dist/tests/vtex/vtex-orders.service.test.js +120 -0
  226. package/dist/tests/vtex/vtex-orders.service.test.js.map +7 -0
  227. package/dist/tests/vtex/vtex-pricing-write-tools.test.js +202 -0
  228. package/dist/tests/vtex/vtex-pricing-write-tools.test.js.map +7 -0
  229. package/dist/tests/vtex/vtex-pricing-write.service.test.js +106 -0
  230. package/dist/tests/vtex/vtex-pricing-write.service.test.js.map +7 -0
  231. package/dist/tests/vtex/vtex-pricing.service.test.js +88 -0
  232. package/dist/tests/vtex/vtex-pricing.service.test.js.map +7 -0
  233. package/dist/tests/vtex/vtex-small-tools.test.js +190 -0
  234. package/dist/tests/vtex/vtex-small-tools.test.js.map +7 -0
  235. package/dist/tests/vtex/vtex-write-simple-tools.test.js +647 -0
  236. package/dist/tests/vtex/vtex-write-simple-tools.test.js.map +7 -0
  237. package/dist/vitest.config.js +15 -0
  238. package/dist/vitest.config.js.map +7 -0
  239. package/package.json +6 -2
@@ -0,0 +1,647 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { z } from "zod";
3
+ import { activateSkuHandler } from "../../src/tools/vtex/activate-sku.js";
4
+ import { deactivateSkuHandler } from "../../src/tools/vtex/deactivate-sku.js";
5
+ import { toggleUnlimitedQuantityHandler } from "../../src/tools/vtex/toggle-unlimited-quantity.js";
6
+ import { updateInventoryHandler } from "../../src/tools/vtex/update-inventory.js";
7
+ import { updateLeadTimeHandler } from "../../src/tools/vtex/update-lead-time.js";
8
+ import { deleteSkuPriceHandler } from "../../src/tools/vtex/delete-sku-price.js";
9
+ import { updateSkuPriceHandler } from "../../src/tools/vtex/update-sku-price.js";
10
+ import {
11
+ updateSkuBasicFields
12
+ } from "../../src/services/vtex/vtex-catalog-write.js";
13
+ import {
14
+ getInventoryByWarehouse,
15
+ updateInventoryLeadTime,
16
+ updateInventoryQuantity
17
+ } from "../../src/services/vtex/vtex-logistics.js";
18
+ import { getSkuPrice } from "../../src/services/vtex/vtex-pricing.js";
19
+ import {
20
+ deleteSkuPrice,
21
+ updateSkuPrice
22
+ } from "../../src/services/vtex/vtex-pricing-write.js";
23
+ import {
24
+ buildWriteSuccessResponse,
25
+ handleVtexWriteError,
26
+ requireExplicitConfirmation,
27
+ resolveVtexWriteProfile
28
+ } from "../../src/tools/vtex/write-helpers.js";
29
+ vi.mock("../../src/tools/vtex/write-helpers.js", () => ({
30
+ vtexProfileIdSchemaField: z.string().optional(),
31
+ confirmationSchemaField: z.boolean().optional(),
32
+ confirmationNoteSchemaField: z.string().optional(),
33
+ resolveVtexWriteProfile: vi.fn(),
34
+ buildWriteSuccessResponse: vi.fn((params) => ({
35
+ kind: "success",
36
+ params
37
+ })),
38
+ requireExplicitConfirmation: vi.fn(),
39
+ handleVtexWriteError: vi.fn((err, fallback) => ({
40
+ kind: "error",
41
+ fallback,
42
+ err
43
+ }))
44
+ }));
45
+ vi.mock("../../src/services/vtex/vtex-catalog-write.js", () => ({
46
+ updateSkuBasicFields: vi.fn()
47
+ }));
48
+ vi.mock("../../src/services/vtex/vtex-logistics.js", () => ({
49
+ getInventoryByWarehouse: vi.fn(),
50
+ updateInventoryQuantity: vi.fn(),
51
+ updateInventoryLeadTime: vi.fn()
52
+ }));
53
+ vi.mock("../../src/services/vtex/vtex-pricing.js", () => ({
54
+ getSkuPrice: vi.fn()
55
+ }));
56
+ vi.mock("../../src/services/vtex/vtex-pricing-write.js", () => ({
57
+ updateSkuPrice: vi.fn(),
58
+ deleteSkuPrice: vi.fn()
59
+ }));
60
+ describe("VTEX write simple tools", () => {
61
+ beforeEach(() => {
62
+ vi.clearAllMocks();
63
+ vi.mocked(requireExplicitConfirmation).mockReturnValue(null);
64
+ vi.mocked(resolveVtexWriteProfile).mockResolvedValue({
65
+ ok: true,
66
+ value: { profileId: "profile-1" }
67
+ });
68
+ });
69
+ describe("activateSkuHandler", () => {
70
+ it("activates a sku using the fetched sku snapshot", async () => {
71
+ const beforeSku = { Id: "sku-1", IsActive: false, Name: "Before" };
72
+ const afterSku = { Id: "sku-1", IsActive: true, Name: "Before" };
73
+ vi.mocked(updateSkuBasicFields).mockResolvedValue({
74
+ before: beforeSku,
75
+ payload: { IsActive: true, Name: "Before" },
76
+ after: afterSku
77
+ });
78
+ const result = await activateSkuHandler({
79
+ profileId: "custom",
80
+ skuId: "sku-1"
81
+ });
82
+ expect(resolveVtexWriteProfile).toHaveBeenCalledWith("custom");
83
+ expect(updateSkuBasicFields).toHaveBeenCalledWith("profile-1", "sku-1", {
84
+ isActive: true
85
+ });
86
+ expect(buildWriteSuccessResponse).toHaveBeenCalledWith({
87
+ profileId: "profile-1",
88
+ operation: "activate_sku",
89
+ resourceId: "sku-1",
90
+ riskLevel: "medium",
91
+ message: "SKU activated successfully.",
92
+ before: beforeSku,
93
+ after: afterSku,
94
+ details: { sku_id: "sku-1" }
95
+ });
96
+ expect(result).toEqual({
97
+ kind: "success",
98
+ params: expect.objectContaining({ operation: "activate_sku" })
99
+ });
100
+ });
101
+ it("returns profile selection payload without mutating anything", async () => {
102
+ vi.mocked(resolveVtexWriteProfile).mockResolvedValue({
103
+ ok: false,
104
+ response: { selection: true }
105
+ });
106
+ const result = await activateSkuHandler({ skuId: "sku-1" });
107
+ expect(result).toEqual({ selection: true });
108
+ expect(updateSkuBasicFields).not.toHaveBeenCalled();
109
+ });
110
+ it("maps service errors through handleVtexWriteError", async () => {
111
+ vi.mocked(updateSkuBasicFields).mockRejectedValue(new Error("boom"));
112
+ const result = await activateSkuHandler({
113
+ profileId: "custom",
114
+ skuId: "sku-1"
115
+ });
116
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
117
+ expect.any(Error),
118
+ "Failed to activate SKU sku-1"
119
+ );
120
+ expect(result).toEqual({
121
+ kind: "error",
122
+ fallback: "Failed to activate SKU sku-1",
123
+ err: expect.any(Error)
124
+ });
125
+ });
126
+ });
127
+ describe("deactivateSkuHandler", () => {
128
+ it("deactivates a sku using the fetched sku snapshot", async () => {
129
+ const beforeSku = { Id: "sku-2", IsActive: true, Name: "Before" };
130
+ const afterSku = { Id: "sku-2", IsActive: false, Name: "Before" };
131
+ vi.mocked(updateSkuBasicFields).mockResolvedValue({
132
+ before: beforeSku,
133
+ payload: { IsActive: false, Name: "Before" },
134
+ after: afterSku
135
+ });
136
+ const result = await deactivateSkuHandler({
137
+ profileId: "custom",
138
+ skuId: "sku-2"
139
+ });
140
+ expect(updateSkuBasicFields).toHaveBeenCalledWith("profile-1", "sku-2", {
141
+ isActive: false
142
+ });
143
+ expect(buildWriteSuccessResponse).toHaveBeenCalledWith({
144
+ profileId: "profile-1",
145
+ operation: "deactivate_sku",
146
+ resourceId: "sku-2",
147
+ riskLevel: "medium",
148
+ message: "SKU deactivated successfully.",
149
+ before: beforeSku,
150
+ after: afterSku,
151
+ details: { sku_id: "sku-2" }
152
+ });
153
+ expect(result).toEqual({
154
+ kind: "success",
155
+ params: expect.objectContaining({ operation: "deactivate_sku" })
156
+ });
157
+ });
158
+ it("returns profile selection payload without mutating anything", async () => {
159
+ vi.mocked(resolveVtexWriteProfile).mockResolvedValue({
160
+ ok: false,
161
+ response: { selection: true }
162
+ });
163
+ const result = await deactivateSkuHandler({ skuId: "sku-2" });
164
+ expect(result).toEqual({ selection: true });
165
+ expect(updateSkuBasicFields).not.toHaveBeenCalled();
166
+ });
167
+ it("maps service errors through handleVtexWriteError", async () => {
168
+ vi.mocked(updateSkuBasicFields).mockRejectedValue(new Error("boom"));
169
+ const result = await deactivateSkuHandler({
170
+ profileId: "custom",
171
+ skuId: "sku-2"
172
+ });
173
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
174
+ expect.any(Error),
175
+ "Failed to deactivate SKU sku-2"
176
+ );
177
+ expect(result).toEqual({
178
+ kind: "error",
179
+ fallback: "Failed to deactivate SKU sku-2",
180
+ err: expect.any(Error)
181
+ });
182
+ });
183
+ });
184
+ describe("toggleUnlimitedQuantityHandler", () => {
185
+ it("reuses the current total quantity when toggling unlimited mode", async () => {
186
+ const beforeInventory = [
187
+ {
188
+ skuId: "sku-3",
189
+ warehouseId: "wh-1",
190
+ totalQuantity: 9,
191
+ isUnlimited: false
192
+ }
193
+ ];
194
+ const afterInventory = [
195
+ {
196
+ skuId: "sku-3",
197
+ warehouseId: "wh-1",
198
+ totalQuantity: 9,
199
+ isUnlimited: true
200
+ }
201
+ ];
202
+ vi.mocked(getInventoryByWarehouse).mockResolvedValueOnce(beforeInventory).mockResolvedValueOnce(afterInventory);
203
+ const result = await toggleUnlimitedQuantityHandler({
204
+ profileId: "custom",
205
+ skuId: "sku-3",
206
+ warehouseId: "wh-1",
207
+ unlimitedQuantity: true
208
+ });
209
+ expect(updateInventoryQuantity).toHaveBeenCalledWith(
210
+ "profile-1",
211
+ "sku-3",
212
+ "wh-1",
213
+ { quantity: 9, unlimitedQuantity: true }
214
+ );
215
+ expect(buildWriteSuccessResponse).toHaveBeenCalledWith({
216
+ profileId: "profile-1",
217
+ operation: "toggle_unlimited_quantity",
218
+ resourceId: "sku-3",
219
+ riskLevel: "low",
220
+ message: "Unlimited quantity mode updated successfully.",
221
+ before: beforeInventory[0],
222
+ after: afterInventory[0],
223
+ details: {
224
+ sku_id: "sku-3",
225
+ warehouse_id: "wh-1",
226
+ unlimited_quantity: true
227
+ }
228
+ });
229
+ expect(result).toEqual({
230
+ kind: "success",
231
+ params: expect.objectContaining({
232
+ operation: "toggle_unlimited_quantity"
233
+ })
234
+ });
235
+ });
236
+ it("returns profile selection payload without mutating anything", async () => {
237
+ vi.mocked(resolveVtexWriteProfile).mockResolvedValue({
238
+ ok: false,
239
+ response: { selection: true }
240
+ });
241
+ const result = await toggleUnlimitedQuantityHandler({
242
+ skuId: "sku-3",
243
+ warehouseId: "wh-1",
244
+ unlimitedQuantity: true
245
+ });
246
+ expect(result).toEqual({ selection: true });
247
+ expect(getInventoryByWarehouse).not.toHaveBeenCalled();
248
+ expect(updateInventoryQuantity).not.toHaveBeenCalled();
249
+ });
250
+ it("maps missing inventory snapshots through handleVtexWriteError", async () => {
251
+ vi.mocked(getInventoryByWarehouse).mockResolvedValueOnce([]);
252
+ const result = await toggleUnlimitedQuantityHandler({
253
+ profileId: "custom",
254
+ skuId: "sku-3",
255
+ warehouseId: "wh-1",
256
+ unlimitedQuantity: true
257
+ });
258
+ expect(updateInventoryQuantity).not.toHaveBeenCalled();
259
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
260
+ expect.any(Error),
261
+ "Failed to update unlimited quantity mode for SKU sku-3 in wh-1"
262
+ );
263
+ expect(result).toEqual({
264
+ kind: "error",
265
+ fallback: "Failed to update unlimited quantity mode for SKU sku-3 in wh-1",
266
+ err: expect.any(Error)
267
+ });
268
+ });
269
+ it("maps service errors through handleVtexWriteError", async () => {
270
+ vi.mocked(getInventoryByWarehouse).mockRejectedValue(new Error("boom"));
271
+ const result = await toggleUnlimitedQuantityHandler({
272
+ profileId: "custom",
273
+ skuId: "sku-3",
274
+ warehouseId: "wh-1",
275
+ unlimitedQuantity: true
276
+ });
277
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
278
+ expect.any(Error),
279
+ "Failed to update unlimited quantity mode for SKU sku-3 in wh-1"
280
+ );
281
+ expect(result).toEqual({
282
+ kind: "error",
283
+ fallback: "Failed to update unlimited quantity mode for SKU sku-3 in wh-1",
284
+ err: expect.any(Error)
285
+ });
286
+ });
287
+ });
288
+ describe("updateLeadTimeHandler", () => {
289
+ it("updates lead time and returns before/after snapshots", async () => {
290
+ const beforeInventory = [
291
+ { skuId: "sku-4", warehouseId: "wh-2", leadTime: "1.00:00:00" }
292
+ ];
293
+ const afterInventory = [
294
+ { skuId: "sku-4", warehouseId: "wh-2", leadTime: "2.00:00:00" }
295
+ ];
296
+ vi.mocked(getInventoryByWarehouse).mockResolvedValueOnce(beforeInventory).mockResolvedValueOnce(afterInventory);
297
+ const result = await updateLeadTimeHandler({
298
+ profileId: "custom",
299
+ skuId: "sku-4",
300
+ warehouseId: "wh-2",
301
+ leadTime: "2.00:00:00"
302
+ });
303
+ expect(updateInventoryLeadTime).toHaveBeenCalledWith(
304
+ "profile-1",
305
+ "sku-4",
306
+ "wh-2",
307
+ { leadTime: "2.00:00:00" }
308
+ );
309
+ expect(buildWriteSuccessResponse).toHaveBeenCalledWith({
310
+ profileId: "profile-1",
311
+ operation: "update_lead_time",
312
+ resourceId: "sku-4",
313
+ riskLevel: "low",
314
+ message: "Lead time updated successfully.",
315
+ before: beforeInventory[0],
316
+ after: afterInventory[0],
317
+ details: {
318
+ sku_id: "sku-4",
319
+ warehouse_id: "wh-2",
320
+ lead_time: "2.00:00:00"
321
+ }
322
+ });
323
+ expect(result).toEqual({
324
+ kind: "success",
325
+ params: expect.objectContaining({ operation: "update_lead_time" })
326
+ });
327
+ });
328
+ it("returns profile selection payload without mutating anything", async () => {
329
+ vi.mocked(resolveVtexWriteProfile).mockResolvedValue({
330
+ ok: false,
331
+ response: { selection: true }
332
+ });
333
+ const result = await updateLeadTimeHandler({
334
+ skuId: "sku-4",
335
+ warehouseId: "wh-2",
336
+ leadTime: "2.00:00:00"
337
+ });
338
+ expect(result).toEqual({ selection: true });
339
+ expect(getInventoryByWarehouse).not.toHaveBeenCalled();
340
+ expect(updateInventoryLeadTime).not.toHaveBeenCalled();
341
+ });
342
+ it("maps service errors through handleVtexWriteError", async () => {
343
+ vi.mocked(getInventoryByWarehouse).mockRejectedValue(new Error("boom"));
344
+ const result = await updateLeadTimeHandler({
345
+ profileId: "custom",
346
+ skuId: "sku-4",
347
+ warehouseId: "wh-2",
348
+ leadTime: "2.00:00:00"
349
+ });
350
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
351
+ expect.any(Error),
352
+ "Failed to update lead time for SKU sku-4 in wh-2"
353
+ );
354
+ expect(result).toEqual({
355
+ kind: "error",
356
+ fallback: "Failed to update lead time for SKU sku-4 in wh-2",
357
+ err: expect.any(Error)
358
+ });
359
+ });
360
+ });
361
+ describe("updateInventoryHandler", () => {
362
+ it("updates inventory with forwarded quantity and sync timestamp", async () => {
363
+ const beforeInventory = [
364
+ { skuId: "sku-5", warehouseId: "wh-3", totalQuantity: 4 }
365
+ ];
366
+ const afterInventory = [
367
+ { skuId: "sku-5", warehouseId: "wh-3", totalQuantity: 12 }
368
+ ];
369
+ vi.mocked(getInventoryByWarehouse).mockResolvedValueOnce(beforeInventory).mockResolvedValueOnce(afterInventory);
370
+ const result = await updateInventoryHandler({
371
+ profileId: "custom",
372
+ skuId: "sku-5",
373
+ warehouseId: "wh-3",
374
+ quantity: 12,
375
+ unlimitedQuantity: false,
376
+ dateUtcOnBalanceSystem: "2026-06-01T10:00:00Z"
377
+ });
378
+ expect(updateInventoryQuantity).toHaveBeenCalledWith(
379
+ "profile-1",
380
+ "sku-5",
381
+ "wh-3",
382
+ {
383
+ quantity: 12,
384
+ unlimitedQuantity: false,
385
+ dateUtcOnBalanceSystem: "2026-06-01T10:00:00Z"
386
+ }
387
+ );
388
+ expect(buildWriteSuccessResponse).toHaveBeenCalledWith({
389
+ profileId: "profile-1",
390
+ operation: "update_inventory",
391
+ resourceId: "sku-5",
392
+ riskLevel: "low",
393
+ message: "Inventory quantity updated successfully.",
394
+ before: beforeInventory[0],
395
+ after: afterInventory[0],
396
+ details: {
397
+ sku_id: "sku-5",
398
+ warehouse_id: "wh-3",
399
+ quantity: 12,
400
+ unlimited_quantity: false
401
+ }
402
+ });
403
+ expect(result).toEqual({
404
+ kind: "success",
405
+ params: expect.objectContaining({ operation: "update_inventory" })
406
+ });
407
+ });
408
+ it("returns profile selection payload without mutating anything", async () => {
409
+ vi.mocked(resolveVtexWriteProfile).mockResolvedValue({
410
+ ok: false,
411
+ response: { selection: true }
412
+ });
413
+ const result = await updateInventoryHandler({
414
+ skuId: "sku-5",
415
+ warehouseId: "wh-3",
416
+ quantity: 12,
417
+ unlimitedQuantity: false
418
+ });
419
+ expect(result).toEqual({ selection: true });
420
+ expect(getInventoryByWarehouse).not.toHaveBeenCalled();
421
+ expect(updateInventoryQuantity).not.toHaveBeenCalled();
422
+ });
423
+ it("maps service errors through handleVtexWriteError", async () => {
424
+ vi.mocked(getInventoryByWarehouse).mockRejectedValue(new Error("boom"));
425
+ const result = await updateInventoryHandler({
426
+ profileId: "custom",
427
+ skuId: "sku-5",
428
+ warehouseId: "wh-3",
429
+ quantity: 12,
430
+ unlimitedQuantity: false
431
+ });
432
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
433
+ expect.any(Error),
434
+ "Failed to update inventory quantity for SKU sku-5 in wh-3"
435
+ );
436
+ expect(result).toEqual({
437
+ kind: "error",
438
+ fallback: "Failed to update inventory quantity for SKU sku-5 in wh-3",
439
+ err: expect.any(Error)
440
+ });
441
+ });
442
+ });
443
+ describe("deleteSkuPriceHandler", () => {
444
+ it("requires explicit confirmation before deleting pricing", async () => {
445
+ vi.mocked(requireExplicitConfirmation).mockReturnValue({ confirmation_required: true });
446
+ const result = await deleteSkuPriceHandler({
447
+ profileId: "custom",
448
+ skuId: "sku-7"
449
+ });
450
+ expect(requireExplicitConfirmation).toHaveBeenCalledWith(void 0, "delete_sku_price", {
451
+ sku_id: "sku-7"
452
+ });
453
+ expect(result).toEqual({ confirmation_required: true });
454
+ expect(resolveVtexWriteProfile).not.toHaveBeenCalled();
455
+ expect(deleteSkuPrice).not.toHaveBeenCalled();
456
+ });
457
+ it("deletes pricing and returns the minimal success contract", async () => {
458
+ const result = await deleteSkuPriceHandler({
459
+ profileId: "custom",
460
+ skuId: "sku-7",
461
+ confirmed: true,
462
+ confirmationNote: "User confirmed deleting the SKU price record."
463
+ });
464
+ expect(resolveVtexWriteProfile).toHaveBeenCalledWith("custom");
465
+ expect(deleteSkuPrice).toHaveBeenCalledWith("profile-1", "sku-7");
466
+ expect(result).toEqual({
467
+ content: [
468
+ {
469
+ text: expect.stringContaining('"operation": "delete_sku_price"'),
470
+ type: "text"
471
+ }
472
+ ],
473
+ structuredContent: {
474
+ success: true,
475
+ profile_id: "profile-1",
476
+ operation: "delete_sku_price",
477
+ resource_id: "sku-7",
478
+ risk_level: "high",
479
+ confirmed: true,
480
+ message: "SKU price delete request accepted by VTEX.",
481
+ warnings: [
482
+ "Price reads may remain stale for several minutes after a successful delete while VTEX propagates the change."
483
+ ]
484
+ },
485
+ _meta: {
486
+ mimeType: "application/json"
487
+ }
488
+ });
489
+ expect(buildWriteSuccessResponse).not.toHaveBeenCalled();
490
+ });
491
+ it("maps service errors through handleVtexWriteError", async () => {
492
+ vi.mocked(deleteSkuPrice).mockRejectedValue(new Error("boom"));
493
+ const result = await deleteSkuPriceHandler({
494
+ profileId: "custom",
495
+ skuId: "sku-7",
496
+ confirmed: true
497
+ });
498
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
499
+ expect.any(Error),
500
+ "Failed to delete price for SKU sku-7"
501
+ );
502
+ expect(result).toEqual({
503
+ kind: "error",
504
+ fallback: "Failed to delete price for SKU sku-7",
505
+ err: expect.any(Error)
506
+ });
507
+ });
508
+ });
509
+ describe("updateSkuPriceHandler", () => {
510
+ it("updates sku pricing and re-fetches before/after price snapshots", async () => {
511
+ const beforePrice = { itemId: "sku-6", basePrice: 100, costPrice: 80 };
512
+ const afterPrice = { itemId: "sku-6", basePrice: 120, costPrice: 80 };
513
+ vi.mocked(getSkuPrice).mockResolvedValueOnce(beforePrice).mockResolvedValueOnce(afterPrice);
514
+ const fixedPrices = [
515
+ {
516
+ tradePolicyId: "1",
517
+ value: 110,
518
+ listPrice: 130,
519
+ minQuantity: 2,
520
+ dateRange: {
521
+ from: "2026-06-01T00:00:00Z",
522
+ to: "2026-06-30T00:00:00Z"
523
+ }
524
+ }
525
+ ];
526
+ const result = await updateSkuPriceHandler({
527
+ profileId: "custom",
528
+ skuId: "sku-6",
529
+ basePrice: 120,
530
+ costPrice: 80,
531
+ listPrice: 140,
532
+ fixedPrices
533
+ });
534
+ expect(updateSkuPrice).toHaveBeenCalledWith("profile-1", "sku-6", {
535
+ basePrice: 120,
536
+ costPrice: 80,
537
+ markup: void 0,
538
+ listPrice: 140,
539
+ fixedPrices
540
+ });
541
+ expect(buildWriteSuccessResponse).toHaveBeenCalledWith({
542
+ profileId: "profile-1",
543
+ operation: "update_sku_price",
544
+ resourceId: "sku-6",
545
+ riskLevel: "low",
546
+ message: "SKU price updated successfully.",
547
+ before: beforePrice,
548
+ after: afterPrice,
549
+ details: { sku_id: "sku-6" }
550
+ });
551
+ expect(result).toEqual({
552
+ kind: "success",
553
+ params: expect.objectContaining({ operation: "update_sku_price" })
554
+ });
555
+ });
556
+ it("does not swallow unrelated 404 price lookup failures", async () => {
557
+ const generic404Error = {
558
+ isAxiosError: true,
559
+ response: { status: 404, data: { message: "SKU pricing endpoint unavailable" } },
560
+ message: "Request failed with status code 404"
561
+ };
562
+ vi.mocked(getSkuPrice).mockRejectedValue(generic404Error);
563
+ const result = await updateSkuPriceHandler({
564
+ profileId: "custom",
565
+ skuId: "sku-6",
566
+ basePrice: 120
567
+ });
568
+ expect(updateSkuPrice).not.toHaveBeenCalled();
569
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
570
+ generic404Error,
571
+ "Failed to update price for SKU sku-6"
572
+ );
573
+ expect(result).toEqual({
574
+ kind: "error",
575
+ fallback: "Failed to update price for SKU sku-6",
576
+ err: generic404Error
577
+ });
578
+ });
579
+ it("creates missing pricing when the seed SKU has no price snapshot yet", async () => {
580
+ const missingPriceError = {
581
+ isAxiosError: true,
582
+ response: { status: 404, data: { message: "Price not found" } },
583
+ message: "Request failed with status code 404"
584
+ };
585
+ const afterPrice = { itemId: "sku-6", basePrice: 1e4, listPrice: 1e4 };
586
+ vi.mocked(getSkuPrice).mockRejectedValueOnce(missingPriceError).mockResolvedValueOnce(afterPrice);
587
+ const result = await updateSkuPriceHandler({
588
+ profileId: "custom",
589
+ skuId: "sku-6",
590
+ basePrice: 100,
591
+ listPrice: 100
592
+ });
593
+ expect(updateSkuPrice).toHaveBeenCalledWith("profile-1", "sku-6", {
594
+ basePrice: 100,
595
+ costPrice: void 0,
596
+ markup: void 0,
597
+ listPrice: 100,
598
+ fixedPrices: void 0
599
+ });
600
+ expect(buildWriteSuccessResponse).toHaveBeenCalledWith({
601
+ profileId: "profile-1",
602
+ operation: "update_sku_price",
603
+ resourceId: "sku-6",
604
+ riskLevel: "low",
605
+ message: "SKU price updated successfully.",
606
+ before: null,
607
+ after: afterPrice,
608
+ details: { sku_id: "sku-6" }
609
+ });
610
+ expect(result).toEqual({
611
+ kind: "success",
612
+ params: expect.objectContaining({ operation: "update_sku_price" })
613
+ });
614
+ });
615
+ it("returns profile selection payload without mutating anything", async () => {
616
+ vi.mocked(resolveVtexWriteProfile).mockResolvedValue({
617
+ ok: false,
618
+ response: { selection: true }
619
+ });
620
+ const result = await updateSkuPriceHandler({
621
+ skuId: "sku-6",
622
+ basePrice: 120
623
+ });
624
+ expect(result).toEqual({ selection: true });
625
+ expect(getSkuPrice).not.toHaveBeenCalled();
626
+ expect(updateSkuPrice).not.toHaveBeenCalled();
627
+ });
628
+ it("maps service errors through handleVtexWriteError", async () => {
629
+ vi.mocked(getSkuPrice).mockRejectedValue(new Error("boom"));
630
+ const result = await updateSkuPriceHandler({
631
+ profileId: "custom",
632
+ skuId: "sku-6",
633
+ basePrice: 120
634
+ });
635
+ expect(handleVtexWriteError).toHaveBeenCalledWith(
636
+ expect.any(Error),
637
+ "Failed to update price for SKU sku-6"
638
+ );
639
+ expect(result).toEqual({
640
+ kind: "error",
641
+ fallback: "Failed to update price for SKU sku-6",
642
+ err: expect.any(Error)
643
+ });
644
+ });
645
+ });
646
+ });
647
+ //# sourceMappingURL=vtex-write-simple-tools.test.js.map