SysOps: voice-agy-webbuilder-backup — 2026-06-23 10:04 UTC

This commit is contained in:
sysops
2026-06-23 10:04:23 +00:00
parent 3bf15c4850
commit 26fe76afdd
165 changed files with 47427 additions and 1264 deletions
+424
View File
@@ -0,0 +1,424 @@
"""Revenue Cockpit — DB operations, import, tracking, agent tasks."""
from __future__ import annotations
import json
from datetime import date, datetime, timezone
from typing import Any, Optional
from app.db import execute, fetch_all, fetch_one
from app.services import agent_integration
from app.services.excel_import import DEFAULT_FILE, DEFAULT_SHEET, parse_revenue_sheet
def fetch_excel_parse(path: str = DEFAULT_FILE, sheet: str | None = DEFAULT_SHEET) -> dict[str, Any]:
result = parse_revenue_sheet(path, sheet)
if not result.get("ok"):
raise RuntimeError(result.get("error") or "Excel parse failed")
return result
async def fetch_excel_parse_async(path: str = DEFAULT_FILE, sheet: str | None = DEFAULT_SHEET) -> dict[str, Any]:
return fetch_excel_parse(path, sheet)
def _ser(row: dict[str, Any] | None) -> dict[str, Any] | None:
if not row:
return None
out = dict(row)
for k, v in list(out.items()):
if hasattr(v, "isoformat"):
out[k] = v.isoformat()
return out
def _log_change(entity_type: str, entity_id: int, field: str, old: Any, new: Any, by: str = "ceo") -> None:
execute(
"""
INSERT INTO revenue_change_log (entity_type, entity_id, field_name, old_value, new_value, changed_by)
VALUES (%s, %s, %s, %s, %s, %s)
""",
(entity_type, entity_id, field, str(old) if old is not None else None, str(new) if new is not None else None, by),
)
def import_from_parsed(parsed: dict[str, Any], imported_by: str = "ceo", replace: bool = True) -> dict[str, Any]:
if replace:
execute("DELETE FROM revenue_objectives WHERE project_id IN (SELECT id FROM revenue_projects)")
execute("DELETE FROM revenue_projects")
execute("UPDATE revenue_cockpit_goals SET is_active = FALSE WHERE is_active = TRUE")
goals = parsed.get("goals") or {}
g = fetch_one(
"""
INSERT INTO revenue_cockpit_goals (vision_text, horizon_text, mid_text, tagline, is_active)
VALUES (%s, %s, %s, %s, TRUE)
RETURNING *
""",
(
goals.get("vision_text", ""),
goals.get("horizon_text", ""),
goals.get("mid_text", ""),
goals.get("tagline", ""),
),
)
count = 0
for p in parsed.get("projects") or []:
row = fetch_one(
"""
INSERT INTO revenue_projects
(name, category, margin_month, margin_year, target_revenue, next_steps, status, sort_order, metadata)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s::jsonb)
RETURNING id
""",
(
p["name"],
p.get("category", "deal"),
p.get("margin_month"),
p.get("margin_year"),
p.get("target_revenue"),
p.get("next_steps"),
p.get("status", "active"),
p.get("sort_order", count),
json.dumps({
"source_row": p.get("source_row"),
"row_style": p.get("row_style", "white"),
"imported": True,
}),
),
)
pid = row["id"] if row else None
if pid and p.get("next_steps"):
for i, line in enumerate([ln.strip() for ln in p["next_steps"].split("\n") if ln.strip()][:5]):
execute(
"""
INSERT INTO revenue_objectives (project_id, title, description, status, sort_order)
VALUES (%s, %s, %s, 'open', %s)
""",
(pid, line[:255], p["next_steps"] if i == 0 else None, i),
)
count += 1
run = fetch_one(
"""
INSERT INTO revenue_import_runs (source_file, sheet_name, rows_imported, goals_imported, imported_by, metadata)
VALUES (%s, %s, %s, TRUE, %s, %s::jsonb)
RETURNING *
""",
(
parsed.get("source_file", ""),
parsed.get("sheet_name", ""),
count,
imported_by,
json.dumps({"parsed_at": parsed.get("parsed_at"), "file_mtime": parsed.get("file_mtime")}),
),
)
take_snapshot()
return {"ok": True, "projects_imported": count, "goals": _ser(g), "import_run": _ser(run)}
def get_active_goals() -> dict[str, Any] | None:
return _ser(fetch_one("SELECT * FROM revenue_cockpit_goals WHERE is_active = TRUE ORDER BY id DESC LIMIT 1"))
def update_goals(data: dict[str, Any], changed_by: str = "ceo") -> dict[str, Any] | None:
old = fetch_one("SELECT * FROM revenue_cockpit_goals WHERE is_active = TRUE ORDER BY id DESC LIMIT 1")
if not old:
return None
fields = ("vision_text", "horizon_text", "mid_text", "tagline")
sets, params = [], []
for k in fields:
if k in data:
sets.append(f"{k} = %s")
params.append(data[k])
if str(old.get(k)) != str(data[k]):
_log_change("goals", old["id"], k, old.get(k), data[k], changed_by)
if not sets:
return get_active_goals()
params.append(old["id"])
execute(
f"UPDATE revenue_cockpit_goals SET {', '.join(sets)}, updated_at = NOW() WHERE id = %s",
tuple(params),
)
return get_active_goals()
def list_projects(status: str | None = None) -> list[dict[str, Any]]:
clauses, params = [], []
if status:
clauses.append("status = %s")
params.append(status)
where = (" WHERE " + " AND ".join(clauses)) if clauses else ""
rows = fetch_all(
f"""
SELECT p.*,
(SELECT COUNT(*) FROM revenue_objectives o WHERE o.project_id = p.id AND o.status = 'open') AS open_objectives,
(SELECT COUNT(*) FROM agent_tasks t WHERE t.revenue_project_id = p.id AND t.status NOT IN ('completed','cancelled')) AS open_tasks
FROM revenue_projects p
{where}
ORDER BY p.sort_order ASC, p.name ASC
""",
tuple(params) if params else None,
)
return [_ser({**r, "row_style": _infer_row_style(r.get("name"), r.get("margin_month"), r.get("metadata"))}) for r in rows]
def get_project(project_id: int) -> dict[str, Any] | None:
p = _ser(fetch_one("SELECT * FROM revenue_projects WHERE id = %s", (project_id,)))
if not p:
return None
p["objectives"] = [_ser(r) for r in fetch_all(
"SELECT * FROM revenue_objectives WHERE project_id = %s ORDER BY sort_order, id",
(project_id,),
)]
p["tasks"] = [_ser(r) for r in fetch_all(
"""
SELECT * FROM agent_tasks WHERE revenue_project_id = %s
ORDER BY created_at DESC LIMIT 50
""",
(project_id,),
)]
p["history"] = [_ser(r) for r in fetch_all(
"""
SELECT * FROM revenue_change_log
WHERE (entity_type = 'project' AND entity_id = %s)
OR (entity_type = 'objective' AND entity_id IN (
SELECT id FROM revenue_objectives WHERE project_id = %s))
ORDER BY created_at DESC LIMIT 30
""",
(project_id, project_id),
)]
p["row_style"] = _infer_row_style(p.get("name"), p.get("margin_month"), p.get("metadata"))
return p
def set_project_row_style(project_id: int, row_style: str) -> None:
old = fetch_one("SELECT metadata FROM revenue_projects WHERE id = %s", (project_id,))
meta = dict(old.get("metadata") or {}) if old else {}
meta["row_style"] = row_style
execute(
"UPDATE revenue_projects SET metadata = %s::jsonb, updated_at = NOW() WHERE id = %s",
(json.dumps(meta), project_id),
)
def update_project(project_id: int, data: dict[str, Any], changed_by: str = "ceo") -> dict[str, Any] | None:
old = fetch_one("SELECT * FROM revenue_projects WHERE id = %s", (project_id,))
if not old:
return None
fields = {
"name": data.get("name"),
"category": data.get("category"),
"margin_month": data.get("margin_month"),
"margin_year": data.get("margin_year"),
"target_revenue": data.get("target_revenue"),
"next_steps": data.get("next_steps"),
"status": data.get("status"),
"priority": data.get("priority"),
}
sets, params = [], []
for k, v in fields.items():
if k in data:
sets.append(f"{k} = %s")
params.append(v)
if str(old.get(k)) != str(v):
_log_change("project", project_id, k, old.get(k), v, changed_by)
if not sets:
return get_project(project_id)
params.append(project_id)
execute(f"UPDATE revenue_projects SET {', '.join(sets)}, updated_at = NOW() WHERE id = %s", tuple(params))
return get_project(project_id)
def _infer_row_style(name: str, margin_month: Any, metadata: Any) -> str:
if isinstance(metadata, dict) and metadata.get("row_style"):
return str(metadata["row_style"])
n = (name or "").lower()
if "foodlinkk food marketing" in n or "total earnings" in n or "loonkosten aissa" in n:
return "yellow"
if "foodservice" in n or n.strip() == "dirk":
return "orange"
if margin_month is not None and margin_month > 0:
return "green"
if any(x in n for x in ("plus", "vomar", "hoogvliet", "deka", "spar", "doner palace", "zakat")):
return "red"
return "white"
def create_objective(project_id: int, title: str, description: str | None = None, priority: str = "normal") -> dict[str, Any]:
row = fetch_one(
"""
INSERT INTO revenue_objectives (project_id, title, description, priority)
VALUES (%s, %s, %s, %s)
RETURNING *
""",
(project_id, title.strip(), description, priority),
)
_log_change("objective", row["id"], "created", None, title, "ceo")
return _ser(row) or {}
def update_objective(objective_id: int, data: dict[str, Any]) -> dict[str, Any] | None:
old = fetch_one("SELECT * FROM revenue_objectives WHERE id = %s", (objective_id,))
if not old:
return None
for k in ("title", "description", "status", "priority", "due_date"):
if k in data:
execute(
f"UPDATE revenue_objectives SET {k} = %s, updated_at = NOW() WHERE id = %s",
(data[k], objective_id),
)
_log_change("objective", objective_id, k, old.get(k), data[k])
return _ser(fetch_one("SELECT * FROM revenue_objectives WHERE id = %s", (objective_id,)))
def dashboard_stats() -> dict[str, Any]:
goals = get_active_goals()
totals = fetch_one(
"""
SELECT
COUNT(*) FILTER (WHERE status = 'active') AS active_projects,
COALESCE(SUM(margin_year) FILTER (WHERE status = 'active'), 0) AS total_margin_year,
COALESCE(SUM(margin_month) FILTER (WHERE status = 'active'), 0) AS total_margin_month,
COUNT(*) FILTER (WHERE category = 'deal' AND status = 'active') AS active_deals
FROM revenue_projects
"""
) or {}
open_obj = fetch_one("SELECT COUNT(*) AS n FROM revenue_objectives WHERE status = 'open'") or {"n": 0}
open_tasks = fetch_one(
"SELECT COUNT(*) AS n FROM agent_tasks WHERE status NOT IN ('completed','cancelled') AND revenue_project_id IS NOT NULL"
) or {"n": 0}
prev = fetch_one(
"SELECT * FROM revenue_snapshots WHERE snapshot_date < CURRENT_DATE ORDER BY snapshot_date DESC LIMIT 1"
)
return {
"goals": goals,
"active_projects": int(totals.get("active_projects") or 0),
"active_deals": int(totals.get("active_deals") or 0),
"total_margin_year": float(totals.get("total_margin_year") or 0),
"total_margin_month": float(totals.get("total_margin_month") or 0),
"open_objectives": int(open_obj.get("n") or 0),
"open_agent_tasks": int(open_tasks.get("n") or 0),
"previous_snapshot": _ser(prev),
}
def take_snapshot() -> dict[str, Any]:
stats = dashboard_stats()
row = fetch_one(
"""
INSERT INTO revenue_snapshots
(snapshot_date, total_margin_year, total_margin_month, active_projects, open_objectives, open_agent_tasks, payload)
VALUES (CURRENT_DATE, %s, %s, %s, %s, %s, %s::jsonb)
ON CONFLICT (snapshot_date) DO UPDATE SET
total_margin_year = EXCLUDED.total_margin_year,
total_margin_month = EXCLUDED.total_margin_month,
active_projects = EXCLUDED.active_projects,
open_objectives = EXCLUDED.open_objectives,
open_agent_tasks = EXCLUDED.open_agent_tasks,
payload = EXCLUDED.payload,
created_at = NOW()
RETURNING *
""",
(
stats["total_margin_year"],
stats["total_margin_month"],
stats["active_projects"],
stats["open_objectives"],
stats["open_agent_tasks"],
json.dumps({"goals_id": (stats.get("goals") or {}).get("id")}),
),
)
return _ser(row) or {}
def list_snapshots(limit: int = 90) -> list[dict[str, Any]]:
rows = fetch_all(
"SELECT * FROM revenue_snapshots ORDER BY snapshot_date DESC LIMIT %s",
(max(1, min(limit, 365)),),
)
return [_ser(r) for r in rows]
def assign_agent_task(
project_id: int,
agent_name: str,
title: str,
description: str | None = None,
objective_id: int | None = None,
priority: str = "normal",
delegate_herman: bool = True,
) -> dict[str, Any]:
project = fetch_one("SELECT name FROM revenue_projects WHERE id = %s", (project_id,))
if not project:
raise ValueError("Project not found")
agent = agent_name.strip().lower()
desc = description or ""
row = fetch_one(
"""
INSERT INTO agent_tasks
(agent_name, title, description, status, priority, assigned_by, revenue_project_id, revenue_objective_id, source)
VALUES (%s, %s, %s, 'pending', %s, 'ceo', %s, %s, 'revenue_cockpit')
RETURNING *
""",
(agent, title.strip(), desc, priority, project_id, objective_id),
)
task = _ser(row) or {}
body = f"Revenue Cockpit · {project['name']}: {title}"
if desc:
body += f"\n{desc}"
try:
execute(
"""
INSERT INTO agent_events (agent_name, agent_type, event_type, title, body, status, channel, metadata, related_table, related_id)
VALUES (%s, 'revenue_cockpit', 'task_assigned', %s, %s, 'pending', 'revenue_cockpit', %s::jsonb, 'agent_tasks', %s)
""",
(
agent,
title.strip(),
body,
json.dumps({"project_id": project_id, "objective_id": objective_id, "task_id": task.get("id")}),
task.get("id"),
),
)
except Exception:
pass
if delegate_herman and agent != "herman":
try:
agent_integration.create_handoff(
"ceo",
agent,
handoff_type="task",
payload={"task_id": task.get("id"), "project_id": project_id, "title": title},
status="pending",
)
except Exception:
pass
_log_change("project", project_id, "agent_task", None, title, "ceo")
return task
def list_agent_tasks(limit: int = 50) -> list[dict[str, Any]]:
rows = fetch_all(
"""
SELECT t.*, p.name AS project_name
FROM agent_tasks t
LEFT JOIN revenue_projects p ON p.id = t.revenue_project_id
WHERE t.revenue_project_id IS NOT NULL
ORDER BY t.created_at DESC
LIMIT %s
""",
(max(1, min(limit, 200)),),
)
return [_ser(r) for r in rows]
async def delegate_via_herman(project_id: int, message: str) -> dict[str, Any]:
from app.services import herman as herman_service
project = get_project(project_id)
if not project:
raise ValueError("Project not found")
prompt = f"[Revenue Cockpit · {project['name']}] {message}"
result = await herman_service.chat(prompt)
return {"ok": True, "result": result, "project_id": project_id}