Platform bundle: marketing publish, IT ops, packaging, agents mesh.
Volledige Foodlinkk Command Center uitbreiding met social automatisering, reclamefolder filters, Proxmox monitoring en documentatie.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
"""Full-system data export for Reports hub."""
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import io
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from app.db import fetch_all
|
||||
|
||||
EXPORT_DATASETS: dict[str, dict[str, str]] = {
|
||||
"clients": {"label": "CRM Klanten", "table": "clients", "order": "updated_at DESC"},
|
||||
"deals": {"label": "CRM Deals", "table": "deals", "order": "updated_at DESC"},
|
||||
"supermarkets": {"label": "Supermarkten", "table": "supermarkets", "order": "name ASC"},
|
||||
"wholesalers": {"label": "Groothandels", "table": "wholesalers", "order": "name ASC"},
|
||||
"supermarket_contacts": {"label": "Supermarkt contacten", "table": "supermarket_contacts", "order": "id ASC"},
|
||||
"wholesaler_contacts": {"label": "Groothandel contacten", "table": "wholesaler_contacts", "order": "id ASC"},
|
||||
"rss_items": {"label": "RSS items", "table": "rss_items", "order": "published_at DESC NULLS LAST"},
|
||||
"rss_bookmarks": {"label": "RSS bookmarks", "table": "rss_bookmarks", "order": "created_at DESC"},
|
||||
"agent_events": {"label": "Agent events", "table": "agent_events", "order": "created_at DESC"},
|
||||
"sales_milestones": {"label": "Sales milestones", "table": "sales_milestones", "order": "created_at DESC"},
|
||||
"promo_campaigns": {"label": "Promo / reclame", "table": "promo_campaigns", "order": "created_at DESC"},
|
||||
"daily_briefings": {"label": "Dagrapporten", "table": "daily_briefings", "order": "created_at DESC"},
|
||||
"document_analytics": {"label": "NAS documenten", "table": "document_analytics", "order": "analyzed_at DESC NULLS LAST"},
|
||||
"products": {"label": "Producten", "table": "products", "order": "name ASC"},
|
||||
"suppliers": {"label": "Leveranciers", "table": "suppliers", "order": "name ASC"},
|
||||
}
|
||||
|
||||
|
||||
def _serialize(val: Any) -> Any:
|
||||
if hasattr(val, "isoformat"):
|
||||
return val.isoformat()
|
||||
if isinstance(val, (dict, list)):
|
||||
return json.dumps(val, default=str)
|
||||
if val is not None and type(val).__name__ == "Decimal":
|
||||
return float(val)
|
||||
return val
|
||||
|
||||
|
||||
def list_datasets() -> list[dict[str, Any]]:
|
||||
out = []
|
||||
for key, meta in EXPORT_DATASETS.items():
|
||||
count = 0
|
||||
try:
|
||||
from app.db import fetch_one
|
||||
row = fetch_one(f"SELECT COUNT(*) AS c FROM {meta['table']}")
|
||||
count = int(row["c"]) if row else 0
|
||||
except Exception:
|
||||
pass
|
||||
out.append({"id": key, "label": meta["label"], "count": count})
|
||||
return out
|
||||
|
||||
|
||||
def fetch_dataset(name: str, limit: int = 10000) -> list[dict[str, Any]]:
|
||||
meta = EXPORT_DATASETS.get(name)
|
||||
if not meta:
|
||||
raise ValueError(f"Unknown dataset: {name}")
|
||||
rows = fetch_all(f"SELECT * FROM {meta['table']} ORDER BY {meta['order']} LIMIT %s", (limit,))
|
||||
for row in rows:
|
||||
for k, v in list(row.items()):
|
||||
row[k] = _serialize(v)
|
||||
return rows
|
||||
|
||||
|
||||
def to_csv(rows: list[dict[str, Any]]) -> str:
|
||||
if not rows:
|
||||
return ""
|
||||
buf = io.StringIO()
|
||||
writer = csv.DictWriter(buf, fieldnames=list(rows[0].keys()), extrasaction="ignore")
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def export_all_json(limit: int = 5000) -> dict[str, Any]:
|
||||
bundle: dict[str, Any] = {
|
||||
"exported_at": datetime.now(timezone.utc).isoformat(),
|
||||
"datasets": {},
|
||||
}
|
||||
for key in EXPORT_DATASETS:
|
||||
try:
|
||||
bundle["datasets"][key] = fetch_dataset(key, limit=min(limit, 5000))
|
||||
except Exception as exc:
|
||||
bundle["datasets"][key] = {"error": str(exc)}
|
||||
return bundle
|
||||
Reference in New Issue
Block a user