Files
cotizador/api/app/routers/import_.py
T
2026-06-10 02:04:37 -06:00

114 lines
3.9 KiB
Python

from __future__ import annotations
import csv
import io
from fastapi import APIRouter, Depends, File, UploadFile
from asyncpg import Connection
from app.dependencies import get_db
from app.auth import require_auth
router = APIRouter(prefix="/import", tags=["Import"])
REQUIRED_COLUMNS = {"nombre", "fase", "tipoPago", "precioBase", "categoria"}
@router.post("/catalogo")
async def import_catalogo_csv(
file: UploadFile = File(...),
_auth: dict = Depends(require_auth),
db: Connection = Depends(get_db),
):
content = await file.read()
text = content.decode("utf-8-sig")
reader = csv.DictReader(io.StringIO(text))
if not reader.fieldnames or not REQUIRED_COLUMNS.issubset(set(reader.fieldnames)):
missing = REQUIRED_COLUMNS - set(reader.fieldnames or [])
return {
"creados": 0,
"omitidos": 0,
"errores": [f"Missing required columns: {', '.join(missing)}"],
}
categorias = await db.fetch('SELECT id, nombre FROM "Categoria" WHERE activo = true')
cat_map = {r["nombre"]: r["id"] for r in categorias}
existing = await db.fetch('SELECT nombre FROM "ServicioCatalogo" WHERE activo = true')
existing_names = {r["nombre"] for r in existing}
creados = 0
omitidos = 0
errores: list[str] = []
async with db.transaction():
for i, row in enumerate(reader, start=2):
nombre = (row.get("nombre") or "").strip()
if not nombre:
omitidos += 1
continue
if nombre in existing_names:
omitidos += 1
continue
cat_nombre = (row.get("categoria") or "").strip()
cat_id = cat_map.get(cat_nombre)
if not cat_id:
errores.append(f"Row {i}: category '{cat_nombre}' not found")
continue
try:
fase = int(row.get("fase", "0"))
if fase not in (0, 1, 2, 3):
raise ValueError
except (ValueError, TypeError):
errores.append(f"Row {i}: invalid fase '{row.get('fase')}'")
continue
tipo_pago = (row.get("tipoPago") or "").strip()
if tipo_pago not in ("unico", "mensual"):
errores.append(f"Row {i}: invalid tipoPago '{tipo_pago}'")
continue
try:
precio = float(row.get("precioBase", "0"))
except (ValueError, TypeError):
errores.append(f"Row {i}: invalid precioBase '{row.get('precioBase')}'")
continue
tiempo = (row.get("tiempoEntrega") or "7 - 14 dias").strip()
variante = (row.get("variante") or "").strip() or None
try:
orden = int(row.get("orden", "0"))
except (ValueError, TypeError):
orden = 0
entregables_raw = (row.get("entregablesDefault") or "").strip()
entregables = [e.strip() for e in entregables_raw.split(";") if e.strip()] if entregables_raw else []
await db.execute(
"""
INSERT INTO "ServicioCatalogo"
(id, nombre, descripcion, fase, "tipoPago", "precioBase",
"tiempoEntrega", "entregablesDefault", "categoriaId",
variante, orden, activo, "createdAt", "updatedAt")
VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, true, now(), now())
""",
nombre,
(row.get("descripcion") or "").strip() or None,
fase,
tipo_pago,
precio,
tiempo,
entregables if entregables else None,
cat_id,
variante,
orden,
)
existing_names.add(nombre)
creados += 1
return {"creados": creados, "omitidos": omitidos, "errores": errores}