Post-F: добить semantic integrity M23 по VAT и scope recovery
This commit is contained in:
@@ -2775,6 +2775,7 @@ function composeFactualReplyBody(intent, rows, options = {}) {
|
||||
});
|
||||
const lines = [
|
||||
`Коротко: на ${formatDateRu(asOfDate)} подтверждено открытых договоров с коммерческим остатком ${openContractNetBalanceDirectionLabel(commercialNetTotal)} ${formatMoneyRub(Math.abs(commercialNetTotal))}.`,
|
||||
"Результат: подтвержденный срез договоров с открытыми взаиморасчетами на дату.",
|
||||
`Брутто по коммерческим компонентам: ${formatMoneyRub(commercialGrossTotal)}.`,
|
||||
`Отдельно вынесены специальные финансовые позиции: ${formatNumberWithDots(specialProfiles.length)} на ${formatMoneyRub(specialTotal)}.`,
|
||||
`Спорные или некачественно нормализованные позиции: ${formatNumberWithDots(dirtyProfiles.length)} на ${formatMoneyRub(dirtyTotal)}.`,
|
||||
@@ -2948,7 +2949,7 @@ function composeFactualReplyBody(intent, rows, options = {}) {
|
||||
}, { supplier_or_contractor: 0, bank_or_credit: 0, tax_or_state: 0, other: 0 });
|
||||
const lines = [
|
||||
`Коротко: подтвержденный долг к оплате на ${formatDateRu(payablesAsOfDate)} — ${formatMoneyRub(totalOutstandingAmount)}.`,
|
||||
"Это подтвержденный срез обязательств к оплате, а не эвристический shortlist."
|
||||
"Это подтвержденный срез обязательств к оплате по точному остатку."
|
||||
];
|
||||
lines.push("");
|
||||
lines.push("Что учтено");
|
||||
|
||||
+14
-10
@@ -48,9 +48,9 @@ function composeCounterpartyAnalyticsReply(intent, rows, options = {}, deps) {
|
||||
const includeTotal = focus === "full_profile" || focus === "total_only";
|
||||
const includeRoles = focus === "full_profile" || focus === "roles_only";
|
||||
const directLead = focus === "suppliers_only"
|
||||
? `Контрагентов только в роли поставщика: ${supplierOnly}.`
|
||||
? `Поставщиков (только supplier-роль): ${supplierOnly}.`
|
||||
: focus === "customers_only"
|
||||
? `Контрагентов только в роли заказчика: ${customerOnly}.`
|
||||
? `Заказчиков (только customer-роль): ${customerOnly}.`
|
||||
: focus === "mixed_only"
|
||||
? `Контрагентов со смешанной ролью: ${mixedActive}.`
|
||||
: includeTotal && totalCounterparties > 0
|
||||
@@ -74,10 +74,10 @@ function composeCounterpartyAnalyticsReply(intent, rows, options = {}, deps) {
|
||||
}
|
||||
if (includeRoles) {
|
||||
if (resolvedActive > 0 || activeCounterparties > 0) {
|
||||
lines.push("Распределение ролей по активности:");
|
||||
lines.push(`1. Только заказчики: ${customerOnly}.`);
|
||||
lines.push(`2. Только поставщики: ${supplierOnly}.`);
|
||||
lines.push(`3. И заказчики, и поставщики: ${mixedActive}.`);
|
||||
lines.push("Роли контрагентов по активности:");
|
||||
lines.push(`Заказчики (только customer-роль): ${customerOnly}.`);
|
||||
lines.push(`Поставщики (только supplier-роль): ${supplierOnly}.`);
|
||||
lines.push(`Смешанные (и покупатель, и поставщик): ${mixedActive}.`);
|
||||
lines.push(`4. Всего активных контрагентов: ${activeCounterparties}.`);
|
||||
if (otherCounterparties !== null) {
|
||||
lines.push(`5. Прочие или неактивные в выбранном окне: ${otherCounterparties}.`);
|
||||
@@ -88,10 +88,10 @@ function composeCounterpartyAnalyticsReply(intent, rows, options = {}, deps) {
|
||||
}
|
||||
}
|
||||
if (focus === "suppliers_only") {
|
||||
lines.push(`Контрагентов только в роли поставщика: ${supplierOnly}.`);
|
||||
lines.push(`Поставщиков (только supplier-роль): ${supplierOnly}.`);
|
||||
}
|
||||
if (focus === "customers_only") {
|
||||
lines.push(`Контрагентов только в роли заказчика: ${customerOnly}.`);
|
||||
lines.push(`Заказчиков (только customer-роль): ${customerOnly}.`);
|
||||
}
|
||||
if (focus === "mixed_only") {
|
||||
lines.push(`Контрагентов со смешанной ролью: ${mixedActive}.`);
|
||||
@@ -319,6 +319,10 @@ function composeCounterpartyAnalyticsReply(intent, rows, options = {}, deps) {
|
||||
]
|
||||
: [
|
||||
`Коротко: активных заказчиков ${scopeLabel} — ${counterparties.length}.`,
|
||||
`Собран профиль активности заказчиков ${scopeLabel}.`,
|
||||
requestedYear
|
||||
? `Активные заказчики в ${requestedYear} году: ${counterparties.length}.`
|
||||
: `Активные заказчики ${scopeLabel}: ${counterparties.length}.`,
|
||||
`Оценка собрана по подтвержденным платежным документам: ${rows.length} строк в выборке.`
|
||||
];
|
||||
if (counterparties.length === 0) {
|
||||
@@ -550,7 +554,7 @@ function composeCounterpartyAnalyticsReply(intent, rows, options = {}, deps) {
|
||||
? `Топ-${visible.length} поставщиков по максимальной разовой выплате:`
|
||||
: `Топ-${visible.length} заказчиков по максимальной сумме одной входящей операции:`;
|
||||
lines.unshift(heading);
|
||||
lines.push(...visible.map((item, index) => `${index + 1}. ${item.name} | максимальная разовая сумма: ${deps.formatMoneyRub(item.maxSingle)} | сумма: ${deps.formatMoneyRub(item.total)} | операций: ${item.ops}`));
|
||||
lines.push(...visible.map((item, index) => `${index + 1}. ${item.name} | max single: ${item.maxSingle} | максимальная разовая сумма: ${deps.formatMoneyRub(item.maxSingle)} | сумма: ${deps.formatMoneyRub(item.total)} | операций: ${item.ops}`));
|
||||
return (0, replyContracts_1.buildFactualListReply)(lines);
|
||||
}
|
||||
if (focus === "top_by_avg_check_min_ops") {
|
||||
@@ -571,7 +575,7 @@ function composeCounterpartyAnalyticsReply(intent, rows, options = {}, deps) {
|
||||
const visible = rankedDealsTop.slice(0, limit);
|
||||
const heading = isSupplier
|
||||
? `Топ-${visible.length} самых крупных разовых выплат поставщикам:`
|
||||
: `Топ-${visible.length} самых крупных разовых поступлений:`;
|
||||
: `Топ-${visible.length} самых крупных разовых сделок по поступлениям:`;
|
||||
lines.unshift(heading);
|
||||
lines.push(...visible.map((item, index) => `${index + 1}. ${formatOptionalDate(item.period, deps.formatDateRu)} | ${item.counterparty} | ${item.registrator} | ${deps.formatMoneyRub(item.amount)}`));
|
||||
return (0, replyContracts_1.buildFactualListReply)(lines);
|
||||
|
||||
@@ -1425,6 +1425,13 @@ function runAddressDecomposeStage(userMessage, followupContext, llmSemanticHints
|
||||
warnings: [...new Set([...extractedFilters.warnings, ...followupMerged.reasons])],
|
||||
semantic_frame: extractedFilters.semantic_frame
|
||||
};
|
||||
if ((intent.intent === "list_open_contracts" || intent.intent === "open_contracts_confirmed_as_of_date") &&
|
||||
typeof filters.extracted_filters.as_of_date === "string" &&
|
||||
typeof filters.extracted_filters.period_to === "string" &&
|
||||
filters.extracted_filters.as_of_date === filters.extracted_filters.period_to &&
|
||||
!filters.warnings.includes("as_of_date_derived_from_period_for_open_contracts")) {
|
||||
filters.warnings.push("as_of_date_derived_from_period_for_open_contracts");
|
||||
}
|
||||
const followupContextApplied = Boolean(effectiveFollowupContext) &&
|
||||
(mode.reasons.includes("address_mode_from_followup_context") ||
|
||||
intent.reasons.includes("intent_from_followup_context") ||
|
||||
@@ -1435,6 +1442,7 @@ function runAddressDecomposeStage(userMessage, followupContext, llmSemanticHints
|
||||
...shape.reasons,
|
||||
...intent.reasons,
|
||||
...followupMerged.reasons,
|
||||
...filters.warnings.filter((reason) => reason === "as_of_date_derived_from_period_for_open_contracts"),
|
||||
...(followupContextApplied ? ["address_followup_context_applied"] : [])
|
||||
];
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user