@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,251 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ const getOrderDocumentMock = vi.fn();
3
+ vi.mock("../vtex-orders.js", () => ({
4
+ getOrderDocument: getOrderDocumentMock
5
+ }));
6
+ const ordersWrite = await import("../vtex-orders-write.js");
7
+ describe("VTEX order write state validation", () => {
8
+ beforeEach(() => {
9
+ vi.clearAllMocks();
10
+ });
11
+ describe("getOrderStateSnapshot", () => {
12
+ it("shapes the snapshot and extracts invoice numbers from invoices and outputs", async () => {
13
+ getOrderDocumentMock.mockResolvedValueOnce({
14
+ status: "handling",
15
+ state: "payment-approved",
16
+ allowCancellation: true,
17
+ invoicedDate: 1717171717,
18
+ invoiceData: {
19
+ invoices: [
20
+ { invoiceNumber: 1234 },
21
+ { number: "A-100" },
22
+ { invoiceId: "INV-9" },
23
+ { receipt: "RCPT-1" },
24
+ { invoiceNumber: 1234 }
25
+ ],
26
+ invoiceOutput: ["A-100", 555, null]
27
+ }
28
+ });
29
+ const snapshot = await ordersWrite.getOrderStateSnapshot(
30
+ "profile-1",
31
+ "order-1",
32
+ "validation-reason"
33
+ );
34
+ expect(getOrderDocumentMock).toHaveBeenCalledWith(
35
+ "profile-1",
36
+ "order-1",
37
+ "validation-reason"
38
+ );
39
+ expect(snapshot).toEqual({
40
+ orderId: "order-1",
41
+ status: "handling",
42
+ state: "payment-approved",
43
+ allowCancellation: true,
44
+ invoicedDate: "1717171717",
45
+ invoiceNumbers: ["1234", "A-100", "INV-9", "RCPT-1", "555"]
46
+ });
47
+ });
48
+ it("returns an empty invoice list when invoice data is missing or malformed", async () => {
49
+ getOrderDocumentMock.mockResolvedValueOnce({
50
+ status: null,
51
+ state: void 0,
52
+ allowCancellation: "yes",
53
+ invoicedDate: null,
54
+ invoiceData: "unexpected"
55
+ });
56
+ const snapshot = await ordersWrite.getOrderStateSnapshot("profile-1", "order-2");
57
+ expect(snapshot).toEqual({
58
+ orderId: "order-2",
59
+ status: void 0,
60
+ state: void 0,
61
+ allowCancellation: void 0,
62
+ invoicedDate: void 0,
63
+ invoiceNumbers: []
64
+ });
65
+ });
66
+ });
67
+ describe("validateOrderForCancellation", () => {
68
+ it("returns the snapshot when the order is still cancelable", async () => {
69
+ getOrderDocumentMock.mockResolvedValueOnce({
70
+ status: "handling",
71
+ state: "handling",
72
+ allowCancellation: true
73
+ });
74
+ await expect(
75
+ ordersWrite.validateOrderForCancellation("profile-1", "order-1", "customer-request")
76
+ ).resolves.toEqual({
77
+ orderId: "order-1",
78
+ status: "handling",
79
+ state: "handling",
80
+ allowCancellation: true,
81
+ invoicedDate: void 0,
82
+ invoiceNumbers: []
83
+ });
84
+ });
85
+ it("rejects cancellation for orders already canceled", async () => {
86
+ getOrderDocumentMock.mockResolvedValueOnce({ status: "canceled", state: "cancelled" });
87
+ await expect(
88
+ ordersWrite.validateOrderForCancellation("profile-1", "order-1")
89
+ ).rejects.toMatchObject({
90
+ name: "VtexOperationError",
91
+ code: "INVALID_ORDER_STATE",
92
+ message: "Order is already canceled.",
93
+ details: {
94
+ status: "canceled",
95
+ state: "cancelled"
96
+ }
97
+ });
98
+ });
99
+ it("rejects cancellation when VTEX disallows it", async () => {
100
+ getOrderDocumentMock.mockResolvedValueOnce({
101
+ status: "handling",
102
+ state: "handling",
103
+ allowCancellation: false
104
+ });
105
+ await expect(
106
+ ordersWrite.validateOrderForCancellation("profile-1", "order-1")
107
+ ).rejects.toMatchObject({
108
+ name: "VtexOperationError",
109
+ code: "INVALID_ORDER_STATE",
110
+ message: "VTEX reports that this order can no longer be canceled."
111
+ });
112
+ });
113
+ it("rejects cancellation for invoiced orders", async () => {
114
+ getOrderDocumentMock.mockResolvedValueOnce({
115
+ status: "handling",
116
+ state: "handling",
117
+ allowCancellation: true,
118
+ invoicedDate: "2026-06-06T10:00:00.000Z"
119
+ });
120
+ await expect(
121
+ ordersWrite.validateOrderForCancellation("profile-1", "order-1")
122
+ ).rejects.toMatchObject({
123
+ name: "VtexOperationError",
124
+ code: "INVALID_ORDER_STATE",
125
+ message: "Order is already invoiced, so VTEX no longer allows cancellation.",
126
+ details: {
127
+ invoiced_date: "2026-06-06T10:00:00.000Z"
128
+ }
129
+ });
130
+ });
131
+ });
132
+ describe("validateOrderForInvoice", () => {
133
+ it("returns the snapshot when the order can be invoiced", async () => {
134
+ getOrderDocumentMock.mockResolvedValueOnce({ status: "ready-for-handling", state: "ready" });
135
+ await expect(ordersWrite.validateOrderForInvoice("profile-1", "order-3")).resolves.toEqual({
136
+ orderId: "order-3",
137
+ status: "ready-for-handling",
138
+ state: "ready",
139
+ allowCancellation: void 0,
140
+ invoicedDate: void 0,
141
+ invoiceNumbers: []
142
+ });
143
+ });
144
+ it("rejects invoicing for canceled orders", async () => {
145
+ getOrderDocumentMock.mockResolvedValueOnce({ status: "canceling", state: "handling" });
146
+ await expect(ordersWrite.validateOrderForInvoice("profile-1", "order-3")).rejects.toMatchObject({
147
+ name: "VtexOperationError",
148
+ code: "INVALID_ORDER_STATE",
149
+ message: "Canceled orders cannot be invoiced."
150
+ });
151
+ });
152
+ it("rejects invoicing when invoice data already exists", async () => {
153
+ getOrderDocumentMock.mockResolvedValueOnce({
154
+ status: "handling",
155
+ state: "handling",
156
+ invoicedDate: "2026-06-06",
157
+ invoiceData: {
158
+ invoices: [{ invoiceNumber: "INV-1" }]
159
+ }
160
+ });
161
+ await expect(ordersWrite.validateOrderForInvoice("profile-1", "order-3")).rejects.toMatchObject({
162
+ name: "VtexOperationError",
163
+ code: "INVALID_ORDER_STATE",
164
+ message: "Order already contains invoice data.",
165
+ details: {
166
+ invoiced_date: "2026-06-06",
167
+ invoice_numbers: ["INV-1"]
168
+ }
169
+ });
170
+ });
171
+ });
172
+ describe("validateOrderForTracking", () => {
173
+ it("returns the snapshot when the invoice exists on the order", async () => {
174
+ getOrderDocumentMock.mockResolvedValueOnce({
175
+ status: "invoiced",
176
+ state: "handling",
177
+ invoiceData: {
178
+ invoices: [{ invoiceNumber: "INV-10" }]
179
+ }
180
+ });
181
+ await expect(
182
+ ordersWrite.validateOrderForTracking("profile-1", "order-4", "INV-10")
183
+ ).resolves.toEqual({
184
+ orderId: "order-4",
185
+ status: "invoiced",
186
+ state: "handling",
187
+ allowCancellation: void 0,
188
+ invoicedDate: void 0,
189
+ invoiceNumbers: ["INV-10"]
190
+ });
191
+ });
192
+ it("allows tracking when VTEX marks the order invoiced even without invoice numbers", async () => {
193
+ getOrderDocumentMock.mockResolvedValueOnce({
194
+ status: "invoiced",
195
+ state: "handling",
196
+ invoicedDate: "2026-06-06T10:00:00.000Z"
197
+ });
198
+ await expect(
199
+ ordersWrite.validateOrderForTracking("profile-1", "order-5", "INV-MISSING")
200
+ ).resolves.toEqual({
201
+ orderId: "order-5",
202
+ status: "invoiced",
203
+ state: "handling",
204
+ allowCancellation: void 0,
205
+ invoicedDate: "2026-06-06T10:00:00.000Z",
206
+ invoiceNumbers: []
207
+ });
208
+ });
209
+ it("rejects tracking for canceled orders", async () => {
210
+ getOrderDocumentMock.mockResolvedValueOnce({ status: "canceled", state: "handling" });
211
+ await expect(
212
+ ordersWrite.validateOrderForTracking("profile-1", "order-4", "INV-10")
213
+ ).rejects.toMatchObject({
214
+ name: "VtexOperationError",
215
+ code: "INVALID_ORDER_STATE",
216
+ message: "Canceled orders cannot receive tracking updates."
217
+ });
218
+ });
219
+ it("rejects tracking when the order is not invoiced yet", async () => {
220
+ getOrderDocumentMock.mockResolvedValueOnce({ status: "handling", state: "handling" });
221
+ await expect(
222
+ ordersWrite.validateOrderForTracking("profile-1", "order-4", "INV-10")
223
+ ).rejects.toMatchObject({
224
+ name: "VtexOperationError",
225
+ code: "INVALID_ORDER_STATE",
226
+ message: "Order is not invoiced yet, so tracking cannot be added."
227
+ });
228
+ });
229
+ it("rejects tracking when the provided invoice number does not exist in VTEX", async () => {
230
+ getOrderDocumentMock.mockResolvedValueOnce({
231
+ status: "invoiced",
232
+ state: "handling",
233
+ invoiceData: {
234
+ invoices: [{ invoiceNumber: "INV-11" }]
235
+ }
236
+ });
237
+ await expect(
238
+ ordersWrite.validateOrderForTracking("profile-1", "order-4", "INV-99")
239
+ ).rejects.toMatchObject({
240
+ name: "VtexOperationError",
241
+ code: "INVALID_OPERATION",
242
+ message: "The provided invoice number is not present in VTEX for this order.",
243
+ details: {
244
+ provided_invoice_number: "INV-99",
245
+ known_invoice_numbers: ["INV-11"]
246
+ }
247
+ });
248
+ });
249
+ });
250
+ });
251
+ //# sourceMappingURL=vtex-orders-write-state-validation.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/services/vtex/__tests__/vtex-orders-write-state-validation.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nconst getOrderDocumentMock = vi.fn();\n\nvi.mock(\"../vtex-orders.js\", () => ({\n getOrderDocument: getOrderDocumentMock,\n}));\n\nconst ordersWrite = await import(\"../vtex-orders-write.js\");\n\ndescribe(\"VTEX order write state validation\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n describe(\"getOrderStateSnapshot\", () => {\n it(\"shapes the snapshot and extracts invoice numbers from invoices and outputs\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: \"handling\",\n state: \"payment-approved\",\n allowCancellation: true,\n invoicedDate: 1717171717,\n invoiceData: {\n invoices: [\n { invoiceNumber: 1234 },\n { number: \"A-100\" },\n { invoiceId: \"INV-9\" },\n { receipt: \"RCPT-1\" },\n { invoiceNumber: 1234 },\n ],\n invoiceOutput: [\"A-100\", 555, null],\n },\n });\n\n const snapshot = await ordersWrite.getOrderStateSnapshot(\n \"profile-1\",\n \"order-1\",\n \"validation-reason\"\n );\n\n expect(getOrderDocumentMock).toHaveBeenCalledWith(\n \"profile-1\",\n \"order-1\",\n \"validation-reason\"\n );\n expect(snapshot).toEqual({\n orderId: \"order-1\",\n status: \"handling\",\n state: \"payment-approved\",\n allowCancellation: true,\n invoicedDate: \"1717171717\",\n invoiceNumbers: [\"1234\", \"A-100\", \"INV-9\", \"RCPT-1\", \"555\"],\n });\n });\n\n it(\"returns an empty invoice list when invoice data is missing or malformed\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: null,\n state: undefined,\n allowCancellation: \"yes\",\n invoicedDate: null,\n invoiceData: \"unexpected\",\n });\n\n const snapshot = await ordersWrite.getOrderStateSnapshot(\"profile-1\", \"order-2\");\n\n expect(snapshot).toEqual({\n orderId: \"order-2\",\n status: undefined,\n state: undefined,\n allowCancellation: undefined,\n invoicedDate: undefined,\n invoiceNumbers: [],\n });\n });\n });\n\n describe(\"validateOrderForCancellation\", () => {\n it(\"returns the snapshot when the order is still cancelable\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: \"handling\",\n state: \"handling\",\n allowCancellation: true,\n });\n\n await expect(\n ordersWrite.validateOrderForCancellation(\"profile-1\", \"order-1\", \"customer-request\")\n ).resolves.toEqual({\n orderId: \"order-1\",\n status: \"handling\",\n state: \"handling\",\n allowCancellation: true,\n invoicedDate: undefined,\n invoiceNumbers: [],\n });\n });\n\n it(\"rejects cancellation for orders already canceled\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({ status: \"canceled\", state: \"cancelled\" });\n\n await expect(\n ordersWrite.validateOrderForCancellation(\"profile-1\", \"order-1\")\n ).rejects.toMatchObject({\n name: \"VtexOperationError\",\n code: \"INVALID_ORDER_STATE\",\n message: \"Order is already canceled.\",\n details: {\n status: \"canceled\",\n state: \"cancelled\",\n },\n });\n });\n\n it(\"rejects cancellation when VTEX disallows it\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: \"handling\",\n state: \"handling\",\n allowCancellation: false,\n });\n\n await expect(\n ordersWrite.validateOrderForCancellation(\"profile-1\", \"order-1\")\n ).rejects.toMatchObject({\n name: \"VtexOperationError\",\n code: \"INVALID_ORDER_STATE\",\n message: \"VTEX reports that this order can no longer be canceled.\",\n });\n });\n\n it(\"rejects cancellation for invoiced orders\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: \"handling\",\n state: \"handling\",\n allowCancellation: true,\n invoicedDate: \"2026-06-06T10:00:00.000Z\",\n });\n\n await expect(\n ordersWrite.validateOrderForCancellation(\"profile-1\", \"order-1\")\n ).rejects.toMatchObject({\n name: \"VtexOperationError\",\n code: \"INVALID_ORDER_STATE\",\n message: \"Order is already invoiced, so VTEX no longer allows cancellation.\",\n details: {\n invoiced_date: \"2026-06-06T10:00:00.000Z\",\n },\n });\n });\n });\n\n describe(\"validateOrderForInvoice\", () => {\n it(\"returns the snapshot when the order can be invoiced\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({ status: \"ready-for-handling\", state: \"ready\" });\n\n await expect(ordersWrite.validateOrderForInvoice(\"profile-1\", \"order-3\")).resolves.toEqual({\n orderId: \"order-3\",\n status: \"ready-for-handling\",\n state: \"ready\",\n allowCancellation: undefined,\n invoicedDate: undefined,\n invoiceNumbers: [],\n });\n });\n\n it(\"rejects invoicing for canceled orders\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({ status: \"canceling\", state: \"handling\" });\n\n await expect(ordersWrite.validateOrderForInvoice(\"profile-1\", \"order-3\")).rejects.toMatchObject({\n name: \"VtexOperationError\",\n code: \"INVALID_ORDER_STATE\",\n message: \"Canceled orders cannot be invoiced.\",\n });\n });\n\n it(\"rejects invoicing when invoice data already exists\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: \"handling\",\n state: \"handling\",\n invoicedDate: \"2026-06-06\",\n invoiceData: {\n invoices: [{ invoiceNumber: \"INV-1\" }],\n },\n });\n\n await expect(ordersWrite.validateOrderForInvoice(\"profile-1\", \"order-3\")).rejects.toMatchObject({\n name: \"VtexOperationError\",\n code: \"INVALID_ORDER_STATE\",\n message: \"Order already contains invoice data.\",\n details: {\n invoiced_date: \"2026-06-06\",\n invoice_numbers: [\"INV-1\"],\n },\n });\n });\n });\n\n describe(\"validateOrderForTracking\", () => {\n it(\"returns the snapshot when the invoice exists on the order\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: \"invoiced\",\n state: \"handling\",\n invoiceData: {\n invoices: [{ invoiceNumber: \"INV-10\" }],\n },\n });\n\n await expect(\n ordersWrite.validateOrderForTracking(\"profile-1\", \"order-4\", \"INV-10\")\n ).resolves.toEqual({\n orderId: \"order-4\",\n status: \"invoiced\",\n state: \"handling\",\n allowCancellation: undefined,\n invoicedDate: undefined,\n invoiceNumbers: [\"INV-10\"],\n });\n });\n\n it(\"allows tracking when VTEX marks the order invoiced even without invoice numbers\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: \"invoiced\",\n state: \"handling\",\n invoicedDate: \"2026-06-06T10:00:00.000Z\",\n });\n\n await expect(\n ordersWrite.validateOrderForTracking(\"profile-1\", \"order-5\", \"INV-MISSING\")\n ).resolves.toEqual({\n orderId: \"order-5\",\n status: \"invoiced\",\n state: \"handling\",\n allowCancellation: undefined,\n invoicedDate: \"2026-06-06T10:00:00.000Z\",\n invoiceNumbers: [],\n });\n });\n\n it(\"rejects tracking for canceled orders\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({ status: \"canceled\", state: \"handling\" });\n\n await expect(\n ordersWrite.validateOrderForTracking(\"profile-1\", \"order-4\", \"INV-10\")\n ).rejects.toMatchObject({\n name: \"VtexOperationError\",\n code: \"INVALID_ORDER_STATE\",\n message: \"Canceled orders cannot receive tracking updates.\",\n });\n });\n\n it(\"rejects tracking when the order is not invoiced yet\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({ status: \"handling\", state: \"handling\" });\n\n await expect(\n ordersWrite.validateOrderForTracking(\"profile-1\", \"order-4\", \"INV-10\")\n ).rejects.toMatchObject({\n name: \"VtexOperationError\",\n code: \"INVALID_ORDER_STATE\",\n message: \"Order is not invoiced yet, so tracking cannot be added.\",\n });\n });\n\n it(\"rejects tracking when the provided invoice number does not exist in VTEX\", async () => {\n getOrderDocumentMock.mockResolvedValueOnce({\n status: \"invoiced\",\n state: \"handling\",\n invoiceData: {\n invoices: [{ invoiceNumber: \"INV-11\" }],\n },\n });\n\n await expect(\n ordersWrite.validateOrderForTracking(\"profile-1\", \"order-4\", \"INV-99\")\n ).rejects.toMatchObject({\n name: \"VtexOperationError\",\n code: \"INVALID_OPERATION\",\n message: \"The provided invoice number is not present in VTEX for this order.\",\n details: {\n provided_invoice_number: \"INV-99\",\n known_invoice_numbers: [\"INV-11\"],\n },\n });\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,111 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ classifyVtexWriteRisk,
4
+ getPreviewRequirements
5
+ } from "../vtex-write.js";
6
+ describe("vtex-write risk and preview contracts", () => {
7
+ describe("classifyVtexWriteRisk", () => {
8
+ it("keeps low-risk operations as low", () => {
9
+ const result = classifyVtexWriteRisk({
10
+ requestedRiskLevel: "low",
11
+ preflight: {
12
+ entities: 1,
13
+ entityTypes: ["product"],
14
+ destructive: false,
15
+ hasDeleteOrReplaceAll: false,
16
+ dependencyFailureCount: 0,
17
+ multiEntityCriticalReassignment: false
18
+ }
19
+ });
20
+ expect(result.requested_risk_level).toBe("low");
21
+ expect(result.effective_risk_level).toBe("low");
22
+ expect(result.escalated).toBe(false);
23
+ expect(result.escalation_reasons).toEqual([]);
24
+ });
25
+ it("keeps medium-risk operations as medium when preflight is under thresholds", () => {
26
+ const result = classifyVtexWriteRisk({
27
+ requestedRiskLevel: "medium",
28
+ preflight: {
29
+ entities: 3,
30
+ entityTypes: ["product", "sku"],
31
+ destructive: false,
32
+ hasDeleteOrReplaceAll: false,
33
+ dependencyFailureCount: 0,
34
+ multiEntityCriticalReassignment: false
35
+ }
36
+ });
37
+ expect(result.effective_risk_level).toBe("medium");
38
+ expect(result.escalated).toBe(false);
39
+ expect(result.escalation_reasons).toEqual([]);
40
+ });
41
+ it("keeps high-risk operations as high", () => {
42
+ const result = classifyVtexWriteRisk({
43
+ requestedRiskLevel: "high",
44
+ preflight: {
45
+ entities: 1,
46
+ entityTypes: ["product"],
47
+ destructive: false,
48
+ hasDeleteOrReplaceAll: false,
49
+ dependencyFailureCount: 0,
50
+ multiEntityCriticalReassignment: false
51
+ }
52
+ });
53
+ expect(result.effective_risk_level).toBe("high");
54
+ expect(result.escalated).toBe(false);
55
+ });
56
+ it("escalates medium-risk to high when entity threshold is exceeded", () => {
57
+ const result = classifyVtexWriteRisk({
58
+ requestedRiskLevel: "medium",
59
+ preflight: {
60
+ entities: 11,
61
+ entityTypes: ["product"],
62
+ destructive: false,
63
+ hasDeleteOrReplaceAll: false,
64
+ dependencyFailureCount: 0,
65
+ multiEntityCriticalReassignment: false
66
+ }
67
+ });
68
+ expect(result.effective_risk_level).toBe("high");
69
+ expect(result.escalated).toBe(true);
70
+ expect(result.escalation_reasons).toContain("entities_threshold_exceeded");
71
+ });
72
+ it("escalates medium-risk to high when operation is destructive", () => {
73
+ const result = classifyVtexWriteRisk({
74
+ requestedRiskLevel: "medium",
75
+ preflight: {
76
+ entities: 2,
77
+ entityTypes: ["product"],
78
+ destructive: true,
79
+ hasDeleteOrReplaceAll: false,
80
+ dependencyFailureCount: 0,
81
+ multiEntityCriticalReassignment: false
82
+ }
83
+ });
84
+ expect(result.effective_risk_level).toBe("high");
85
+ expect(result.escalated).toBe(true);
86
+ expect(result.escalation_reasons).toContain("destructive_operation_detected");
87
+ });
88
+ });
89
+ describe("getPreviewRequirements", () => {
90
+ it("does not require preview for low risk", () => {
91
+ const result = getPreviewRequirements("low");
92
+ expect(result.preview_required).toBe(false);
93
+ expect(result.apply_requires_confirmation).toBe(false);
94
+ expect(result.preview_id_required_for_apply).toBe(false);
95
+ });
96
+ it("does not require preview for medium risk", () => {
97
+ const result = getPreviewRequirements("medium");
98
+ expect(result.preview_required).toBe(false);
99
+ expect(result.apply_requires_confirmation).toBe(false);
100
+ expect(result.preview_id_required_for_apply).toBe(false);
101
+ });
102
+ it("requires preview and confirmation for high risk", () => {
103
+ const result = getPreviewRequirements("high");
104
+ expect(result.preview_required).toBe(true);
105
+ expect(result.apply_requires_confirmation).toBe(true);
106
+ expect(result.preview_id_required_for_apply).toBe(true);
107
+ expect(result.reason).toContain("high-risk");
108
+ });
109
+ });
110
+ });
111
+ //# sourceMappingURL=vtex-write.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/services/vtex/__tests__/vtex-write.test.ts"],
4
+ "sourcesContent": ["import { describe, expect, it } from \"vitest\";\n\nimport {\n classifyVtexWriteRisk,\n getPreviewRequirements,\n} from \"../vtex-write.js\";\n\ndescribe(\"vtex-write risk and preview contracts\", () => {\n describe(\"classifyVtexWriteRisk\", () => {\n it(\"keeps low-risk operations as low\", () => {\n const result = classifyVtexWriteRisk({\n requestedRiskLevel: \"low\",\n preflight: {\n entities: 1,\n entityTypes: [\"product\"],\n destructive: false,\n hasDeleteOrReplaceAll: false,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n });\n\n expect(result.requested_risk_level).toBe(\"low\");\n expect(result.effective_risk_level).toBe(\"low\");\n expect(result.escalated).toBe(false);\n expect(result.escalation_reasons).toEqual([]);\n });\n\n it(\"keeps medium-risk operations as medium when preflight is under thresholds\", () => {\n const result = classifyVtexWriteRisk({\n requestedRiskLevel: \"medium\",\n preflight: {\n entities: 3,\n entityTypes: [\"product\", \"sku\"],\n destructive: false,\n hasDeleteOrReplaceAll: false,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n });\n\n expect(result.effective_risk_level).toBe(\"medium\");\n expect(result.escalated).toBe(false);\n expect(result.escalation_reasons).toEqual([]);\n });\n\n it(\"keeps high-risk operations as high\", () => {\n const result = classifyVtexWriteRisk({\n requestedRiskLevel: \"high\",\n preflight: {\n entities: 1,\n entityTypes: [\"product\"],\n destructive: false,\n hasDeleteOrReplaceAll: false,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n });\n\n expect(result.effective_risk_level).toBe(\"high\");\n expect(result.escalated).toBe(false);\n });\n\n it(\"escalates medium-risk to high when entity threshold is exceeded\", () => {\n const result = classifyVtexWriteRisk({\n requestedRiskLevel: \"medium\",\n preflight: {\n entities: 11,\n entityTypes: [\"product\"],\n destructive: false,\n hasDeleteOrReplaceAll: false,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n });\n\n expect(result.effective_risk_level).toBe(\"high\");\n expect(result.escalated).toBe(true);\n expect(result.escalation_reasons).toContain(\"entities_threshold_exceeded\");\n });\n\n it(\"escalates medium-risk to high when operation is destructive\", () => {\n const result = classifyVtexWriteRisk({\n requestedRiskLevel: \"medium\",\n preflight: {\n entities: 2,\n entityTypes: [\"product\"],\n destructive: true,\n hasDeleteOrReplaceAll: false,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n });\n\n expect(result.effective_risk_level).toBe(\"high\");\n expect(result.escalated).toBe(true);\n expect(result.escalation_reasons).toContain(\"destructive_operation_detected\");\n });\n });\n\n describe(\"getPreviewRequirements\", () => {\n it(\"does not require preview for low risk\", () => {\n const result = getPreviewRequirements(\"low\");\n\n expect(result.preview_required).toBe(false);\n expect(result.apply_requires_confirmation).toBe(false);\n expect(result.preview_id_required_for_apply).toBe(false);\n });\n\n it(\"does not require preview for medium risk\", () => {\n const result = getPreviewRequirements(\"medium\");\n\n expect(result.preview_required).toBe(false);\n expect(result.apply_requires_confirmation).toBe(false);\n expect(result.preview_id_required_for_apply).toBe(false);\n });\n\n it(\"requires preview and confirmation for high risk\", () => {\n const result = getPreviewRequirements(\"high\");\n\n expect(result.preview_required).toBe(true);\n expect(result.apply_requires_confirmation).toBe(true);\n expect(result.preview_id_required_for_apply).toBe(true);\n expect(result.reason).toContain(\"high-risk\");\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -151,6 +151,37 @@ async function deleteAllSkuEans(profileId, skuId) {
151
151
  const { vtexApi } = await getVtexApiClients(profileId);
152
152
  await vtexApi.delete(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean`);
153
153
  }
154
+ function normalizeEans(eans) {
155
+ const normalized = eans.map((ean) => ean.trim()).filter(Boolean);
156
+ return [...new Set(normalized)];
157
+ }
158
+ async function addSkuEan(profileId, skuId, ean) {
159
+ const normalized = ean.trim();
160
+ if (!normalized) {
161
+ return getSkuEans(profileId, skuId);
162
+ }
163
+ await createSkuEan(profileId, skuId, normalized);
164
+ return getSkuEans(profileId, skuId);
165
+ }
166
+ async function replaceSkuEans(profileId, skuId, eans) {
167
+ await deleteAllSkuEans(profileId, skuId);
168
+ for (const ean of normalizeEans(eans)) {
169
+ await createSkuEan(profileId, skuId, ean);
170
+ }
171
+ return getSkuEans(profileId, skuId);
172
+ }
173
+ async function updateProductBasicFields(profileId, productId, updates) {
174
+ const before = await getProduct(profileId, productId);
175
+ const payload = buildProductUpdatePayload(before, updates);
176
+ const after = await updateProduct(profileId, productId, payload);
177
+ return { before, payload, after };
178
+ }
179
+ async function updateSkuBasicFields(profileId, skuId, updates) {
180
+ const before = await getSku(profileId, skuId);
181
+ const payload = buildSkuUpdatePayload(before, updates);
182
+ const after = await updateSku(profileId, skuId, payload);
183
+ return { before, payload, after };
184
+ }
154
185
  async function createBrand(profileId, payload) {
155
186
  const { vtexApi } = await getVtexApiClients(profileId);
156
187
  const response = await vtexApi.post("/api/catalog/pvt/brand", payload);
@@ -161,6 +192,35 @@ async function getBrand(profileId, brandId) {
161
192
  const response = await vtexApi.get(`/api/catalog/pvt/brand/${brandId}`);
162
193
  return response.data;
163
194
  }
195
+ async function updateBrand(profileId, brandId, payload) {
196
+ const { vtexApi } = await getVtexApiClients(profileId);
197
+ const response = await vtexApi.put(`/api/catalog/pvt/brand/${brandId}`, payload);
198
+ return response.data;
199
+ }
200
+ function buildBrandUpdatePayload(current, updates) {
201
+ const payload = pickRecord(current, [
202
+ "Id",
203
+ "Name",
204
+ "Text",
205
+ "Keywords",
206
+ "SiteTitle",
207
+ "Active",
208
+ "MenuHome",
209
+ "LinkId",
210
+ "Score",
211
+ "AdWordsRemarketingCode",
212
+ "LomadeeCampaignCode"
213
+ ]);
214
+ if (updates.name !== void 0) payload.Name = updates.name;
215
+ if (updates.text !== void 0) payload.Text = updates.text;
216
+ if (updates.keywords !== void 0) payload.Keywords = updates.keywords;
217
+ if (updates.siteTitle !== void 0) payload.SiteTitle = updates.siteTitle;
218
+ if (updates.active !== void 0) payload.Active = updates.active;
219
+ if (updates.menuHome !== void 0) payload.MenuHome = updates.menuHome;
220
+ if (updates.linkId !== void 0) payload.LinkId = updates.linkId;
221
+ if (updates.score !== void 0) payload.Score = updates.score;
222
+ return payload;
223
+ }
164
224
  async function createCategory(profileId, payload) {
165
225
  const { vtexApi } = await getVtexApiClients(profileId);
166
226
  const response = await vtexApi.post("/api/catalog/pvt/category", payload);
@@ -171,11 +231,54 @@ async function getCategory(profileId, categoryId) {
171
231
  const response = await vtexApi.get(`/api/catalog/pvt/category/${categoryId}`);
172
232
  return response.data;
173
233
  }
234
+ async function updateCategory(profileId, categoryId, payload) {
235
+ const { vtexApi } = await getVtexApiClients(profileId);
236
+ const response = await vtexApi.put(`/api/catalog/pvt/category/${categoryId}`, payload);
237
+ return response.data;
238
+ }
239
+ function buildCategoryUpdatePayload(current, updates) {
240
+ const payload = pickRecord(current, [
241
+ "Id",
242
+ "Name",
243
+ "Keywords",
244
+ "Title",
245
+ "Description",
246
+ "AdWordsRemarketingCode",
247
+ "LomadeeCampaignCode",
248
+ "FatherCategoryId",
249
+ "GlobalCategoryId",
250
+ "ShowInStoreFront",
251
+ "IsActive",
252
+ "ActiveStoreFrontLink",
253
+ "ShowBrandFilter",
254
+ "Score",
255
+ "StockKeepingUnitSelectionMode"
256
+ ]);
257
+ if (updates.name !== void 0) payload.Name = updates.name;
258
+ if (updates.title !== void 0) payload.Title = updates.title;
259
+ if (updates.description !== void 0) payload.Description = updates.description;
260
+ if (updates.keywords !== void 0) payload.Keywords = updates.keywords;
261
+ if (updates.isActive !== void 0) payload.IsActive = updates.isActive;
262
+ if (updates.fatherCategoryId !== void 0) {
263
+ payload.FatherCategoryId = updates.fatherCategoryId;
264
+ }
265
+ return payload;
266
+ }
174
267
  async function createSpecification(profileId, payload) {
175
268
  const { vtexApi } = await getVtexApiClients(profileId);
176
269
  const response = await vtexApi.post("/api/catalog/pvt/specification", payload);
177
270
  return response.data;
178
271
  }
272
+ async function getSpecification(profileId, fieldId) {
273
+ const { vtexApi } = await getVtexApiClients(profileId);
274
+ const response = await vtexApi.get(`/api/catalog/pvt/specification/${fieldId}`);
275
+ return response.data;
276
+ }
277
+ async function updateSpecification(profileId, fieldId, payload) {
278
+ const { vtexApi } = await getVtexApiClients(profileId);
279
+ const response = await vtexApi.put(`/api/catalog/pvt/specification/${fieldId}`, payload);
280
+ return response.data;
281
+ }
179
282
  async function createSpecificationValue(profileId, payload) {
180
283
  const { vtexApi } = await getVtexApiClients(profileId);
181
284
  const response = await vtexApi.post(
@@ -184,6 +287,21 @@ async function createSpecificationValue(profileId, payload) {
184
287
  );
185
288
  return response.data;
186
289
  }
290
+ async function getSpecificationValue(profileId, fieldValueId) {
291
+ const { vtexApi } = await getVtexApiClients(profileId);
292
+ const response = await vtexApi.get(
293
+ `/api/catalog/pvt/specificationvalue/${fieldValueId}`
294
+ );
295
+ return response.data;
296
+ }
297
+ async function updateSpecificationValue(profileId, fieldValueId, payload) {
298
+ const { vtexApi } = await getVtexApiClients(profileId);
299
+ const response = await vtexApi.put(
300
+ `/api/catalog/pvt/specificationvalue/${fieldValueId}`,
301
+ payload
302
+ );
303
+ return response.data;
304
+ }
187
305
  async function associateProductSpecification(profileId, productId, payload) {
188
306
  const { vtexApi } = await getVtexApiClients(profileId);
189
307
  const response = await vtexApi.post(
@@ -192,6 +310,39 @@ async function associateProductSpecification(profileId, productId, payload) {
192
310
  );
193
311
  return response.data;
194
312
  }
313
+ async function getProductSpecifications(profileId, productId) {
314
+ const { vtexApi } = await getVtexApiClients(profileId);
315
+ const response = await vtexApi.get(`/api/catalog/pvt/product/${productId}/specification`);
316
+ const data = response.data;
317
+ if (!Array.isArray(data)) {
318
+ return [];
319
+ }
320
+ return data.filter((item) => item !== null && typeof item === "object");
321
+ }
322
+ async function deleteProductSpecification(profileId, productId, specificationId) {
323
+ const { vtexApi } = await getVtexApiClients(profileId);
324
+ await vtexApi.delete(`/api/catalog/pvt/product/${productId}/specification/${specificationId}`);
325
+ }
326
+ async function deleteAllProductSpecifications(profileId, productId) {
327
+ const { vtexApi } = await getVtexApiClients(profileId);
328
+ await vtexApi.delete(`/api/catalog/pvt/product/${productId}/specification`);
329
+ }
330
+ async function deleteBrand(profileId, brandId) {
331
+ const { vtexApi } = await getVtexApiClients(profileId);
332
+ await vtexApi.delete(`/api/catalog/pvt/brand/${brandId}`);
333
+ }
334
+ async function deleteSkuFile(profileId, skuId, fileId) {
335
+ const { vtexApi } = await getVtexApiClients(profileId);
336
+ await vtexApi.delete(`/api/catalog/pvt/stockkeepingunit/${skuId}/file/${fileId}`);
337
+ }
338
+ async function deleteSkuSpecification(profileId, skuId, specificationId) {
339
+ const { vtexApi } = await getVtexApiClients(profileId);
340
+ await vtexApi.delete(`/api/catalog/pvt/stockkeepingunit/${skuId}/specification/${specificationId}`);
341
+ }
342
+ async function deleteAllSkuSpecifications(profileId, skuId) {
343
+ const { vtexApi } = await getVtexApiClients(profileId);
344
+ await vtexApi.delete(`/api/catalog/pvt/stockkeepingunit/${skuId}/specification`);
345
+ }
195
346
  async function associateSkuSpecification(profileId, skuId, payload) {
196
347
  const { vtexApi } = await getVtexApiClients(profileId);
197
348
  const response = await vtexApi.post(
@@ -208,9 +359,33 @@ async function createSkuFile(profileId, skuId, payload) {
208
359
  );
209
360
  return response.data;
210
361
  }
362
+ async function getSkuImages(profileId, skuId) {
363
+ const { vtexApi } = await getVtexApiClients(profileId);
364
+ const response = await vtexApi.get(`/api/catalog/pvt/stockkeepingunit/${skuId}/file`);
365
+ const data = response.data;
366
+ if (!Array.isArray(data)) {
367
+ return [];
368
+ }
369
+ return data.filter((item) => item !== null && typeof item === "object");
370
+ }
371
+ async function attachSkuImage(profileId, skuId, payload) {
372
+ return createSkuFile(profileId, skuId, { ...payload });
373
+ }
374
+ async function updateSkuImage(profileId, skuId, imageId, payload) {
375
+ const { vtexApi } = await getVtexApiClients(profileId);
376
+ const response = await vtexApi.put(
377
+ `/api/catalog/pvt/stockkeepingunit/${skuId}/file/${imageId}`,
378
+ payload
379
+ );
380
+ return response.data;
381
+ }
211
382
  export {
383
+ addSkuEan,
212
384
  associateProductSpecification,
213
385
  associateSkuSpecification,
386
+ attachSkuImage,
387
+ buildBrandUpdatePayload,
388
+ buildCategoryUpdatePayload,
214
389
  buildProductUpdatePayload,
215
390
  buildSkuUpdatePayload,
216
391
  createBrand,
@@ -221,13 +396,31 @@ export {
221
396
  createSkuFile,
222
397
  createSpecification,
223
398
  createSpecificationValue,
399
+ deleteAllProductSpecifications,
224
400
  deleteAllSkuEans,
401
+ deleteAllSkuSpecifications,
402
+ deleteBrand,
403
+ deleteProductSpecification,
404
+ deleteSkuFile,
405
+ deleteSkuSpecification,
225
406
  getBrand,
226
407
  getCategory,
227
408
  getProduct,
409
+ getProductSpecifications,
228
410
  getSku,
229
411
  getSkuEans,
412
+ getSkuImages,
413
+ getSpecification,
414
+ getSpecificationValue,
415
+ replaceSkuEans,
416
+ updateBrand,
417
+ updateCategory,
230
418
  updateProduct,
231
- updateSku
419
+ updateProductBasicFields,
420
+ updateSku,
421
+ updateSkuBasicFields,
422
+ updateSkuImage,
423
+ updateSpecification,
424
+ updateSpecificationValue
232
425
  };
233
426
  //# sourceMappingURL=vtex-catalog-write.js.map