import { describe, expect, it } from "vitest"; import { resolveCounterpartyAddressIntent } from "../src/services/addressCounterpartyIntentSignals"; import { resolveAddressIntent } from "../src/services/addressIntentResolver"; const defaultDeps = { hasAny: (text: string, hints: readonly string[]) => hints.some((hint) => text.includes(hint)), openItemsHints: ["хвост", "долг", "open items"], openContractsHints: ["договор", "контракт", "open contracts"], documentsByCounterpartyHints: ["документы по", "documents by counterparty"], bankOperationsByCounterpartyHints: ["банк", "выписка", "bank operations by counterparty"], documentsByContractHints: ["документы по договору", "documents by contract"], hasCounterpartyDebtLongevitySignal: () => false, hasInventoryAgingSignal: () => false, hasInventoryProvenanceSignalV2: () => false, hasInventoryPurchaseDocumentsSignalV2: () => false, hasInventorySaleTraceSignalV2: () => false, hasAccountNumberAnchor: (text: string) => /60/.test(text), hasCompactAccountCodeToken: () => false, hasPeriodCoverageProfileSignal: (text: string) => text.includes("year coverage"), hasPartyAnchorMention: (text: string) => text.includes("чепурнов"), hasContractAnchorSignal: (text: string) => text.includes("договор"), hasAccountBalanceSignal: (text: string) => text.includes("balance by account"), hasDocumentTypeAndAccountSectionProfileSignal: (text: string) => text.includes("document profile"), hasCounterpartyPopulationAndRolesSignal: (text: string) => text.includes("population and roles"), hasCounterpartyActivityLifecycleSignal: (text: string) => text.includes("activity lifecycle"), hasContractUsageOverviewSignal: (text: string) => text.includes("usage overview"), hasOpenContractsListSignal: (text: string) => text.includes("open contracts"), hasCustomerRevenueAndPaymentsSignal: (text: string) => text.includes("revenue and payments"), hasSupplierPayoutsProfileSignal: (text: string) => text.includes("supplier payouts"), hasContractUsageAndValueSignal: (text: string) => text.includes("usage and value"), hasContractListByCounterpartySignal: (text: string) => text.includes("contracts by counterparty"), hasBankOperationSignal: (text: string) => text.includes("банк"), hasDocumentSignal: (text: string) => text.includes("документ"), hasLooseByAnchorMention: (text: string) => text.includes("по нему"), hasHeuristicCounterpartyAnchor: (text: string) => text.includes("чепурнов"), hasCounterpartyShipmentItemFlowSignal: (text: string) => text.includes("отгружал"), hasImplicitCounterpartyAnchorAroundDocs: () => false, hasGenericAddressLookupSignal: (text: string) => text.includes("покажи") }; describe("addressCounterpartyIntentSignals", () => { it("classifies open-items wording through the extracted counterparty owner", () => { const result = resolveCounterpartyAddressIntent("хвосты покажи по счету 60 на август 2022", defaultDeps); expect(result?.intent).toBe("open_items_by_counterparty_or_contract"); expect(result?.reasons).toContain("open_items_signal_detected"); }); it("classifies counterparty document-flow wording through the extracted counterparty owner", () => { const result = resolveCounterpartyAddressIntent("что нам отгружал чепурнов", defaultDeps); expect(result?.intent).toBe("list_documents_by_counterparty"); expect(result?.reasons).toContain("counterparty_item_flow_signal_detected"); }); it("keeps the main resolver behavior stable through counterparty-owner delegation", () => { const result = resolveAddressIntent("хвосты покажи по счету 60 на август 2022"); expect(result.intent).toBe("open_items_by_counterparty_or_contract"); }); it("does not steal inventory wording into the counterparty owner", () => { const result = resolveCounterpartyAddressIntent("show inventory on hand as of 2020-03-15", defaultDeps); expect(result).toBeNull(); }); });