@yoryoboy/bi-mcp 1.16.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.js +179 -6
- package/dist/index.js.map +2 -2
- package/dist/mcp-use.json +3 -6
- package/dist/src/config/__tests__/google-store.test.js +30 -0
- package/dist/src/config/__tests__/google-store.test.js.map +7 -0
- package/dist/src/config/__tests__/mcp-tool-deadline.test.js +64 -0
- package/dist/src/config/__tests__/mcp-tool-deadline.test.js.map +7 -0
- package/dist/src/config/google-store.js +18 -0
- package/dist/src/config/google-store.js.map +2 -2
- package/dist/src/config/mcp-tool-deadline-context.js +34 -0
- package/dist/src/config/mcp-tool-deadline-context.js.map +7 -0
- package/dist/src/config/mcp-tool-deadline.js +67 -0
- package/dist/src/config/mcp-tool-deadline.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js +38 -3
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js.map +2 -2
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js +226 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js +127 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-kits.test.js +103 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-kits.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-order-billing-info.test.js +582 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-order-billing-info.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js +10 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js.map +2 -2
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-packs.test.js +36 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-packs.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-payments.test.js +137 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-payments.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-group-ads.test.js +105 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-group-ads.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-groups.test.js +143 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-groups.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-campaigns.test.js +100 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-campaigns.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads.test.js +350 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-return-reconciliation.test.js +228 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-return-reconciliation.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-shipping.test.js +58 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-shipping.test.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-api.js +15 -3
- package/dist/src/services/mercadolibre/mercadolibre-api.js.map +2 -2
- package/dist/src/services/mercadolibre/mercadolibre-billing.js +110 -3
- package/dist/src/services/mercadolibre/mercadolibre-billing.js.map +2 -2
- package/dist/src/services/mercadolibre/mercadolibre-buyer-reconciliation.js +368 -0
- package/dist/src/services/mercadolibre/mercadolibre-buyer-reconciliation.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-claim-reconciliation.js +399 -0
- package/dist/src/services/mercadolibre/mercadolibre-claim-reconciliation.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-kits.js +55 -0
- package/dist/src/services/mercadolibre/mercadolibre-kits.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-order-billing-info.js +392 -0
- package/dist/src/services/mercadolibre/mercadolibre-order-billing-info.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-orders.js +8 -8
- package/dist/src/services/mercadolibre/mercadolibre-orders.js.map +2 -2
- package/dist/src/services/mercadolibre/mercadolibre-packs.js +21 -0
- package/dist/src/services/mercadolibre/mercadolibre-packs.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-payments.js +60 -0
- package/dist/src/services/mercadolibre/mercadolibre-payments.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-product-ads.js +429 -0
- package/dist/src/services/mercadolibre/mercadolibre-product-ads.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-return-reconciliation.js +436 -0
- package/dist/src/services/mercadolibre/mercadolibre-return-reconciliation.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-shipping.js +35 -0
- package/dist/src/services/mercadolibre/mercadolibre-shipping.js.map +7 -0
- package/dist/src/services/vtex/__tests__/vtex-api.test.js +67 -0
- package/dist/src/services/vtex/__tests__/vtex-api.test.js.map +7 -0
- package/dist/src/services/vtex/vtex-api.js +6 -0
- package/dist/src/services/vtex/vtex-api.js.map +2 -2
- package/dist/src/tools/config/__tests__/list-profiles.test.js +154 -0
- package/dist/src/tools/config/__tests__/list-profiles.test.js.map +7 -0
- package/dist/src/tools/config/list-profiles.js +39 -3
- package/dist/src/tools/config/list-profiles.js.map +2 -2
- package/dist/src/tools/mercadolibre/__tests__/get-order-billing-info.test.js +339 -0
- package/dist/src/tools/mercadolibre/__tests__/get-order-billing-info.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-group-ads.test.js +225 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-group-ads.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-groups.test.js +148 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-groups.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-campaigns.test.js +60 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-campaigns.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-helpers.test.js +128 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-helpers.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-tools.test.js +435 -0
- package/dist/src/tools/mercadolibre/__tests__/product-ads-tools.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/reconcile-buyer-data.test.js +31 -0
- package/dist/src/tools/mercadolibre/__tests__/reconcile-buyer-data.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/reconcile-claim-data.test.js +36 -0
- package/dist/src/tools/mercadolibre/__tests__/reconcile-claim-data.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/validate-connection.test.js +205 -0
- package/dist/src/tools/mercadolibre/__tests__/validate-connection.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-billing-provisions-by-order.js +313 -0
- package/dist/src/tools/mercadolibre/get-billing-provisions-by-order.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-bundle-context-by-item.js +176 -0
- package/dist/src/tools/mercadolibre/get-bundle-context-by-item.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-full-storage-charges.js +183 -0
- package/dist/src/tools/mercadolibre/get-full-storage-charges.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-order-billing-info.js +189 -0
- package/dist/src/tools/mercadolibre/get-order-billing-info.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-pack-context-by-order.js +150 -0
- package/dist/src/tools/mercadolibre/get-pack-context-by-order.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-payment-details.js +322 -0
- package/dist/src/tools/mercadolibre/get-payment-details.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-product-ads-ad-group-ads.js +144 -0
- package/dist/src/tools/mercadolibre/get-product-ads-ad-group-ads.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-product-ads-advertisers.js +59 -0
- package/dist/src/tools/mercadolibre/get-product-ads-advertisers.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-shipping-quote-by-declared-dimensions.js +104 -0
- package/dist/src/tools/mercadolibre/get-shipping-quote-by-declared-dimensions.js.map +7 -0
- package/dist/src/tools/mercadolibre/index.js +32 -0
- package/dist/src/tools/mercadolibre/index.js.map +2 -2
- package/dist/src/tools/mercadolibre/product-ads-helpers.js +130 -0
- package/dist/src/tools/mercadolibre/product-ads-helpers.js.map +7 -0
- package/dist/src/tools/mercadolibre/reconcile-buyer-data.js +27 -0
- package/dist/src/tools/mercadolibre/reconcile-buyer-data.js.map +7 -0
- package/dist/src/tools/mercadolibre/reconcile-claim-data.js +46 -0
- package/dist/src/tools/mercadolibre/reconcile-claim-data.js.map +7 -0
- package/dist/src/tools/mercadolibre/reconcile-return-data.js +25 -0
- package/dist/src/tools/mercadolibre/reconcile-return-data.js.map +7 -0
- package/dist/src/tools/mercadolibre/search-product-ads-ad-groups.js +162 -0
- package/dist/src/tools/mercadolibre/search-product-ads-ad-groups.js.map +7 -0
- package/dist/src/tools/mercadolibre/search-product-ads-ads.js +216 -0
- package/dist/src/tools/mercadolibre/search-product-ads-ads.js.map +7 -0
- package/dist/src/tools/mercadolibre/search-product-ads-campaigns.js +116 -0
- package/dist/src/tools/mercadolibre/search-product-ads-campaigns.js.map +7 -0
- package/dist/src/tools/mercadolibre/validate-connection.js +40 -12
- package/dist/src/tools/mercadolibre/validate-connection.js.map +2 -2
- package/dist/tests/meli/mercadolibre-billing-provisions.test.js +378 -0
- package/dist/tests/meli/mercadolibre-billing-provisions.test.js.map +2 -2
- package/dist/tests/meli/mercadolibre-order-billing-info-surface.test.js +123 -0
- package/dist/tests/meli/mercadolibre-order-billing-info-surface.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-payment-details.test.js +356 -0
- package/dist/tests/meli/mercadolibre-payment-details.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-payments.test.js +62 -0
- package/dist/tests/meli/mercadolibre-payments.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-product-ads-ad-groups-surface.test.js +90 -0
- package/dist/tests/meli/mercadolibre-product-ads-ad-groups-surface.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-product-ads-campaigns-surface.test.js +72 -0
- package/dist/tests/meli/mercadolibre-product-ads-campaigns-surface.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-pack-kit-shipping.test.js +400 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-pack-kit-shipping.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js +31 -12
- package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js.map +2 -2
- package/dist/tests/vtex/vtex-commercial-conditions-docs.test.js +1 -1
- package/dist/tests/vtex/vtex-commercial-conditions-docs.test.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/google-ads/report-utils.js +0 -78
- package/dist/src/google-ads/report-utils.js.map +0 -7
- package/dist/src/search-console/search-console-utils.js +0 -275
- package/dist/src/search-console/search-console-utils.js.map +0 -7
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js +0 -165
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js.map +0 -7
- package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js +0 -233
- package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js.map +0 -7
- package/dist/src/tools/vtex/catalog-admin-batch.js +0 -298
- package/dist/src/tools/vtex/catalog-admin-batch.js.map +0 -7
package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nconst { billingMock, orderMock, shipmentMock, ownershipMock } = vi.hoisted(() => ({\n billingMock: vi.fn(), orderMock: vi.fn(), shipmentMock: vi.fn(), ownershipMock: vi.fn(),\n}));\nvi.mock(\"../mercadolibre-order-billing-info.js\", () => ({ getMercadoLibreSaleBillingInfo: billingMock, verifyMercadoLibreOrderOwnership: ownershipMock }));\nvi.mock(\"../mercadolibre-orders.js\", () => ({ getMercadoLibreOrder: orderMock, getMercadoLibreShipment: shipmentMock }));\n\nimport { MercadoLibreApiError } from \"../mercadolibre-api.js\";\nimport { getBuyerReconciliationSafetyMarginMs, reconcileMercadoLibreBuyerData } from \"../mercadolibre-buyer-reconciliation.js\";\nimport { createMcpToolDeadlineMiddleware } from \"../../../config/mcp-tool-deadline.js\";\n\nconst order = (id: string, shipment = \"1001\") => ({ id, seller: { id: \"seller-1\" }, buyer: { nickname: \"buyer-nick\" }, shipping: { id: shipment } });\nconst available = (id: string, type = \"DNI\", number = \"123\", shipment = \"1001\") => ({\n available: true as const,\n order: order(id, shipment),\n billingInfo: { buyer: { billing_info: {\n name: \"Ada\", last_name: \"Lovelace\", identification: { type, number },\n address: { street_name: \"Main\", street_number: 10, city_name: \"City\", state: { code: \"S\", name: \"State\" }, zip_code: \"1000\", country_id: \"AR\" },\n taxes: { taxpayer_type: { id: \"CONSUMIDOR_FINAL\", description: \"Consumidor Final\" } },\n } } },\n});\nconst missingFiscal = { available: false as const, reason: \"billing_info_fiscal_fields_missing\" as const };\nconst shipment = { destination: { shipping_address: { street_name: \"Shipping\", street_number: \"20\", city_name: \"Port\", state: { name: \"Province\" }, zip_code: \"2000\", country_id: \"AR\" } } };\n\ndescribe(\"reconcileMercadoLibreBuyerData\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n ownershipMock.mockResolvedValue(\"owned\");\n shipmentMock.mockResolvedValue(shipment);\n });\n\n it(\"derives a bounded safety margin from the global timeout\", () => {\n expect(getBuyerReconciliationSafetyMarginMs(300_000)).toBe(10_000);\n expect(getBuyerReconciliationSafetyMarginMs(2_000)).toBe(100);\n expect(getBuyerReconciliationSafetyMarginMs(1_000_000)).toBe(10_000);\n });\n\n it(\"returns a complete direct order with buyer, document, fiscal and shipping addresses\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: available(\"o-1\", \"DNI\", \"111\") });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n const item = result.results[0];\n expect(item).toMatchObject({ sale_reference: \"sale-1\", resolution: { kind: \"order\", status: \"resolved\" }, data: { completeness: \"complete\" } });\n expect(item.data.buyer).toMatchObject({ full_name: \"Ada Lovelace\", nickname: \"buyer-nick\", document: { type: \"DNI\", number: \"111\" }, fiscal_address: { state: \"State\" }, shipping_address: { street: \"Shipping 20\" } });\n expect(item.data).not.toHaveProperty(\"sources\");\n expect(item.data).not.toHaveProperty(\"missing_fields\");\n expect(item.data).not.toHaveProperty(\"reasons\");\n expect(item).not.toHaveProperty(\"metadata\");\n expect(result).not.toHaveProperty(\"metadata\");\n expect(result.summary).toEqual({ requested: 1, complete: 1, partial: 0, unavailable: 0, orders: 1, packs: 0, unknown: 0 });\n });\n\n it(\"keeps useful order buyer data when fiscal fields are partial\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: missingFiscal });\n orderMock.mockResolvedValue(order(\"o-1\"));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0].data).toMatchObject({ completeness: \"partial\", buyer: { nickname: \"buyer-nick\" } });\n expect(result.results[0].data.issues).toContainEqual(expect.objectContaining({ field: \"fiscal_address\", code: \"billing_info_fiscal_fields_missing\" }));\n });\n\n it.each([[\"DNI\", \"DNI\"], [\"CUIT\", \"CUIT\"]] as const)(\"normalizes %s documents without changing the number\", async (source, expected) => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: available(\"o-1\", source, \"999\") });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0].data.buyer?.document).toEqual({ type: expected, number: \"999\" });\n });\n\n it(\"consolidates a unanimous pack at top-level data and hides member identifiers\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [\n { orderId: \"m-1\", accessible: true, result: available(\"m-1\", \"DNI\", \"123\", \"1001\") }, { orderId: \"m-2\", accessible: true, result: available(\"m-2\", \"DNI\", \"123\", \"1002\") },\n ] });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0]).toMatchObject({ pack: { agreement: \"unanimous\" }, data: { completeness: \"complete\" } });\n expect(result.results[0].data).not.toHaveProperty(\"issues\");\n expect(result.results[0]).not.toHaveProperty(\"metadata\");\n expect(result.results[0].pack).not.toHaveProperty(\"consolidated\");\n expect(result.results[0].pack).not.toHaveProperty(\"members\");\n expect(JSON.stringify(result)).not.toMatch(/pack-secret|m-1|m-2/);\n });\n\n it(\"does not consolidate a pack when shipping destinations differ\", async () => {\n const secondShipment = { destination: { shipping_address: { street_name: \"Other\", street_number: \"20\", city_name: \"Port\", state: { name: \"Province\" }, zip_code: \"2000\", country_id: \"AR\" } } };\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [\n { orderId: \"m-1\", accessible: true, result: available(\"m-1\", \"DNI\", \"123\", \"1001\") }, { orderId: \"m-2\", accessible: true, result: available(\"m-2\", \"DNI\", \"123\", \"1002\") },\n ] });\n shipmentMock.mockImplementation(async (_profile: string, shipmentId: string) => shipmentId === \"1002\" ? secondShipment : shipment);\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0].pack?.agreement).toBe(\"disagreement\");\n expect(result.results[0].data.completeness).toBe(\"partial\");\n expect(result.results[0].pack).toHaveProperty(\"members\");\n expect(result.summary).toMatchObject({ complete: 0, partial: 1, unavailable: 0 });\n });\n\n it(\"returns opaque indexed members for disagreement and partial packs\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [\n { orderId: \"m-1\", accessible: true, result: available(\"m-1\", \"DNI\", \"1\") }, { orderId: \"m-2\", accessible: true, result: available(\"m-2\", \"CUIT\", \"2\") },\n ] });\n let result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0].pack).toMatchObject({ agreement: \"disagreement\", members: [{ member_index: 0 }, { member_index: 1 }] });\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [{ orderId: \"m-1\", accessible: true, result: missingFiscal }, { orderId: \"m-2\", accessible: false, failureReason: \"access_denied\" }] });\n result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0].pack?.agreement).toBe(\"partial\");\n expect(result.results[0].pack?.members?.[1]).toMatchObject({ member_index: 1, data: { completeness: \"unavailable\" } });\n expect(result.results[0].data.issues).toContainEqual(expect.objectContaining({ field: \"pack_members\", code: \"pack_partial_coverage\" }));\n expect(result.summary).toMatchObject({ complete: 0, partial: 1, unavailable: 0 });\n });\n\n it(\"exposes a safe shipping issue without operational metadata\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: available(\"o-1\") });\n shipmentMock.mockRejectedValue(new MercadoLibreApiError(\"temporary\", 503));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { maxRetries: 1, sleep: async () => undefined });\n expect(result.results[0].data.issues).toContainEqual(expect.objectContaining({ field: \"shipping_address\", code: \"shipping_source_unavailable\" }));\n expect(result.results[0]).not.toHaveProperty(\"metadata\");\n expect(result).not.toHaveProperty(\"metadata\");\n });\n\n it(\"counts only actual shipping retry exhaustion in the degraded event\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: available(\"o-1\") });\n shipmentMock.mockRejectedValue(new MercadoLibreApiError(\"temporary\", 503));\n\n const withoutRetry = vi.fn();\n await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { maxRetries: 0, onDegradedOutcome: withoutRetry });\n expect(withoutRetry).toHaveBeenCalledWith(expect.objectContaining({ retry: 0 }));\n\n const exhausted = vi.fn();\n await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { maxRetries: 1, sleep: async () => undefined, onDegradedOutcome: exhausted });\n expect(exhausted).toHaveBeenCalledWith(expect.objectContaining({ retry: 1 }));\n expect(shipmentMock).toHaveBeenCalledTimes(3);\n });\n\n it(\"reports pack member issues without operational metadata or upstream details\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [\n { orderId: \"m-1\", accessible: false, failureReason: \"operation_deadline_exceeded\" },\n { orderId: \"m-2\", accessible: false, failureReason: \"upstream_unavailable\", attempts: 3, retryable: true },\n ] });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0].pack?.members?.[0].data.issues).toContainEqual(expect.objectContaining({ code: \"operation_deadline_exceeded\" }));\n expect(result.results[0].pack?.members?.[1].data.issues).toContainEqual(expect.objectContaining({ code: \"upstream_unavailable\" }));\n expect(result.results[0]).not.toHaveProperty(\"metadata\");\n expect(result).not.toHaveProperty(\"metadata\");\n expect(JSON.stringify(result)).not.toContain(\"temporary\");\n });\n\n it(\"propagates an unavailable pack deadline as a safe issue\", async () => {\n billingMock.mockResolvedValue({\n resolutionKind: \"pack\",\n packId: \"pack-secret\",\n members: [],\n unavailableReason: \"pack_operation_deadline_exceeded\",\n metadata: { memberCount: 0 },\n });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0]).toMatchObject({ resolution: { kind: \"pack\", status: \"unavailable\" }, data: { issues: [expect.objectContaining({ code: \"operation_deadline_exceeded\" })] } });\n expect(result).not.toHaveProperty(\"metadata\");\n expect(result.summary).toMatchObject({ requested: 1, unavailable: 1, partial: 0 });\n });\n\n it.each([\"mismatch\", \"unverifiable\"] as const)(\"returns no PII when ownership is %s\", async (ownership) => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"foreign-order\", result: missingFiscal });\n orderMock.mockResolvedValue({ ...order(\"foreign-order\"), buyer: { nickname: \"secret-buyer\" } });\n ownershipMock.mockResolvedValue(ownership);\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0].data.buyer).toBeUndefined();\n expect(JSON.stringify(result)).not.toContain(\"secret-buyer\");\n expect(shipmentMock).not.toHaveBeenCalled();\n });\n\n it(\"does not turn a deadline during order lookup into pack fallback\", async () => {\n billingMock.mockRejectedValue(new MercadoLibreApiError(\"timeout\", undefined));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { operationDeadlineMs: 1, now: () => 10 });\n expect(result.results[0].resolution.kind).toBe(\"unknown\");\n expect(billingMock).toHaveBeenCalledTimes(1);\n expect(orderMock).not.toHaveBeenCalled();\n });\n\n it(\"marks already-expired references as partial processing\", async () => {\n const now = vi.fn().mockReturnValueOnce(10).mockReturnValue(11);\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { operationDeadlineMs: 1, now });\n expect(result.results[0]).toMatchObject({ data: { issues: [expect.objectContaining({ code: \"operation_deadline_exceeded\" })] } });\n expect(result).not.toHaveProperty(\"metadata\");\n expect(result.summary).toMatchObject({ requested: 1, unavailable: 1, partial: 0 });\n });\n\n it(\"returns a structured reference issue before the outer middleware deadline\", async () => {\n vi.useFakeTimers();\n billingMock.mockImplementation(() => new Promise((_, reject) => {\n setTimeout(() => reject(new Error(\"billing source unavailable\")), 10);\n }));\n const middleware = createMcpToolDeadlineMiddleware(25);\n const resultPromise = middleware({}, () => reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]));\n\n await vi.advanceTimersByTimeAsync(10);\n await expect(resultPromise).resolves.toMatchObject({\n results: [{ data: { issues: [expect.objectContaining({ code: \"operation_deadline_exceeded\" })] } }],\n });\n vi.useRealTimers();\n });\n\n it.each([\n [\"AbortError\", Object.assign(new Error(\"cancelled\"), { name: \"AbortError\" })],\n [\"timeout sentinel\", Object.assign(new Error(\"request timed out\"), { code: \"ETIMEDOUT\" })],\n ])(\"classifies %s as an operation deadline\", async (_label, failure) => {\n billingMock.mockRejectedValue(failure);\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0]).toMatchObject({ data: { issues: [expect.objectContaining({ code: \"operation_deadline_exceeded\" })] } });\n expect(result).not.toHaveProperty(\"metadata\");\n });\n\n it(\"keeps nondeadline resolution failures as reference_unavailable\", async () => {\n billingMock.mockRejectedValue(new Error(\"billing source unavailable\"));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0]).toMatchObject({ resolution: { kind: \"unknown\", status: \"unavailable\" }, data: { issues: [expect.objectContaining({ code: \"reference_unavailable\" })] } });\n expect(result).not.toHaveProperty(\"metadata\");\n expect(result.summary).toMatchObject({ requested: 1, unavailable: 1, partial: 0, unknown: 1 });\n });\n\n it(\"preserves duplicate occurrences and input order\", async () => {\n billingMock.mockImplementation(async (_profile: string, reference: string) => ({ resolutionKind: \"order\", orderId: reference, result: available(reference) }));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"second\", \"first\", \"second\"]);\n expect(result.results.map((item) => item.sale_reference)).toEqual([\"second\", \"first\", \"second\"]);\n expect(result.summary.requested).toBe(3);\n });\n\n it(\"emits only aggregate degraded events and keeps the public response unchanged\", async () => {\n const warn = vi.spyOn(console, \"warn\").mockImplementation(() => undefined);\n const error = vi.spyOn(console, \"error\").mockImplementation(() => undefined);\n try {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-secret\", result: available(\"o-secret\", \"CUIT\", \"secret-doc\") });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-secret\"]);\n expect(warn).not.toHaveBeenCalled();\n expect(error).not.toHaveBeenCalled();\n expect(result.results[0].data.buyer?.document?.number).toBe(\"secret-doc\");\n\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-secret\", result: missingFiscal });\n const degraded = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-secret\"], { onDegradedOutcome: (event) => warn(JSON.stringify(event)) });\n expect(warn).toHaveBeenCalledOnce();\n expect(warn.mock.calls[0]?.[0]).not.toContain(\"secret-doc\");\n expect(degraded).not.toHaveProperty(\"operational_event\");\n expect(degraded).not.toHaveProperty(\"telemetry\");\n\n } finally { warn.mockRestore(); error.mockRestore(); }\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["shipment"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { MercadoLibreApiError, getMercadoLibreApiContext } from "../mercadolibre-api.js";
|
|
3
|
+
import { getClaimReconciliationDeadlineMs, reconcileMercadoLibreClaimData } from "../mercadolibre-claim-reconciliation.js";
|
|
4
|
+
import { getMcpToolDeadlineRemainingMs, runWithMcpToolDeadlineContext } from "../../../config/mcp-tool-deadline-context.js";
|
|
5
|
+
const { getMock } = vi.hoisted(() => ({ getMock: vi.fn() }));
|
|
6
|
+
vi.mock("../mercadolibre-api.js", async () => {
|
|
7
|
+
const actual = await vi.importActual("../mercadolibre-api.js");
|
|
8
|
+
return { ...actual, getMercadoLibreApiContext: vi.fn() };
|
|
9
|
+
});
|
|
10
|
+
describe("reconcileMercadoLibreClaimData", () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
vi.clearAllMocks();
|
|
13
|
+
vi.mocked(getMercadoLibreApiContext).mockResolvedValue({ api: { get: getMock }, sellerId: "seller-1", accessToken: "token" });
|
|
14
|
+
});
|
|
15
|
+
it("uses the shorter MCP caller budget with a bounded safety margin", async () => {
|
|
16
|
+
const signal = new AbortController().signal;
|
|
17
|
+
await runWithMcpToolDeadlineContext(signal, async () => {
|
|
18
|
+
expect(getMcpToolDeadlineRemainingMs(1e4)).toBe(1e3);
|
|
19
|
+
expect(getClaimReconciliationDeadlineMs(getMcpToolDeadlineRemainingMs(1e4))).toBe(900);
|
|
20
|
+
}, 11e3);
|
|
21
|
+
expect(getClaimReconciliationDeadlineMs(3e5)).toBe(29e4);
|
|
22
|
+
});
|
|
23
|
+
it("derives full message summaries from the projected messages", async () => {
|
|
24
|
+
getMock.mockImplementation(async (path, config) => {
|
|
25
|
+
if (path === "/post-purchase/v1/claims/search") {
|
|
26
|
+
return { data: { paging: { total: config?.params?.type === "returns" ? 1 : 0, limit: 50, offset: 0 }, data: config?.params?.type === "returns" ? [{ id: "claim-1", resource_id: "order-1" }] : [] } };
|
|
27
|
+
}
|
|
28
|
+
if (path === "/orders/order-1") return { data: { seller: { id: "seller-1" } } };
|
|
29
|
+
if (path === "/post-purchase/v1/claims/claim-1") return { data: { type: "returns", status: "opened", players: [{ role: "respondent" }] } };
|
|
30
|
+
if (path.endsWith("/actions-history")) return { data: [] };
|
|
31
|
+
if (path.endsWith("/expected-resolutions")) return { data: [] };
|
|
32
|
+
if (path.endsWith("/messages")) return { data: [
|
|
33
|
+
{ id: "m1", sender_role: "respondent", moderation_status: "approved", text: "untrusted" },
|
|
34
|
+
{ id: "m2", sender_role: "complainant", moderation_status: "rejected", text: "untrusted" },
|
|
35
|
+
{ id: "m3", sender_role: "respondent", moderation_status: "approved", text: "untrusted" }
|
|
36
|
+
] };
|
|
37
|
+
if (path.endsWith("/actions")) return { data: [] };
|
|
38
|
+
if (path.includes("/post-purchase/v2/claims/") || path.includes("/charges/return-cost") || path.includes("/returns/")) throw new MercadoLibreApiError("not found", 404);
|
|
39
|
+
throw new Error(`unexpected ${path}`);
|
|
40
|
+
});
|
|
41
|
+
const result = await reconcileMercadoLibreClaimData("triplim", ["order-1"], "full");
|
|
42
|
+
const claim = result.results[0].claim_context.claims[0];
|
|
43
|
+
expect(claim.message_summary).toEqual({ count: 3, by_role: { respondent: 2, complainant: 1 }, by_moderation_status: { approved: 2, rejected: 1 } });
|
|
44
|
+
expect(claim.messages).toHaveLength(3);
|
|
45
|
+
});
|
|
46
|
+
it("keeps standard summaries text-free and marks message failures as unknown", async () => {
|
|
47
|
+
let messagesAvailable = true;
|
|
48
|
+
getMock.mockImplementation(async (path, config) => {
|
|
49
|
+
if (path === "/post-purchase/v1/claims/search") return { data: { paging: { total: config?.params?.type === "returns" ? 1 : 0, limit: 50, offset: 0 }, data: config?.params?.type === "returns" ? [{ id: "claim-1", resource_id: "order-1" }] : [] } };
|
|
50
|
+
if (path === "/orders/order-1") return { data: { seller: { id: "seller-1" } } };
|
|
51
|
+
if (path === "/post-purchase/v1/claims/claim-1") return { data: { status: "opened" } };
|
|
52
|
+
if (path.endsWith("/actions-history") || path.endsWith("/expected-resolutions")) return { data: [] };
|
|
53
|
+
if (path.endsWith("/messages")) {
|
|
54
|
+
if (!messagesAvailable) throw new MercadoLibreApiError("unavailable", 503);
|
|
55
|
+
return { data: [{ id: "m1", sender_role: "respondent", moderation_status: "approved", text: "must not be returned in standard mode" }] };
|
|
56
|
+
}
|
|
57
|
+
if (path.includes("/post-purchase/v2/claims/")) throw new MercadoLibreApiError("not found", 404);
|
|
58
|
+
throw new Error(`unexpected ${path}`);
|
|
59
|
+
});
|
|
60
|
+
const standard = await reconcileMercadoLibreClaimData("triplim", ["order-1"]);
|
|
61
|
+
const standardClaim = standard.results[0].claim_context.claims[0];
|
|
62
|
+
expect(standardClaim.message_summary).toEqual({ count: 1, by_role: { respondent: 1 }, by_moderation_status: { approved: 1 } });
|
|
63
|
+
messagesAvailable = false;
|
|
64
|
+
const unavailable = await reconcileMercadoLibreClaimData("triplim", ["order-1"]);
|
|
65
|
+
const unavailableClaim = unavailable.results[0].claim_context.claims[0];
|
|
66
|
+
const issues = unavailable.results[0].claim_context.issues;
|
|
67
|
+
expect(issues).toContainEqual(expect.objectContaining({ code: "messages_unavailable" }));
|
|
68
|
+
expect(unavailableClaim.message_summary).toBeUndefined();
|
|
69
|
+
});
|
|
70
|
+
it("does not claim absence when a claims page is rate-limited", async () => {
|
|
71
|
+
getMock.mockImplementation(async (path, config) => {
|
|
72
|
+
if (path === "/post-purchase/v1/claims/search" && config?.params?.type === "returns" && config.params.offset === 0) {
|
|
73
|
+
return { data: { paging: { total: 51, limit: 50, offset: 0 }, data: [] } };
|
|
74
|
+
}
|
|
75
|
+
if (path === "/post-purchase/v1/claims/search" && config?.params?.type === "mediations") {
|
|
76
|
+
return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };
|
|
77
|
+
}
|
|
78
|
+
if (path === "/post-purchase/v1/claims/search") throw new MercadoLibreApiError("rate limited", 429);
|
|
79
|
+
if (path === "/orders/order-1") return { data: { seller: { id: "seller-1" } } };
|
|
80
|
+
throw new Error(`unexpected ${path}`);
|
|
81
|
+
});
|
|
82
|
+
const result = await reconcileMercadoLibreClaimData("triplim", ["order-1"]);
|
|
83
|
+
expect(result.results[0]).toMatchObject({
|
|
84
|
+
resolution: { kind: "order", status: "partial" },
|
|
85
|
+
claim_context: { status: "claim_status_unknown", completeness: "partial" }
|
|
86
|
+
});
|
|
87
|
+
const claimContext = result.results[0].claim_context;
|
|
88
|
+
expect(claimContext?.issues).toContainEqual(expect.objectContaining({ code: "claims_page_partial" }));
|
|
89
|
+
expect(result.summary).toMatchObject({ without_claims: 0, partial: 1, unavailable: 0 });
|
|
90
|
+
});
|
|
91
|
+
it("treats a failed first-page universe as unknown rather than without claims", async () => {
|
|
92
|
+
getMock.mockImplementation(async (path) => {
|
|
93
|
+
if (path === "/post-purchase/v1/claims/search") throw new MercadoLibreApiError("deadline", 429);
|
|
94
|
+
if (path === "/orders/order-1") return { data: { seller: { id: "seller-1" } } };
|
|
95
|
+
throw new Error(`unexpected ${path}`);
|
|
96
|
+
});
|
|
97
|
+
const result = await reconcileMercadoLibreClaimData("triplim", ["order-1"]);
|
|
98
|
+
expect(result.results[0]).toMatchObject({ resolution: { kind: "order", status: "partial" }, claim_context: { status: "claim_status_unknown" } });
|
|
99
|
+
expect(result.summary.without_claims).toBe(0);
|
|
100
|
+
});
|
|
101
|
+
it("returns unavailable when no pack member can be ownership-validated", async () => {
|
|
102
|
+
getMock.mockImplementation(async (path) => {
|
|
103
|
+
if (path === "/post-purchase/v1/claims/search") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };
|
|
104
|
+
if (path === "/orders/pack-1") throw new MercadoLibreApiError("not found", 404);
|
|
105
|
+
if (path === "/packs/pack-1") return { data: { orders: [{ id: "member-1" }, { id: "member-2" }] } };
|
|
106
|
+
if (path === "/orders/member-1" || path === "/orders/member-2") throw new MercadoLibreApiError("upstream", 503);
|
|
107
|
+
throw new Error(`unexpected ${path}`);
|
|
108
|
+
});
|
|
109
|
+
const result = await reconcileMercadoLibreClaimData("triplim", ["pack-1"]);
|
|
110
|
+
expect(result.results[0]).toMatchObject({ resolution: { kind: "pack", status: "unavailable" } });
|
|
111
|
+
expect(result.summary).toMatchObject({ unavailable: 1, partial: 0, without_claims: 0 });
|
|
112
|
+
});
|
|
113
|
+
it("withholds foreign orders and marks full projected context untrusted", async () => {
|
|
114
|
+
getMock.mockImplementation(async (path) => {
|
|
115
|
+
if (path === "/post-purchase/v1/claims/search") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };
|
|
116
|
+
if (path === "/orders/foreign-order") return { data: { seller: { id: "foreign-seller" } } };
|
|
117
|
+
if (path === "/orders/owned-order") return { data: { seller: { id: "seller-1" } } };
|
|
118
|
+
if (path === "/post-purchase/v1/claims/search") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };
|
|
119
|
+
throw new Error(`unexpected ${path}`);
|
|
120
|
+
});
|
|
121
|
+
const result = await reconcileMercadoLibreClaimData("triplim", ["foreign-order", "owned-order"], "full");
|
|
122
|
+
expect(result.results[0]).toMatchObject({ resolution: { status: "unavailable" } });
|
|
123
|
+
expect(result.results[1]).toMatchObject({ resolution: { status: "resolved" }, claim_context: { content_trust: "untrusted_user_generated" } });
|
|
124
|
+
expect(result.safety_notice).toContain("untrusted");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=mercadolibre-claim-reconciliation.test.js.map
|
package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { MercadoLibreApiError, getMercadoLibreApiContext } from \"../mercadolibre-api.js\";\nimport { getClaimReconciliationDeadlineMs, reconcileMercadoLibreClaimData } from \"../mercadolibre-claim-reconciliation.js\";\nimport { getMcpToolDeadlineRemainingMs, runWithMcpToolDeadlineContext } from \"../../../config/mcp-tool-deadline-context.js\";\n\nconst { getMock } = vi.hoisted(() => ({ getMock: vi.fn() }));\n\nvi.mock(\"../mercadolibre-api.js\", async () => {\n const actual = await vi.importActual<typeof import(\"../mercadolibre-api.js\")>(\"../mercadolibre-api.js\");\n return { ...actual, getMercadoLibreApiContext: vi.fn() };\n});\n\ndescribe(\"reconcileMercadoLibreClaimData\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n vi.mocked(getMercadoLibreApiContext).mockResolvedValue({ api: { get: getMock }, sellerId: \"seller-1\", accessToken: \"token\" } as never);\n });\n\n it(\"uses the shorter MCP caller budget with a bounded safety margin\", async () => {\n const signal = new AbortController().signal;\n await runWithMcpToolDeadlineContext(signal, async () => {\n expect(getMcpToolDeadlineRemainingMs(10_000)).toBe(1_000);\n expect(getClaimReconciliationDeadlineMs(getMcpToolDeadlineRemainingMs(10_000)!)).toBe(900);\n }, 11_000);\n\n expect(getClaimReconciliationDeadlineMs(300_000)).toBe(290_000);\n });\n\n it(\"derives full message summaries from the projected messages\", async () => {\n getMock.mockImplementation(async (path: string, config?: { params?: { type?: string } }) => {\n if (path === \"/post-purchase/v1/claims/search\") {\n return { data: { paging: { total: config?.params?.type === \"returns\" ? 1 : 0, limit: 50, offset: 0 }, data: config?.params?.type === \"returns\" ? [{ id: \"claim-1\", resource_id: \"order-1\" }] : [] } };\n }\n if (path === \"/orders/order-1\") return { data: { seller: { id: \"seller-1\" } } };\n if (path === \"/post-purchase/v1/claims/claim-1\") return { data: { type: \"returns\", status: \"opened\", players: [{ role: \"respondent\" }] } };\n if (path.endsWith(\"/actions-history\")) return { data: [] };\n if (path.endsWith(\"/expected-resolutions\")) return { data: [] };\n if (path.endsWith(\"/messages\")) return { data: [\n { id: \"m1\", sender_role: \"respondent\", moderation_status: \"approved\", text: \"untrusted\" },\n { id: \"m2\", sender_role: \"complainant\", moderation_status: \"rejected\", text: \"untrusted\" },\n { id: \"m3\", sender_role: \"respondent\", moderation_status: \"approved\", text: \"untrusted\" },\n ] };\n if (path.endsWith(\"/actions\")) return { data: [] };\n if (path.includes(\"/post-purchase/v2/claims/\") || path.includes(\"/charges/return-cost\") || path.includes(\"/returns/\")) throw new MercadoLibreApiError(\"not found\", 404);\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"], \"full\");\n const claim = (result.results[0] as { claim_context: { claims: Array<{ message_summary: unknown; messages: unknown[] }> } }).claim_context.claims[0];\n\n expect(claim.message_summary).toEqual({ count: 3, by_role: { respondent: 2, complainant: 1 }, by_moderation_status: { approved: 2, rejected: 1 } });\n expect(claim.messages).toHaveLength(3);\n });\n\n it(\"keeps standard summaries text-free and marks message failures as unknown\", async () => {\n let messagesAvailable = true;\n getMock.mockImplementation(async (path: string, config?: { params?: { type?: string } }) => {\n if (path === \"/post-purchase/v1/claims/search\") return { data: { paging: { total: config?.params?.type === \"returns\" ? 1 : 0, limit: 50, offset: 0 }, data: config?.params?.type === \"returns\" ? [{ id: \"claim-1\", resource_id: \"order-1\" }] : [] } };\n if (path === \"/orders/order-1\") return { data: { seller: { id: \"seller-1\" } } };\n if (path === \"/post-purchase/v1/claims/claim-1\") return { data: { status: \"opened\" } };\n if (path.endsWith(\"/actions-history\") || path.endsWith(\"/expected-resolutions\")) return { data: [] };\n if (path.endsWith(\"/messages\")) {\n if (!messagesAvailable) throw new MercadoLibreApiError(\"unavailable\", 503);\n return { data: [{ id: \"m1\", sender_role: \"respondent\", moderation_status: \"approved\", text: \"must not be returned in standard mode\" }] };\n }\n if (path.includes(\"/post-purchase/v2/claims/\")) throw new MercadoLibreApiError(\"not found\", 404);\n throw new Error(`unexpected ${path}`);\n });\n\n const standard = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"]);\n const standardClaim = (standard.results[0] as { claim_context: { claims: Array<{ message_summary: unknown }> } }).claim_context.claims[0];\n expect(standardClaim.message_summary).toEqual({ count: 1, by_role: { respondent: 1 }, by_moderation_status: { approved: 1 } });\n\n messagesAvailable = false;\n const unavailable = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"]);\n const unavailableClaim = (unavailable.results[0] as { claim_context: { claims: Array<{ message_summary?: unknown; issues: Array<{ code: string }> }> } }).claim_context.claims[0];\n\n const issues = (unavailable.results[0] as { claim_context: { issues: Array<{ code: string }> } }).claim_context.issues;\n expect(issues).toContainEqual(expect.objectContaining({ code: \"messages_unavailable\" }));\n expect(unavailableClaim.message_summary).toBeUndefined();\n });\n\n it(\"does not claim absence when a claims page is rate-limited\", async () => {\n getMock.mockImplementation(async (path: string, config?: { params?: { type?: string; offset?: number } }) => {\n if (path === \"/post-purchase/v1/claims/search\" && config?.params?.type === \"returns\" && config.params.offset === 0) {\n return { data: { paging: { total: 51, limit: 50, offset: 0 }, data: [] } };\n }\n if (path === \"/post-purchase/v1/claims/search\" && config?.params?.type === \"mediations\") {\n return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };\n }\n if (path === \"/post-purchase/v1/claims/search\") throw new MercadoLibreApiError(\"rate limited\", 429);\n if (path === \"/orders/order-1\") return { data: { seller: { id: \"seller-1\" } } };\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"]);\n\n expect(result.results[0]).toMatchObject({\n resolution: { kind: \"order\", status: \"partial\" },\n claim_context: { status: \"claim_status_unknown\", completeness: \"partial\" },\n });\n const claimContext = (result.results[0] as { claim_context?: { issues?: unknown[] } }).claim_context;\n expect(claimContext?.issues).toContainEqual(expect.objectContaining({ code: \"claims_page_partial\" }));\n expect(result.summary).toMatchObject({ without_claims: 0, partial: 1, unavailable: 0 });\n });\n\n it(\"treats a failed first-page universe as unknown rather than without claims\", async () => {\n getMock.mockImplementation(async (path: string) => {\n if (path === \"/post-purchase/v1/claims/search\") throw new MercadoLibreApiError(\"deadline\", 429);\n if (path === \"/orders/order-1\") return { data: { seller: { id: \"seller-1\" } } };\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"]);\n\n expect(result.results[0]).toMatchObject({ resolution: { kind: \"order\", status: \"partial\" }, claim_context: { status: \"claim_status_unknown\" } });\n expect(result.summary.without_claims).toBe(0);\n });\n\n it(\"returns unavailable when no pack member can be ownership-validated\", async () => {\n getMock.mockImplementation(async (path: string) => {\n if (path === \"/post-purchase/v1/claims/search\") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };\n if (path === \"/orders/pack-1\") throw new MercadoLibreApiError(\"not found\", 404);\n if (path === \"/packs/pack-1\") return { data: { orders: [{ id: \"member-1\" }, { id: \"member-2\" }] } };\n if (path === \"/orders/member-1\" || path === \"/orders/member-2\") throw new MercadoLibreApiError(\"upstream\", 503);\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"pack-1\"]);\n\n expect(result.results[0]).toMatchObject({ resolution: { kind: \"pack\", status: \"unavailable\" } });\n expect(result.summary).toMatchObject({ unavailable: 1, partial: 0, without_claims: 0 });\n });\n\n it(\"withholds foreign orders and marks full projected context untrusted\", async () => {\n getMock.mockImplementation(async (path: string) => {\n if (path === \"/post-purchase/v1/claims/search\") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };\n if (path === \"/orders/foreign-order\") return { data: { seller: { id: \"foreign-seller\" } } };\n if (path === \"/orders/owned-order\") return { data: { seller: { id: \"seller-1\" } } };\n if (path === \"/post-purchase/v1/claims/search\") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"foreign-order\", \"owned-order\"], \"full\");\n\n expect(result.results[0]).toMatchObject({ resolution: { status: \"unavailable\" } });\n expect(result.results[1]).toMatchObject({ resolution: { status: \"resolved\" }, claim_context: { content_trust: \"untrusted_user_generated\" } });\n expect(result.safety_notice).toContain(\"untrusted\");\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { getMercadoLibreApiContext, runMercadoLibreBatch } from "../mercadolibre-api.js";
|
|
3
|
+
import {
|
|
4
|
+
getMercadoLibreUserProduct,
|
|
5
|
+
getMercadoLibreUserProductBundles,
|
|
6
|
+
getMercadoLibreUserProductBundlesBatch,
|
|
7
|
+
getMercadoLibreUserProductsBatch,
|
|
8
|
+
resolveMercadoLibreUserProductsFromItems
|
|
9
|
+
} from "../mercadolibre-kits.js";
|
|
10
|
+
import { getMercadoLibreItemDetailsBatch } from "../mercadolibre-items.js";
|
|
11
|
+
vi.mock("../mercadolibre-api.js", () => ({
|
|
12
|
+
getMercadoLibreApiContext: vi.fn(),
|
|
13
|
+
runMercadoLibreBatch: vi.fn()
|
|
14
|
+
}));
|
|
15
|
+
vi.mock("../mercadolibre-items.js", () => ({
|
|
16
|
+
getMercadoLibreItemDetailsBatch: vi.fn()
|
|
17
|
+
}));
|
|
18
|
+
describe("mercadolibre-kits service", () => {
|
|
19
|
+
const getMock = vi.fn();
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
vi.clearAllMocks();
|
|
22
|
+
vi.mocked(getMercadoLibreApiContext).mockResolvedValue({
|
|
23
|
+
api: { get: getMock },
|
|
24
|
+
sellerId: "seller-from-profile",
|
|
25
|
+
accessToken: "token"
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
it("fetches user product bundle context from the official user-products endpoint", async () => {
|
|
29
|
+
getMock.mockResolvedValueOnce({ data: { id: "MLAU1", tags: ["bundle"], bundle: { type: "kit" } } });
|
|
30
|
+
const result = await getMercadoLibreUserProduct("profile-1", "MLAU1");
|
|
31
|
+
expect(getMock).toHaveBeenCalledWith("/user-products/MLAU1");
|
|
32
|
+
expect(result).toEqual({ id: "MLAU1", tags: ["bundle"], bundle: { type: "kit" } });
|
|
33
|
+
});
|
|
34
|
+
it("fetches bundle memberships from the official bundles endpoint", async () => {
|
|
35
|
+
getMock.mockResolvedValueOnce({ data: { user_product_id: "MLAU2", bundles: ["MLAU9"] } });
|
|
36
|
+
const result = await getMercadoLibreUserProductBundles("profile-1", "MLAU2");
|
|
37
|
+
expect(getMock).toHaveBeenCalledWith("/user-products/MLAU2/bundles");
|
|
38
|
+
expect(result).toEqual({ user_product_id: "MLAU2", bundles: ["MLAU9"] });
|
|
39
|
+
});
|
|
40
|
+
it("delegates user product batch fetching through the shared batch runner", async () => {
|
|
41
|
+
vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({
|
|
42
|
+
successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
|
|
43
|
+
failed: []
|
|
44
|
+
}));
|
|
45
|
+
getMock.mockResolvedValueOnce({ data: { id: "MLAU1" } });
|
|
46
|
+
const result = await getMercadoLibreUserProductsBatch("profile-1", ["MLAU1"], { maxRetries: 1 });
|
|
47
|
+
expect(runMercadoLibreBatch).toHaveBeenCalledWith(["MLAU1"], expect.any(Function), { maxRetries: 1 });
|
|
48
|
+
expect(getMock).toHaveBeenCalledWith("/user-products/MLAU1");
|
|
49
|
+
expect(result).toEqual({ successful: [{ id: "MLAU1", document: { id: "MLAU1" } }], failed: [] });
|
|
50
|
+
});
|
|
51
|
+
it("resolves user product ids from item multiget responses", async () => {
|
|
52
|
+
vi.mocked(getMercadoLibreItemDetailsBatch).mockResolvedValue([
|
|
53
|
+
{ id: "MLA1", user_product_id: "MLAU1", title: "Kit" },
|
|
54
|
+
{ id: "MLA2", title: "Component" }
|
|
55
|
+
]);
|
|
56
|
+
const result = await resolveMercadoLibreUserProductsFromItems("profile-1", ["MLA1", "MLA2"]);
|
|
57
|
+
expect(getMercadoLibreItemDetailsBatch).toHaveBeenCalledWith("profile-1", ["MLA1", "MLA2"], [
|
|
58
|
+
"id",
|
|
59
|
+
"user_product_id",
|
|
60
|
+
"title",
|
|
61
|
+
"catalog_product_id",
|
|
62
|
+
"domain_id",
|
|
63
|
+
"family_id"
|
|
64
|
+
]);
|
|
65
|
+
expect(result).toEqual([
|
|
66
|
+
{
|
|
67
|
+
itemId: "MLA1",
|
|
68
|
+
userProductId: "MLAU1",
|
|
69
|
+
title: "Kit",
|
|
70
|
+
catalogProductId: "",
|
|
71
|
+
domainId: "",
|
|
72
|
+
familyId: ""
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
itemId: "MLA2",
|
|
76
|
+
userProductId: "",
|
|
77
|
+
title: "Component",
|
|
78
|
+
catalogProductId: "",
|
|
79
|
+
domainId: "",
|
|
80
|
+
familyId: ""
|
|
81
|
+
}
|
|
82
|
+
]);
|
|
83
|
+
});
|
|
84
|
+
it("delegates bundle membership batch fetching through the shared batch runner", async () => {
|
|
85
|
+
vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({
|
|
86
|
+
successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
|
|
87
|
+
failed: []
|
|
88
|
+
}));
|
|
89
|
+
getMock.mockResolvedValueOnce({ data: { user_product_id: "MLAU1", bundles: ["MLAU2"] } });
|
|
90
|
+
const result = await getMercadoLibreUserProductBundlesBatch("profile-1", ["MLAU1"], {
|
|
91
|
+
maxConcurrency: 2
|
|
92
|
+
});
|
|
93
|
+
expect(runMercadoLibreBatch).toHaveBeenCalledWith(["MLAU1"], expect.any(Function), {
|
|
94
|
+
maxConcurrency: 2
|
|
95
|
+
});
|
|
96
|
+
expect(getMock).toHaveBeenCalledWith("/user-products/MLAU1/bundles");
|
|
97
|
+
expect(result).toEqual({
|
|
98
|
+
successful: [{ id: "MLAU1", document: { user_product_id: "MLAU1", bundles: ["MLAU2"] } }],
|
|
99
|
+
failed: []
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=mercadolibre-kits.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/services/mercadolibre/__tests__/mercadolibre-kits.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { getMercadoLibreApiContext, runMercadoLibreBatch } from \"../mercadolibre-api.js\";\nimport {\n getMercadoLibreUserProduct,\n getMercadoLibreUserProductBundles,\n getMercadoLibreUserProductBundlesBatch,\n getMercadoLibreUserProductsBatch,\n resolveMercadoLibreUserProductsFromItems,\n} from \"../mercadolibre-kits.js\";\nimport { getMercadoLibreItemDetailsBatch } from \"../mercadolibre-items.js\";\n\nvi.mock(\"../mercadolibre-api.js\", () => ({\n getMercadoLibreApiContext: vi.fn(),\n runMercadoLibreBatch: vi.fn(),\n}));\n\nvi.mock(\"../mercadolibre-items.js\", () => ({\n getMercadoLibreItemDetailsBatch: vi.fn(),\n}));\n\ndescribe(\"mercadolibre-kits service\", () => {\n const getMock = vi.fn();\n\n beforeEach(() => {\n vi.clearAllMocks();\n vi.mocked(getMercadoLibreApiContext).mockResolvedValue({\n api: { get: getMock },\n sellerId: \"seller-from-profile\",\n accessToken: \"token\",\n } as never);\n });\n\n it(\"fetches user product bundle context from the official user-products endpoint\", async () => {\n getMock.mockResolvedValueOnce({ data: { id: \"MLAU1\", tags: [\"bundle\"], bundle: { type: \"kit\" } } });\n\n const result = await getMercadoLibreUserProduct(\"profile-1\", \"MLAU1\");\n\n expect(getMock).toHaveBeenCalledWith(\"/user-products/MLAU1\");\n expect(result).toEqual({ id: \"MLAU1\", tags: [\"bundle\"], bundle: { type: \"kit\" } });\n });\n\n it(\"fetches bundle memberships from the official bundles endpoint\", async () => {\n getMock.mockResolvedValueOnce({ data: { user_product_id: \"MLAU2\", bundles: [\"MLAU9\"] } });\n\n const result = await getMercadoLibreUserProductBundles(\"profile-1\", \"MLAU2\");\n\n expect(getMock).toHaveBeenCalledWith(\"/user-products/MLAU2/bundles\");\n expect(result).toEqual({ user_product_id: \"MLAU2\", bundles: [\"MLAU9\"] });\n });\n\n it(\"delegates user product batch fetching through the shared batch runner\", async () => {\n vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({\n successful: [{ id: ids[0], document: await fetcher(ids[0]) }],\n failed: [],\n }));\n getMock.mockResolvedValueOnce({ data: { id: \"MLAU1\" } });\n\n const result = await getMercadoLibreUserProductsBatch(\"profile-1\", [\"MLAU1\"], { maxRetries: 1 });\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([\"MLAU1\"], expect.any(Function), { maxRetries: 1 });\n expect(getMock).toHaveBeenCalledWith(\"/user-products/MLAU1\");\n expect(result).toEqual({ successful: [{ id: \"MLAU1\", document: { id: \"MLAU1\" } }], failed: [] });\n });\n\n it(\"resolves user product ids from item multiget responses\", async () => {\n vi.mocked(getMercadoLibreItemDetailsBatch).mockResolvedValue([\n { id: \"MLA1\", user_product_id: \"MLAU1\", title: \"Kit\" },\n { id: \"MLA2\", title: \"Component\" },\n ] as never);\n\n const result = await resolveMercadoLibreUserProductsFromItems(\"profile-1\", [\"MLA1\", \"MLA2\"]);\n\n expect(getMercadoLibreItemDetailsBatch).toHaveBeenCalledWith(\"profile-1\", [\"MLA1\", \"MLA2\"], [\n \"id\",\n \"user_product_id\",\n \"title\",\n \"catalog_product_id\",\n \"domain_id\",\n \"family_id\",\n ]);\n expect(result).toEqual([\n {\n itemId: \"MLA1\",\n userProductId: \"MLAU1\",\n title: \"Kit\",\n catalogProductId: \"\",\n domainId: \"\",\n familyId: \"\",\n },\n {\n itemId: \"MLA2\",\n userProductId: \"\",\n title: \"Component\",\n catalogProductId: \"\",\n domainId: \"\",\n familyId: \"\",\n },\n ]);\n });\n\n it(\"delegates bundle membership batch fetching through the shared batch runner\", async () => {\n vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({\n successful: [{ id: ids[0], document: await fetcher(ids[0]) }],\n failed: [],\n }));\n getMock.mockResolvedValueOnce({ data: { user_product_id: \"MLAU1\", bundles: [\"MLAU2\"] } });\n\n const result = await getMercadoLibreUserProductBundlesBatch(\"profile-1\", [\"MLAU1\"], {\n maxConcurrency: 2,\n });\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([\"MLAU1\"], expect.any(Function), {\n maxConcurrency: 2,\n });\n expect(getMock).toHaveBeenCalledWith(\"/user-products/MLAU1/bundles\");\n expect(result).toEqual({\n successful: [{ id: \"MLAU1\", document: { user_product_id: \"MLAU1\", bundles: [\"MLAU2\"] } }],\n failed: [],\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|