157 lines
5.5 KiB
TypeScript
157 lines
5.5 KiB
TypeScript
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<typeof import("../src/services/addressMcpClient")>(
|
||
"../src/services/addressMcpClient"
|
||
);
|
||
return {
|
||
...actual,
|
||
executeAddressMcpQuery: executeAddressMcpQueryMock
|
||
};
|
||
});
|
||
|
||
import { AddressQueryService } from "../src/services/addressQueryService";
|
||
|
||
afterEach(() => {
|
||
executeAddressMcpQueryMock.mockReset();
|
||
vi.restoreAllMocks();
|
||
});
|
||
|
||
describe("counterparty lifecycle organization scope regressions", () => {
|
||
it("keeps carried organization scope without false empty-match when rows omit organization column", async () => {
|
||
executeAddressMcpQueryMock.mockResolvedValueOnce({
|
||
fetched_rows: 3,
|
||
matched_rows: 3,
|
||
raw_rows: [
|
||
{
|
||
Period: "2020-01-15T00:00:00Z",
|
||
Registrator: "CP_CUSTOMER_ACTIVITY",
|
||
AccountDt: "62.01",
|
||
AccountKt: "90.01",
|
||
Amount: 12,
|
||
Counterparty: 'ООО "Ромашка"'
|
||
},
|
||
{
|
||
Period: "2020-02-20T00:00:00Z",
|
||
Registrator: "CP_CUSTOMER_ACTIVITY",
|
||
AccountDt: "62.01",
|
||
AccountKt: "90.01",
|
||
Amount: 8,
|
||
Counterparty: 'ООО "Ландыш"'
|
||
},
|
||
{
|
||
Period: "2020-03-10T00:00:00Z",
|
||
Registrator: "CP_CUSTOMER_ACTIVITY",
|
||
AccountDt: "62.01",
|
||
AccountKt: "90.01",
|
||
Amount: 4,
|
||
Counterparty: 'ООО "Ромашка"'
|
||
}
|
||
],
|
||
rows: [],
|
||
error: null
|
||
});
|
||
|
||
const service = new AddressQueryService();
|
||
const result = await service.tryHandle("какие клиенты заплатили больше всего денег за все время", {
|
||
followupContext: {
|
||
previous_intent: "vat_payable_forecast",
|
||
previous_filters: {
|
||
organization: 'ООО "Альтернатива Плюс"',
|
||
period_from: "2020-01-01",
|
||
period_to: "2020-03-31"
|
||
},
|
||
previous_anchor_type: "organization",
|
||
previous_anchor_value: 'ООО "Альтернатива Плюс"'
|
||
}
|
||
});
|
||
|
||
expect(result?.handled).toBe(true);
|
||
expect(result?.reply_type).toBe("factual");
|
||
expect(result?.response_type).toBe("FACTUAL_LIST");
|
||
expect(result?.debug.detected_intent).toBe("customer_revenue_and_payments");
|
||
expect(result?.debug.selected_recipe).toBe("address_customer_revenue_and_payments_v1");
|
||
expect(result?.debug.extracted_filters?.organization).toBe('ООО "Альтернатива Плюс"');
|
||
expect(result?.debug.extracted_filters?.counterparty).toBeUndefined();
|
||
expect(result?.debug.match_failure_reason).toBeNull();
|
||
expect(result?.debug.rows_matched).toBe(3);
|
||
expect(String(result?.reply_text ?? "")).toContain('ООО "Ромашка"');
|
||
});
|
||
|
||
it("does not turn 'за все время' into a bogus counterparty anchor for highest-value customer wording", async () => {
|
||
executeAddressMcpQueryMock.mockResolvedValueOnce({
|
||
fetched_rows: 2,
|
||
matched_rows: 2,
|
||
raw_rows: [
|
||
{
|
||
Period: "2020-01-15T00:00:00Z",
|
||
Registrator: "CP_CUSTOMER_ACTIVITY",
|
||
AccountDt: "62.01",
|
||
AccountKt: "90.01",
|
||
Amount: 120,
|
||
Counterparty: 'ООО "Ромашка"'
|
||
},
|
||
{
|
||
Period: "2020-02-20T00:00:00Z",
|
||
Registrator: "CP_CUSTOMER_ACTIVITY",
|
||
AccountDt: "62.01",
|
||
AccountKt: "90.01",
|
||
Amount: 80,
|
||
Counterparty: 'ООО "Ландыш"'
|
||
}
|
||
],
|
||
rows: [],
|
||
error: null
|
||
});
|
||
|
||
const service = new AddressQueryService();
|
||
const result = await service.tryHandle("какой у нас самый доходный клиент за все время");
|
||
|
||
expect(result?.handled).toBe(true);
|
||
expect(result?.debug.detected_intent).toBe("customer_revenue_and_payments");
|
||
expect(result?.debug.selected_recipe).toBe("address_customer_revenue_and_payments_v1");
|
||
expect(result?.debug.extracted_filters?.counterparty).toBeUndefined();
|
||
expect(String(result?.reply_text ?? "")).toContain('ООО "Ромашка"');
|
||
});
|
||
|
||
it("routes who-is-the-highest-value-customer wording to revenue ranking, not lifecycle activity", async () => {
|
||
executeAddressMcpQueryMock.mockResolvedValueOnce({
|
||
fetched_rows: 2,
|
||
matched_rows: 2,
|
||
raw_rows: [
|
||
{
|
||
Period: "2021-01-15T00:00:00Z",
|
||
Registrator: "CP_CUSTOMER_ACTIVITY",
|
||
AccountDt: "51",
|
||
AccountKt: "62.01",
|
||
Amount: 150000,
|
||
Counterparty: "Группа СВК"
|
||
},
|
||
{
|
||
Period: "2021-02-20T00:00:00Z",
|
||
Registrator: "CP_CUSTOMER_ACTIVITY",
|
||
AccountDt: "51",
|
||
AccountKt: "62.01",
|
||
Amount: 80000,
|
||
Counterparty: "Чепурнов П.Д."
|
||
}
|
||
],
|
||
rows: [],
|
||
error: null
|
||
});
|
||
|
||
const service = new AddressQueryService();
|
||
const result = await service.tryHandle("кто у нас самый доходный клиент за все время");
|
||
|
||
expect(result?.handled).toBe(true);
|
||
expect(result?.debug.detected_intent).toBe("customer_revenue_and_payments");
|
||
expect(result?.debug.selected_recipe).toBe("address_customer_revenue_and_payments_v1");
|
||
expect(String(result?.reply_text ?? "")).toContain("Самый доходный клиент");
|
||
expect(String(result?.reply_text ?? "")).toContain("Группа СВК");
|
||
});
|
||
});
|