Open-World: добавить sales-to-stock proxy в бизнес-обзор

This commit is contained in:
2026-05-04 10:22:08 +03:00
parent 062655eca0
commit bf3ae110ef
9 changed files with 251 additions and 20 deletions
@@ -474,18 +474,30 @@ describe("assistant MCP discovery answer adapter", () => {
{ Period: "2020-01-10T00:00:00", Amount: 200000, Quantity: 8, Item: "Товар А" }
]
},
{ rows: [{ Period: "2020-01-15T00:00:00", Registrator: "Поступление 1" }] }
{ rows: [{ Period: "2020-01-15T00:00:00", Registrator: "Поступление 1" }] },
{
rows: [
{ Period: "2020-03-01T00:00:00", Amount: 600000, Item: "Товар А", Counterparty: "Клиент А", AccountKt: "41.01" },
{ Period: "2020-02-01T00:00:00", Amount: 240000, Item: "Товар А", Counterparty: "Поставщик А", AccountDt: "41.01" }
]
}
])
);
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
expect(draft.headline).toContain("складской срез");
expect(draft.headline).toContain("оборотный proxy склада");
expect(draft.confirmed_lines.join("\n")).toContain("Складской срез на 2020-12-31");
expect(draft.confirmed_lines.join("\n")).toContain("Товар А");
expect(draft.unknown_lines.join("\n")).toContain("оборачиваемость");
expect(draft.confirmed_lines.join("\n")).toContain("Оборотный proxy склада за 2020");
expect(draft.confirmed_lines.join("\n")).toContain("sales-to-stock ratio 2x");
expect(draft.inference_lines.join("\n")).toContain("оборотный proxy склада");
expect(draft.unknown_lines.join("\n")).toContain("Полная складская ликвидность");
expect(draft.reason_codes).toContain("answer_contains_business_overview_inventory_position");
expect(draft.reason_codes).toContain("answer_contains_business_overview_inventory_turnover_proxy");
expect(draft.must_not_claim).toContain("Do not present an inventory snapshot or purchase-date aging signal as turnover, obsolescence, liquidation value, or full inventory health.");
expect(draft.must_not_claim).toContain("Do not present business overview inventory turnover proxy as full inventory liquidity, FIFO turnover, obsolescence analysis, or liquidation value.");
});
it("renders metadata-scoped movement all-time follow-up as an all-time bounded answer", async () => {
@@ -553,7 +553,12 @@ describe("assistant MCP discovery pilot executor", () => {
{ Period: "2020-12-15T00:00:00", Registrator: "Поступление 2" }
]
},
{ rows: [] }
{
rows: [
{ Period: "2020-03-01T00:00:00", Amount: 600000, Item: "Товар А", Counterparty: "Клиент А", AccountKt: "41.01" },
{ Period: "2020-02-01T00:00:00", Amount: 240000, Item: "Товар А", Counterparty: "Поставщик А", AccountDt: "41.01" }
]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
@@ -579,12 +584,24 @@ describe("assistant MCP discovery pilot executor", () => {
total_amount: 250000,
total_quantity: 10
});
expect(result.derived_business_overview?.inventory_turnover_proxy).toMatchObject({
period_scope: "2020",
as_of_date: "2020-12-31",
sales_revenue: 600000,
inventory_amount: 300000,
sales_to_stock_amount_ratio: 2,
stock_to_sales_revenue_pct: 50
});
expect(result.derived_business_overview?.missing_signal_families).not.toContain("inventory_position");
expect(result.derived_business_overview?.missing_signal_families).toContain("inventory_turnover_quality");
expect(result.derived_business_overview?.missing_signal_families).not.toContain("inventory_turnover_quality");
expect(result.derived_business_overview?.missing_signal_families).toContain("inventory_liquidity_quality");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Складской срез на 2020-12-31");
expect(result.evidence.unknown_facts.join("\n")).toContain("оборачиваемость");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Оборотный proxy склада за 2020");
expect(result.evidence.confirmed_facts.join("\n")).toContain("sales-to-stock ratio 2x");
expect(result.evidence.unknown_facts.join("\n")).toContain("Полная складская ликвидность");
expect(result.reason_codes).toContain("pilot_business_overview_inventory_query_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_business_overview_inventory_position_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_inventory_turnover_proxy_from_confirmed_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(10);
const inventoryCall = deps.executeAddressMcpQuery.mock.calls[6]?.[0];
expect(inventoryCall?.account_scope).toContain("41.01");