import { afterEach, describe, expect, it, vi } from "vitest"; const { executeAddressMcpQueryMock } = vi.hoisted(() => ({ executeAddressMcpQueryMock: vi.fn() })); vi.mock("../src/services/addressMcpClient", async () => { const actual = await vi.importActual( "../src/services/addressMcpClient" ); return { ...actual, executeAddressMcpQuery: executeAddressMcpQueryMock }; }); import { AddressQueryService } from "../src/services/addressQueryService"; afterEach(() => { executeAddressMcpQueryMock.mockReset(); vi.restoreAllMocks(); }); describe("inventory sale trace selected-object regressions", () => { const saleRow = { Period: "2021-04-15T00:00:00Z", Registrator: "Реализация товаров и услуг 00000000201 от 15.04.2021 0:00:00", AccountDt: "", AccountKt: "41.01", Amount: 165.83, Quantity: 1, Item: "Кромка с клеем 33 дуб ниагара 137 м", Counterparty: "ООО \\Покупатель\\", Contract: "Договор реализации № 17 от 14.04.2021", Organization: "ООО \\Альтернатива Плюс\\" }; const followupContext = { previous_intent: "inventory_purchase_provenance_for_item" as const, previous_filters: { as_of_date: "2021-03-31", period_from: "2021-03-01", period_to: "2021-03-31", item: "Кромка с клеем 33 дуб ниагара 137 м", organization: "ООО \\Альтернатива Плюс\\" }, previous_anchor_type: "item" as const, previous_anchor_value: "Кромка с клеем 33 дуб ниагара 137 м" }; it("keeps the full selected item for explicit selected-object buyer wording from the live log", async () => { executeAddressMcpQueryMock.mockResolvedValueOnce({ fetched_rows: 1, matched_rows: 1, raw_rows: [saleRow], rows: [], error: null }); const service = new AddressQueryService(); const result = await service.tryHandle('По выбранному объекту "Кромка с клеем 33 дуб ниагара 137 м": кому продали', { followupContext }); expect(result?.handled).toBe(true); expect(result?.response_type).toBe("FACTUAL_LIST"); expect(result?.debug.detected_intent).toBe("inventory_sale_trace_for_item"); expect(result?.debug.extracted_filters?.item).toBe("Кромка с клеем 33 дуб ниагара 137 м"); expect(String(result?.reply_text ?? "")).toContain("ООО \\Покупатель\\"); expect(executeAddressMcpQueryMock).toHaveBeenCalledTimes(1); const query = String(executeAddressMcpQueryMock.mock.calls[0]?.[0]?.query ?? ""); expect(query).toContain("Документ.РеализацияТоваровУслуг.Товары КАК Товары"); expect(query).toContain('Номенклатура.Наименование = "Кромка с клеем 33 дуб ниагара 137 м"'); expect(query).not.toContain('Номенклатура.Наименование = "Кромка"'); }); it("routes selected-object delivery wording 'кому мы это поставили' into sale trace", async () => { executeAddressMcpQueryMock.mockResolvedValueOnce({ fetched_rows: 1, matched_rows: 1, raw_rows: [saleRow], rows: [], error: null }); const service = new AddressQueryService(); const result = await service.tryHandle( 'По выбранному объекту "Кромка с клеем 33 дуб ниагара 137 м": кому мы это поставили', { followupContext: { previous_intent: "inventory_on_hand_as_of_date", previous_filters: { as_of_date: "2021-03-31", period_from: "2021-03-01", period_to: "2021-03-31", organization: "ООО \\Альтернатива Плюс\\" }, previous_anchor_type: "unknown", previous_anchor_value: null } } ); expect(result?.handled).toBe(true); expect(result?.response_type).toBe("FACTUAL_LIST"); expect(result?.debug.detected_intent).toBe("inventory_sale_trace_for_item"); expect(result?.debug.extracted_filters?.item).toBe("Кромка с клеем 33 дуб ниагара 137 м"); expect(String(result?.reply_text ?? "")).toContain("ООО \\Покупатель\\"); }); it("keeps the full selected item for canonical selected-object buyer wording", async () => { executeAddressMcpQueryMock.mockResolvedValueOnce({ fetched_rows: 1, matched_rows: 1, raw_rows: [saleRow], rows: [], error: null }); const service = new AddressQueryService(); const result = await service.tryHandle( "Определить контрагента, которому была продана позиция «Кромка с клеем 33 дуб ниагара 137 м» по выбранному объекту", { followupContext } ); expect(result?.handled).toBe(true); expect(result?.response_type).toBe("FACTUAL_LIST"); expect(result?.debug.detected_intent).toBe("inventory_sale_trace_for_item"); expect(result?.debug.extracted_filters?.item).toBe("Кромка с клеем 33 дуб ниагара 137 м"); expect(String(result?.reply_text ?? "")).toContain("ООО \\Покупатель\\"); expect(executeAddressMcpQueryMock).toHaveBeenCalledTimes(1); const query = String(executeAddressMcpQueryMock.mock.calls[0]?.[0]?.query ?? ""); expect(query).toContain('Номенклатура.Наименование = "Кромка с клеем 33 дуб ниагара 137 м"'); expect(query).not.toContain('Номенклатура.Наименование = "Кромка"'); }); });