114 lines
3.9 KiB
Python
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}
|