Перейти до змісту

Finance Analyst Agent — Plan & Progress

Мета

Перетворити ESWF-Chat на фінансового аналітика, який відповідає на питання: - "Яка дебіторська заборгованість?" - "Скільки ми отримали за березень?" - "Які рахунки прострочені?" - "Покажи рух грошей за квартал" - "Топ-5 клієнтів по виручці" - "Скільки ми маємо отримати наступного тижня?"


Архітектура

Користувач → ChatDrawer → SSE Stream → Django View
                                    llm.py (OpenRouter)
                                    tools.py (Finance Tools)
                                    Django ORM → SQLite/PostgreSQL
                                    JSON результат → LLM → відповідь

Нові Tools (6 штук)

Tool Опис Моделі
get_receivables Дебіторська заборгованість по клієнтах Invoice
get_cashflow Рух грошових коштів по місяцях/тижнях IncomingPayment, OutgoingPayment
get_revenue_report Виручка по клієнтах або по місяцях Invoice (posted)
get_top_clients Топ клієнтів по виручці або платежах Invoice, IncomingPayment
get_payment_plan Очікувані надходження (незакриті рахунки) Invoice
get_financial_summary Зведений P&L за період Invoice, IncomingPayment, OutgoingPayment

Деталі реалізації

get_receivables

Параметри:
  - client_name (опціонально)
  - min_days_overdue: int (default 0)
  - limit: int (default 20)

Логіка:
  Invoice.objects.filter(tenant, status IN [sent, overdue, partially_paid])
  debt = total_gross - paid_amount
  days_overdue = (today - payment_due_date).days (якщо past due)
  Сортування: за сумою боргу DESC

Повертає: [{client, invoice_number, total_gross, paid_amount, debt, due_date, days_overdue}]

get_cashflow

Параметри:
  - date_from: YYYY-MM-DD
  - date_to: YYYY-MM-DD
  - group_by: "month" | "week" (default "month")

Логіка:
  IncomingPayment (posted, functional_amount) → income
  OutgoingPayment (posted, functional_amount) → expense
  Групування по трункованій даті

Повертає: [{period, income, expense, net}], totals

get_revenue_report

Параметри:
  - date_from: YYYY-MM-DD
  - date_to: YYYY-MM-DD
  - group_by: "client" | "month" | "week" (default "month")
  - limit: int

Логіка:
  Invoice.objects.filter(posted, date range)
  .values(group_key).annotate(Sum(total_gross), Sum(vat_amount), Count)

Повертає: [{period/client, revenue, vat, count}], totals

get_top_clients

Параметри:
  - metric: "revenue" | "payments" (default "revenue")
  - date_from: YYYY-MM-DD (опціонально)
  - date_to: YYYY-MM-DD (опціонально)
  - limit: int (default 10)

Логіка:
  revenue: Invoice(posted).group_by(client).sum(total_gross)
  payments: IncomingPayment(posted).group_by(client).sum(functional_amount)

Повертає: [{rank, client, amount, count}]

get_payment_plan

Параметри:
  - date_from: YYYY-MM-DD (default today)
  - date_to: YYYY-MM-DD (default today + 30 days)
  - group_by: "week" | "client" (default "week")

Логіка:
  Invoice.objects.filter(posted, status NOT IN [paid, closed, cancelled])
  .filter(payment_due_date range)
  expected = total_gross - paid_amount

Повертає: [{period/client, expected_amount, invoice_count}], total

get_financial_summary

Параметри:
  - date_from: YYYY-MM-DD
  - date_to: YYYY-MM-DD

Логіка:
  revenue = Invoice(posted, date range).sum(total_gross)
  vat = Invoice(posted).sum(vat_amount)
  income_received = IncomingPayment(posted).sum(functional_amount)
  expenses_paid = OutgoingPayment(posted).sum(functional_amount)
  receivables = Invoice(not paid).sum(total_gross - paid_amount)
  overdue_count = Invoice(overdue or past_due_date).count()

Повертає: один об'єкт з усіма показниками

SYSTEM_PROMPT — нові інструкції

FINANCE ANALYST capabilities:
- When the user asks about receivables, debts, overdue invoices → use get_receivables
- When the user asks about cash flow, money movement, income/expense → use get_cashflow
- When the user asks about revenue, sales, turnover by period → use get_revenue_report
- When the user asks for top clients, best customers → use get_top_clients
- When the user asks about expected payments, payment plan → use get_payment_plan
- When the user asks for a financial summary, P&L, overview → use get_financial_summary
- Always present amounts in UAH with thousands separators
- For overdue invoices, highlight the urgency
- Compare periods when relevant (e.g., this month vs last month)

Хід роботи

# Задача Статус Дата
1 Створення MD-файлу плану ✅ Виконано 2026-04-03
2 Додати 6 tool schemas у DOP_TOOLS ✅ Виконано 2026-04-03
3 Додати 6 tool implementations у tools.py ✅ Виконано 2026-04-03
4 Зареєструвати у _TOOL_MAP ✅ Виконано 2026-04-03
5 Оновити SYSTEM_PROMPT у llm.py ✅ Виконано 2026-04-03
6 Тестування в чаті ⏳ Очікує

Приклади запитів після реалізації

Користувач: "Яка дебіторська заборгованість?"
Агент: get_receivables() → "Загальна заборгованість: 485,200 грн
       Прострочено (понад 30 днів): 3 клієнти, 127,400 грн
       Найбільший боржник: ТОВ Альфа — 89,500 грн (45 днів)"

Користувач: "Скільки ми отримали за 1 квартал 2026?"
Агент: get_cashflow(date_from=2026-01-01, date_to=2026-03-31) →
       "Надходження Q1: 1,240,000 грн
        Витрати Q1: 890,000 грн
        Чистий рух: +350,000 грн"

Користувач: "Топ клієнтів цього місяця"
Агент: get_top_clients(date_from=...) → таблиця топ-10

Результат

Що реалізовано (2026-04-03)

Файли змінено: - backend/eswf_chat/tools.py — додано 6 tool schemas + 6 реалізацій + реєстрація в _TOOL_MAP - backend/eswf_chat/llm.py — оновлено SYSTEM_PROMPT з інструкціями фін. аналітика

Нові tools (17 total, було 11): | Tool | Моделі | Повертає | |------|--------|---------| | get_receivables | Invoice | Борги по клієнтах, прострочення | | get_cashflow | IncomingPayment, OutgoingPayment | Рух грошей по місяцях/тижнях | | get_revenue_report | Invoice (posted) | Виручка по клієнтах або по місяцях | | get_top_clients | Invoice / IncomingPayment | Топ-N клієнтів | | get_payment_plan | Invoice | Очікувані платежі по тижнях | | get_financial_summary | Invoice + Payments | Зведений P&L за період |

Приклади запитів що тепер працюють:

"Яка дебіторська заборгованість?"
"Скільки ми отримали за березень?"
"Покажи рух грошей за I квартал"
"Топ-5 клієнтів по виручці цього місяця"
"Які рахунки прострочені більше 30 днів?"
"Скільки очікувати наступного тижня?"
"Дай фінансовий підсумок за квітень"