ДОМЕНЫ - ВОПРОСЫ - СКЛАД - Починить selected-object follow-up по складу и включить разговорные/UI-варианты в обязательный domain-loop
This commit is contained in:
@@ -689,6 +689,130 @@ function buildInventoryOnHandAggregate(rows, asOfDate) {
|
||||
return left.item.localeCompare(right.item, "ru");
|
||||
});
|
||||
}
|
||||
function inventoryTraceDateLabel(value) {
|
||||
return value ? formatDateRu(value) : "дата не указана";
|
||||
}
|
||||
function hasInventoryAccountPrefix(value, prefix) {
|
||||
const normalized = String(value ?? "")
|
||||
.trim()
|
||||
.replace(",", ".");
|
||||
return normalized === prefix || normalized.startsWith(`${prefix}.`) || normalized.startsWith(prefix);
|
||||
}
|
||||
function isInventoryPurchaseMovement(row) {
|
||||
return hasInventoryAccountPrefix(row.account_dt, "41.01");
|
||||
}
|
||||
function isInventorySaleMovement(row) {
|
||||
return hasInventoryAccountPrefix(row.account_kt, "41.01");
|
||||
}
|
||||
function looksLikeInventoryTraceDocumentToken(value) {
|
||||
const normalized = String(value ?? "").trim();
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return (/(?:№|contract|invoice|payment|order|накладн|акт|счет|сч[её]т|поступлен|реализац|договор)/iu.test(normalized) ||
|
||||
/(?:[a-zа-яё].*\d|\d.*[a-zа-яё])/iu.test(normalized));
|
||||
}
|
||||
function looksLikeInventoryPartyToken(value) {
|
||||
const normalized = String(value ?? "").trim();
|
||||
if (!normalized || normalized.length < 3) {
|
||||
return false;
|
||||
}
|
||||
if (/^(?:0|<пусто>|пустая ссылка)$/iu.test(normalized)) {
|
||||
return false;
|
||||
}
|
||||
if (/^\d{4}-\d{2}-\d{2}/.test(normalized)) {
|
||||
return false;
|
||||
}
|
||||
if (/(?:склад|warehouse)/iu.test(normalized)) {
|
||||
return false;
|
||||
}
|
||||
if (looksLikeInventoryTraceDocumentToken(normalized)) {
|
||||
return false;
|
||||
}
|
||||
if (/(?:ооо|ао|пао|зао|ип|llc|ltd|inc|corp|компани|организац|департамент|комитет|министерств|служб|управлен|торговый\s+дом)/iu.test(normalized)) {
|
||||
return true;
|
||||
}
|
||||
const letterChars = (normalized.match(/[A-Za-zА-Яа-яЁё]/g) ?? []).length;
|
||||
if (letterChars < 3) {
|
||||
return false;
|
||||
}
|
||||
const words = normalized.split(/\s+/u).filter(Boolean);
|
||||
if (words.length >= 2) {
|
||||
return true;
|
||||
}
|
||||
return normalized === normalized.toUpperCase() && normalized.length >= 4;
|
||||
}
|
||||
function extractInventoryCounterpartyCandidates(row) {
|
||||
const itemToken = normalizeEntityToken(extractInventoryItemName(row));
|
||||
const warehouseToken = normalizeEntityToken(extractInventoryWarehouseName(row));
|
||||
const organizationToken = normalizeEntityToken(extractInventoryOrganizationName(row));
|
||||
const candidates = [];
|
||||
for (const token of row.analytics) {
|
||||
const normalized = String(token ?? "").trim();
|
||||
if (!normalized || !looksLikeInventoryPartyToken(normalized)) {
|
||||
continue;
|
||||
}
|
||||
const comparable = normalizeEntityToken(normalized);
|
||||
if (!comparable || comparable === itemToken || comparable === warehouseToken || comparable === organizationToken) {
|
||||
continue;
|
||||
}
|
||||
candidates.push(normalized);
|
||||
}
|
||||
return uniqueStrings(candidates);
|
||||
}
|
||||
function summarizeInventoryTraceRows(rows) {
|
||||
const items = uniqueStrings(rows
|
||||
.map((row) => extractInventoryItemName(row))
|
||||
.filter((item) => Boolean(item)));
|
||||
const warehouses = uniqueStrings(rows
|
||||
.map((row) => extractInventoryWarehouseName(row))
|
||||
.filter((item) => Boolean(item)));
|
||||
const organizations = uniqueStrings(rows
|
||||
.map((row) => extractInventoryOrganizationName(row))
|
||||
.filter((item) => Boolean(item)));
|
||||
const counterparties = uniqueStrings(rows.flatMap((row) => extractInventoryCounterpartyCandidates(row)));
|
||||
const documents = uniqueStrings(rows
|
||||
.map((row) => String(row.registrator ?? "").trim())
|
||||
.filter((item) => item.length > 0 && item !== "(без названия)"));
|
||||
const periods = rows
|
||||
.map((row) => String(row.period ?? "").trim())
|
||||
.filter((item) => item.length > 0)
|
||||
.sort((left, right) => left.localeCompare(right, "ru"));
|
||||
const totalAmount = rows.reduce((sum, row) => sum + (typeof row.amount === "number" && Number.isFinite(row.amount) ? row.amount : 0), 0);
|
||||
return {
|
||||
item: items[0] ?? null,
|
||||
warehouses,
|
||||
organizations,
|
||||
counterparties,
|
||||
documents,
|
||||
firstPeriod: periods[0] ?? null,
|
||||
lastPeriod: periods.length > 0 ? periods[periods.length - 1] : null,
|
||||
totalAmount
|
||||
};
|
||||
}
|
||||
function formatInventoryTraceRows(rows, limit = 10) {
|
||||
return rows.slice(0, limit).map((row, index) => {
|
||||
const parties = extractInventoryCounterpartyCandidates(row);
|
||||
const warehouse = extractInventoryWarehouseName(row);
|
||||
const organization = extractInventoryOrganizationName(row);
|
||||
const amount = typeof row.amount === "number" && Number.isFinite(row.amount) ? formatMoneyRub(row.amount) : "сумма не указана";
|
||||
const parts = [
|
||||
`${index + 1}. ${row.registrator}`,
|
||||
`дата: ${inventoryTraceDateLabel(row.period)}`,
|
||||
`сумма: ${amount}`
|
||||
];
|
||||
if (warehouse) {
|
||||
parts.push(`склад: ${warehouse}`);
|
||||
}
|
||||
if (organization) {
|
||||
parts.push(`организация: ${organization}`);
|
||||
}
|
||||
if (parties.length > 0) {
|
||||
parts.push(`контрагент: ${parties[0]}`);
|
||||
}
|
||||
return parts.join(" | ");
|
||||
});
|
||||
}
|
||||
function liabilityCategoryLabel(category) {
|
||||
if (category === "supplier_or_contractor") {
|
||||
return "поставщики/подрядчики";
|
||||
@@ -2873,6 +2997,257 @@ function composeFactualReply(intent, rows, options = {}) {
|
||||
}
|
||||
};
|
||||
}
|
||||
if (intent === "inventory_purchase_documents_for_item") {
|
||||
const asOfDate = resolvePayablesAsOfDate(options);
|
||||
const purchaseRows = rows.filter((row) => isInventoryPurchaseMovement(row));
|
||||
const summary = summarizeInventoryTraceRows(purchaseRows);
|
||||
const itemLabel = summary.item ?? "товар не определен";
|
||||
const lines = [
|
||||
`Собран подтвержденный список документов поступления по товару ${itemLabel} до ${formatDateRu(asOfDate)}.`,
|
||||
"",
|
||||
"Блок 1. Статус результата",
|
||||
"- Результат: подтвержденные движения поступления товара на 41.01 по доступным бухгалтерским проводкам.",
|
||||
"",
|
||||
"Блок 2. Что учтено",
|
||||
`- Дата верхней границы: ${formatDateRu(asOfDate)}.`,
|
||||
"- Контур: движения, где товар поступает на счет 41.01.",
|
||||
`- Документов в выборке: ${formatNumberWithDots(summary.documents.length)}.`,
|
||||
`- Операций в выборке: ${formatNumberWithDots(purchaseRows.length)}.`
|
||||
];
|
||||
if (summary.counterparties.length > 0) {
|
||||
lines.push(`- Найденные контрагенты в закупочных движениях: ${summary.counterparties.slice(0, 3).join("; ")}.`);
|
||||
}
|
||||
lines.push("", "Блок 3. Документы");
|
||||
if (purchaseRows.length > 0) {
|
||||
lines.push(...formatInventoryTraceRows(purchaseRows, 12));
|
||||
}
|
||||
else {
|
||||
lines.push("- По выбранному товару не найдено проводок поступления на 41.01 в доступном контуре.");
|
||||
}
|
||||
return {
|
||||
responseType: purchaseRows.length > 0 ? "FACTUAL_LIST" : "FACTUAL_SUMMARY",
|
||||
text: joinLines(lines),
|
||||
semantics: {
|
||||
result_mode: "confirmed_balance",
|
||||
evidence_strength: purchaseRows.length > 0 ? "strong" : "medium",
|
||||
balance_confirmed: purchaseRows.length > 0
|
||||
}
|
||||
};
|
||||
}
|
||||
if (intent === "inventory_purchase_provenance_for_item") {
|
||||
const asOfDate = resolvePayablesAsOfDate(options);
|
||||
const purchaseRows = rows.filter((row) => isInventoryPurchaseMovement(row));
|
||||
const summary = summarizeInventoryTraceRows(purchaseRows);
|
||||
const itemLabel = summary.item ?? "товар не определен";
|
||||
const lines = [
|
||||
`Собран подтвержденный закупочный след по товару ${itemLabel} до ${formatDateRu(asOfDate)}.`,
|
||||
"",
|
||||
"Блок 1. Статус результата",
|
||||
"- Результат: показаны подтвержденные закупочные движения на 41.01 по выбранному товару.",
|
||||
"- Важно: без партионности этот контур не подменяет собой лот-level доказательство происхождения текущего остатка.",
|
||||
"",
|
||||
"Блок 2. Сводка",
|
||||
`- Первая найденная дата закупочного движения: ${inventoryTraceDateLabel(summary.firstPeriod)}.`,
|
||||
`- Последняя найденная дата закупочного движения: ${inventoryTraceDateLabel(summary.lastPeriod)}.`,
|
||||
`- Документов поступления: ${formatNumberWithDots(summary.documents.length)}.`,
|
||||
`- Операций поступления: ${formatNumberWithDots(purchaseRows.length)}.`
|
||||
];
|
||||
if (summary.counterparties.length === 1) {
|
||||
lines.push(`- По доступным закупочным движениям товар связан с поставщиком: ${summary.counterparties[0]}.`);
|
||||
}
|
||||
else if (summary.counterparties.length > 1) {
|
||||
lines.push(`- По доступным закупочным движениям найдено несколько поставщиков: ${summary.counterparties.slice(0, 4).join("; ")}.`);
|
||||
}
|
||||
else if (purchaseRows.length > 0) {
|
||||
lines.push("- Закупочные документы найдены, но поставщик не материализован отдельным полем в текущем exact-контуре.");
|
||||
}
|
||||
if (summary.documents.length > 0) {
|
||||
lines.push("", "Блок 3. Опорные документы", ...formatInventoryTraceRows(purchaseRows, 8));
|
||||
}
|
||||
return {
|
||||
responseType: purchaseRows.length > 0 ? "FACTUAL_SUMMARY" : "FACTUAL_SUMMARY",
|
||||
text: joinLines(lines),
|
||||
semantics: {
|
||||
result_mode: "confirmed_balance",
|
||||
evidence_strength: purchaseRows.length > 0 ? (summary.counterparties.length === 1 ? "strong" : "medium") : "medium",
|
||||
balance_confirmed: purchaseRows.length > 0
|
||||
}
|
||||
};
|
||||
}
|
||||
if (intent === "inventory_supplier_stock_overlap_as_of_date") {
|
||||
const asOfDate = resolvePayablesAsOfDate(options);
|
||||
const purchaseRows = rows.filter((row) => isInventoryPurchaseMovement(row));
|
||||
const summary = summarizeInventoryTraceRows(purchaseRows);
|
||||
const unresolvedRows = purchaseRows.filter((row) => extractInventoryCounterpartyCandidates(row).length === 0);
|
||||
const warehouseLabel = summary.warehouses[0] ?? "не указанного склада";
|
||||
const lines = [
|
||||
`Собран exact-срез supplier overlap для складского остатка до ${formatDateRu(asOfDate)}.`,
|
||||
"",
|
||||
"Блок 1. Статус результата",
|
||||
`- Контур: подтвержденные закупочные движения на 41.01, связанные со складом ${warehouseLabel}.`,
|
||||
"- Важно: без партионности этот контур показывает документально наблюдаемые supplier candidates, но не подменяет собой лот-level атрибуцию текущего остатка.",
|
||||
"",
|
||||
"Блок 2. Сводка",
|
||||
`- Первая найденная дата закупочного движения: ${inventoryTraceDateLabel(summary.firstPeriod)}.`,
|
||||
`- Последняя найденная дата закупочного движения: ${inventoryTraceDateLabel(summary.lastPeriod)}.`,
|
||||
`- Закупочных документов в выборке: ${formatNumberWithDots(summary.documents.length)}.`,
|
||||
`- Закупочных операций в выборке: ${formatNumberWithDots(purchaseRows.length)}.`
|
||||
];
|
||||
if (summary.counterparties.length > 0) {
|
||||
lines.push(`- Найденные поставщики в наблюдаемом контуре: ${summary.counterparties.slice(0, 6).join("; ")}.`);
|
||||
}
|
||||
else if (purchaseRows.length > 0) {
|
||||
lines.push("- Закупочные движения найдены, но поставщик не материализован отдельным полем в текущем exact-контуре.");
|
||||
}
|
||||
else {
|
||||
lines.push("- В доступном exact-контуре не найдено закупочных движений по 41.01 для выбранного складского среза.");
|
||||
}
|
||||
if (unresolvedRows.length > 0) {
|
||||
lines.push(`- Операций без явно материализованного поставщика: ${formatNumberWithDots(unresolvedRows.length)}.`);
|
||||
}
|
||||
if (purchaseRows.length > 0) {
|
||||
lines.push("", "Блок 3. Опорные документы", ...formatInventoryTraceRows(purchaseRows, 10));
|
||||
}
|
||||
return {
|
||||
responseType: "FACTUAL_SUMMARY",
|
||||
text: joinLines(lines),
|
||||
semantics: {
|
||||
result_mode: "confirmed_balance",
|
||||
evidence_strength: purchaseRows.length > 0 ? (summary.counterparties.length > 0 ? "strong" : "medium") : "medium",
|
||||
balance_confirmed: purchaseRows.length > 0
|
||||
}
|
||||
};
|
||||
}
|
||||
if (intent === "inventory_aging_by_purchase_date") {
|
||||
const asOfDate = resolvePayablesAsOfDate(options);
|
||||
const purchaseRows = rows.filter((row) => isInventoryPurchaseMovement(row));
|
||||
const summary = summarizeInventoryTraceRows(purchaseRows);
|
||||
const firstPeriodTime = summary.firstPeriod ? Date.parse(summary.firstPeriod) : Number.NaN;
|
||||
const asOfTime = Date.parse(`${asOfDate}T23:59:59.000Z`);
|
||||
const ageDays = Number.isFinite(firstPeriodTime) && Number.isFinite(asOfTime) && firstPeriodTime <= asOfTime
|
||||
? Math.floor((asOfTime - firstPeriodTime) / 86_400_000)
|
||||
: null;
|
||||
const itemLabel = summary.item ?? "выбранному складскому остатку";
|
||||
const lines = [
|
||||
`Собран exact-срез возраста закупочного следа по ${itemLabel} до ${formatDateRu(asOfDate)}.`,
|
||||
"",
|
||||
"Блок 1. Статус результата",
|
||||
"- Контур: показаны подтвержденные закупочные движения на 41.01 и их временной разброс.",
|
||||
"- Важно: без партионности этот контур не доказывает возраст конкретного лота, а показывает документально наблюдаемый диапазон закупок.",
|
||||
"",
|
||||
"Блок 2. Сводка",
|
||||
`- Первая найденная дата закупочного движения: ${inventoryTraceDateLabel(summary.firstPeriod)}.`,
|
||||
`- Последняя найденная дата закупочного движения: ${inventoryTraceDateLabel(summary.lastPeriod)}.`,
|
||||
`- Закупочных документов в выборке: ${formatNumberWithDots(summary.documents.length)}.`,
|
||||
`- Закупочных операций в выборке: ${formatNumberWithDots(purchaseRows.length)}.`
|
||||
];
|
||||
if (ageDays !== null) {
|
||||
lines.push(`- Между самой ранней найденной закупкой и датой среза прошло ${formatNumberWithDots(ageDays)} дн.`);
|
||||
}
|
||||
if (summary.counterparties.length > 0) {
|
||||
lines.push(`- Поставщики, встречающиеся в наблюдаемом закупочном следе: ${summary.counterparties.slice(0, 4).join("; ")}.`);
|
||||
}
|
||||
if (purchaseRows.length > 0) {
|
||||
lines.push("", "Блок 3. Опорные документы", ...formatInventoryTraceRows(purchaseRows, 8));
|
||||
}
|
||||
else {
|
||||
lines.push("", "Блок 3. Опорные документы", "- В доступном exact-контуре не найдено закупочных движений по 41.01 для выбранного среза.");
|
||||
}
|
||||
return {
|
||||
responseType: "FACTUAL_SUMMARY",
|
||||
text: joinLines(lines),
|
||||
semantics: {
|
||||
result_mode: "confirmed_balance",
|
||||
evidence_strength: purchaseRows.length > 0 ? "strong" : "medium",
|
||||
balance_confirmed: purchaseRows.length > 0
|
||||
}
|
||||
};
|
||||
}
|
||||
if (intent === "inventory_sale_trace_for_item") {
|
||||
const asOfDate = resolvePayablesAsOfDate(options);
|
||||
const saleRows = rows.filter((row) => isInventorySaleMovement(row));
|
||||
const summary = summarizeInventoryTraceRows(saleRows);
|
||||
const itemLabel = summary.item ?? "товар не определен";
|
||||
const lines = [
|
||||
`Собран подтвержденный след выбытия по товару ${itemLabel} до ${formatDateRu(asOfDate)}.`,
|
||||
"",
|
||||
"Блок 1. Статус результата",
|
||||
"- Результат: показаны подтвержденные движения выбытия товара со счета 41.01.",
|
||||
"",
|
||||
"Блок 2. Сводка",
|
||||
`- Первая найденная дата выбытия: ${inventoryTraceDateLabel(summary.firstPeriod)}.`,
|
||||
`- Последняя найденная дата выбытия: ${inventoryTraceDateLabel(summary.lastPeriod)}.`,
|
||||
`- Документов выбытия: ${formatNumberWithDots(summary.documents.length)}.`,
|
||||
`- Операций выбытия: ${formatNumberWithDots(saleRows.length)}.`
|
||||
];
|
||||
if (summary.counterparties.length === 1) {
|
||||
lines.push(`- По доступным движениям товар отгружался покупателю: ${summary.counterparties[0]}.`);
|
||||
}
|
||||
else if (summary.counterparties.length > 1) {
|
||||
lines.push(`- По доступным движениям найдено несколько покупателей: ${summary.counterparties.slice(0, 4).join("; ")}.`);
|
||||
}
|
||||
else if (saleRows.length > 0) {
|
||||
lines.push("- Документы выбытия найдены, но покупатель не материализован отдельным полем в текущем exact-контуре.");
|
||||
}
|
||||
lines.push("", "Блок 3. Документы выбытия");
|
||||
if (saleRows.length > 0) {
|
||||
lines.push(...formatInventoryTraceRows(saleRows, 12));
|
||||
}
|
||||
else {
|
||||
lines.push("- По выбранному товару не найдено проводок выбытия со счета 41.01 в доступном контуре.");
|
||||
}
|
||||
return {
|
||||
responseType: saleRows.length > 0 ? "FACTUAL_LIST" : "FACTUAL_SUMMARY",
|
||||
text: joinLines(lines),
|
||||
semantics: {
|
||||
result_mode: "confirmed_balance",
|
||||
evidence_strength: saleRows.length > 0 ? (summary.counterparties.length > 0 ? "strong" : "medium") : "medium",
|
||||
balance_confirmed: saleRows.length > 0
|
||||
}
|
||||
};
|
||||
}
|
||||
if (intent === "inventory_purchase_to_sale_chain") {
|
||||
const asOfDate = resolvePayablesAsOfDate(options);
|
||||
const purchaseRows = rows.filter((row) => isInventoryPurchaseMovement(row));
|
||||
const saleRows = rows.filter((row) => isInventorySaleMovement(row));
|
||||
const purchaseSummary = summarizeInventoryTraceRows(purchaseRows);
|
||||
const saleSummary = summarizeInventoryTraceRows(saleRows);
|
||||
const itemLabel = purchaseSummary.item ?? saleSummary.item ?? "товар не определен";
|
||||
const lines = [
|
||||
`Собрана документальная цепочка по товару ${itemLabel} до ${formatDateRu(asOfDate)}.`,
|
||||
"",
|
||||
"Блок 1. Статус результата",
|
||||
`- Закупочных движений на 41.01: ${formatNumberWithDots(purchaseRows.length)}.`,
|
||||
`- Движений выбытия со счета 41.01: ${formatNumberWithDots(saleRows.length)}.`
|
||||
];
|
||||
if (purchaseRows.length > 0 && saleRows.length > 0) {
|
||||
lines.push("- В текущем контуре найдены обе стороны цепочки: поступление и последующее выбытие.");
|
||||
}
|
||||
else if (purchaseRows.length > 0) {
|
||||
lines.push("- Найдена только закупочная часть цепочки; выбытие в текущем exact-контуре не подтверждено.");
|
||||
}
|
||||
else if (saleRows.length > 0) {
|
||||
lines.push("- Найдена только часть выбытия; закупочная часть цепочки в текущем exact-контуре не подтверждена.");
|
||||
}
|
||||
else {
|
||||
lines.push("- Для выбранного товара не найдено движений по 41.01, из которых можно собрать цепочку.");
|
||||
}
|
||||
if (purchaseRows.length > 0) {
|
||||
lines.push("", "Блок 2. Закупка", `- Первая дата: ${inventoryTraceDateLabel(purchaseSummary.firstPeriod)}.`, `- Последняя дата: ${inventoryTraceDateLabel(purchaseSummary.lastPeriod)}.`, ...formatInventoryTraceRows(purchaseRows, 6));
|
||||
}
|
||||
if (saleRows.length > 0) {
|
||||
lines.push("", "Блок 3. Выбытие", `- Первая дата: ${inventoryTraceDateLabel(saleSummary.firstPeriod)}.`, `- Последняя дата: ${inventoryTraceDateLabel(saleSummary.lastPeriod)}.`, ...formatInventoryTraceRows(saleRows, 6));
|
||||
}
|
||||
return {
|
||||
responseType: purchaseRows.length > 0 || saleRows.length > 0 ? "FACTUAL_SUMMARY" : "FACTUAL_SUMMARY",
|
||||
text: joinLines(lines),
|
||||
semantics: {
|
||||
result_mode: "confirmed_balance",
|
||||
evidence_strength: purchaseRows.length > 0 && saleRows.length > 0 ? "strong" : purchaseRows.length > 0 || saleRows.length > 0 ? "medium" : "weak",
|
||||
balance_confirmed: purchaseRows.length > 0 || saleRows.length > 0
|
||||
}
|
||||
};
|
||||
}
|
||||
if (intent === "open_contracts_confirmed_as_of_date") {
|
||||
const asOfDate = resolvePayablesAsOfDate(options);
|
||||
const confirmedContracts = buildOpenContractConfirmedBalanceAggregate(rows, asOfDate);
|
||||
|
||||
@@ -390,6 +390,12 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
|
||||
intent === "list_open_contracts" ||
|
||||
intent === "open_contracts_confirmed_as_of_date" ||
|
||||
intent === "inventory_on_hand_as_of_date" ||
|
||||
intent === "inventory_purchase_provenance_for_item" ||
|
||||
intent === "inventory_purchase_documents_for_item" ||
|
||||
intent === "inventory_supplier_stock_overlap_as_of_date" ||
|
||||
intent === "inventory_sale_trace_for_item" ||
|
||||
intent === "inventory_purchase_to_sale_chain" ||
|
||||
intent === "inventory_aging_by_purchase_date" ||
|
||||
intent === "payables_confirmed_as_of_date" ||
|
||||
intent === "receivables_confirmed_as_of_date" ||
|
||||
intent === "vat_payable_confirmed_as_of_date") {
|
||||
@@ -420,6 +426,19 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
|
||||
reasons.push("as_of_date_from_followup_context");
|
||||
}
|
||||
}
|
||||
if (!sameDateRequested &&
|
||||
(intent === "inventory_sale_trace_for_item" || intent === "inventory_purchase_to_sale_chain") &&
|
||||
!hasExplicitPeriodLiteral(userMessage) &&
|
||||
!hasExplicitCurrentDateHint(userMessage)) {
|
||||
const inheritedAsOfDate = previousAsOfDate ?? previousPeriodTo ?? previousPeriodFrom;
|
||||
const currentAsOfDate = toNonEmptyString(merged.as_of_date);
|
||||
const todayIso = new Date().toISOString().slice(0, 10);
|
||||
const currentLooksDefaultedToToday = currentAsOfDate === todayIso;
|
||||
if (inheritedAsOfDate && (!currentAsOfDate || currentLooksDefaultedToToday) && currentAsOfDate !== inheritedAsOfDate) {
|
||||
merged.as_of_date = inheritedAsOfDate;
|
||||
reasons.push("as_of_date_from_followup_context");
|
||||
}
|
||||
}
|
||||
if (!sameDateRequested &&
|
||||
hasFollowupSignalForConfirmed &&
|
||||
!hasExplicitPeriodLiteral(userMessage) &&
|
||||
@@ -460,6 +479,12 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
|
||||
intent === "documents_forming_balance" ||
|
||||
intent === "open_contracts_confirmed_as_of_date" ||
|
||||
intent === "inventory_on_hand_as_of_date" ||
|
||||
intent === "inventory_purchase_provenance_for_item" ||
|
||||
intent === "inventory_purchase_documents_for_item" ||
|
||||
intent === "inventory_supplier_stock_overlap_as_of_date" ||
|
||||
intent === "inventory_sale_trace_for_item" ||
|
||||
intent === "inventory_purchase_to_sale_chain" ||
|
||||
intent === "inventory_aging_by_purchase_date" ||
|
||||
intent === "payables_confirmed_as_of_date" ||
|
||||
intent === "receivables_confirmed_as_of_date" ||
|
||||
intent === "vat_payable_confirmed_as_of_date";
|
||||
|
||||
Reference in New Issue
Block a user