Сжать supplier-overlap ответы и detector utility gap
This commit is contained in:
+4
-17
@@ -543,7 +543,7 @@ function composeInventoryReply(intent, rows, options, deps) {
|
||||
if (supplierScopedItemQuestion) {
|
||||
const requestedSupplierLabel = summary.counterparties[0] ?? String(options.counterpartyHint ?? "").trim();
|
||||
const directAnswerLine = supplierScopedItems.length > 0
|
||||
? `По поставщику ${requestedSupplierLabel} в складском срезе ${warehouseLabel} на ${deps.formatDateRu(asOfDate)} подтверждены позиции: ${inventoryItemLeadList(supplierScopedItems)}.`
|
||||
? `По поставщику ${requestedSupplierLabel} в складском срезе ${warehouseLabel} на ${deps.formatDateRu(asOfDate)} подтверждено позиций: ${deps.formatNumberWithDots(supplierScopedItems.length)}.`
|
||||
: `По поставщику ${requestedSupplierLabel} в складском срезе ${warehouseLabel} на ${deps.formatDateRu(asOfDate)} позиции не подтверждены в доступном закупочном следе.`;
|
||||
const lines = [directAnswerLine];
|
||||
if (supplierScopedItems.length > 0) {
|
||||
@@ -552,24 +552,11 @@ function composeInventoryReply(intent, rows, options, deps) {
|
||||
lines.push(`- Показаны первые 8 из ${deps.formatNumberWithDots(supplierScopedItems.length)} позиций.`);
|
||||
}
|
||||
}
|
||||
(0, inventoryReplyPresentation_1.appendInventoryBulletSection)(lines, "Что проверили:", [
|
||||
`Дата среза: ${deps.formatDateRu(asOfDate)}.`,
|
||||
`Период найденного закупочного следа: ${purchasePeriodLabel}.`,
|
||||
`Закупочных документов / операций в выборке: ${deps.formatNumberWithDots(summary.documents.length)} / ${deps.formatNumberWithDots(purchaseRows.length)}.`
|
||||
]);
|
||||
(0, inventoryReplyPresentation_1.appendInventoryBulletSection)(lines, "Ограничения:", [
|
||||
"Без партионного учета этот ответ показывает закупочный след текущего остатка, но не доказывает владельца каждой конкретной партии.",
|
||||
INVENTORY_SUPPLIER_ATTRIBUTION_NEXT_ACTION
|
||||
]);
|
||||
lines.push("", `Проверка: срез ${deps.formatDateRu(asOfDate)}; закупочный след ${purchasePeriodLabel}; документов/операций: ${deps.formatNumberWithDots(summary.documents.length)} / ${deps.formatNumberWithDots(purchaseRows.length)}.`);
|
||||
if (observedCounterparties.length > 0) {
|
||||
lines.push(`- Найденные поставщики: ${inventoryPartyLeadList(observedCounterparties)}.`);
|
||||
}
|
||||
if (purchaseRows.length > 0) {
|
||||
(0, inventoryReplyPresentation_1.appendInventorySection)(lines, "Опорные документы:", deps.formatInventoryTraceRows(purchaseRows, INVENTORY_TRACE_EVIDENCE_ROW_LIMIT));
|
||||
if (purchaseRows.length > INVENTORY_TRACE_EVIDENCE_ROW_LIMIT) {
|
||||
lines.push(`- Показаны первые ${INVENTORY_TRACE_EVIDENCE_ROW_LIMIT} из ${deps.formatNumberWithDots(purchaseRows.length)} найденных строк; полный след остается в подтвержденном срезе.`);
|
||||
}
|
||||
lines.push(`Поставщик в найденном следе: ${inventoryPartyLeadList(observedCounterparties)}.`);
|
||||
}
|
||||
lines.push("Ограничение: без партионного учета это закупочный след остатка, а не доказательство владельца каждой конкретной партии.", INVENTORY_SUPPLIER_ATTRIBUTION_NEXT_ACTION);
|
||||
return (0, replyContracts_1.buildFactualSummaryReply)(lines, (0, replyContracts_1.buildConfirmedBalanceSemantics)(purchaseRows.length > 0 ? (supplierScopedItems.length > 0 ? "strong" : "medium") : "medium", purchaseRows.length > 0));
|
||||
}
|
||||
const directAnswerLine = observedCounterparties.length === 1
|
||||
|
||||
@@ -747,7 +747,7 @@ export function composeInventoryReply(
|
||||
const requestedSupplierLabel = summary.counterparties[0] ?? String(options.counterpartyHint ?? "").trim();
|
||||
const directAnswerLine =
|
||||
supplierScopedItems.length > 0
|
||||
? `По поставщику ${requestedSupplierLabel} в складском срезе ${warehouseLabel} на ${deps.formatDateRu(asOfDate)} подтверждены позиции: ${inventoryItemLeadList(supplierScopedItems)}.`
|
||||
? `По поставщику ${requestedSupplierLabel} в складском срезе ${warehouseLabel} на ${deps.formatDateRu(asOfDate)} подтверждено позиций: ${deps.formatNumberWithDots(supplierScopedItems.length)}.`
|
||||
: `По поставщику ${requestedSupplierLabel} в складском срезе ${warehouseLabel} на ${deps.formatDateRu(asOfDate)} позиции не подтверждены в доступном закупочном следе.`;
|
||||
const lines: string[] = [directAnswerLine];
|
||||
if (supplierScopedItems.length > 0) {
|
||||
@@ -760,30 +760,17 @@ export function composeInventoryReply(
|
||||
lines.push(`- Показаны первые 8 из ${deps.formatNumberWithDots(supplierScopedItems.length)} позиций.`);
|
||||
}
|
||||
}
|
||||
appendInventoryBulletSection(lines, "Что проверили:", [
|
||||
`Дата среза: ${deps.formatDateRu(asOfDate)}.`,
|
||||
`Период найденного закупочного следа: ${purchasePeriodLabel}.`,
|
||||
`Закупочных документов / операций в выборке: ${deps.formatNumberWithDots(summary.documents.length)} / ${deps.formatNumberWithDots(purchaseRows.length)}.`
|
||||
]);
|
||||
appendInventoryBulletSection(lines, "Ограничения:", [
|
||||
"Без партионного учета этот ответ показывает закупочный след текущего остатка, но не доказывает владельца каждой конкретной партии.",
|
||||
INVENTORY_SUPPLIER_ATTRIBUTION_NEXT_ACTION
|
||||
]);
|
||||
lines.push(
|
||||
"",
|
||||
`Проверка: срез ${deps.formatDateRu(asOfDate)}; закупочный след ${purchasePeriodLabel}; документов/операций: ${deps.formatNumberWithDots(summary.documents.length)} / ${deps.formatNumberWithDots(purchaseRows.length)}.`
|
||||
);
|
||||
if (observedCounterparties.length > 0) {
|
||||
lines.push(`- Найденные поставщики: ${inventoryPartyLeadList(observedCounterparties)}.`);
|
||||
}
|
||||
if (purchaseRows.length > 0) {
|
||||
appendInventorySection(
|
||||
lines,
|
||||
"Опорные документы:",
|
||||
deps.formatInventoryTraceRows(purchaseRows, INVENTORY_TRACE_EVIDENCE_ROW_LIMIT)
|
||||
);
|
||||
if (purchaseRows.length > INVENTORY_TRACE_EVIDENCE_ROW_LIMIT) {
|
||||
lines.push(
|
||||
`- Показаны первые ${INVENTORY_TRACE_EVIDENCE_ROW_LIMIT} из ${deps.formatNumberWithDots(purchaseRows.length)} найденных строк; полный след остается в подтвержденном срезе.`
|
||||
);
|
||||
}
|
||||
lines.push(`Поставщик в найденном следе: ${inventoryPartyLeadList(observedCounterparties)}.`);
|
||||
}
|
||||
lines.push(
|
||||
"Ограничение: без партионного учета это закупочный след остатка, а не доказательство владельца каждой конкретной партии.",
|
||||
INVENTORY_SUPPLIER_ATTRIBUTION_NEXT_ACTION
|
||||
);
|
||||
return buildFactualSummaryReply(
|
||||
lines,
|
||||
buildConfirmedBalanceSemantics(
|
||||
|
||||
@@ -6308,11 +6308,18 @@ it("routes old purchase residue questions to aging-by-purchase-date", () => {
|
||||
);
|
||||
|
||||
const firstLine = reply.text.split("\n")[0] ?? "";
|
||||
expect(firstLine).toContain("подтверждены позиции");
|
||||
expect(firstLine).toContain("Столешница 600*3050*26 альмандин");
|
||||
expect(firstLine).toContain("Столешница 600*3050*26 дуб ниагара");
|
||||
expect(firstLine).toContain("подтверждено позиций: 2");
|
||||
expect(firstLine).not.toContain("выявлен поставщик закупочного следа");
|
||||
expect(reply.text).toContain("Позиции:");
|
||||
expect(reply.text.indexOf("Позиции:")).toBeLessThan(reply.text.indexOf("Проверка:"));
|
||||
expect(reply.text).toContain("Столешница 600*3050*26 альмандин");
|
||||
expect(reply.text).toContain("Столешница 600*3050*26 дуб ниагара");
|
||||
expect(reply.text).toContain("Проверка:");
|
||||
expect(reply.text).toContain("Ограничение:");
|
||||
expect(reply.text).toContain("Следующий шаг:");
|
||||
expect(reply.text).not.toContain("Что проверили:");
|
||||
expect(reply.text).not.toContain("Опорные документы:");
|
||||
expect(reply.text).not.toContain("Поступление товаров и услуг");
|
||||
});
|
||||
|
||||
it("routes inventory provenance questions to a dedicated intent", () => {
|
||||
|
||||
Reference in New Issue
Block a user