Этап 4 corrective pack 2 по family isolation после текущих routing fixes
This commit is contained in:
@@ -112,6 +112,25 @@ function collectDateLikeSpans(text: string): Array<{ start: number; end: number
|
||||
return spans;
|
||||
}
|
||||
|
||||
function collectContractLikeSpans(text: string): Array<{ start: number; end: number }> {
|
||||
const spans: Array<{ start: number; end: number }> = [];
|
||||
const patterns = [
|
||||
/(?:\b(?:договор(?:а|у|ом|е)?|contract)\b[^\r\n]{0,24}(?:№|#|n|no\.?)\s*[a-zа-я0-9][a-zа-я0-9/_-]{1,})/giu,
|
||||
/(?:№|#)\s*[a-zа-я0-9_-]{1,10}\/[a-zа-я0-9_-]{1,12}/giu,
|
||||
/\b\d{2}\/\d{2}(?:-[a-zа-я]{1,10})?\b/giu
|
||||
];
|
||||
for (const pattern of patterns) {
|
||||
let match: RegExpExecArray | null = null;
|
||||
while ((match = pattern.exec(text)) !== null) {
|
||||
spans.push({
|
||||
start: match.index,
|
||||
end: match.index + match[0].length
|
||||
});
|
||||
}
|
||||
}
|
||||
return spans;
|
||||
}
|
||||
|
||||
function collectAmountLikeSpans(text: string): Array<{ start: number; end: number }> {
|
||||
const spans: Array<{ start: number; end: number }> = [];
|
||||
const patterns = [/\b\d{1,3}(?:[ \u00A0]\d{3})+(?:[.,]\d{2})?\b/g, /\b\d+[.,]\d{2}\b/g];
|
||||
@@ -154,7 +173,12 @@ function hasAccountContextAround(text: string, start: number, end: number): bool
|
||||
|
||||
function detectAccounts(text: string): string[] {
|
||||
const lower = String(text ?? "").toLowerCase();
|
||||
const blockedSpans = [...collectDateLikeSpans(lower), ...collectAmountLikeSpans(lower), ...collectPercentLikeSpans(lower)];
|
||||
const blockedSpans = [
|
||||
...collectDateLikeSpans(lower),
|
||||
...collectAmountLikeSpans(lower),
|
||||
...collectPercentLikeSpans(lower),
|
||||
...collectContractLikeSpans(lower)
|
||||
];
|
||||
const hasAccountingLexeme =
|
||||
/(?:\bсчет(?:а|у|ом|ов)?\b|\bсч\.?\b|\baccount(?:s)?\b|\bschet(?:a|u|om|ov)?\b|оплат|расчет|расч[её]т|аванс|долг|settlement|payment|supplier|customer|ндс|vat|рбп|deferred|амортиз)/iu.test(
|
||||
lower
|
||||
@@ -217,37 +241,47 @@ function detectPeriod(text: string): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function detectExplicitDomainHint(text: string): string | null {
|
||||
export function inferP0DomainFromMessage(text: string): string | null {
|
||||
const messageCorpus = String(text ?? "").toLowerCase();
|
||||
const accounts = detectAccounts(text);
|
||||
const hasSettlementSignal =
|
||||
accounts.some((item) => isSettlementAccount(item)) ||
|
||||
/(?:60(?:\.\d{2})?|62(?:\.\d{2})?|оплат|расч[её]т|зач[её]т|аванс|долг|поставщ|покупат|settlement|payment|supplier|customer)/i.test(
|
||||
const hasSettlementAccount = accounts.some((item) => isSettlementAccount(item));
|
||||
const hasVatAccount = accounts.some((item) => isVatAccount(item));
|
||||
const hasCloseAccount = accounts.some((item) => isCloseCostsAccount(item));
|
||||
const hasFixedAssetAccount = accounts.some((item) => isFixedAssetAccount(item));
|
||||
|
||||
const hasSettlementLexical = /(?:60(?:\.\d{2})?|62(?:\.\d{2})?|оплат|расч[её]т|зач[её]т|аванс|долг|поставщ|покупат|settlement|payment|supplier|customer)/i.test(
|
||||
messageCorpus
|
||||
);
|
||||
const hasVatLexical = /(?:ндс|сч[её]т[\s-]?фактур|книг[аи]|vat|invoice|book|register)/i.test(messageCorpus);
|
||||
const hasCloseLexical =
|
||||
/(?:закрыти|месяц|затрат|распредел|списан|period\s*close|month\s*close|allocation|residual|cost|рбп)/i.test(messageCorpus);
|
||||
const hasExplicitFixedAssetLexical =
|
||||
/(?:амортиз|основн(ые|ых|ым)?\s+средств|объект[а-яё]*\s+ос|fixed\s*asset|depreciat|сч[её]т(?:а|у|ом|е)?\s*(?:01|02|08)|account\s*0[128])/i.test(
|
||||
messageCorpus
|
||||
);
|
||||
if (hasSettlementSignal) {
|
||||
const hasBroadMonthCloseLexical =
|
||||
/(?:после\s+закрытия|косвенн|период(?:а)?\s+закрыт|month\s*close|period\s*close|регламентн)/i.test(messageCorpus);
|
||||
|
||||
// Keep settlement lane stable when 60/62 lexical/account anchors are explicit
|
||||
// and there is no explicit VAT intent.
|
||||
if ((hasSettlementAccount || hasSettlementLexical) && !hasVatLexical && !hasVatAccount && !hasExplicitFixedAssetLexical) {
|
||||
return "settlements_60_62";
|
||||
}
|
||||
const hasVatSignal =
|
||||
accounts.some((item) => isVatAccount(item)) ||
|
||||
/(?:ндс|сч[её]т[\s-]?фактур|книг[аи]|vat|invoice|book|register)/i.test(messageCorpus);
|
||||
if (hasVatSignal) {
|
||||
return "vat_document_register_book";
|
||||
}
|
||||
const hasCloseSignal =
|
||||
accounts.some((item) => isCloseCostsAccount(item)) ||
|
||||
/(?:закрыти|месяц|затрат|распредел|списан|period\s*close|month\s*close|allocation|residual|cost|рбп)/i.test(messageCorpus);
|
||||
if (hasCloseSignal) {
|
||||
if ((hasCloseAccount || hasCloseLexical || hasBroadMonthCloseLexical) && !hasVatLexical && !hasVatAccount && !hasExplicitFixedAssetLexical && !hasFixedAssetAccount) {
|
||||
return "month_close_costs_20_44";
|
||||
}
|
||||
const hasFixedAssetSignal =
|
||||
accounts.some((item) => isFixedAssetAccount(item)) ||
|
||||
/(?:амортиз|основн(ые|ых|ым)?\s+средств|(?:^|[^a-zа-яё])ос(?:$|[^a-zа-яё])|объект[а-яё]*\s+ос|fixed\s*asset|depreciat)/i.test(
|
||||
messageCorpus
|
||||
);
|
||||
if (hasFixedAssetSignal) {
|
||||
if (hasVatAccount || hasVatLexical) {
|
||||
return "vat_document_register_book";
|
||||
}
|
||||
if (hasFixedAssetAccount || hasExplicitFixedAssetLexical) {
|
||||
return "fixed_asset_amortization";
|
||||
}
|
||||
if (hasCloseAccount || hasCloseLexical) {
|
||||
return "month_close_costs_20_44";
|
||||
}
|
||||
if (hasSettlementAccount || hasSettlementLexical) {
|
||||
return "settlements_60_62";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -283,7 +317,7 @@ function deriveScopeOrigin(input: {
|
||||
}
|
||||
const hasExplicitPeriod = Boolean(detectPeriod(input.userMessage));
|
||||
const hasExplicitAccounts = detectAccounts(input.userMessage).length > 0;
|
||||
const explicitDomain = detectExplicitDomainHint(input.userMessage);
|
||||
const explicitDomain = inferP0DomainFromMessage(input.userMessage);
|
||||
if (hasExplicitPeriod || hasExplicitAccounts || explicitDomain) {
|
||||
return "explicit_from_message";
|
||||
}
|
||||
@@ -406,7 +440,7 @@ function inferFollowupActiveDomain(input: {
|
||||
: messageCorpus;
|
||||
|
||||
const hasFixedAssetLexicalSignal =
|
||||
/(?:амортиз|основн(ые|ых|ым)?\s+средств|(?:^|[^a-zа-яё])ос(?:$|[^a-zа-яё])|объект[а-яё]*\s+ос|fixed\s*asset|depreciat)/i.test(
|
||||
/(?:амортиз|основн(ые|ых|ым)?\s+средств|объект[а-яё]*\s+ос|fixed\s*asset|depreciat|сч[её]т(?:а|у|ом|е)?\s*(?:01|02|08)|account\s*0[128])/i.test(
|
||||
messageCorpus
|
||||
);
|
||||
const hasFixedAssetAccountSignal =
|
||||
@@ -414,6 +448,17 @@ function inferFollowupActiveDomain(input: {
|
||||
/(?:сч[её]т(?:а|у|ом|е)?\s*(?:01|02|08)|(?:01|02|08)(?:\.\d{2})?\s*\/\s*(?:01|02|08)(?:\.\d{2})?|\b0[128](?:\.\d{2})?\b)/i.test(
|
||||
messageCorpus
|
||||
);
|
||||
const hasBroadMonthCloseSignal =
|
||||
/(?:после\s+закрытия|косвенн|период(?:а)?\s+закрыт|регламентн|month\s*close|period\s*close)/i.test(messageCorpus);
|
||||
if (
|
||||
(input.focusAccounts.some((item) => isCloseCostsAccount(item)) ||
|
||||
/(?:закрыти|месяц|затрат|распредел|списан|period\s*close|month\s*close|allocation|residual|cost)/i.test(messageCorpus) ||
|
||||
hasBroadMonthCloseSignal) &&
|
||||
!hasFixedAssetLexicalSignal &&
|
||||
!hasFixedAssetAccountSignal
|
||||
) {
|
||||
return "month_close_costs_20_44";
|
||||
}
|
||||
if (hasFixedAssetLexicalSignal || hasFixedAssetAccountSignal) {
|
||||
return "fixed_asset_amortization";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user