ДОМЕНЫ - ВОПРОСЫ - Усилить НДС forecast: сумма в начале ответа, расширенный MCP probe источников и форматирование чисел

This commit is contained in:
2026-04-12 23:39:05 +03:00
parent 98872c2f11
commit f1ef5f9d3c
11 changed files with 1483 additions and 101 deletions
@@ -1,5 +1,5 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { executeAddressMcpQuery } from "../src/services/addressMcpClient";
import { afterEach, describe, expect, it, vi } from "vitest";
import { executeAddressMcpMetadata, executeAddressMcpQuery } from "../src/services/addressMcpClient";
const ORIGINAL_FETCH = globalThis.fetch;
@@ -44,4 +44,33 @@ describe("address MCP encoding repair", () => {
expect(result.rows[0]?.["Контрагент"]).toBe("Группа СВК");
expect(result.rows[0]?.["Регистратор"]).toContain("Поступление");
});
it("parses get_metadata text-table payload", async () => {
const payload = {
success: true,
data: `[2]{"FullName","Synonym"}:
Document.VATDoc,VAT document
Register.VATRegister,VAT register`
};
globalThis.fetch = vi.fn(async () =>
new Response(JSON.stringify(payload), {
status: 200,
headers: {
"content-type": "application/json"
}
})
) as typeof fetch;
const result = await executeAddressMcpMetadata({
meta_type: "Документ",
name_mask: "ндс",
limit: 10
});
expect(result.error).toBeNull();
expect(result.fetched_rows).toBe(2);
expect(result.rows[0]?.["FullName"]).toBe("Document.VATDoc");
expect(result.rows[0]?.["Synonym"]).toBe("VAT document");
});
});
@@ -1256,6 +1256,7 @@ describe("address compose stage utf8 headers", () => {
expect(reply.responseType).toBe("FACTUAL_SUMMARY");
expect(reply.text).toContain("Почему прогноз к уплате 0");
expect(reply.text).toContain("max(0, 68 Кт - 68 Дт)");
expect(reply.text).toContain("Собран прогноз НДС к уплате: 0.00.");
expect(reply.text).toContain("За период 68 Кт = 9126.00, 68 Дт = 115342.00, разница = -106216.00.");
expect(reply.text).toContain("Разница неположительная");
expect(reply.text).toContain("оперативный прогноз по оборотам НДС-субсчетов 68.02*/19*");
@@ -1283,7 +1284,7 @@ describe("address compose stage utf8 headers", () => {
}
],
{
userMessage: "сколько НДС нужно заплатить по состоянию на 15 марта 2020 года",
userMessage: "какие сроки уплаты и сдачи декларации по НДС по состоянию на 15 марта 2020 года",
periodFrom: "2020-01-01",
periodTo: "2020-03-15"
}
@@ -1292,8 +1293,8 @@ describe("address compose stage utf8 headers", () => {
expect(reply.responseType).toBe("FACTUAL_SUMMARY");
expect(reply.text).toContain("Период расчета (срез обязательств): 01.01.2020..15.03.2020.");
expect(reply.text).toContain("Налоговый период: 1 кв. 2020.");
expect(reply.text).toContain("Срок сдачи декларации: до 25.04.2020.");
expect(reply.text).toContain("Сроки уплаты: 28.04.2020, 28.05.2020, 28.06.2020.");
expect(reply.text).toContain("Срок сдачи декларации: до 27.04.2020.");
expect(reply.text).toContain("Сроки уплаты: 28.04.2020, 28.05.2020, 29.06.2020.");
expect(reply.text).toContain("Ориентир по долям к уплате: 100.00 / 100.00 / 100.00.");
});
@@ -1311,7 +1312,7 @@ describe("address compose stage utf8 headers", () => {
}
],
{
userMessage: "прогноз НДС на 31 декабря 2020",
userMessage: "когда платить НДС за 4 квартал 2020",
periodFrom: "2020-10-01",
periodTo: "2020-12-31"
}
@@ -1320,7 +1321,7 @@ describe("address compose stage utf8 headers", () => {
expect(reply.responseType).toBe("FACTUAL_SUMMARY");
expect(reply.text).toContain("Налоговый период: 4 кв. 2020.");
expect(reply.text).toContain("Срок сдачи декларации: до 25.01.2021.");
expect(reply.text).toContain("Сроки уплаты: 28.01.2021, 28.02.2021, 28.03.2021.");
expect(reply.text).toContain("Сроки уплаты: 28.01.2021, 01.03.2021, 29.03.2021.");
expect(reply.text).toContain("Ориентир по долям к уплате: 30.00 / 30.00 / 30.00.");
});
@@ -1369,7 +1370,7 @@ describe("address compose stage utf8 headers", () => {
);
expect(reply.responseType).toBe("FACTUAL_SUMMARY");
expect(reply.text).toContain("Прогноз НДС к уплате: 0.00.");
expect(reply.text).toContain("Собран прогноз НДС к уплате: 0.00.");
expect(reply.text).toContain("не найдено движений по НДС-субсчетам 68.02*/19*");
expect(reply.text).toContain("Чеклист проверки в 1С (почему к уплате 0):");
expect(reply.text).toContain("Проверьте наличие движений в РегистрБухгалтерии.Хозрасчетный");
@@ -1404,10 +1405,160 @@ describe("address compose stage utf8 headers", () => {
);
expect(reply.responseType).toBe("FACTUAL_SUMMARY");
expect(reply.text).toContain("Прогноз НДС к уплате: 0.00.");
expect(reply.text).toContain("Собран прогноз НДС к уплате: 0.00.");
expect(reply.text).toContain("обороты по 68* взаимно перекрылись");
expect(reply.text).toContain("Чеклист проверки в 1С (почему к уплате 0):");
});
it("adds MCP VAT source coverage block for VAT forecast response", () => {
const reply = composeFactualReply(
"vat_payable_forecast",
[
{
period: "2019-12-31T23:59:59Z",
registrator: "VAT_68_CREDIT",
account_dt: "68",
account_kt: "",
amount: 1000,
analytics: []
}
],
{
userMessage: "прикинь ндс за декабрь 2019",
periodFrom: "2019-12-01",
periodTo: "2019-12-31",
vatDirectSourceProbe: {
status: "ok",
objectsTotal: 5,
documentsTotal: 2,
registersTotal: 3,
probedSources: [
{
fullName: "РегистрНакопления.НДСПродажи",
objectType: "register",
status: "ok",
rowsFetched: 1,
lastPeriod: "2019-12-31T23:59:59Z"
},
{
fullName: "РегистрНакопления.НДСПокупки",
objectType: "register",
status: "empty",
rowsFetched: 0
}
],
errors: []
}
}
);
expect(reply.responseType).toBe("FACTUAL_SUMMARY");
expect(reply.text).toContain("Покрытие VAT-источников через MCP");
expect(reply.text).toContain("Найдено VAT-объектов: 5");
expect(reply.text).toContain("РегистрНакопления.НДСПродажи");
});
it("formats VAT forecast amounts in rubles and emphasizes numbers when requested", () => {
const reply = composeFactualReply(
"vat_payable_forecast",
[
{
period: "2019-12-31T23:59:59Z",
registrator: "VAT_68_CREDIT",
account_dt: "68",
account_kt: "",
amount: 1234567.89,
analytics: []
}
],
{
userMessage: "прикинь ндс",
useRubCurrency: true,
emphasizeNumbers: true
}
);
expect(reply.text).toContain("**1.234.567,89** ₽");
expect(reply.text).toContain("Собран прогноз НДС к уплате:");
});
it("adds MCP VAT source probe block for confirmed VAT as-of response", () => {
const reply = composeFactualReply(
"vat_payable_confirmed_as_of_date",
[
{
period: "2020-03-31T23:59:59Z",
registrator: "Остатки на дату",
account_dt: null,
account_kt: "68.02",
amount: 123456.78,
analytics: []
}
],
{
asOfDate: "2020-03-31",
vatDirectSourceProbe: {
status: "ok",
objectsTotal: 3,
documentsTotal: 1,
registersTotal: 2,
probedSources: [
{
fullName: "РегистрНакопления.НДСНачисленный",
objectType: "register",
status: "ok",
rowsFetched: 1,
lastPeriod: "2020-03-31T23:59:59Z",
sampleRegistrator: "Отражение начисления НДС 0001"
},
{
fullName: "Документ.РегистрацияОплатыНДСВБюджет",
objectType: "document",
status: "empty",
rowsFetched: 0
}
],
errors: []
}
}
);
expect(reply.responseType).toBe("FACTUAL_LIST");
expect(reply.text).toContain("Блок 2.1. MCP-проверка VAT-источников");
expect(reply.text).toContain("VAT-объектов в метаданных 1С: 3");
expect(reply.text).toContain("Источников с движениями до даты среза: 1");
expect(reply.text).toContain("РегистрНакопления.НДСНачисленный");
});
it("adds VAT probe error note for confirmed VAT as-of response", () => {
const reply = composeFactualReply(
"vat_payable_confirmed_as_of_date",
[
{
period: "2020-03-31T23:59:59Z",
registrator: "Остатки на дату",
account_dt: null,
account_kt: "68.02",
amount: 1000,
analytics: []
}
],
{
asOfDate: "2020-03-31",
vatDirectSourceProbe: {
status: "error",
objectsTotal: 0,
documentsTotal: 0,
registersTotal: 0,
probedSources: [],
errors: ["metadata timeout"]
}
}
);
expect(reply.responseType).toBe("FACTUAL_LIST");
expect(reply.text).toContain("Probe VAT-источников завершился ошибкой");
});
});
describe("address intent resolver expansion (M2.3a)", () => {