1
This commit is contained in:
@@ -0,0 +1,565 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
|
||||
from app.auth import require_auth
|
||||
from app.database import get_pool
|
||||
from app.dependencies import PaginationParams, parse_date
|
||||
from app.models.common import Meta, OkResponse, PaginatedResponse
|
||||
from app.models.cotizacion import (
|
||||
ActualizarPrecioRequest,
|
||||
CambiarEstadoRequest,
|
||||
CotizacionCreate,
|
||||
CotizacionResponse,
|
||||
CotizacionUpdate,
|
||||
)
|
||||
from app.services.calculators import ESTADOS_COTIZACION
|
||||
|
||||
router = APIRouter(prefix="/cotizaciones", tags=["Cotizaciones"])
|
||||
|
||||
|
||||
def _cuid() -> str:
|
||||
return uuid.uuid4().hex[:25]
|
||||
|
||||
|
||||
def _build_cotizacion_dict(cot, cliente=None, asesor=None, servicios=None, plan=None) -> dict:
|
||||
d = dict(cot)
|
||||
d["cliente"] = dict(cliente) if cliente else None
|
||||
d["asesor"] = dict(asesor) if asesor else None
|
||||
d["servicios"] = [dict(s) for s in servicios] if servicios else []
|
||||
d["planBucefalo"] = dict(plan) if plan else None
|
||||
return d
|
||||
|
||||
|
||||
async def _fetch_cotizacion_full(conn, cot_id: str) -> dict | None:
|
||||
cot = await conn.fetchrow('SELECT * FROM "Cotizacion" WHERE id = $1', cot_id)
|
||||
if not cot:
|
||||
return None
|
||||
|
||||
cliente = await conn.fetchrow('SELECT * FROM "Cliente" WHERE id = $1', cot["clienteId"])
|
||||
asesor = await conn.fetchrow('SELECT id, email, name, role FROM "User" WHERE id = $1', cot["asesorId"])
|
||||
servicios = await conn.fetch(
|
||||
"""
|
||||
SELECT sc.*, sc."servicioCatalogoId" as "catalogoId",
|
||||
s.nombre, s.descripcion, s."categoriaId"
|
||||
FROM "ServicioCotizado" sc
|
||||
JOIN "ServicioCatalogo" s ON s.id = sc."servicioCatalogoId"
|
||||
WHERE sc."cotizacionId" = $1
|
||||
ORDER BY sc.fase, sc.id
|
||||
""",
|
||||
cot_id,
|
||||
)
|
||||
plan = await conn.fetchrow('SELECT * FROM "PlanBucefaloCotizacion" WHERE "cotizacionId" = $1', cot_id)
|
||||
|
||||
return _build_cotizacion_dict(cot, cliente, asesor, servicios, plan)
|
||||
|
||||
|
||||
async def _resolve_bucefalo_servicio(conn) -> str | None:
|
||||
row = await conn.fetchrow(
|
||||
"""
|
||||
SELECT s.id FROM "ServicioCatalogo" s
|
||||
JOIN "Categoria" c ON c.id = s."categoriaId"
|
||||
WHERE c.nombre = 'CRM' AND s."tipoPago" = 'mensual' AND s.activo = true
|
||||
ORDER BY s.orden LIMIT 1
|
||||
"""
|
||||
)
|
||||
return row["id"] if row else None
|
||||
|
||||
|
||||
async def _find_or_create_cliente(conn, nombre: str, empresa: str, email: str, telefono: str) -> str:
|
||||
row = await conn.fetchrow(
|
||||
'SELECT id FROM "Cliente" WHERE nombre = $1 AND COALESCE(empresa, \'\') = $2',
|
||||
nombre,
|
||||
empresa or "",
|
||||
)
|
||||
if row:
|
||||
if email or telefono:
|
||||
await conn.execute(
|
||||
'UPDATE "Cliente" SET email = COALESCE($1, email), telefono = COALESCE($2, telefono), "updatedAt" = NOW() WHERE id = $3',
|
||||
email or None,
|
||||
telefono or None,
|
||||
row["id"],
|
||||
)
|
||||
return row["id"]
|
||||
|
||||
new_id = _cuid()
|
||||
await conn.execute(
|
||||
'INSERT INTO "Cliente" (id, nombre, empresa, email, telefono, "createdAt", "updatedAt") VALUES ($1, $2, $3, $4, $5, NOW(), NOW())',
|
||||
new_id,
|
||||
nombre,
|
||||
empresa or None,
|
||||
email or None,
|
||||
telefono or None,
|
||||
)
|
||||
return new_id
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. GET /cotizaciones — List with filters + pagination
|
||||
# ---------------------------------------------------------------------------
|
||||
@router.get("", response_model=PaginatedResponse[CotizacionResponse])
|
||||
async def list_cotizaciones(
|
||||
pagination: PaginationParams = Depends(),
|
||||
estado: str | None = Query(None),
|
||||
asesorId: str | None = Query(None),
|
||||
clienteId: str | None = Query(None),
|
||||
q: str | None = Query(None),
|
||||
desde: str | None = Query(None),
|
||||
hasta: str | None = Query(None),
|
||||
_auth: dict = Depends(require_auth),
|
||||
):
|
||||
pool = await get_pool()
|
||||
|
||||
conditions: list[str] = []
|
||||
params: list = []
|
||||
idx = 1
|
||||
|
||||
if estado:
|
||||
conditions.append(f'c.estado = ${idx}')
|
||||
params.append(estado)
|
||||
idx += 1
|
||||
if asesorId:
|
||||
conditions.append(f'c."asesorId" = ${idx}')
|
||||
params.append(asesorId)
|
||||
idx += 1
|
||||
if clienteId:
|
||||
conditions.append(f'c."clienteId" = ${idx}')
|
||||
params.append(clienteId)
|
||||
idx += 1
|
||||
if q:
|
||||
conditions.append(
|
||||
f'(c.numero ILIKE ${idx} OR cl.nombre ILIKE ${idx} OR c.proyecto ILIKE ${idx})'
|
||||
)
|
||||
params.append(f"%{q}%")
|
||||
idx += 1
|
||||
desde_dt = parse_date(desde)
|
||||
if desde_dt:
|
||||
conditions.append(f'c.fecha >= ${idx}')
|
||||
params.append(desde_dt)
|
||||
idx += 1
|
||||
hasta_dt = parse_date(hasta)
|
||||
if hasta_dt:
|
||||
conditions.append(f'c.fecha <= ${idx}')
|
||||
params.append(hasta_dt)
|
||||
idx += 1
|
||||
|
||||
where = "WHERE " + " AND ".join(conditions) if conditions else ""
|
||||
|
||||
count_row = await pool.fetchrow(
|
||||
f'SELECT COUNT(*) FROM "Cotizacion" c LEFT JOIN "Cliente" cl ON cl.id = c."clienteId" {where}',
|
||||
*params,
|
||||
)
|
||||
total = count_row["count"]
|
||||
|
||||
rows = await pool.fetch(
|
||||
f"""
|
||||
SELECT c.* FROM "Cotizacion" c
|
||||
LEFT JOIN "Cliente" cl ON cl.id = c."clienteId"
|
||||
{where}
|
||||
ORDER BY c."createdAt" DESC
|
||||
LIMIT ${idx} OFFSET ${idx + 1}
|
||||
""",
|
||||
*params,
|
||||
pagination.limit,
|
||||
pagination.offset,
|
||||
)
|
||||
|
||||
cotizaciones = []
|
||||
for r in rows:
|
||||
full = await _fetch_cotizacion_full(pool, r["id"])
|
||||
if full:
|
||||
cotizaciones.append(full)
|
||||
|
||||
pages = (total + pagination.limit - 1) // pagination.limit if total > 0 else 0
|
||||
|
||||
return PaginatedResponse(
|
||||
data=cotizaciones,
|
||||
meta=Meta(total=total, page=pagination.page, limit=pagination.limit, pages=pages),
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. POST /cotizaciones — Create
|
||||
# ---------------------------------------------------------------------------
|
||||
@router.post("", response_model=CotizacionResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_cotizacion(body: CotizacionCreate, _auth: dict = Depends(require_auth)):
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
async with conn.transaction():
|
||||
cliente_id = await _find_or_create_cliente(
|
||||
conn,
|
||||
body.cliente.nombre,
|
||||
body.cliente.empresa,
|
||||
body.cliente.email,
|
||||
body.cliente.telefono,
|
||||
)
|
||||
|
||||
cot_id = _cuid()
|
||||
now = datetime.now(timezone.utc)
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO "Cotizacion"
|
||||
(id, numero, fecha, vigencia, moneda, "tipoCambio", proyecto, "esquemaPago",
|
||||
estado, "incluirBonos", "incluirFinanciamiento", observaciones,
|
||||
"clienteId", "asesorId", "createdAt", "updatedAt")
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,'borrador',$9,$10,$11,$12,$13,$14,$14)
|
||||
""",
|
||||
cot_id,
|
||||
body.numero,
|
||||
body.fecha,
|
||||
body.vigencia,
|
||||
body.moneda,
|
||||
body.tipoCambio,
|
||||
body.proyecto,
|
||||
body.esquemaPago,
|
||||
body.incluirBonos,
|
||||
body.incluirFinanciamiento,
|
||||
body.observaciones or None,
|
||||
cliente_id,
|
||||
body.asesorId,
|
||||
now,
|
||||
)
|
||||
|
||||
bucefalo_servicio_id = await _resolve_bucefalo_servicio(conn)
|
||||
|
||||
for svc in body.servicios:
|
||||
catalogo_id = svc.catalogoId
|
||||
if catalogo_id.startswith("bucefalo-") and bucefalo_servicio_id:
|
||||
catalogo_id = bucefalo_servicio_id
|
||||
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO "ServicioCotizado"
|
||||
(id, "cotizacionId", "servicioCatalogoId", fase, "tipoPago", precio,
|
||||
"tiempoEntrega", entregables, notas, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,true,$10,$10)
|
||||
""",
|
||||
_cuid(),
|
||||
cot_id,
|
||||
catalogo_id,
|
||||
svc.fase,
|
||||
svc.tipoPago,
|
||||
svc.precio,
|
||||
svc.tiempoEntrega,
|
||||
json.dumps(svc.entregables),
|
||||
None,
|
||||
now,
|
||||
)
|
||||
|
||||
if body.planBucefalo:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO "PlanBucefaloCotizacion"
|
||||
(id, "cotizacionId", nivel, precio, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES ($1,$2,$3,$4,true,$5,$5)
|
||||
""",
|
||||
_cuid(),
|
||||
cot_id,
|
||||
body.planBucefalo.nivel,
|
||||
body.planBucefalo.precio,
|
||||
now,
|
||||
)
|
||||
|
||||
row = await pool.fetchrow('SELECT * FROM "Cotizacion" WHERE id = $1', cot_id)
|
||||
return dict(row)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. GET /cotizaciones/{id} — Get with relations
|
||||
# ---------------------------------------------------------------------------
|
||||
@router.get("/{cotizacion_id}", response_model=CotizacionResponse)
|
||||
async def get_cotizacion(cotizacion_id: str, _auth: dict = Depends(require_auth)):
|
||||
pool = await get_pool()
|
||||
full = await _fetch_cotizacion_full(pool, cotizacion_id)
|
||||
if not full:
|
||||
raise HTTPException(status_code=404, detail="Cotización no encontrada")
|
||||
return full
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. PUT /cotizaciones/{id} — Update
|
||||
# ---------------------------------------------------------------------------
|
||||
@router.put("/{cotizacion_id}", response_model=CotizacionResponse)
|
||||
async def update_cotizacion(
|
||||
cotizacion_id: str,
|
||||
body: CotizacionUpdate,
|
||||
_auth: dict = Depends(require_auth),
|
||||
):
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
existing = await conn.fetchrow('SELECT * FROM "Cotizacion" WHERE id = $1', cotizacion_id)
|
||||
if not existing:
|
||||
raise HTTPException(status_code=404, detail="Cotización no encontrada")
|
||||
|
||||
async with conn.transaction():
|
||||
cliente_id = existing["clienteId"]
|
||||
if body.cliente:
|
||||
cliente_id = await _find_or_create_cliente(
|
||||
conn,
|
||||
body.cliente.nombre,
|
||||
body.cliente.empresa,
|
||||
body.cliente.email,
|
||||
body.cliente.telefono,
|
||||
)
|
||||
|
||||
updates: list[str] = []
|
||||
params: list = []
|
||||
idx = 1
|
||||
|
||||
def _add(field: str, col: str, val):
|
||||
nonlocal idx
|
||||
if val is not None:
|
||||
updates.append(f'{col} = ${idx}')
|
||||
params.append(val)
|
||||
idx += 1
|
||||
|
||||
_add("fecha", "fecha", body.fecha)
|
||||
_add("vigencia", "vigencia", body.vigencia)
|
||||
_add("moneda", "moneda", body.moneda)
|
||||
_add("tipoCambio", '"tipoCambio"', body.tipoCambio)
|
||||
_add("proyecto", "proyecto", body.proyecto)
|
||||
_add("esquemaPago", '"esquemaPago"', body.esquemaPago)
|
||||
_add("incluirBonos", '"incluirBonos"', body.incluirBonos)
|
||||
_add("incluirFinanciamiento", '"incluirFinanciamiento"', body.incluirFinanciamiento)
|
||||
_add("observaciones", "observaciones", body.observaciones)
|
||||
_add("estado", "estado", body.estado)
|
||||
|
||||
if cliente_id != existing["clienteId"]:
|
||||
updates.append(f'"clienteId" = ${idx}')
|
||||
params.append(cliente_id)
|
||||
idx += 1
|
||||
|
||||
if updates:
|
||||
updates.append(f'"updatedAt" = ${idx}')
|
||||
params.append(datetime.now(timezone.utc))
|
||||
idx += 1
|
||||
params.append(cotizacion_id)
|
||||
await conn.execute(
|
||||
f'UPDATE "Cotizacion" SET {", ".join(updates)} WHERE id = ${idx}',
|
||||
*params,
|
||||
)
|
||||
|
||||
if body.servicios is not None:
|
||||
await conn.execute('DELETE FROM "ServicioCotizado" WHERE "cotizacionId" = $1', cotizacion_id)
|
||||
bucefalo_servicio_id = await _resolve_bucefalo_servicio(conn)
|
||||
now = datetime.now(timezone.utc)
|
||||
for svc in body.servicios:
|
||||
catalogo_id = svc.catalogoId
|
||||
if catalogo_id.startswith("bucefalo-") and bucefalo_servicio_id:
|
||||
catalogo_id = bucefalo_servicio_id
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO "ServicioCotizado"
|
||||
(id, "cotizacionId", "servicioCatalogoId", fase, "tipoPago", precio,
|
||||
"tiempoEntrega", entregables, notas, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,true,$10,$10)
|
||||
""",
|
||||
_cuid(),
|
||||
cotizacion_id,
|
||||
catalogo_id,
|
||||
svc.fase,
|
||||
svc.tipoPago,
|
||||
svc.precio,
|
||||
svc.tiempoEntrega,
|
||||
json.dumps(svc.entregables),
|
||||
None,
|
||||
now,
|
||||
)
|
||||
|
||||
if body.planBucefalo is not None:
|
||||
existing_plan = await conn.fetchrow(
|
||||
'SELECT id FROM "PlanBucefaloCotizacion" WHERE "cotizacionId" = $1',
|
||||
cotizacion_id,
|
||||
)
|
||||
now = datetime.now(timezone.utc)
|
||||
if existing_plan:
|
||||
await conn.execute(
|
||||
'UPDATE "PlanBucefaloCotizacion" SET nivel = $1, precio = $2, "updatedAt" = $3 WHERE id = $4',
|
||||
body.planBucefalo.nivel,
|
||||
body.planBucefalo.precio,
|
||||
now,
|
||||
existing_plan["id"],
|
||||
)
|
||||
else:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO "PlanBucefaloCotizacion"
|
||||
(id, "cotizacionId", nivel, precio, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES ($1,$2,$3,$4,true,$5,$5)
|
||||
""",
|
||||
_cuid(),
|
||||
cotizacion_id,
|
||||
body.planBucefalo.nivel,
|
||||
body.planBucefalo.precio,
|
||||
now,
|
||||
)
|
||||
elif body.planBucefalo is None and "planBucefalo" in body.model_fields_set:
|
||||
await conn.execute(
|
||||
'DELETE FROM "PlanBucefaloCotizacion" WHERE "cotizacionId" = $1',
|
||||
cotizacion_id,
|
||||
)
|
||||
|
||||
full = await _fetch_cotizacion_full(pool, cotizacion_id)
|
||||
return full
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5. DELETE /cotizaciones/{id}
|
||||
# ---------------------------------------------------------------------------
|
||||
@router.delete("/{cotizacion_id}", response_model=OkResponse)
|
||||
async def delete_cotizacion(cotizacion_id: str, _auth: dict = Depends(require_auth)):
|
||||
pool = await get_pool()
|
||||
existing = await pool.fetchrow('SELECT id FROM "Cotizacion" WHERE id = $1', cotizacion_id)
|
||||
if not existing:
|
||||
raise HTTPException(status_code=404, detail="Cotización no encontrada")
|
||||
await pool.execute('DELETE FROM "Cotizacion" WHERE id = $1', cotizacion_id)
|
||||
return OkResponse(ok=True)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 6. PATCH /cotizaciones/{id}/precio
|
||||
# ---------------------------------------------------------------------------
|
||||
@router.patch("/{cotizacion_id}/precio", response_model=OkResponse)
|
||||
async def update_precio_servicio(
|
||||
cotizacion_id: str,
|
||||
body: ActualizarPrecioRequest,
|
||||
_auth: dict = Depends(require_auth),
|
||||
):
|
||||
pool = await get_pool()
|
||||
cot = await pool.fetchrow('SELECT id FROM "Cotizacion" WHERE id = $1', cotizacion_id)
|
||||
if not cot:
|
||||
raise HTTPException(status_code=404, detail="Cotización no encontrada")
|
||||
|
||||
svc = await pool.fetchrow(
|
||||
'SELECT id FROM "ServicioCotizado" WHERE id = $1 AND "cotizacionId" = $2',
|
||||
body.servicioId,
|
||||
cotizacion_id,
|
||||
)
|
||||
if not svc:
|
||||
raise HTTPException(status_code=404, detail="Servicio no pertenece a esta cotización")
|
||||
|
||||
await pool.execute(
|
||||
'UPDATE "ServicioCotizado" SET precio = $1, "updatedAt" = NOW() WHERE id = $2',
|
||||
body.precio,
|
||||
body.servicioId,
|
||||
)
|
||||
return OkResponse(ok=True)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 7. PATCH /cotizaciones/{id}/estado
|
||||
# ---------------------------------------------------------------------------
|
||||
@router.patch("/{cotizacion_id}/estado", response_model=OkResponse)
|
||||
async def cambiar_estado(
|
||||
cotizacion_id: str,
|
||||
body: CambiarEstadoRequest,
|
||||
_auth: dict = Depends(require_auth),
|
||||
):
|
||||
if body.estado not in ESTADOS_COTIZACION:
|
||||
raise HTTPException(
|
||||
status_code=422,
|
||||
detail=f"Estado inválido. Permitidos: {', '.join(ESTADOS_COTIZACION)}",
|
||||
)
|
||||
|
||||
pool = await get_pool()
|
||||
result = await pool.execute(
|
||||
'UPDATE "Cotizacion" SET estado = $1, "updatedAt" = NOW() WHERE id = $2',
|
||||
body.estado,
|
||||
cotizacion_id,
|
||||
)
|
||||
if result == "UPDATE 0":
|
||||
raise HTTPException(status_code=404, detail="Cotización no encontrada")
|
||||
return OkResponse(ok=True)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 8. POST /cotizaciones/{id}/duplicate
|
||||
# ---------------------------------------------------------------------------
|
||||
@router.post("/{cotizacion_id}/duplicate", response_model=CotizacionResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def duplicate_cotizacion(cotizacion_id: str, _auth: dict = Depends(require_auth)):
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
original = await conn.fetchrow('SELECT * FROM "Cotizacion" WHERE id = $1', cotizacion_id)
|
||||
if not original:
|
||||
raise HTTPException(status_code=404, detail="Cotización no encontrada")
|
||||
|
||||
servicios = await conn.fetch(
|
||||
'SELECT * FROM "ServicioCotizado" WHERE "cotizacionId" = $1',
|
||||
cotizacion_id,
|
||||
)
|
||||
plan = await conn.fetchrow(
|
||||
'SELECT * FROM "PlanBucefaloCotizacion" WHERE "cotizacionId" = $1',
|
||||
cotizacion_id,
|
||||
)
|
||||
|
||||
async with conn.transaction():
|
||||
now = datetime.now(timezone.utc)
|
||||
new_id = _cuid()
|
||||
new_numero = original["numero"] + "-COPY"
|
||||
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO "Cotizacion"
|
||||
(id, numero, fecha, vigencia, moneda, "tipoCambio", proyecto, "esquemaPago",
|
||||
estado, "incluirBonos", "incluirFinanciamiento", observaciones,
|
||||
"clienteId", "asesorId", "createdAt", "updatedAt")
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,'borrador',$9,$10,$11,$12,$13,$14,$14)
|
||||
""",
|
||||
new_id,
|
||||
new_numero,
|
||||
original["fecha"],
|
||||
original["vigencia"],
|
||||
original["moneda"],
|
||||
original["tipoCambio"],
|
||||
original["proyecto"],
|
||||
original["esquemaPago"],
|
||||
original["incluirBonos"],
|
||||
original["incluirFinanciamiento"],
|
||||
original["observaciones"],
|
||||
original["clienteId"],
|
||||
original["asesorId"],
|
||||
now,
|
||||
)
|
||||
|
||||
for svc in servicios:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO "ServicioCotizado"
|
||||
(id, "cotizacionId", "servicioCatalogoId", fase, "tipoPago", precio,
|
||||
"tiempoEntrega", entregables, notas, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$11)
|
||||
""",
|
||||
_cuid(),
|
||||
new_id,
|
||||
svc["servicioCatalogoId"],
|
||||
svc["fase"],
|
||||
svc["tipoPago"],
|
||||
svc["precio"],
|
||||
svc["tiempoEntrega"],
|
||||
svc["entregables"],
|
||||
svc["notas"],
|
||||
svc["seleccionado"],
|
||||
now,
|
||||
)
|
||||
|
||||
if plan:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO "PlanBucefaloCotizacion"
|
||||
(id, "cotizacionId", nivel, precio, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$6)
|
||||
""",
|
||||
_cuid(),
|
||||
new_id,
|
||||
plan["nivel"],
|
||||
plan["precio"],
|
||||
plan["seleccionado"],
|
||||
now,
|
||||
)
|
||||
|
||||
full = await _fetch_cotizacion_full(pool, new_id)
|
||||
return full
|
||||
Reference in New Issue
Block a user