Restaurar funcionalidades desde stash + setup de despliegue Coolify
- Recupera el trabajo revertido (doble propuesta, retainer, niveles, API Python) desde el stash de GitHub Desktop - Dockerfile multi-stage para Next.js (migraciones automáticas al arrancar, seed opcional via RUN_SEED) - docker-compose.coolify.yml: postgres + web + api con healthchecks y SERVICE_FQDN_* - Endpoint público /api/health (verifica BD) para healthchecks - seed.ts parametrizado: conexión DB_* y credenciales SEED_* por entorno (sin passwords hardcodeadas) - .env.example, .dockerignore, uvicorn con --proxy-headers - Limpieza: .xlsx y __pycache__ fuera del repo Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
+20
-13
@@ -168,6 +168,8 @@ async def _crear_cotizacion(conn, args: dict) -> dict:
|
||||
moneda = args.get("moneda", "MXN")
|
||||
proyecto = args.get("proyecto", "MKT Digital")
|
||||
esquema = args.get("esquema_pago", "Pago Unico/Mensual")
|
||||
es_doble = bool(args.get("es_doble", False))
|
||||
opciones_metadata = args.get("opciones_metadata") if es_doble else None
|
||||
|
||||
cliente = await conn.fetchrow(
|
||||
'SELECT id FROM "Cliente" WHERE nombre = $1 AND empresa = $2',
|
||||
@@ -194,10 +196,13 @@ async def _crear_cotizacion(conn, args: dict) -> dict:
|
||||
async with conn.transaction():
|
||||
cot = await conn.fetchrow(
|
||||
"""INSERT INTO "Cotizacion" (id, numero, fecha, vigencia, moneda, "tipoCambio", proyecto, "esquemaPago",
|
||||
estado, "incluirBonos", "incluirFinanciamiento", observaciones, "clienteId", "asesorId", "createdAt", "updatedAt")
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4, 'NA', $5, $6, 'borrador', false, false, '', $7, $8, NOW(), NOW())
|
||||
estado, "incluirBonos", "incluirFinanciamiento", "esDoble", "opcionesMetadata", observaciones, "clienteId", "asesorId", "createdAt", "updatedAt")
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4, 'NA', $5, $6, 'borrador', false, false, $7, $8, '', $9, $10, NOW(), NOW())
|
||||
RETURNING id, numero""",
|
||||
numero, now, vigencia, moneda, proyecto, esquema, cliente_id, "agent",
|
||||
numero, now, vigencia, moneda, proyecto, esquema,
|
||||
es_doble,
|
||||
json.dumps(opciones_metadata) if opciones_metadata else None,
|
||||
cliente_id, "agent",
|
||||
)
|
||||
cot_id = cot["id"]
|
||||
|
||||
@@ -218,12 +223,14 @@ async def _crear_cotizacion(conn, args: dict) -> dict:
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
entregables = []
|
||||
|
||||
opcion = (srv.get("opcion") or "ambas") if es_doble else None
|
||||
|
||||
await conn.fetchrow(
|
||||
"""INSERT INTO "ServicioCotizado" (id, "cotizacionId", "servicioCatalogoId", fase, "tipoPago",
|
||||
precio, "tiempoEntrega", entregables, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, true, NOW(), NOW())""",
|
||||
precio, "tiempoEntrega", entregables, opcion, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, true, NOW(), NOW())""",
|
||||
cot_id, catalogo_id, cat_row["fase"], cat_row["tipoPago"],
|
||||
precio, cat_row["tiempoEntrega"], json.dumps(entregables or []),
|
||||
precio, cat_row["tiempoEntrega"], json.dumps(entregables or []), opcion,
|
||||
)
|
||||
|
||||
if plan_bucefalo:
|
||||
@@ -363,13 +370,13 @@ async def _duplicar_cotizacion(conn, args: dict) -> dict:
|
||||
async with conn.transaction():
|
||||
new_cot = await conn.fetchrow(
|
||||
"""INSERT INTO "Cotizacion" (id, numero, fecha, vigencia, moneda, "tipoCambio", proyecto, "esquemaPago",
|
||||
estado, "incluirBonos", "incluirFinanciamiento", observaciones, "clienteId", "asesorId", "createdAt", "updatedAt")
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, 'borrador', $8, $9, $10, $11, $12, NOW(), NOW())
|
||||
estado, "incluirBonos", "incluirFinanciamiento", "esDoble", "opcionesMetadata", observaciones, "clienteId", "asesorId", "createdAt", "updatedAt")
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, 'borrador', $8, $9, $10, $11, $12, $13, $14, NOW(), NOW())
|
||||
RETURNING id, numero""",
|
||||
new_numero, now, original["vigencia"], original["moneda"], original["tipoCambio"],
|
||||
original["proyecto"], original["esquemaPago"], original["incluirBonos"],
|
||||
original["incluirFinanciamiento"], original["observaciones"],
|
||||
original["clienteId"], original["asesorId"],
|
||||
original["incluirFinanciamiento"], original["esDoble"], original["opcionesMetadata"],
|
||||
original["observaciones"], original["clienteId"], original["asesorId"],
|
||||
)
|
||||
new_id = new_cot["id"]
|
||||
|
||||
@@ -379,10 +386,10 @@ async def _duplicar_cotizacion(conn, args: dict) -> dict:
|
||||
for s in servicios:
|
||||
await conn.fetchrow(
|
||||
"""INSERT INTO "ServicioCotizado" (id, "cotizacionId", "servicioCatalogoId", fase, "tipoPago",
|
||||
precio, "tiempoEntrega", entregables, notas, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), NOW())""",
|
||||
precio, "tiempoEntrega", entregables, notas, opcion, seleccionado, "createdAt", "updatedAt")
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW(), NOW())""",
|
||||
new_id, s["servicioCatalogoId"], s["fase"], s["tipoPago"],
|
||||
s["precio"], s["tiempoEntrega"], s["entregables"], s["notas"], s["seleccionado"],
|
||||
s["precio"], s["tiempoEntrega"], s["entregables"], s["notas"], s["opcion"], s["seleccionado"],
|
||||
)
|
||||
|
||||
plan = await conn.fetchrow(
|
||||
|
||||
+17
-1
@@ -45,7 +45,10 @@ TOOLS = [
|
||||
"Incluye servicios del catálogo con precios personalizables, plan CRM Bucefalo opcional, "
|
||||
"y configuración de moneda y esquema de pago. "
|
||||
"La cotización se crea en estado 'borrador'. "
|
||||
"Precios CRM Bucefalo: basico=$1,000/mes, estandar=$3,500/mes, premium=$4,500/mes, empresarial=$7,500/mes."
|
||||
"Precios CRM Bucefalo: basico=$1,000/mes, estandar=$3,500/mes, premium=$4,500/mes, empresarial=$7,500/mes. "
|
||||
"Soporta DOBLE PROPUESTA: con es_doble=true se presentan dos opciones comparables; cada servicio "
|
||||
"se asigna a la opción '1', '2' o 'ambas' (compartido), y opciones_metadata define el título, "
|
||||
"descripción y exclusiones de cada opción."
|
||||
),
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
@@ -67,11 +70,24 @@ TOOLS = [
|
||||
"properties": {
|
||||
"servicio_id": {"type": "string", "description": "ID del servicio del catálogo (obtener con buscar_servicios)"},
|
||||
"precio_personalizado": {"type": "number", "description": "Precio personalizado (opcional, usa precio base si no se especifica)"},
|
||||
"opcion": {"type": "string", "enum": ["1", "2", "ambas"], "description": "Solo en doble propuesta: opción a la que pertenece el servicio ('ambas' = compartido). Default 'ambas'."},
|
||||
},
|
||||
"required": ["servicio_id"],
|
||||
},
|
||||
"description": "Lista de servicios a incluir en la cotización",
|
||||
},
|
||||
"es_doble": {
|
||||
"type": "boolean",
|
||||
"description": "Si es true, la cotización presenta dos opciones comparables (doble propuesta).",
|
||||
},
|
||||
"opciones_metadata": {
|
||||
"type": "object",
|
||||
"description": "Solo en doble propuesta. Metadatos por opción, p.ej. {\"1\": {\"titulo\": \"...\", \"descripcion\": \"...\", \"noIncluye\": \"...\"}, \"2\": {...}}.",
|
||||
"properties": {
|
||||
"1": {"type": "object", "properties": {"titulo": {"type": "string"}, "descripcion": {"type": "string"}, "noIncluye": {"type": "string"}}},
|
||||
"2": {"type": "object", "properties": {"titulo": {"type": "string"}, "descripcion": {"type": "string"}, "noIncluye": {"type": "string"}}},
|
||||
},
|
||||
},
|
||||
"plan_bucefalo": {
|
||||
"type": "string",
|
||||
"enum": ["basico", "estandar", "premium", "empresarial"],
|
||||
|
||||
Reference in New Issue
Block a user