Стабилизировать маржинальность номенклатуры 1С
This commit is contained in:
+1
-1
@@ -387,7 +387,7 @@ describe("inventory profitability selected-object regressions", () => {
|
||||
expect(reply).toContain("\u041d\u0438\u0437\u043a\u0430\u044f \u0438\u043b\u0438 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f");
|
||||
expect(reply).toContain("Item A");
|
||||
expect(reply).toContain("Item B");
|
||||
expect(reply).toContain("\u043d\u0435 \u0447\u0438\u0441\u0442\u0430\u044f \u043f\u0440\u0438\u0431\u044b\u043b\u044c \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438");
|
||||
expect(reply).toContain("\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u0447\u0438\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u0431\u044b\u043b\u0438");
|
||||
expect(reply).not.toContain("\u041e\u0421");
|
||||
expect(reply).not.toContain("\u0430\u043c\u043e\u0440\u0442\u0438\u0437");
|
||||
expect(executeAddressMcpQueryMock).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -329,9 +329,9 @@ describe("address reply builders regressions", () => {
|
||||
expect(firstLine).toContain("7.271,20");
|
||||
expect(firstLine).toContain("Авант мебель");
|
||||
expect(firstLine).not.toContain("3.677.454,14");
|
||||
expect(result.text).toContain("встречных остатков");
|
||||
expect(result.text).toContain("Встречная часть");
|
||||
expect(result.text).toContain("Комитет государственных услуг г. Москвы");
|
||||
expect(result.text).toContain("Финансовое обеспечение заявки");
|
||||
expect(result.text).not.toContain("Финансовое обеспечение заявки");
|
||||
expect(result.text).not.toContain("договор/аналитика: ООО \\Альтернатива Плюс\\");
|
||||
});
|
||||
|
||||
@@ -380,7 +380,7 @@ describe("address reply builders regressions", () => {
|
||||
expect(firstLine).toContain("9.612.904,90");
|
||||
expect(firstLine).toContain("Департамент капитального ремонта города Москвы.");
|
||||
expect(firstLine).not.toContain("13.290.359,04");
|
||||
expect(result.text).toContain("встречных остатков");
|
||||
expect(result.text).toContain("Встречная часть");
|
||||
expect(result.text).toContain("Комитет государственных услуг г. Москвы");
|
||||
});
|
||||
|
||||
@@ -525,4 +525,58 @@ describe("address reply builders regressions", () => {
|
||||
expect(result?.text).toContain("Общее количество не свожу в один управленческий показатель");
|
||||
expect(result?.text).toContain("Следующий шаг: могу раскрыть полный список");
|
||||
});
|
||||
|
||||
it("answers cost-base evidence follow-up directly when margin ranking has sales without confirmed cost", () => {
|
||||
const result = composeInventoryReply(
|
||||
"inventory_margin_ranking_for_nomenclature",
|
||||
[
|
||||
{
|
||||
amount: 120000,
|
||||
quantity: 2,
|
||||
item: "Рабочая станция",
|
||||
period: "2020-05-20",
|
||||
registrator: "Реализация"
|
||||
} as any
|
||||
],
|
||||
{
|
||||
userMessage: "покажи найденные строки себестоимостной базы",
|
||||
periodFrom: "2020-05-01",
|
||||
periodTo: "2020-05-31"
|
||||
},
|
||||
{
|
||||
resolvePayablesAsOfDate: () => "2020-05-31",
|
||||
buildInventoryOnHandAggregate: () => [],
|
||||
uniqueStrings: (values: string[]) => Array.from(new Set(values)),
|
||||
formatDateRu: (value: string) => value,
|
||||
formatNumberWithDots: (value: number, fractionDigits = 0) => value.toFixed(fractionDigits),
|
||||
formatMoneyRub: (value: number) => `${value} ₽`,
|
||||
isInventoryPurchaseMovement: () => false,
|
||||
summarizeInventoryTraceRows: (rows: any[]) => ({
|
||||
item: rows[0]?.item ?? null,
|
||||
warehouses: [],
|
||||
organizations: [],
|
||||
counterparties: [],
|
||||
documents: [],
|
||||
firstPeriod: null,
|
||||
lastPeriod: null,
|
||||
totalAmount: 0
|
||||
}),
|
||||
formatInventoryTraceRows: () => [],
|
||||
hasInventoryPurchaseDateActionFocus: () => false,
|
||||
inventoryTraceDateLabel: () => "",
|
||||
extractInventoryCounterpartyCandidates: () => [],
|
||||
buildInventoryAgingByItemAggregate: () => [],
|
||||
formatInventoryAgingRows: () => [],
|
||||
isInventorySaleMovement: () => true
|
||||
}
|
||||
);
|
||||
|
||||
expect(result?.text.split("\n")[0]).toContain(
|
||||
"подтвержденных строк себестоимостной базы по реализованной номенклатуре не найдено"
|
||||
);
|
||||
expect(result?.text).toContain("Есть реализация по 1 номенклатурной позиции");
|
||||
expect(result?.text).toContain("Строк себестоимости реализации / себестоимостной базы для показа нет");
|
||||
expect(result?.text).not.toContain("входящих денежных поступлений");
|
||||
expect(result?.text).not.toContain("амортизац");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -135,6 +135,42 @@ describe("assistant MCP discovery response policy", () => {
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_not_discovery_ready_address_candidate");
|
||||
});
|
||||
|
||||
it("keeps inventory margin-ranking exact reply over stale value-flow discovery candidate", () => {
|
||||
const result = applyAssistantMcpDiscoveryResponsePolicy({
|
||||
currentReply:
|
||||
"За период 2017 рейтинг прибыльности номенклатуры построить нельзя: нет подтвержденной себестоимости реализации.",
|
||||
currentReplySource: "address_query_runtime_v1",
|
||||
currentReplyType: "partial_coverage",
|
||||
addressRuntimeMeta: {
|
||||
detected_intent: "inventory_margin_ranking_for_nomenclature",
|
||||
selected_recipe: "address_inventory_margin_ranking_for_nomenclature_v1",
|
||||
capability_id: "inventory_inventory_margin_ranking_for_nomenclature",
|
||||
assistant_mcp_discovery_entry_point_v1: entryPoint({
|
||||
turn_input: {
|
||||
adapter_status: "ready",
|
||||
should_run_discovery: true,
|
||||
turn_meaning_ref: {
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover"
|
||||
},
|
||||
data_need_graph: {
|
||||
business_fact_family: "value_flow",
|
||||
clarification_gaps: []
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.applied).toBe(false);
|
||||
expect(result.decision).toBe("keep_current_reply");
|
||||
expect(result.reply_text).toContain("рейтинг прибыльности номенклатуры");
|
||||
expect(result.reason_codes).toContain(
|
||||
"mcp_discovery_response_policy_keep_inventory_margin_ranking_address_reply"
|
||||
);
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_candidate_applied");
|
||||
});
|
||||
|
||||
it("lets a grounded business overview candidate override a semantically wrong exact address recipe", () => {
|
||||
const result = applyAssistantMcpDiscoveryResponsePolicy({
|
||||
currentReply: "Supplier and stock overlap was confirmed for 2020.",
|
||||
|
||||
@@ -183,6 +183,75 @@ describe("assistantRoutePolicy", () => {
|
||||
expect(decision.livingMode).toBe("address_data");
|
||||
});
|
||||
|
||||
it("keeps margin-ranking found-rows follow-up in address lane", () => {
|
||||
const policy = buildPolicy();
|
||||
|
||||
const decision = policy.resolveAssistantOrchestrationDecision({
|
||||
rawUserMessage: "покажи найденные строки себестоимостной базы",
|
||||
effectiveAddressUserMessage: "покажи найденные строки себестоимостной базы",
|
||||
followupContext: {
|
||||
previous_intent: "inventory_margin_ranking_for_nomenclature",
|
||||
root_intent: "inventory_margin_ranking_for_nomenclature",
|
||||
previous_filters: {
|
||||
organization: "ООО Альтернатива Плюс",
|
||||
period_from: "2020-05-01",
|
||||
period_to: "2020-05-31"
|
||||
}
|
||||
},
|
||||
llmPreDecomposeMeta: {
|
||||
applied: false,
|
||||
predecomposeContract: {
|
||||
mode: "unsupported",
|
||||
mode_confidence: "low",
|
||||
intent: "unknown",
|
||||
intent_confidence: "low"
|
||||
}
|
||||
},
|
||||
useMock: false
|
||||
});
|
||||
|
||||
expect(decision.runAddressLane).toBe(true);
|
||||
expect(decision.toolGateDecision).toBe("run_address_lane");
|
||||
expect(decision.toolGateReason).toBe("followup_context_detected");
|
||||
expect(decision.livingMode).toBe("address_data");
|
||||
expect(decision.orchestrationContract?.hard_meta_mode).toBe(null);
|
||||
expect(decision.orchestrationContract?.final_decision?.tool_gate_reason).toBe("followup_context_detected");
|
||||
});
|
||||
|
||||
it("keeps margin-ranking period expansion follow-up in address lane", () => {
|
||||
const policy = buildPolicy();
|
||||
|
||||
const decision = policy.resolveAssistantOrchestrationDecision({
|
||||
rawUserMessage: "расширь до 2017 года",
|
||||
effectiveAddressUserMessage: "расширь до 2017 года",
|
||||
followupContext: {
|
||||
previous_intent: "inventory_margin_ranking_for_nomenclature",
|
||||
root_intent: "inventory_margin_ranking_for_nomenclature",
|
||||
previous_filters: {
|
||||
organization: "ООО Альтернатива Плюс",
|
||||
period_from: "2020-05-01",
|
||||
period_to: "2020-05-31"
|
||||
}
|
||||
},
|
||||
llmPreDecomposeMeta: {
|
||||
applied: false,
|
||||
predecomposeContract: {
|
||||
mode: "unsupported",
|
||||
mode_confidence: "low",
|
||||
intent: "unknown",
|
||||
intent_confidence: "low"
|
||||
}
|
||||
},
|
||||
useMock: false
|
||||
});
|
||||
|
||||
expect(decision.runAddressLane).toBe(true);
|
||||
expect(decision.toolGateDecision).toBe("run_address_lane");
|
||||
expect(decision.toolGateReason).toBe("followup_context_detected");
|
||||
expect(decision.livingMode).toBe("address_data");
|
||||
expect(decision.orchestrationContract?.hard_meta_mode).toBe(null);
|
||||
});
|
||||
|
||||
it("does not let deep session continuation override an exact VAT period route", () => {
|
||||
const policy = buildPolicy({
|
||||
detectAddressQuestionMode: () => ({ mode: "address_query", confidence: "high" }),
|
||||
|
||||
Reference in New Issue
Block a user