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 organization scope grounding", () => { it("asks for organization clarification when multiple known companies exist", async () => { const service = new AddressQueryService(); const result = await service.tryHandle("покажи остатки по складу", { knownOrganizations: ["ООО Альтернатива Плюс", "ООО Лайсвуд"] }); expect(result?.handled).toBe(true); expect(result?.response_type).toBe("LIMITED_WITH_REASON"); expect(result?.debug.limited_reason_category).toBe("missing_anchor"); expect(result?.debug.organization_candidates).toEqual(["ООО Альтернатива Плюс", "ООО Лайсвуд"]); expect(String(result?.reply_text ?? "")).toContain("ООО Альтернатива Плюс"); expect(String(result?.reply_text ?? "")).toContain("ООО Лайсвуд"); expect(executeAddressMcpQueryMock).not.toHaveBeenCalled(); }); it("auto-selects the only known organization for inventory root queries", async () => { executeAddressMcpQueryMock.mockResolvedValueOnce({ fetched_rows: 1, matched_rows: 1, raw_rows: [ { Period: "2026-04-15T23:59:59Z", Registrator: "Остатки товаров на складах", AccountDt: "41.01", AccountKt: "00.00", Amount: 6490, Quantity: 1, SubcontoDt1: "Пуф арий", Warehouse: "Основной склад", Organization: "ООО Альтернатива Плюс" } ], rows: [], error: null }); const service = new AddressQueryService(); const result = await service.tryHandle("покажи остатки по складу", { knownOrganizations: ["ООО Альтернатива Плюс"] }); expect(result?.handled).toBe(true); expect(result?.response_type).toBe("FACTUAL_LIST"); expect(result?.debug.extracted_filters?.organization).toBe("ООО Альтернатива Плюс"); expect(result?.debug.reasons).toContain("organization_auto_selected_from_single_scope_candidate"); expect(executeAddressMcpQueryMock).toHaveBeenCalledTimes(1); }); it("grounds organization from observed rows when the result belongs to a single company", async () => { executeAddressMcpQueryMock.mockResolvedValueOnce({ fetched_rows: 1, matched_rows: 1, raw_rows: [ { Period: "2020-05-31T23:59:59Z", Registrator: "Остатки товаров на складах", AccountDt: "41.01", AccountKt: "00.00", Amount: 13490, Quantity: 1, SubcontoDt1: "Кресло орион", Warehouse: "Основной склад", Organization: "ООО \\Альтернатива Плюс\\" } ], rows: [], error: null }); const service = new AddressQueryService(); const result = await service.tryHandle("покажи остатки по складу"); expect(result?.handled).toBe(true); expect(result?.response_type).toBe("FACTUAL_LIST"); expect(result?.debug.extracted_filters?.organization).toBe("ООО \\Альтернатива Плюс\\"); expect(result?.debug.reasons).toContain("organization_grounded_from_observed_rows"); }); it("asks for organization clarification when observed rows contain multiple companies", async () => { executeAddressMcpQueryMock.mockResolvedValueOnce({ fetched_rows: 2, matched_rows: 2, raw_rows: [ { Period: "2020-05-31T23:59:59Z", Registrator: "Остатки товаров на складах", AccountDt: "41.01", AccountKt: "00.00", Amount: 6490, Quantity: 1, SubcontoDt1: "Пуф арий", Warehouse: "Основной склад", Organization: "ООО Альтернатива Плюс" }, { Period: "2020-05-31T23:59:59Z", Registrator: "Остатки товаров на складах", AccountDt: "41.01", AccountKt: "00.00", Amount: 34490, Quantity: 1, SubcontoDt1: "Диван трехместный", Warehouse: "Основной склад", Organization: "ООО Лайсвуд" } ], rows: [], error: null }); const service = new AddressQueryService(); const result = await service.tryHandle("покажи остатки по складу"); expect(result?.handled).toBe(true); expect(result?.response_type).toBe("LIMITED_WITH_REASON"); expect(result?.debug.limited_reason_category).toBe("missing_anchor"); expect(result?.debug.organization_candidates).toEqual(["ООО Альтернатива Плюс", "ООО Лайсвуд"]); expect(String(result?.reply_text ?? "")).toContain("ООО Альтернатива Плюс"); expect(String(result?.reply_text ?? "")).toContain("ООО Лайсвуд"); expect(executeAddressMcpQueryMock).toHaveBeenCalledTimes(1); }); });