Expand Phase 15 Sales and Income accounting menus
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Request
|
||||
from sqlalchemy import select
|
||||
|
||||
from app.core.db.common import CommonSessionLocal
|
||||
from app.core.security.csrf import get_or_create_csrf_token
|
||||
from app.core.templating import templates
|
||||
from app.modules.accounting.sales_learning_models import AccountingSalesHistoricalRun
|
||||
from app.modules.accounting.sales_learning_service import historical_sales_rows, ingest_completed_sales_run, learning_summary, sales_mappings
|
||||
from app.modules.accounting.ui import _require_partner, _visible_clients
|
||||
from app.modules.core.rbac.deps import get_user_permissions, get_user_roles
|
||||
|
||||
router = APIRouter(prefix="/tools/accounting", tags=["accounting-sales-menu-ui"])
|
||||
|
||||
|
||||
def _context(db, request, user, title, client_id):
|
||||
clients, scope = _visible_clients(db, request, user)
|
||||
selected = next((c for c in clients if client_id and int(c.id) == int(client_id)), None)
|
||||
return selected, scope, {
|
||||
"request": request,
|
||||
"current_user": user,
|
||||
"current_user_roles": get_user_roles(db, user.id),
|
||||
"current_user_permissions": get_user_permissions(db, user.id),
|
||||
"csrf_token": get_or_create_csrf_token(request),
|
||||
"title": title,
|
||||
"clients": clients,
|
||||
"selected_client": selected,
|
||||
}
|
||||
|
||||
|
||||
def _sync_runs(db, tenant_id, client_id):
|
||||
runs = list(db.execute(select(AccountingSalesHistoricalRun).where(
|
||||
AccountingSalesHistoricalRun.tenant_id == int(tenant_id),
|
||||
AccountingSalesHistoricalRun.client_id == int(client_id),
|
||||
).order_by(AccountingSalesHistoricalRun.id.desc()).limit(20)).scalars().all())
|
||||
for run in runs:
|
||||
if run.status not in {"completed", "failed"}:
|
||||
ingest_completed_sales_run(db, run)
|
||||
return runs
|
||||
|
||||
|
||||
@router.get("/customer-intelligence")
|
||||
def customer_intelligence(request: Request, client_id: int | None = None):
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user, denied = _require_partner(request, db, "accounting.learning.view")
|
||||
if denied: return denied
|
||||
selected, scope, ctx = _context(db, request, user, "Customer Intelligence", client_id)
|
||||
mappings = []
|
||||
summary = {"mapping_count": 0, "historical_rows": 0, "review_confirmed": 0, "high_confidence": 0}
|
||||
if selected:
|
||||
mappings = sales_mappings(db, tenant_id=scope.tenant_id, client_id=selected.id)
|
||||
summary = learning_summary(db, tenant_id=scope.tenant_id, client_id=selected.id)
|
||||
ctx.update(mappings=mappings, summary=summary)
|
||||
return templates.TemplateResponse("modules/accounting/templates/accounting/customer_intelligence.html", ctx)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.get("/historical-sales-learning")
|
||||
def historical_sales_learning(request: Request, client_id: int | None = None):
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user, denied = _require_partner(request, db, "accounting.learning.view")
|
||||
if denied: return denied
|
||||
selected, scope, ctx = _context(db, request, user, "Historical Sales Learning", client_id)
|
||||
evidence, runs = [], []
|
||||
summary = {"mapping_count": 0, "historical_rows": 0, "review_confirmed": 0, "high_confidence": 0}
|
||||
if selected:
|
||||
runs = _sync_runs(db, scope.tenant_id, selected.id)
|
||||
evidence = historical_sales_rows(db, tenant_id=scope.tenant_id, client_id=selected.id)[:500]
|
||||
summary = learning_summary(db, tenant_id=scope.tenant_id, client_id=selected.id)
|
||||
ctx.update(evidence=evidence, runs=runs, summary=summary)
|
||||
return templates.TemplateResponse("modules/accounting/templates/accounting/historical_sales_learning.html", ctx)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.get("/sales-ledger-learning")
|
||||
def sales_ledger_learning(request: Request, client_id: int | None = None):
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user, denied = _require_partner(request, db, "accounting.learning.view")
|
||||
if denied: return denied
|
||||
selected, scope, ctx = _context(db, request, user, "Sales Ledger Learning", client_id)
|
||||
mappings, evidence = [], []
|
||||
summary = {"mapping_count": 0, "historical_rows": 0, "review_confirmed": 0, "high_confidence": 0}
|
||||
if selected:
|
||||
_sync_runs(db, scope.tenant_id, selected.id)
|
||||
mappings = sales_mappings(db, tenant_id=scope.tenant_id, client_id=selected.id)
|
||||
evidence = historical_sales_rows(db, tenant_id=scope.tenant_id, client_id=selected.id)[:500]
|
||||
summary = learning_summary(db, tenant_id=scope.tenant_id, client_id=selected.id)
|
||||
hist = {}
|
||||
for e in evidence:
|
||||
hist.setdefault(str(e.party_ledger_name or '').strip().casefold(), []).append(e)
|
||||
rows = []
|
||||
for m in mappings:
|
||||
key = str(m.tally_customer_ledger_name or m.customer_name or '').strip().casefold()
|
||||
h = hist.get(key, [])
|
||||
rows.append({"mapping": m, "history": h[0] if h else None, "history_count": len(h)})
|
||||
ctx.update(learning_rows=rows, summary=summary)
|
||||
return templates.TemplateResponse("modules/accounting/templates/accounting/sales_ledger_learning.html", ctx)
|
||||
finally:
|
||||
db.close()
|
||||
Reference in New Issue
Block a user