@yoryoboy/bi-mcp 1.19.0 → 1.20.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/dist/.tsbuildinfo +1 -1
- package/dist/mcp-use.json +6 -3
- package/dist/scripts/profile-mercadolibre-billing.js +634 -0
- package/dist/scripts/profile-mercadolibre-billing.js.map +7 -0
- package/dist/src/config/__tests__/tiendanube-profile-store.test.js +50 -0
- package/dist/src/config/__tests__/tiendanube-profile-store.test.js.map +7 -0
- package/dist/src/config/tiendanube-profile-store.js +31 -0
- package/dist/src/config/tiendanube-profile-store.js.map +7 -0
- package/dist/src/google-ads/report-utils.js +78 -0
- package/dist/src/google-ads/report-utils.js.map +7 -0
- package/dist/src/search-console/search-console-utils.js +275 -0
- package/dist/src/search-console/search-console-utils.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-sales-report-ventas.test.js +358 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-sales-report-ventas.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-sales-report.test.js +96 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-sales-report.test.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-claim-return-lookup.js +15 -0
- package/dist/src/services/mercadolibre/mercadolibre-claim-return-lookup.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-observability.js +12 -0
- package/dist/src/services/mercadolibre/mercadolibre-observability.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-sale-reference.js +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-sale-reference.js.map +7 -0
- package/dist/src/services/mercadolibre/mercadolibre-sales-report.js +553 -0
- package/dist/src/services/mercadolibre/mercadolibre-sales-report.js.map +7 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js +165 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js.map +7 -0
- package/dist/src/tools/config/__tests__/list-profiles.test.js +144 -1
- package/dist/src/tools/config/__tests__/list-profiles.test.js.map +2 -2
- package/dist/src/tools/config/list-profiles.js +50 -6
- package/dist/src/tools/config/list-profiles.js.map +2 -2
- package/dist/src/tools/mercadolibre/__tests__/get-sales-report-foundation.test.js +417 -0
- package/dist/src/tools/mercadolibre/__tests__/get-sales-report-foundation.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/get-sales-report.js +474 -0
- package/dist/src/tools/mercadolibre/get-sales-report.js.map +7 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js +233 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js.map +7 -0
- package/dist/src/tools/vtex/catalog-admin-batch.js +298 -0
- package/dist/src/tools/vtex/catalog-admin-batch.js.map +7 -0
- package/dist/tests/meli/meli-sales-report-buyers-mcp-e2e.test.js +137 -0
- package/dist/tests/meli/meli-sales-report-buyers-mcp-e2e.test.js.map +7 -0
- package/dist/tests/meli/meli-sales-report-mcp-e2e-server.js +24 -0
- package/dist/tests/meli/meli-sales-report-mcp-e2e-server.js.map +7 -0
- package/dist/tests/meli/meli-sales-report-mcp-e2e.test.js +207 -0
- package/dist/tests/meli/meli-sales-report-mcp-e2e.test.js.map +7 -0
- package/dist/tests/meli/meli-sales-report-public-mcp-e2e-server.js +10 -0
- package/dist/tests/meli/meli-sales-report-public-mcp-e2e-server.js.map +7 -0
- package/dist/tests/meli/meli-sales-report-public-registration.test.js +98 -0
- package/dist/tests/meli/meli-sales-report-public-registration.test.js.map +7 -0
- package/dist/tests/smoke/process-harness.js +89 -0
- package/dist/tests/smoke/process-harness.js.map +7 -0
- package/dist/tests/smoke/process-harness.test.js +39 -0
- package/dist/tests/smoke/process-harness.test.js.map +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { object } from "mcp-use/server";
|
|
4
|
+
import { mercadoLibreDateRegex } from "./helpers.js";
|
|
5
|
+
import {
|
|
6
|
+
fetchMercadoLibreOrderUniverse,
|
|
7
|
+
buildOrderUniversePagePlan,
|
|
8
|
+
fetchMercadoLibreShipmentEvidence,
|
|
9
|
+
enrichSalesReportEnvios,
|
|
10
|
+
SALES_REPORT_ENVIOS_FIELDS,
|
|
11
|
+
enrichSalesReportVentas,
|
|
12
|
+
enrichSalesReportPublicaciones,
|
|
13
|
+
enrichSalesReportFacturacion,
|
|
14
|
+
enrichSalesReportCompradores,
|
|
15
|
+
enrichSalesReportDevolucionesReclamos,
|
|
16
|
+
fetchMercadoLibreFiscalEvidence,
|
|
17
|
+
SALES_REPORT_FACTURACION_FIELDS,
|
|
18
|
+
groupMercadoLibreOrders,
|
|
19
|
+
selectMercadoLibreOrdersById
|
|
20
|
+
} from "../../services/mercadolibre/mercadolibre-sales-report.js";
|
|
21
|
+
import { getMercadoLibreBillingProvisionsByOrder } from "../../services/mercadolibre/mercadolibre-billing.js";
|
|
22
|
+
import { getMercadoLibreApiContext } from "../../services/mercadolibre/mercadolibre-api.js";
|
|
23
|
+
import { reconcileMercadoLibreClaimData } from "../../services/mercadolibre/mercadolibre-claim-reconciliation.js";
|
|
24
|
+
import { reconcileMercadoLibreReturnData } from "../../services/mercadolibre/mercadolibre-return-reconciliation.js";
|
|
25
|
+
import { createMercadoLibreClaimReturnLookup } from "../../services/mercadolibre/mercadolibre-claim-return-lookup.js";
|
|
26
|
+
const SALES_REPORT_TIME_ZONE = "America/Argentina/Buenos_Aires";
|
|
27
|
+
const SALES_REPORT_DEFAULT_LIMIT = 200;
|
|
28
|
+
const SALES_REPORT_MAX_LIMIT = 1e3;
|
|
29
|
+
const SALES_REPORT_CURSOR_VERSION = 1;
|
|
30
|
+
const CURSOR_DOMAIN = "bi-mcp:meli-sales-report-cursor:v1";
|
|
31
|
+
function isCalendarDate(value) {
|
|
32
|
+
if (!mercadoLibreDateRegex.test(value)) return false;
|
|
33
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
34
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
35
|
+
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
36
|
+
}
|
|
37
|
+
const salesReportDateSchema = z.string().refine(isCalendarDate, "Expected a valid calendar date in YYYY-MM-DD format");
|
|
38
|
+
const meliGetSalesReportSchema = z.object({
|
|
39
|
+
profileId: z.string().trim().min(1).describe("Explicit MercadoLibre profile id to use."),
|
|
40
|
+
startDate: salesReportDateSchema.optional().describe(
|
|
41
|
+
`Inclusive sales start date in YYYY-MM-DD format using ${SALES_REPORT_TIME_ZONE}.`
|
|
42
|
+
),
|
|
43
|
+
endDate: salesReportDateSchema.optional().describe(
|
|
44
|
+
`Inclusive sales end date in YYYY-MM-DD format using ${SALES_REPORT_TIME_ZONE}.`
|
|
45
|
+
),
|
|
46
|
+
limit: z.number().int().min(1).max(SALES_REPORT_MAX_LIMIT).optional().describe("Target maximum complete commercial operations to return."),
|
|
47
|
+
cursor: z.string().trim().min(1).optional().describe("Opaque continuation cursor returned by a previous call for the same report scope."),
|
|
48
|
+
orderIds: z.array(z.string().trim().min(1, "Order IDs cannot be empty")).min(1).max(100).optional().describe("One to 100 opaque order IDs. Packs expand to all seller-owned member orders.")
|
|
49
|
+
}).strict().superRefine((value, context) => {
|
|
50
|
+
const explicit = value.orderIds !== void 0;
|
|
51
|
+
const hasAnyRangeField = value.startDate !== void 0 || value.endDate !== void 0 || value.limit !== void 0 || value.cursor !== void 0;
|
|
52
|
+
if (explicit && hasAnyRangeField) {
|
|
53
|
+
context.addIssue({ code: "custom", path: ["orderIds"], message: "orderIds cannot be combined with startDate, endDate, limit, or cursor" });
|
|
54
|
+
}
|
|
55
|
+
if (!explicit && (value.startDate === void 0 || value.endDate === void 0)) {
|
|
56
|
+
context.addIssue({ code: "custom", path: ["startDate"], message: "Range mode requires both startDate and endDate" });
|
|
57
|
+
}
|
|
58
|
+
if (value.startDate && value.endDate && value.startDate > value.endDate) {
|
|
59
|
+
context.addIssue({
|
|
60
|
+
code: "custom",
|
|
61
|
+
path: ["endDate"],
|
|
62
|
+
message: "endDate must be on or after startDate"
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
function createSalesReportPerformanceTracker(now = performance.now.bind(performance)) {
|
|
67
|
+
const handlerStartedAt = now();
|
|
68
|
+
const durations = /* @__PURE__ */ new Map();
|
|
69
|
+
const elapsed = (startedAt) => Math.max(0, Math.round(now() - startedAt));
|
|
70
|
+
return {
|
|
71
|
+
start: now,
|
|
72
|
+
finish(stage, startedAt) {
|
|
73
|
+
const duration = elapsed(startedAt);
|
|
74
|
+
durations.set(stage, duration);
|
|
75
|
+
return duration;
|
|
76
|
+
},
|
|
77
|
+
async measure(stage, operation) {
|
|
78
|
+
const startedAt = now();
|
|
79
|
+
try {
|
|
80
|
+
return await operation();
|
|
81
|
+
} finally {
|
|
82
|
+
durations.set(stage, elapsed(startedAt));
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
duration(stage) {
|
|
86
|
+
return durations.get(stage) ?? 0;
|
|
87
|
+
},
|
|
88
|
+
total() {
|
|
89
|
+
return elapsed(handlerStartedAt);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function getSalesReportPostPurchaseCoverageState(readStatus, resolutions = [], incidents = 0) {
|
|
94
|
+
if (readStatus === "rejected") return "unavailable";
|
|
95
|
+
return incidents > 0 || resolutions.some((resolution) => resolution.status !== "resolved") ? "partial" : "complete";
|
|
96
|
+
}
|
|
97
|
+
async function meliGetSalesReportHandler(input) {
|
|
98
|
+
const performanceTracker = createSalesReportPerformanceTracker();
|
|
99
|
+
const parsed = meliGetSalesReportSchema.parse(input);
|
|
100
|
+
const profileStartedAt = performanceTracker.start();
|
|
101
|
+
const profileContext = await getMercadoLibreApiContext(parsed.profileId);
|
|
102
|
+
performanceTracker.finish("contexto_perfil", profileStartedAt);
|
|
103
|
+
const explicitMode = parsed.orderIds !== void 0;
|
|
104
|
+
const submittedOrderIds = parsed.orderIds ?? [];
|
|
105
|
+
const uniqueOrderIds = [...new Set(submittedOrderIds)];
|
|
106
|
+
const rangeLimit = parsed.limit ?? SALES_REPORT_DEFAULT_LIMIT;
|
|
107
|
+
const scope = explicitMode ? null : { profileId: parsed.profileId, startDate: parsed.startDate, endDate: parsed.endDate };
|
|
108
|
+
const cursor = !explicitMode && parsed.cursor ? decodeSalesReportCursor(parsed.cursor, scope) : null;
|
|
109
|
+
const selectionStartedAt = performanceTracker.start();
|
|
110
|
+
const selection = explicitMode ? await selectMercadoLibreOrdersById(parsed.profileId, profileContext.sellerId, uniqueOrderIds) : null;
|
|
111
|
+
const universe = explicitMode ? { orders: selection.orders, paging: { total: selection.orders.length, limit: 0, offset: 0 }, failedPages: [] } : await fetchMercadoLibreOrderUniverse(
|
|
112
|
+
parsed.profileId,
|
|
113
|
+
buildSalesReportDateBoundaries(parsed.startDate, parsed.endDate).from,
|
|
114
|
+
buildSalesReportDateBoundaries(parsed.startDate, parsed.endDate).to,
|
|
115
|
+
rangeLimit
|
|
116
|
+
);
|
|
117
|
+
const operations = groupMercadoLibreOrders(universe.orders).filter((operation) => !cursor || isSalesReportOperationAfterCursor(operation, cursor));
|
|
118
|
+
const items = explicitMode ? operations : operations.slice(0, rangeLimit);
|
|
119
|
+
performanceTracker.finish("seleccion_ordenes", selectionStartedAt);
|
|
120
|
+
const selectedOrderIds = items.flatMap((item) => item.ordenes.map((order) => order.order_id));
|
|
121
|
+
const billingStartedAt = performanceTracker.start();
|
|
122
|
+
const billing = await getMercadoLibreBillingProvisionsByOrder(parsed.profileId, {
|
|
123
|
+
orderIds: selectedOrderIds
|
|
124
|
+
});
|
|
125
|
+
const ventas = enrichSalesReportVentas(items, billing);
|
|
126
|
+
const publicaciones = enrichSalesReportPublicaciones(ventas.operations, billing);
|
|
127
|
+
performanceTracker.finish("billing", billingStartedAt);
|
|
128
|
+
const shipmentStartedAt = performanceTracker.start();
|
|
129
|
+
const shipments = await fetchMercadoLibreShipmentEvidence(parsed.profileId, selectedOrderIds);
|
|
130
|
+
const envios = enrichSalesReportEnvios(publicaciones.operations, shipments.successful.map((result) => ({ order_id: result.id, shipment: result.document })));
|
|
131
|
+
performanceTracker.finish("envios", shipmentStartedAt);
|
|
132
|
+
const fiscalStartedAt = performanceTracker.start();
|
|
133
|
+
const fiscal = await fetchMercadoLibreFiscalEvidence(parsed.profileId, selectedOrderIds);
|
|
134
|
+
const facturacion = enrichSalesReportFacturacion(envios.operations, fiscal.successful, fiscal.failed);
|
|
135
|
+
const compradores = enrichSalesReportCompradores(facturacion.operations, profileContext.sellerId);
|
|
136
|
+
performanceTracker.finish("facturacion_fiscal", fiscalStartedAt);
|
|
137
|
+
const references = items.map((item) => ({
|
|
138
|
+
reference: getSalesReportOperationKey(item),
|
|
139
|
+
kind: item.pack_id ? "pack" : "order"
|
|
140
|
+
}));
|
|
141
|
+
const postPurchaseStartedAt = performanceTracker.start();
|
|
142
|
+
const claimReturnLookup = createMercadoLibreClaimReturnLookup();
|
|
143
|
+
const [returnRead, claimRead] = await Promise.allSettled([
|
|
144
|
+
performanceTracker.measure("devoluciones", () => reconcileMercadoLibreReturnData(parsed.profileId, references, { claimReturnLookup })),
|
|
145
|
+
performanceTracker.measure("reclamos", () => reconcileMercadoLibreClaimData(parsed.profileId, references, "standard", claimReturnLookup))
|
|
146
|
+
]);
|
|
147
|
+
const postPurchase = enrichSalesReportDevolucionesReclamos(compradores.operations, {
|
|
148
|
+
returns: returnRead.status === "fulfilled" ? returnRead.value : void 0,
|
|
149
|
+
claims: claimRead.status === "fulfilled" ? claimRead.value : void 0,
|
|
150
|
+
returnFailure: returnRead.status === "rejected" ? returnRead.reason : void 0,
|
|
151
|
+
claimFailure: claimRead.status === "rejected" ? claimRead.reason : void 0
|
|
152
|
+
});
|
|
153
|
+
performanceTracker.finish("postventa", postPurchaseStartedAt);
|
|
154
|
+
const assemblyStartedAt = performanceTracker.start();
|
|
155
|
+
const shipmentFieldProvenance = SALES_REPORT_ENVIOS_FIELDS.map((campo) => {
|
|
156
|
+
const coverage = envios.fieldCoverage[campo];
|
|
157
|
+
return { campo: `envios.${campo}`, fuente: "shipments", estado: coverage.obtenidos === coverage.solicitados ? "available" : "unavailable", detalle: `Orders shipment evidence: ${coverage.obtenidos}/${coverage.solicitados} orders.` };
|
|
158
|
+
});
|
|
159
|
+
const fiscalFieldProvenance = SALES_REPORT_FACTURACION_FIELDS.map((campo) => {
|
|
160
|
+
const coverage = facturacion.fieldCoverage[campo];
|
|
161
|
+
const unsupported = campo === "factura_adjunta" || campo === "numero_iibb";
|
|
162
|
+
return { campo: `facturacion_al_comprador.${campo}`, fuente: "billing_info", estado: unsupported ? "unsupported" : coverage.obtenidos === coverage.solicitados ? "available" : "unavailable", detalle: unsupported ? "No validated official buyer-fiscal evidence for this field." : `Mercado Libre Orders billing-info evidence: ${coverage.obtenidos}/${coverage.solicitados} orders.` };
|
|
163
|
+
});
|
|
164
|
+
const returnFields = ["unidades", "revisado_por_mercado_libre", "fecha_de_revision", "resultado", "destino", "motivo_del_resultado"];
|
|
165
|
+
const unsupportedReturnFields = ["forma_de_entrega", "fecha_en_camino", "fecha_entregado", "transportista", "numero_de_seguimiento", "url_de_seguimiento", "dinero_a_favor"];
|
|
166
|
+
const returnIncidents = postPurchase.incidents.filter((incident) => incident.fuente === "returns").length;
|
|
167
|
+
const claimIncidents = postPurchase.incidents.filter((incident) => incident.fuente === "claims").length;
|
|
168
|
+
const returnProvenance = [...returnFields.map((campo) => {
|
|
169
|
+
const c = postPurchase.coverage[`devoluciones.${campo}`];
|
|
170
|
+
return { campo: `devoluciones.${campo}`, fuente: "returns", estado: c.obtenidos === c.solicitados && returnRead.status === "fulfilled" ? "available" : "unavailable", detalle: "Validated post-purchase return evidence; absence remains unknown." };
|
|
171
|
+
}), ...unsupportedReturnFields.map((campo) => ({ campo: `devoluciones.${campo}`, fuente: "returns", estado: "unsupported", detalle: "No official/direct evidence supports this sales-report field." }))];
|
|
172
|
+
const claimProvenance = ["unidades", "reclamo_abierto", "reclamo_cerrado", "con_mediacion"].map((campo) => {
|
|
173
|
+
const c = postPurchase.coverage[`reclamos.${campo}`];
|
|
174
|
+
return { campo: `reclamos.${campo}`, fuente: "claims", estado: c.obtenidos === c.solicitados && claimRead.status === "fulfilled" ? "available" : "unavailable", detalle: "Validated claim detail evidence; absence remains unknown." };
|
|
175
|
+
});
|
|
176
|
+
const last = items.at(-1);
|
|
177
|
+
const hasMore = !explicitMode && (universe.failedPages.length > 0 || universe.orders.length < universe.paging.total || operations.length > items.length);
|
|
178
|
+
const nextCursor = hasMore && last ? encodeSalesReportCursor({ ...scope, lastSaleTimestamp: getSalesReportOperationSaleTimestamp(last), lastOperationKey: getSalesReportOperationKey(last) }) : null;
|
|
179
|
+
const baseMetadata = buildSalesReportMetadata({
|
|
180
|
+
profileId: parsed.profileId,
|
|
181
|
+
startDate: scope?.startDate ?? null,
|
|
182
|
+
endDate: scope?.endDate ?? null,
|
|
183
|
+
itemsReturned: items.length,
|
|
184
|
+
requestedLimit: explicitMode ? null : rangeLimit,
|
|
185
|
+
selectionMode: explicitMode ? "ordenes_explicitas" : "rango_fechas",
|
|
186
|
+
explicitSelection: explicitMode ? {
|
|
187
|
+
ids_solicitados: submittedOrderIds,
|
|
188
|
+
ids_unicos: uniqueOrderIds,
|
|
189
|
+
cantidad_solicitada: submittedOrderIds.length,
|
|
190
|
+
cantidad_unica: uniqueOrderIds.length,
|
|
191
|
+
cantidad_duplicada: submittedOrderIds.length - uniqueOrderIds.length,
|
|
192
|
+
ids_resueltos: uniqueOrderIds.filter((id) => !selection.unavailableRequestedIds.includes(id)),
|
|
193
|
+
cantidad_resuelta: uniqueOrderIds.length - selection.unavailableRequestedIds.length,
|
|
194
|
+
ids_no_disponibles: selection.unavailableRequestedIds,
|
|
195
|
+
cantidad_no_disponible: selection.unavailableRequestedIds.length
|
|
196
|
+
} : null,
|
|
197
|
+
currencies: ventas.currencies,
|
|
198
|
+
packsReturned: items.filter((item) => item.pack_id !== null).length,
|
|
199
|
+
ordersReturned: items.reduce((count, item) => count + item.ordenes.length, 0),
|
|
200
|
+
sourceCoverage: [
|
|
201
|
+
{ fuente: "orders", estado: explicitMode ? selection.incidents.length ? "partial" : "complete" : universe.failedPages.length || universe.orders.length < universe.paging.total ? "partial" : "complete", solicitados: explicitMode ? uniqueOrderIds.length : universe.paging.total, obtenidos: explicitMode ? uniqueOrderIds.length - selection.unavailableRequestedIds.length : universe.orders.length, incidentes: explicitMode ? selection.incidents.length : universe.failedPages.length },
|
|
202
|
+
{ fuente: "billing", estado: billing.failures.length ? "partial" : "complete", solicitados: billing.order_ids_requested.length, obtenidos: billing.order_ids_found.length, incidentes: billing.failures.length + billing.order_ids_not_found.length },
|
|
203
|
+
{ fuente: "billing_info", estado: fiscal.failed.length || facturacion.incidents.length ? "partial" : "complete", solicitados: selectedOrderIds.length, obtenidos: new Set(fiscal.successful.filter((entry) => entry.result?.available).map((entry) => entry.orderId)).size, incidentes: fiscal.failed.length + facturacion.incidents.length },
|
|
204
|
+
buildSalesReportShipmentCoverage(selectedOrderIds.length, shipments.successful.length, envios.incidents.length, shipments.failed.length),
|
|
205
|
+
{ fuente: "returns", estado: getSalesReportPostPurchaseCoverageState(returnRead.status, returnRead.status === "fulfilled" ? returnRead.value.results.map((result) => result.resolution) : [], returnIncidents), solicitados: selectedOrderIds.length, obtenidos: postPurchase.returnContexts, incidentes: returnIncidents },
|
|
206
|
+
{ fuente: "claims", estado: getSalesReportPostPurchaseCoverageState(claimRead.status, claimRead.status === "fulfilled" ? claimRead.value.results.map((result) => result.resolution) : [], claimIncidents), solicitados: selectedOrderIds.length, obtenidos: postPurchase.claimContexts, incidentes: claimIncidents }
|
|
207
|
+
],
|
|
208
|
+
fieldProvenance: [
|
|
209
|
+
{ campo: "publicidad.venta_por_publicidad", fuente: "derived", estado: "unsupported", detalle: "Product Ads exposes listing-level aggregate metrics without a deterministic order/sale identifier; no attribution is inferred." },
|
|
210
|
+
{ campo: "ventas.cargo_por_diferencias_en_medidas_y_peso_del_paquete", fuente: "billing", estado: "unsupported", detalle: "No validated Billing-by-order source." },
|
|
211
|
+
{ campo: "ventas.pertenece_a_un_kit", fuente: "billing", estado: billing.failures.length ? "unavailable" : "available", detalle: "Billing items_info.item_kit_id per member order." },
|
|
212
|
+
{ campo: "publicaciones.sku", fuente: "orders", estado: "available", detalle: "Orders order_items.item.seller_sku." },
|
|
213
|
+
{ campo: "publicaciones.numero_de_publicacion", fuente: "orders", estado: "available", detalle: "Orders order_items.item.id." },
|
|
214
|
+
{ campo: "publicaciones.titulo_de_la_publicacion", fuente: "orders", estado: "available", detalle: "Orders order_items.item.title, Billing fallback." },
|
|
215
|
+
{ campo: "publicaciones.variante", fuente: "orders", estado: "available", detalle: "Orders variation_attributes formatted as name/value pairs." },
|
|
216
|
+
{ campo: "publicaciones.precio_unitario_de_venta_de_la_publicacion_ars", fuente: "orders", estado: "available", detalle: "Orders order_items.unit_price, Billing fallback." },
|
|
217
|
+
{ campo: "publicaciones.canal_de_venta", fuente: "billing", estado: billing.failures.length ? "unavailable" : "available", detalle: billing.failures.length ? "Billing coverage is partial." : "Billing sales_info.sales_channel." },
|
|
218
|
+
{ campo: "publicaciones.tiene_cuotas_agregadas", fuente: "billing", estado: billing.failures.length ? "unavailable" : "available", detalle: "Billing items_info.fees_added_in_publication; exact Si/No only." },
|
|
219
|
+
...shipmentFieldProvenance,
|
|
220
|
+
...fiscalFieldProvenance,
|
|
221
|
+
...returnProvenance,
|
|
222
|
+
...claimProvenance,
|
|
223
|
+
{ campo: "compradores.comprador", fuente: "orders", estado: compradores.incidents.length ? "unavailable" : "available", detalle: "Orders buyer.nickname only after explicit seller ownership verification." },
|
|
224
|
+
...["negocio", "dni", "domicilio", "ciudad", "estado", "codigo_postal", "pais"].map((campo) => ({ campo: `compradores.${campo}`, fuente: "orders", estado: "unsupported", detalle: "Bulk buyer PII is blocked by policy." }))
|
|
225
|
+
],
|
|
226
|
+
scopedIncidents: [
|
|
227
|
+
...selection?.incidents ?? [],
|
|
228
|
+
...universe.failedPages.map((page) => ({ fuente: "orders", alcance: "page", identificadores: [page], mensaje: "Orders page retrieval failed.", reintentable: true })),
|
|
229
|
+
...ventas.incidents,
|
|
230
|
+
...publicaciones.incidents,
|
|
231
|
+
...envios.incidents,
|
|
232
|
+
...facturacion.incidents,
|
|
233
|
+
...compradores.incidents,
|
|
234
|
+
...postPurchase.incidents,
|
|
235
|
+
...billing.failures.map((failure) => ({ fuente: "billing", alcance: "chunk", identificadores: failure.order_ids, mensaje: failure.message, reintentable: true })),
|
|
236
|
+
...shipments.failed.map((failure) => ({ fuente: "shipments", alcance: "order", identificadores: [failure.id], mensaje: failure.message, reintentable: failure.retryable }))
|
|
237
|
+
],
|
|
238
|
+
unsupportedFields: ["publicidad.venta_por_publicidad", "ventas.cargo_por_diferencias_en_medidas_y_peso_del_paquete", ...unsupportedReturnFields.map((campo) => `devoluciones.${campo}`), ...["negocio", "dni", "domicilio", "ciudad", "estado", "codigo_postal", "pais"].map((campo) => `compradores.${campo}`)],
|
|
239
|
+
unknownBillingConcepts: ventas.unknownConcepts,
|
|
240
|
+
hasMore,
|
|
241
|
+
nextCursor
|
|
242
|
+
});
|
|
243
|
+
performanceTracker.finish("ensamblado", assemblyStartedAt);
|
|
244
|
+
const metadata = {
|
|
245
|
+
...baseMetadata,
|
|
246
|
+
rendimiento: {
|
|
247
|
+
duracion_total_ms: performanceTracker.total(),
|
|
248
|
+
etapas: {
|
|
249
|
+
contexto_perfil: { duracion_ms: performanceTracker.duration("contexto_perfil") },
|
|
250
|
+
seleccion_ordenes: {
|
|
251
|
+
duracion_ms: performanceTracker.duration("seleccion_ordenes"),
|
|
252
|
+
ids_solicitados: explicitMode ? submittedOrderIds.length : universe.paging.total,
|
|
253
|
+
ids_unicos: explicitMode ? uniqueOrderIds.length : universe.paging.total,
|
|
254
|
+
ids_resueltos: explicitMode ? uniqueOrderIds.length - selection.unavailableRequestedIds.length : universe.orders.length,
|
|
255
|
+
operaciones_resueltas: items.length,
|
|
256
|
+
ordenes_resueltas: selectedOrderIds.length,
|
|
257
|
+
paginas_solicitadas: explicitMode ? 0 : 1 + buildOrderUniversePagePlan(universe.paging, rangeLimit).length,
|
|
258
|
+
paginas_fallidas: universe.failedPages.length
|
|
259
|
+
},
|
|
260
|
+
billing: {
|
|
261
|
+
duracion_ms: performanceTracker.duration("billing"),
|
|
262
|
+
ids_solicitados: billing.order_ids_requested.length,
|
|
263
|
+
ids_encontrados: billing.order_ids_found.length,
|
|
264
|
+
ids_no_encontrados: billing.order_ids_not_found.length,
|
|
265
|
+
lotes_totales: billing.chunks_total,
|
|
266
|
+
lotes_exitosos: billing.chunks_succeeded,
|
|
267
|
+
lotes_fallidos: billing.chunks_failed,
|
|
268
|
+
fallas: billing.failures.length
|
|
269
|
+
},
|
|
270
|
+
envios: {
|
|
271
|
+
duracion_ms: performanceTracker.duration("envios"),
|
|
272
|
+
solicitados: selectedOrderIds.length,
|
|
273
|
+
exitosos: shipments.successful.length,
|
|
274
|
+
fallidos: shipments.failed.length
|
|
275
|
+
},
|
|
276
|
+
facturacion_fiscal: {
|
|
277
|
+
duracion_ms: performanceTracker.duration("facturacion_fiscal"),
|
|
278
|
+
solicitados: selectedOrderIds.length,
|
|
279
|
+
exitosos: new Set(fiscal.successful.map((entry) => entry.orderId)).size,
|
|
280
|
+
fallidos: fiscal.failed.length
|
|
281
|
+
},
|
|
282
|
+
postventa: {
|
|
283
|
+
duracion_ms: performanceTracker.duration("postventa"),
|
|
284
|
+
devoluciones_ms: performanceTracker.duration("devoluciones"),
|
|
285
|
+
reclamos_ms: performanceTracker.duration("reclamos"),
|
|
286
|
+
referencias_solicitadas: references.length,
|
|
287
|
+
contextos_devoluciones: postPurchase.returnContexts,
|
|
288
|
+
contextos_reclamos: postPurchase.claimContexts,
|
|
289
|
+
incidentes_devoluciones: returnIncidents,
|
|
290
|
+
incidentes_reclamos: claimIncidents
|
|
291
|
+
},
|
|
292
|
+
ensamblado: { duracion_ms: performanceTracker.duration("ensamblado") }
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
return object({
|
|
297
|
+
items: postPurchase.operations,
|
|
298
|
+
metadata
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
function buildSalesReportDateBoundaries(startDate, endDate) {
|
|
302
|
+
const parsed = {
|
|
303
|
+
startDate: salesReportDateSchema.parse(startDate),
|
|
304
|
+
endDate: salesReportDateSchema.parse(endDate)
|
|
305
|
+
};
|
|
306
|
+
if (parsed.startDate > parsed.endDate) {
|
|
307
|
+
throw new Error("endDate must be on or after startDate");
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
timeZone: SALES_REPORT_TIME_ZONE,
|
|
311
|
+
from: `${parsed.startDate}T00:00:00.000${getBuenosAiresOffset(parsed.startDate)}`,
|
|
312
|
+
to: `${parsed.endDate}T23:59:59.999${getBuenosAiresOffset(parsed.endDate)}`
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function getBuenosAiresOffset(date) {
|
|
316
|
+
const offset = new Intl.DateTimeFormat("en-US", {
|
|
317
|
+
timeZone: SALES_REPORT_TIME_ZONE,
|
|
318
|
+
timeZoneName: "longOffset",
|
|
319
|
+
hour: "2-digit",
|
|
320
|
+
minute: "2-digit"
|
|
321
|
+
}).formatToParts(/* @__PURE__ */ new Date(`${date}T12:00:00.000Z`)).find((part) => part.type === "timeZoneName")?.value;
|
|
322
|
+
const match = offset?.match(/^GMT([+-]\d{2}:\d{2})$/);
|
|
323
|
+
if (!match) throw new Error(`Unable to resolve ${SALES_REPORT_TIME_ZONE} offset for ${date}`);
|
|
324
|
+
return match[1];
|
|
325
|
+
}
|
|
326
|
+
function buildSalesReportShipmentCoverage(requested, obtained, mappingIncidents, batchFailures) {
|
|
327
|
+
return {
|
|
328
|
+
fuente: "shipments",
|
|
329
|
+
estado: mappingIncidents || batchFailures ? "partial" : "complete",
|
|
330
|
+
solicitados: requested,
|
|
331
|
+
obtenidos: obtained,
|
|
332
|
+
incidentes: mappingIncidents + batchFailures
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function buildSalesReportMetadata(input) {
|
|
336
|
+
const sourceCoverage = input.sourceCoverage ?? [];
|
|
337
|
+
const partialSections = input.partialSections ?? [];
|
|
338
|
+
const scopedIncidents = input.scopedIncidents ?? [];
|
|
339
|
+
const fieldProvenance = input.fieldProvenance ?? [];
|
|
340
|
+
const unavailableFields = [.../* @__PURE__ */ new Set([
|
|
341
|
+
...input.unsupportedFields ?? [],
|
|
342
|
+
...fieldProvenance.filter((field) => field.estado !== "available").map((field) => field.campo)
|
|
343
|
+
])].sort();
|
|
344
|
+
const coverageComplete = partialSections.length === 0 && scopedIncidents.length === 0 && fieldProvenance.every((field) => field.estado === "available") && unavailableFields.length === 0 && sourceCoverage.every((source) => source.estado === "complete");
|
|
345
|
+
const cutoffReason = input.cutoffReason ?? null;
|
|
346
|
+
return {
|
|
347
|
+
profile_id: input.profileId,
|
|
348
|
+
modo_seleccion: input.selectionMode ?? "rango_fechas",
|
|
349
|
+
seleccion_explicita: input.explicitSelection ?? null,
|
|
350
|
+
fecha_desde: input.startDate,
|
|
351
|
+
fecha_hasta: input.endDate,
|
|
352
|
+
monedas: [...new Set(input.currencies ?? [])].sort(),
|
|
353
|
+
items_devueltos: input.itemsReturned,
|
|
354
|
+
limite_solicitado: input.requestedLimit,
|
|
355
|
+
motivo_del_corte: cutoffReason,
|
|
356
|
+
packs_devueltos: input.packsReturned,
|
|
357
|
+
ordenes_devueltas: input.ordersReturned,
|
|
358
|
+
cobertura_completa: coverageComplete,
|
|
359
|
+
secciones_parciales: partialSections,
|
|
360
|
+
cobertura_por_fuente: sourceCoverage,
|
|
361
|
+
incidentes_acotados: scopedIncidents,
|
|
362
|
+
campos_no_disponibles: unavailableFields,
|
|
363
|
+
conceptos_de_facturacion_desconocidos: input.unknownBillingConcepts ?? [],
|
|
364
|
+
advertencias: input.warnings ?? [],
|
|
365
|
+
corte_adaptativo: {
|
|
366
|
+
aplicado: input.adaptiveCutoffApplied ?? false,
|
|
367
|
+
motivo: cutoffReason
|
|
368
|
+
},
|
|
369
|
+
tiene_mas: input.hasMore,
|
|
370
|
+
cursor_siguiente: input.nextCursor ?? null,
|
|
371
|
+
guia_de_continuacion: input.hasMore ? "Para continuar, repet\xED la consulta con el mismo profileId, startDate y endDate y envi\xE1 metadata.cursor_siguiente en cursor." : null
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function getSalesReportOperationKey(operation) {
|
|
375
|
+
return operation.pack_id ?? operation.ordenes[0].order_id;
|
|
376
|
+
}
|
|
377
|
+
function getSalesReportOperationSaleTimestamp(operation) {
|
|
378
|
+
return operation.ordenes.reduce(
|
|
379
|
+
(latest, order) => Date.parse(order.ventas.fecha_de_venta) > Date.parse(latest) ? order.ventas.fecha_de_venta : latest,
|
|
380
|
+
operation.ordenes[0].ventas.fecha_de_venta
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
function compareSalesReportOperations(left, right) {
|
|
384
|
+
const timestampDifference = Date.parse(getSalesReportOperationSaleTimestamp(right)) - Date.parse(getSalesReportOperationSaleTimestamp(left));
|
|
385
|
+
return timestampDifference || getSalesReportOperationKey(right).localeCompare(getSalesReportOperationKey(left));
|
|
386
|
+
}
|
|
387
|
+
function sortSalesReportOperations(operations) {
|
|
388
|
+
return [...operations].sort(compareSalesReportOperations);
|
|
389
|
+
}
|
|
390
|
+
function isSalesReportOperationAfterCursor(operation, cursor) {
|
|
391
|
+
const timestampDifference = Date.parse(getSalesReportOperationSaleTimestamp(operation)) - Date.parse(cursor.lastSaleTimestamp);
|
|
392
|
+
return timestampDifference < 0 || timestampDifference === 0 && getSalesReportOperationKey(operation) < cursor.lastOperationKey;
|
|
393
|
+
}
|
|
394
|
+
function getCursorSigningKey() {
|
|
395
|
+
const rawValue = process.env.DB_ENCRYPTION_KEY?.trim();
|
|
396
|
+
if (!rawValue) {
|
|
397
|
+
throw new Error("Missing DB_ENCRYPTION_KEY. Configure it before using sales report cursors.");
|
|
398
|
+
}
|
|
399
|
+
const key = Buffer.from(rawValue, "hex");
|
|
400
|
+
if (key.length !== 32 || rawValue.length !== 64) {
|
|
401
|
+
throw new Error(
|
|
402
|
+
"Invalid DB_ENCRYPTION_KEY. Expected a 32-byte key encoded as 64 hex characters."
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
return createHmac("sha256", key).update(CURSOR_DOMAIN).digest();
|
|
406
|
+
}
|
|
407
|
+
function signCursorPayload(encodedPayload) {
|
|
408
|
+
return createHmac("sha256", getCursorSigningKey()).update(encodedPayload).digest();
|
|
409
|
+
}
|
|
410
|
+
const cursorPayloadSchema = z.object({
|
|
411
|
+
version: z.literal(SALES_REPORT_CURSOR_VERSION),
|
|
412
|
+
profileId: z.string().trim().min(1),
|
|
413
|
+
startDate: salesReportDateSchema,
|
|
414
|
+
endDate: salesReportDateSchema,
|
|
415
|
+
lastSaleTimestamp: z.string().refine((value) => !Number.isNaN(Date.parse(value))),
|
|
416
|
+
lastOperationKey: z.string().trim().min(1)
|
|
417
|
+
});
|
|
418
|
+
function encodeSalesReportCursor(input) {
|
|
419
|
+
const payload = cursorPayloadSchema.parse({
|
|
420
|
+
version: SALES_REPORT_CURSOR_VERSION,
|
|
421
|
+
...input
|
|
422
|
+
});
|
|
423
|
+
const encodedPayload = Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
424
|
+
const signature = signCursorPayload(encodedPayload).toString("base64url");
|
|
425
|
+
return `${encodedPayload}.${signature}`;
|
|
426
|
+
}
|
|
427
|
+
function decodeSalesReportCursor(token, expectedScope) {
|
|
428
|
+
const [encodedPayload, encodedSignature, extra] = token.split(".");
|
|
429
|
+
if (!encodedPayload || !encodedSignature || extra) {
|
|
430
|
+
throw new Error("Invalid sales report cursor");
|
|
431
|
+
}
|
|
432
|
+
let receivedSignature;
|
|
433
|
+
try {
|
|
434
|
+
receivedSignature = Buffer.from(encodedSignature, "base64url");
|
|
435
|
+
} catch {
|
|
436
|
+
throw new Error("Invalid sales report cursor");
|
|
437
|
+
}
|
|
438
|
+
const expectedSignature = signCursorPayload(encodedPayload);
|
|
439
|
+
if (receivedSignature.length !== expectedSignature.length || !timingSafeEqual(receivedSignature, expectedSignature)) {
|
|
440
|
+
throw new Error("Invalid sales report cursor");
|
|
441
|
+
}
|
|
442
|
+
let candidate;
|
|
443
|
+
try {
|
|
444
|
+
candidate = JSON.parse(Buffer.from(encodedPayload, "base64url").toString("utf8"));
|
|
445
|
+
} catch {
|
|
446
|
+
throw new Error("Invalid sales report cursor");
|
|
447
|
+
}
|
|
448
|
+
const payload = cursorPayloadSchema.parse(candidate);
|
|
449
|
+
if (payload.profileId !== expectedScope.profileId || payload.startDate !== expectedScope.startDate || payload.endDate !== expectedScope.endDate) {
|
|
450
|
+
throw new Error("Sales report cursor does not match the requested report scope");
|
|
451
|
+
}
|
|
452
|
+
return payload;
|
|
453
|
+
}
|
|
454
|
+
export {
|
|
455
|
+
SALES_REPORT_CURSOR_VERSION,
|
|
456
|
+
SALES_REPORT_DEFAULT_LIMIT,
|
|
457
|
+
SALES_REPORT_MAX_LIMIT,
|
|
458
|
+
SALES_REPORT_TIME_ZONE,
|
|
459
|
+
buildSalesReportDateBoundaries,
|
|
460
|
+
buildSalesReportMetadata,
|
|
461
|
+
buildSalesReportShipmentCoverage,
|
|
462
|
+
compareSalesReportOperations,
|
|
463
|
+
createSalesReportPerformanceTracker,
|
|
464
|
+
decodeSalesReportCursor,
|
|
465
|
+
encodeSalesReportCursor,
|
|
466
|
+
getSalesReportOperationKey,
|
|
467
|
+
getSalesReportOperationSaleTimestamp,
|
|
468
|
+
getSalesReportPostPurchaseCoverageState,
|
|
469
|
+
isSalesReportOperationAfterCursor,
|
|
470
|
+
meliGetSalesReportHandler,
|
|
471
|
+
meliGetSalesReportSchema,
|
|
472
|
+
sortSalesReportOperations
|
|
473
|
+
};
|
|
474
|
+
//# sourceMappingURL=get-sales-report.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/tools/mercadolibre/get-sales-report.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nimport { z } from \"zod\";\nimport { object } from \"mcp-use/server\";\n\nimport { mercadoLibreDateRegex } from \"./helpers.js\";\nimport {\n fetchMercadoLibreOrderUniverse,\n buildOrderUniversePagePlan,\n fetchMercadoLibreShipmentEvidence,\n enrichSalesReportEnvios,\n SALES_REPORT_ENVIOS_FIELDS,\n enrichSalesReportVentas,\n enrichSalesReportPublicaciones,\n enrichSalesReportFacturacion,\n enrichSalesReportCompradores,\n enrichSalesReportDevolucionesReclamos,\n fetchMercadoLibreFiscalEvidence,\n SALES_REPORT_FACTURACION_FIELDS,\n groupMercadoLibreOrders,\n selectMercadoLibreOrdersById,\n} from \"../../services/mercadolibre/mercadolibre-sales-report.js\";\nimport { getMercadoLibreBillingProvisionsByOrder } from \"../../services/mercadolibre/mercadolibre-billing.js\";\nimport { getMercadoLibreApiContext } from \"../../services/mercadolibre/mercadolibre-api.js\";\nimport { reconcileMercadoLibreClaimData } from \"../../services/mercadolibre/mercadolibre-claim-reconciliation.js\";\nimport { reconcileMercadoLibreReturnData } from \"../../services/mercadolibre/mercadolibre-return-reconciliation.js\";\nimport { createMercadoLibreClaimReturnLookup } from \"../../services/mercadolibre/mercadolibre-claim-return-lookup.js\";\n\nexport const SALES_REPORT_TIME_ZONE = \"America/Argentina/Buenos_Aires\";\nexport const SALES_REPORT_DEFAULT_LIMIT = 200;\nexport const SALES_REPORT_MAX_LIMIT = 1000;\nexport const SALES_REPORT_CURSOR_VERSION = 1;\n\nconst CURSOR_DOMAIN = \"bi-mcp:meli-sales-report-cursor:v1\";\n\nfunction isCalendarDate(value: string): boolean {\n if (!mercadoLibreDateRegex.test(value)) return false;\n\n const [year, month, day] = value.split(\"-\").map(Number);\n const date = new Date(Date.UTC(year, month - 1, day));\n return (\n date.getUTCFullYear() === year &&\n date.getUTCMonth() === month - 1 &&\n date.getUTCDate() === day\n );\n}\n\nconst salesReportDateSchema = z\n .string()\n .refine(isCalendarDate, \"Expected a valid calendar date in YYYY-MM-DD format\");\n\nexport const meliGetSalesReportSchema = z\n .object({\n profileId: z.string().trim().min(1).describe(\"Explicit MercadoLibre profile id to use.\"),\n startDate: salesReportDateSchema.optional().describe(\n `Inclusive sales start date in YYYY-MM-DD format using ${SALES_REPORT_TIME_ZONE}.`\n ),\n endDate: salesReportDateSchema.optional().describe(\n `Inclusive sales end date in YYYY-MM-DD format using ${SALES_REPORT_TIME_ZONE}.`\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(SALES_REPORT_MAX_LIMIT)\n .optional()\n .describe(\"Target maximum complete commercial operations to return.\"),\n cursor: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\"Opaque continuation cursor returned by a previous call for the same report scope.\"),\n orderIds: z\n .array(z.string().trim().min(1, \"Order IDs cannot be empty\"))\n .min(1)\n .max(100)\n .optional()\n .describe(\"One to 100 opaque order IDs. Packs expand to all seller-owned member orders.\"),\n })\n .strict()\n .superRefine((value, context) => {\n const explicit = value.orderIds !== undefined;\n const hasAnyRangeField = value.startDate !== undefined || value.endDate !== undefined || value.limit !== undefined || value.cursor !== undefined;\n if (explicit && hasAnyRangeField) {\n context.addIssue({ code: \"custom\", path: [\"orderIds\"], message: \"orderIds cannot be combined with startDate, endDate, limit, or cursor\" });\n }\n if (!explicit && (value.startDate === undefined || value.endDate === undefined)) {\n context.addIssue({ code: \"custom\", path: [\"startDate\"], message: \"Range mode requires both startDate and endDate\" });\n }\n if (value.startDate && value.endDate && value.startDate > value.endDate) {\n context.addIssue({\n code: \"custom\",\n path: [\"endDate\"],\n message: \"endDate must be on or after startDate\",\n });\n }\n });\n\nexport type MeliGetSalesReportInput = z.infer<typeof meliGetSalesReportSchema>;\n\nexport type SalesReportMonotonicClock = () => number;\n\nexport function createSalesReportPerformanceTracker(\n now: SalesReportMonotonicClock = performance.now.bind(performance),\n) {\n const handlerStartedAt = now();\n const durations = new Map<string, number>();\n const elapsed = (startedAt: number) => Math.max(0, Math.round(now() - startedAt));\n\n return {\n start: now,\n finish(stage: string, startedAt: number) {\n const duration = elapsed(startedAt);\n durations.set(stage, duration);\n return duration;\n },\n async measure<T>(stage: string, operation: () => Promise<T>): Promise<T> {\n const startedAt = now();\n try {\n return await operation();\n } finally {\n durations.set(stage, elapsed(startedAt));\n }\n },\n duration(stage: string) {\n return durations.get(stage) ?? 0;\n },\n total() {\n return elapsed(handlerStartedAt);\n },\n };\n}\n\nexport function getSalesReportPostPurchaseCoverageState(readStatus: \"fulfilled\" | \"rejected\", resolutions: unknown[] = [], incidents = 0): SalesReportCoverageStatus {\n if (readStatus === \"rejected\") return \"unavailable\";\n return incidents > 0 || resolutions.some((resolution) => (resolution as { status?: string }).status !== \"resolved\") ? \"partial\" : \"complete\";\n}\n\nexport async function meliGetSalesReportHandler(input: MeliGetSalesReportInput) {\n const performanceTracker = createSalesReportPerformanceTracker();\n const parsed = meliGetSalesReportSchema.parse(input);\n const profileStartedAt = performanceTracker.start();\n const profileContext = await getMercadoLibreApiContext(parsed.profileId);\n performanceTracker.finish(\"contexto_perfil\", profileStartedAt);\n const explicitMode = parsed.orderIds !== undefined;\n const submittedOrderIds = parsed.orderIds ?? [];\n const uniqueOrderIds = [...new Set(submittedOrderIds)];\n const rangeLimit = parsed.limit ?? SALES_REPORT_DEFAULT_LIMIT;\n const scope = explicitMode ? null : { profileId: parsed.profileId, startDate: parsed.startDate!, endDate: parsed.endDate! };\n const cursor = !explicitMode && parsed.cursor ? decodeSalesReportCursor(parsed.cursor, scope!) : null;\n const selectionStartedAt = performanceTracker.start();\n const selection = explicitMode\n ? await selectMercadoLibreOrdersById(parsed.profileId, profileContext.sellerId, uniqueOrderIds)\n : null;\n const universe = explicitMode\n ? { orders: selection!.orders, paging: { total: selection!.orders.length, limit: 0, offset: 0 }, failedPages: [] }\n : await fetchMercadoLibreOrderUniverse(\n parsed.profileId,\n buildSalesReportDateBoundaries(parsed.startDate!, parsed.endDate!).from,\n buildSalesReportDateBoundaries(parsed.startDate!, parsed.endDate!).to,\n rangeLimit,\n );\n const operations = groupMercadoLibreOrders(universe.orders).filter((operation) => !cursor || isSalesReportOperationAfterCursor(operation, cursor));\n const items = explicitMode ? operations : operations.slice(0, rangeLimit);\n performanceTracker.finish(\"seleccion_ordenes\", selectionStartedAt);\n const selectedOrderIds = items.flatMap((item) => item.ordenes.map((order) => order.order_id));\n const billingStartedAt = performanceTracker.start();\n const billing = await getMercadoLibreBillingProvisionsByOrder(parsed.profileId, {\n orderIds: selectedOrderIds,\n });\n const ventas = enrichSalesReportVentas(items, billing);\n const publicaciones = enrichSalesReportPublicaciones(ventas.operations, billing);\n performanceTracker.finish(\"billing\", billingStartedAt);\n const shipmentStartedAt = performanceTracker.start();\n const shipments = await fetchMercadoLibreShipmentEvidence(parsed.profileId, selectedOrderIds);\n const envios = enrichSalesReportEnvios(publicaciones.operations, shipments.successful.map((result) => ({ order_id: result.id, shipment: result.document })));\n performanceTracker.finish(\"envios\", shipmentStartedAt);\n const fiscalStartedAt = performanceTracker.start();\n const fiscal = await fetchMercadoLibreFiscalEvidence(parsed.profileId, selectedOrderIds);\n const facturacion = enrichSalesReportFacturacion(envios.operations, fiscal.successful, fiscal.failed);\n const compradores = enrichSalesReportCompradores(facturacion.operations, profileContext.sellerId);\n performanceTracker.finish(\"facturacion_fiscal\", fiscalStartedAt);\n const references = items.map((item) => ({\n reference: getSalesReportOperationKey(item),\n kind: item.pack_id ? \"pack\" as const : \"order\" as const,\n }));\n const postPurchaseStartedAt = performanceTracker.start();\n const claimReturnLookup = createMercadoLibreClaimReturnLookup();\n const [returnRead, claimRead] = await Promise.allSettled([\n performanceTracker.measure(\"devoluciones\", () => reconcileMercadoLibreReturnData(parsed.profileId, references, { claimReturnLookup })),\n performanceTracker.measure(\"reclamos\", () => reconcileMercadoLibreClaimData(parsed.profileId, references, \"standard\", claimReturnLookup)),\n ]);\n const postPurchase = enrichSalesReportDevolucionesReclamos(compradores.operations, {\n returns: returnRead.status === \"fulfilled\" ? returnRead.value : undefined,\n claims: claimRead.status === \"fulfilled\" ? claimRead.value : undefined,\n returnFailure: returnRead.status === \"rejected\" ? returnRead.reason : undefined,\n claimFailure: claimRead.status === \"rejected\" ? claimRead.reason : undefined,\n });\n performanceTracker.finish(\"postventa\", postPurchaseStartedAt);\n const assemblyStartedAt = performanceTracker.start();\n const shipmentFieldProvenance = SALES_REPORT_ENVIOS_FIELDS.map((campo) => {\n const coverage = envios.fieldCoverage[campo];\n return { campo: `envios.${campo}`, fuente: \"shipments\" as const, estado: coverage.obtenidos === coverage.solicitados ? \"available\" as const : \"unavailable\" as const, detalle: `Orders shipment evidence: ${coverage.obtenidos}/${coverage.solicitados} orders.` };\n });\n const fiscalFieldProvenance = SALES_REPORT_FACTURACION_FIELDS.map((campo) => {\n const coverage = facturacion.fieldCoverage[campo];\n const unsupported = campo === \"factura_adjunta\" || campo === \"numero_iibb\";\n return { campo: `facturacion_al_comprador.${campo}`, fuente: \"billing_info\" as const, estado: unsupported ? \"unsupported\" as const : coverage.obtenidos === coverage.solicitados ? \"available\" as const : \"unavailable\" as const, detalle: unsupported ? \"No validated official buyer-fiscal evidence for this field.\" : `Mercado Libre Orders billing-info evidence: ${coverage.obtenidos}/${coverage.solicitados} orders.` };\n });\n const returnFields = [\"unidades\", \"revisado_por_mercado_libre\", \"fecha_de_revision\", \"resultado\", \"destino\", \"motivo_del_resultado\"];\n const unsupportedReturnFields = [\"forma_de_entrega\", \"fecha_en_camino\", \"fecha_entregado\", \"transportista\", \"numero_de_seguimiento\", \"url_de_seguimiento\", \"dinero_a_favor\"];\n const returnIncidents = postPurchase.incidents.filter((incident) => incident.fuente === \"returns\").length;\n const claimIncidents = postPurchase.incidents.filter((incident) => incident.fuente === \"claims\").length;\n const returnProvenance = [...returnFields.map((campo) => { const c = postPurchase.coverage[`devoluciones.${campo}`]; return { campo: `devoluciones.${campo}`, fuente: \"returns\" as const, estado: c.obtenidos === c.solicitados && returnRead.status === \"fulfilled\" ? \"available\" as const : \"unavailable\" as const, detalle: \"Validated post-purchase return evidence; absence remains unknown.\" }; }), ...unsupportedReturnFields.map((campo) => ({ campo: `devoluciones.${campo}`, fuente: \"returns\" as const, estado: \"unsupported\" as const, detalle: \"No official/direct evidence supports this sales-report field.\" }))];\n const claimProvenance = [\"unidades\", \"reclamo_abierto\", \"reclamo_cerrado\", \"con_mediacion\"].map((campo) => { const c = postPurchase.coverage[`reclamos.${campo}`]; return { campo: `reclamos.${campo}`, fuente: \"claims\" as const, estado: c.obtenidos === c.solicitados && claimRead.status === \"fulfilled\" ? \"available\" as const : \"unavailable\" as const, detalle: \"Validated claim detail evidence; absence remains unknown.\" }; });\n const last = items.at(-1);\n const hasMore = !explicitMode && (universe.failedPages.length > 0 ||\n universe.orders.length < universe.paging.total || operations.length > items.length);\n const nextCursor = hasMore && last\n ? encodeSalesReportCursor({ ...scope!, lastSaleTimestamp: getSalesReportOperationSaleTimestamp(last), lastOperationKey: getSalesReportOperationKey(last) })\n : null;\n const baseMetadata = buildSalesReportMetadata({\n profileId: parsed.profileId,\n startDate: scope?.startDate ?? null,\n endDate: scope?.endDate ?? null,\n itemsReturned: items.length,\n requestedLimit: explicitMode ? null : rangeLimit,\n selectionMode: explicitMode ? \"ordenes_explicitas\" : \"rango_fechas\",\n explicitSelection: explicitMode ? {\n ids_solicitados: submittedOrderIds,\n ids_unicos: uniqueOrderIds,\n cantidad_solicitada: submittedOrderIds.length,\n cantidad_unica: uniqueOrderIds.length,\n cantidad_duplicada: submittedOrderIds.length - uniqueOrderIds.length,\n ids_resueltos: uniqueOrderIds.filter((id) => !selection!.unavailableRequestedIds.includes(id)),\n cantidad_resuelta: uniqueOrderIds.length - selection!.unavailableRequestedIds.length,\n ids_no_disponibles: selection!.unavailableRequestedIds,\n cantidad_no_disponible: selection!.unavailableRequestedIds.length,\n } : null,\n currencies: ventas.currencies,\n packsReturned: items.filter((item) => item.pack_id !== null).length,\n ordersReturned: items.reduce((count, item) => count + item.ordenes.length, 0),\n sourceCoverage: [\n { fuente: \"orders\", estado: explicitMode ? selection!.incidents.length ? \"partial\" : \"complete\" : universe.failedPages.length || universe.orders.length < universe.paging.total ? \"partial\" : \"complete\", solicitados: explicitMode ? uniqueOrderIds.length : universe.paging.total, obtenidos: explicitMode ? uniqueOrderIds.length - selection!.unavailableRequestedIds.length : universe.orders.length, incidentes: explicitMode ? selection!.incidents.length : universe.failedPages.length },\n { fuente: \"billing\", estado: billing.failures.length ? \"partial\" : \"complete\", solicitados: billing.order_ids_requested.length, obtenidos: billing.order_ids_found.length, incidentes: billing.failures.length + billing.order_ids_not_found.length },\n { fuente: \"billing_info\", estado: fiscal.failed.length || facturacion.incidents.length ? \"partial\" : \"complete\", solicitados: selectedOrderIds.length, obtenidos: new Set(fiscal.successful.filter((entry) => entry.result?.available).map((entry) => entry.orderId)).size, incidentes: fiscal.failed.length + facturacion.incidents.length },\n buildSalesReportShipmentCoverage(selectedOrderIds.length, shipments.successful.length, envios.incidents.length, shipments.failed.length),\n { fuente: \"returns\", estado: getSalesReportPostPurchaseCoverageState(returnRead.status, returnRead.status === \"fulfilled\" ? returnRead.value.results.map((result: any) => result.resolution) : [], returnIncidents), solicitados: selectedOrderIds.length, obtenidos: postPurchase.returnContexts, incidentes: returnIncidents },\n { fuente: \"claims\", estado: getSalesReportPostPurchaseCoverageState(claimRead.status, claimRead.status === \"fulfilled\" ? claimRead.value.results.map((result: any) => result.resolution) : [], claimIncidents), solicitados: selectedOrderIds.length, obtenidos: postPurchase.claimContexts, incidentes: claimIncidents },\n ],\n fieldProvenance: [\n { campo: \"publicidad.venta_por_publicidad\", fuente: \"derived\", estado: \"unsupported\", detalle: \"Product Ads exposes listing-level aggregate metrics without a deterministic order/sale identifier; no attribution is inferred.\" },\n { campo: \"ventas.cargo_por_diferencias_en_medidas_y_peso_del_paquete\", fuente: \"billing\", estado: \"unsupported\", detalle: \"No validated Billing-by-order source.\" },\n { campo: \"ventas.pertenece_a_un_kit\", fuente: \"billing\", estado: billing.failures.length ? \"unavailable\" : \"available\", detalle: \"Billing items_info.item_kit_id per member order.\" },\n { campo: \"publicaciones.sku\", fuente: \"orders\", estado: \"available\", detalle: \"Orders order_items.item.seller_sku.\" },\n { campo: \"publicaciones.numero_de_publicacion\", fuente: \"orders\", estado: \"available\", detalle: \"Orders order_items.item.id.\" },\n { campo: \"publicaciones.titulo_de_la_publicacion\", fuente: \"orders\", estado: \"available\", detalle: \"Orders order_items.item.title, Billing fallback.\" },\n { campo: \"publicaciones.variante\", fuente: \"orders\", estado: \"available\", detalle: \"Orders variation_attributes formatted as name/value pairs.\" },\n { campo: \"publicaciones.precio_unitario_de_venta_de_la_publicacion_ars\", fuente: \"orders\", estado: \"available\", detalle: \"Orders order_items.unit_price, Billing fallback.\" },\n { campo: \"publicaciones.canal_de_venta\", fuente: \"billing\", estado: billing.failures.length ? \"unavailable\" : \"available\", detalle: billing.failures.length ? \"Billing coverage is partial.\" : \"Billing sales_info.sales_channel.\" },\n { campo: \"publicaciones.tiene_cuotas_agregadas\", fuente: \"billing\", estado: billing.failures.length ? \"unavailable\" : \"available\", detalle: \"Billing items_info.fees_added_in_publication; exact Si/No only.\" },\n ...shipmentFieldProvenance,\n ...fiscalFieldProvenance,\n ...returnProvenance,\n ...claimProvenance,\n { campo: \"compradores.comprador\", fuente: \"orders\", estado: compradores.incidents.length ? \"unavailable\" as const : \"available\" as const, detalle: \"Orders buyer.nickname only after explicit seller ownership verification.\" },\n ...[\"negocio\", \"dni\", \"domicilio\", \"ciudad\", \"estado\", \"codigo_postal\", \"pais\"].map((campo) => ({ campo: `compradores.${campo}`, fuente: \"orders\" as const, estado: \"unsupported\" as const, detalle: \"Bulk buyer PII is blocked by policy.\" })),\n ],\n scopedIncidents: [\n ...(selection?.incidents ?? []),\n ...universe.failedPages.map((page) => ({ fuente: \"orders\" as const, alcance: \"page\", identificadores: [page], mensaje: \"Orders page retrieval failed.\", reintentable: true })),\n ...ventas.incidents,\n ...publicaciones.incidents,\n ...envios.incidents,\n ...facturacion.incidents,\n ...compradores.incidents,\n ...postPurchase.incidents,\n ...billing.failures.map((failure) => ({ fuente: \"billing\" as const, alcance: \"chunk\", identificadores: failure.order_ids, mensaje: failure.message, reintentable: true })),\n ...shipments.failed.map((failure) => ({ fuente: \"shipments\" as const, alcance: \"order\", identificadores: [failure.id], mensaje: failure.message, reintentable: failure.retryable })),\n ],\n unsupportedFields: [\"publicidad.venta_por_publicidad\", \"ventas.cargo_por_diferencias_en_medidas_y_peso_del_paquete\", ...unsupportedReturnFields.map((campo) => `devoluciones.${campo}`), ...[\"negocio\", \"dni\", \"domicilio\", \"ciudad\", \"estado\", \"codigo_postal\", \"pais\"].map((campo) => `compradores.${campo}`)],\n unknownBillingConcepts: ventas.unknownConcepts,\n hasMore, nextCursor,\n });\n performanceTracker.finish(\"ensamblado\", assemblyStartedAt);\n const metadata: SalesReportMetadata = {\n ...baseMetadata,\n rendimiento: {\n duracion_total_ms: performanceTracker.total(),\n etapas: {\n contexto_perfil: { duracion_ms: performanceTracker.duration(\"contexto_perfil\") },\n seleccion_ordenes: {\n duracion_ms: performanceTracker.duration(\"seleccion_ordenes\"),\n ids_solicitados: explicitMode ? submittedOrderIds.length : universe.paging.total,\n ids_unicos: explicitMode ? uniqueOrderIds.length : universe.paging.total,\n ids_resueltos: explicitMode ? uniqueOrderIds.length - selection!.unavailableRequestedIds.length : universe.orders.length,\n operaciones_resueltas: items.length,\n ordenes_resueltas: selectedOrderIds.length,\n paginas_solicitadas: explicitMode ? 0 : 1 + buildOrderUniversePagePlan(universe.paging, rangeLimit).length,\n paginas_fallidas: universe.failedPages.length,\n },\n billing: {\n duracion_ms: performanceTracker.duration(\"billing\"),\n ids_solicitados: billing.order_ids_requested.length,\n ids_encontrados: billing.order_ids_found.length,\n ids_no_encontrados: billing.order_ids_not_found.length,\n lotes_totales: billing.chunks_total,\n lotes_exitosos: billing.chunks_succeeded,\n lotes_fallidos: billing.chunks_failed,\n fallas: billing.failures.length,\n },\n envios: {\n duracion_ms: performanceTracker.duration(\"envios\"),\n solicitados: selectedOrderIds.length,\n exitosos: shipments.successful.length,\n fallidos: shipments.failed.length,\n },\n facturacion_fiscal: {\n duracion_ms: performanceTracker.duration(\"facturacion_fiscal\"),\n solicitados: selectedOrderIds.length,\n exitosos: new Set(fiscal.successful.map((entry) => entry.orderId)).size,\n fallidos: fiscal.failed.length,\n },\n postventa: {\n duracion_ms: performanceTracker.duration(\"postventa\"),\n devoluciones_ms: performanceTracker.duration(\"devoluciones\"),\n reclamos_ms: performanceTracker.duration(\"reclamos\"),\n referencias_solicitadas: references.length,\n contextos_devoluciones: postPurchase.returnContexts,\n contextos_reclamos: postPurchase.claimContexts,\n incidentes_devoluciones: returnIncidents,\n incidentes_reclamos: claimIncidents,\n },\n ensamblado: { duracion_ms: performanceTracker.duration(\"ensamblado\") },\n },\n },\n };\n return object({\n items: postPurchase.operations,\n metadata,\n });\n}\n\nexport interface SalesReportDateBoundaries {\n timeZone: typeof SALES_REPORT_TIME_ZONE;\n from: string;\n to: string;\n}\n\nexport function buildSalesReportDateBoundaries(\n startDate: string,\n endDate: string\n): SalesReportDateBoundaries {\n const parsed = {\n startDate: salesReportDateSchema.parse(startDate),\n endDate: salesReportDateSchema.parse(endDate),\n };\n\n if (parsed.startDate > parsed.endDate) {\n throw new Error(\"endDate must be on or after startDate\");\n }\n\n return {\n timeZone: SALES_REPORT_TIME_ZONE,\n from: `${parsed.startDate}T00:00:00.000${getBuenosAiresOffset(parsed.startDate)}`,\n to: `${parsed.endDate}T23:59:59.999${getBuenosAiresOffset(parsed.endDate)}`,\n };\n}\n\nfunction getBuenosAiresOffset(date: string): string {\n const offset = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: SALES_REPORT_TIME_ZONE,\n timeZoneName: \"longOffset\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n }).formatToParts(new Date(`${date}T12:00:00.000Z`)).find((part) => part.type === \"timeZoneName\")?.value;\n const match = offset?.match(/^GMT([+-]\\d{2}:\\d{2})$/);\n if (!match) throw new Error(`Unable to resolve ${SALES_REPORT_TIME_ZONE} offset for ${date}`);\n return match[1];\n}\n\nexport interface SalesReportOperationSales {\n paquete_de_varios_productos: boolean;\n cargo_por_venta: number | null;\n costo_fijo: number | null;\n costo_por_ofrecer_cuotas: number | null;\n ingresos_por_envio_ars: number | null;\n costos_de_envio_ars: number | null;\n costo_de_envio_por_cambio_de_producto: number | null;\n costo_de_envio_basado_en_medidas_y_peso_declarados: number | null;\n cargo_por_diferencias_en_medidas_y_peso_del_paquete: number | null;\n impuestos: number | null;\n descuentos_y_bonificaciones: number | null;\n anulaciones_y_reembolsos_ars: number | null;\n total_ars: number | null;\n periodos_de_facturacion: string[];\n}\n\nexport interface SalesReportOrderSales {\n fecha_de_venta: string;\n estado: string | null;\n descripcion_del_estado: string | null;\n pertenece_a_un_kit: boolean | null;\n unidades: number | null;\n ingresos_por_productos_ars: number | null;\n orden_de_compra: string | null;\n}\n\nexport interface SalesReportOrder {\n order_id: string;\n ventas: SalesReportOrderSales;\n publicidad: { venta_por_publicidad: boolean | null };\n publicaciones: {\n sku: string | null;\n numero_de_publicacion: string | null;\n canal_de_venta: string | null;\n titulo_de_la_publicacion: string | null;\n variante: string | null;\n precio_unitario_de_venta_de_la_publicacion_ars: number | null;\n tiene_cuotas_agregadas: boolean | null;\n };\n facturacion_al_comprador: {\n factura_adjunta: string | null;\n datos_personales_o_de_empresa: string | null;\n tipo_y_numero_de_documento: string | null;\n direccion: string | null;\n condicion_fiscal_iva: string | null;\n numero_iibb: string | null;\n };\n compradores: {\n comprador: string | null;\n negocio: string | null;\n dni: string | null;\n domicilio: string | null;\n ciudad: string | null;\n estado: string | null;\n codigo_postal: string | null;\n pais: string | null;\n };\n envios: {\n forma_de_entrega: string | null;\n fecha_en_camino: string | null;\n fecha_entregado: string | null;\n transportista: string | null;\n numero_de_seguimiento: string | null;\n url_de_seguimiento: string | null;\n };\n devoluciones: {\n unidades: number | null;\n forma_de_entrega: string | null;\n fecha_en_camino: string | null;\n fecha_entregado: string | null;\n transportista: string | null;\n numero_de_seguimiento: string | null;\n url_de_seguimiento: string | null;\n revisado_por_mercado_libre: boolean | null;\n fecha_de_revision: string | null;\n dinero_a_favor: number | null;\n resultado: string | null;\n destino: string | null;\n motivo_del_resultado: string | null;\n };\n reclamos: {\n unidades: number | null;\n reclamo_abierto: boolean | null;\n reclamo_cerrado: boolean | null;\n con_mediacion: boolean | null;\n };\n}\n\nexport interface SalesReportOperation {\n pack_id: string | null;\n ventas: SalesReportOperationSales;\n ordenes: [SalesReportOrder, ...SalesReportOrder[]];\n}\n\nexport type SalesReportSource = \"orders\" | \"packs\" | \"billing\" | \"billing_info\" | \"shipments\" | \"returns\" | \"claims\";\nexport type SalesReportCoverageStatus = \"complete\" | \"partial\" | \"unavailable\";\n\nexport interface SalesReportScopedIncident {\n fuente: SalesReportSource;\n alcance: string;\n identificadores: string[];\n mensaje: string;\n reintentable: boolean;\n estado_http?: number | null;\n}\n\nexport interface SalesReportSourceCoverage {\n fuente: SalesReportSource;\n estado: SalesReportCoverageStatus;\n solicitados: number;\n obtenidos: number;\n incidentes: number;\n}\n\nexport function buildSalesReportShipmentCoverage(\n requested: number,\n obtained: number,\n mappingIncidents: number,\n batchFailures: number,\n): SalesReportSourceCoverage {\n return {\n fuente: \"shipments\",\n estado: mappingIncidents || batchFailures ? \"partial\" : \"complete\",\n solicitados: requested,\n obtenidos: obtained,\n incidentes: mappingIncidents + batchFailures,\n };\n}\n\nexport interface SalesReportFieldProvenance {\n campo: string;\n fuente: SalesReportSource | \"derived\";\n estado: \"available\" | \"unavailable\" | \"unsupported\";\n detalle: string | null;\n}\n\nexport interface SalesReportMetadata {\n profile_id: string;\n modo_seleccion: \"rango_fechas\" | \"ordenes_explicitas\";\n seleccion_explicita: {\n ids_solicitados: string[];\n ids_unicos: string[];\n cantidad_solicitada: number;\n cantidad_unica: number;\n cantidad_duplicada: number;\n ids_resueltos: string[];\n cantidad_resuelta: number;\n ids_no_disponibles: string[];\n cantidad_no_disponible: number;\n } | null;\n fecha_desde: string | null;\n fecha_hasta: string | null;\n monedas: string[];\n items_devueltos: number;\n limite_solicitado: number | null;\n motivo_del_corte: string | null;\n packs_devueltos: number;\n ordenes_devueltas: number;\n cobertura_completa: boolean;\n secciones_parciales: string[];\n cobertura_por_fuente: SalesReportSourceCoverage[];\n incidentes_acotados: SalesReportScopedIncident[];\n campos_no_disponibles: string[];\n conceptos_de_facturacion_desconocidos: string[];\n advertencias: string[];\n corte_adaptativo: {\n aplicado: boolean;\n motivo: string | null;\n };\n tiene_mas: boolean;\n cursor_siguiente: string | null;\n guia_de_continuacion: string | null;\n rendimiento: {\n duracion_total_ms: number;\n etapas: {\n contexto_perfil: { duracion_ms: number };\n seleccion_ordenes: { duracion_ms: number; ids_solicitados: number; ids_unicos: number; ids_resueltos: number; operaciones_resueltas: number; ordenes_resueltas: number; paginas_solicitadas: number; paginas_fallidas: number };\n billing: { duracion_ms: number; ids_solicitados: number; ids_encontrados: number; ids_no_encontrados: number; lotes_totales: number; lotes_exitosos: number; lotes_fallidos: number; fallas: number };\n envios: { duracion_ms: number; solicitados: number; exitosos: number; fallidos: number };\n facturacion_fiscal: { duracion_ms: number; solicitados: number; exitosos: number; fallidos: number };\n postventa: { duracion_ms: number; devoluciones_ms: number; reclamos_ms: number; referencias_solicitadas: number; contextos_devoluciones: number; contextos_reclamos: number; incidentes_devoluciones: number; incidentes_reclamos: number };\n ensamblado: { duracion_ms: number };\n };\n };\n}\n\nexport interface SalesReportOutput {\n items: SalesReportOperation[];\n metadata: SalesReportMetadata;\n}\n\nexport interface BuildSalesReportMetadataInput {\n profileId: string;\n startDate: string | null;\n endDate: string | null;\n selectionMode?: \"rango_fechas\" | \"ordenes_explicitas\";\n explicitSelection?: SalesReportMetadata[\"seleccion_explicita\"];\n currencies?: string[];\n itemsReturned: number;\n requestedLimit: number | null;\n cutoffReason?: string | null;\n packsReturned: number;\n ordersReturned: number;\n partialSections?: string[];\n sourceCoverage?: SalesReportSourceCoverage[];\n fieldProvenance?: SalesReportFieldProvenance[];\n scopedIncidents?: SalesReportScopedIncident[];\n unsupportedFields?: string[];\n unknownBillingConcepts?: string[];\n warnings?: string[];\n adaptiveCutoffApplied?: boolean;\n hasMore: boolean;\n nextCursor?: string | null;\n}\n\nexport function buildSalesReportMetadata(\n input: BuildSalesReportMetadataInput\n): Omit<SalesReportMetadata, \"rendimiento\"> {\n const sourceCoverage = input.sourceCoverage ?? [];\n const partialSections = input.partialSections ?? [];\n const scopedIncidents = input.scopedIncidents ?? [];\n const fieldProvenance = input.fieldProvenance ?? [];\n const unavailableFields = [...new Set([\n ...(input.unsupportedFields ?? []),\n ...fieldProvenance.filter((field) => field.estado !== \"available\").map((field) => field.campo),\n ])].sort();\n const coverageComplete =\n partialSections.length === 0 &&\n scopedIncidents.length === 0 &&\n fieldProvenance.every((field) => field.estado === \"available\") &&\n unavailableFields.length === 0 &&\n sourceCoverage.every((source) => source.estado === \"complete\");\n const cutoffReason = input.cutoffReason ?? null;\n\n return {\n profile_id: input.profileId,\n modo_seleccion: input.selectionMode ?? \"rango_fechas\",\n seleccion_explicita: input.explicitSelection ?? null,\n fecha_desde: input.startDate,\n fecha_hasta: input.endDate,\n monedas: [...new Set(input.currencies ?? [])].sort(),\n items_devueltos: input.itemsReturned,\n limite_solicitado: input.requestedLimit,\n motivo_del_corte: cutoffReason,\n packs_devueltos: input.packsReturned,\n ordenes_devueltas: input.ordersReturned,\n cobertura_completa: coverageComplete,\n secciones_parciales: partialSections,\n cobertura_por_fuente: sourceCoverage,\n incidentes_acotados: scopedIncidents,\n campos_no_disponibles: unavailableFields,\n conceptos_de_facturacion_desconocidos: input.unknownBillingConcepts ?? [],\n advertencias: input.warnings ?? [],\n corte_adaptativo: {\n aplicado: input.adaptiveCutoffApplied ?? false,\n motivo: cutoffReason,\n },\n tiene_mas: input.hasMore,\n cursor_siguiente: input.nextCursor ?? null,\n guia_de_continuacion: input.hasMore\n ? \"Para continuar, repet\u00ED la consulta con el mismo profileId, startDate y endDate y envi\u00E1 metadata.cursor_siguiente en cursor.\"\n : null,\n };\n}\n\nexport function getSalesReportOperationKey(operation: SalesReportOperation): string {\n return operation.pack_id ?? operation.ordenes[0].order_id;\n}\n\nexport function getSalesReportOperationSaleTimestamp(operation: SalesReportOperation): string {\n return operation.ordenes.reduce(\n (latest, order) =>\n Date.parse(order.ventas.fecha_de_venta) > Date.parse(latest)\n ? order.ventas.fecha_de_venta\n : latest,\n operation.ordenes[0].ventas.fecha_de_venta\n );\n}\n\nexport function compareSalesReportOperations(\n left: SalesReportOperation,\n right: SalesReportOperation\n): number {\n const timestampDifference =\n Date.parse(getSalesReportOperationSaleTimestamp(right)) -\n Date.parse(getSalesReportOperationSaleTimestamp(left));\n return (\n timestampDifference ||\n getSalesReportOperationKey(right).localeCompare(getSalesReportOperationKey(left))\n );\n}\n\nexport function sortSalesReportOperations(\n operations: readonly SalesReportOperation[]\n): SalesReportOperation[] {\n return [...operations].sort(compareSalesReportOperations);\n}\n\nexport function isSalesReportOperationAfterCursor(\n operation: SalesReportOperation,\n cursor: Pick<SalesReportCursorPayload, \"lastSaleTimestamp\" | \"lastOperationKey\">\n): boolean {\n const timestampDifference =\n Date.parse(getSalesReportOperationSaleTimestamp(operation)) - Date.parse(cursor.lastSaleTimestamp);\n return timestampDifference < 0 ||\n (timestampDifference === 0 && getSalesReportOperationKey(operation) < cursor.lastOperationKey);\n}\n\nexport interface SalesReportCursorScope {\n profileId: string;\n startDate: string;\n endDate: string;\n}\n\nexport interface SalesReportCursorPayload extends SalesReportCursorScope {\n version: typeof SALES_REPORT_CURSOR_VERSION;\n lastSaleTimestamp: string;\n lastOperationKey: string;\n}\n\nfunction getCursorSigningKey(): Buffer {\n const rawValue = process.env.DB_ENCRYPTION_KEY?.trim();\n if (!rawValue) {\n throw new Error(\"Missing DB_ENCRYPTION_KEY. Configure it before using sales report cursors.\");\n }\n\n const key = Buffer.from(rawValue, \"hex\");\n if (key.length !== 32 || rawValue.length !== 64) {\n throw new Error(\n \"Invalid DB_ENCRYPTION_KEY. Expected a 32-byte key encoded as 64 hex characters.\"\n );\n }\n\n return createHmac(\"sha256\", key).update(CURSOR_DOMAIN).digest();\n}\n\nfunction signCursorPayload(encodedPayload: string): Buffer {\n return createHmac(\"sha256\", getCursorSigningKey()).update(encodedPayload).digest();\n}\n\nconst cursorPayloadSchema = z.object({\n version: z.literal(SALES_REPORT_CURSOR_VERSION),\n profileId: z.string().trim().min(1),\n startDate: salesReportDateSchema,\n endDate: salesReportDateSchema,\n lastSaleTimestamp: z.string().refine((value) => !Number.isNaN(Date.parse(value))),\n lastOperationKey: z.string().trim().min(1),\n});\n\nexport function encodeSalesReportCursor(\n input: SalesReportCursorScope & Pick<SalesReportCursorPayload, \"lastSaleTimestamp\" | \"lastOperationKey\">\n): string {\n const payload = cursorPayloadSchema.parse({\n version: SALES_REPORT_CURSOR_VERSION,\n ...input,\n });\n const encodedPayload = Buffer.from(JSON.stringify(payload), \"utf8\").toString(\"base64url\");\n const signature = signCursorPayload(encodedPayload).toString(\"base64url\");\n return `${encodedPayload}.${signature}`;\n}\n\nexport function decodeSalesReportCursor(\n token: string,\n expectedScope: SalesReportCursorScope\n): SalesReportCursorPayload {\n const [encodedPayload, encodedSignature, extra] = token.split(\".\");\n if (!encodedPayload || !encodedSignature || extra) {\n throw new Error(\"Invalid sales report cursor\");\n }\n\n let receivedSignature: Buffer;\n try {\n receivedSignature = Buffer.from(encodedSignature, \"base64url\");\n } catch {\n throw new Error(\"Invalid sales report cursor\");\n }\n\n const expectedSignature = signCursorPayload(encodedPayload);\n if (\n receivedSignature.length !== expectedSignature.length ||\n !timingSafeEqual(receivedSignature, expectedSignature)\n ) {\n throw new Error(\"Invalid sales report cursor\");\n }\n\n let candidate: unknown;\n try {\n candidate = JSON.parse(Buffer.from(encodedPayload, \"base64url\").toString(\"utf8\"));\n } catch {\n throw new Error(\"Invalid sales report cursor\");\n }\n\n const payload = cursorPayloadSchema.parse(candidate);\n if (\n payload.profileId !== expectedScope.profileId ||\n payload.startDate !== expectedScope.startDate ||\n payload.endDate !== expectedScope.endDate\n ) {\n throw new Error(\"Sales report cursor does not match the requested report scope\");\n }\n\n return payload;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|