Files
HoruxDespachosNuevo/docs/sessions/2026-05-04-fix-clientes-crea-despacho.md
Horux Dev e8aaf9ff15 fix(clientes): crear tenant como despacho desde admin global
Antes, createTenant() solo seteaba nombre, rfc, plan y databaseName.
Ahora registra tenants completos como despachos:

- dbMode: 'MANAGED'
- verticalProfile: CONTABLE | JURIDICO | ARQUITECTURA
- trialEndsAt: +30 días para plan trial
- codigoPostal: opcional (se llena automáticamente de la CSF al subir FIEL)

Frontend:
- Selector de Tipo de Despacho en /clientes
- C.P. omitido del formulario (viene de CSF -> sincronizarDatosFiscales)
- Tipos Tenant y CreateTenantData actualizados

Backend:
- getAllTenants y getTenantById retornan verticalProfile y codigoPostal

Refs: docs/sessions/2026-05-04-fix-clientes-crea-despacho.md
2026-05-17 06:11:29 +00:00

4.3 KiB

Sesión: Fix — Crear cliente desde /clientes registra como despacho

Fecha: 2026-05-04
Bug: El admin global creaba tenants "legacy" (sin dbMode, verticalProfile, trialEndsAt) desde /clientes. Ahora se registran como despachos completos.


1. Problema

Síntoma

Cuando el administrador global creaba un nuevo cliente desde /clientes, el tenant se creaba sin los campos de despacho:

  • dbMode = null (debería ser MANAGED)
  • verticalProfile = null (debería ser CONTABLE/JURIDICO/ARQUITECTURA)
  • trialEndsAt = null (debería ser +30 días para plan trial)
  • codigoPostal no se seteaba

Esto causaba que el nuevo cliente no funcionara correctamente como despacho (no aparecía en el selector de despachos, no tenía trial, etc.).

Causa raíz

El flujo de registro público (/register-despachosignupDespacho()) sí seteaba estos campos correctamente.
Pero el flujo de creación por admin (/clientescreateTenant()) no lo hacía — solo creaba el tenant con nombre, rfc, plan, databaseName.


2. Cambios realizados

2.1 Backend — tenants.service.ts

Firma ampliada:

export async function createTenant(data: {
  // ... campos existentes ...
  verticalProfile?: 'CONTABLE' | 'JURIDICO' | 'ARQUITECTURA';
  codigoPostal?: string;
})

Creación del tenant ahora setea despacho fields:

const tenant = await prisma.tenant.create({
  data: {
    nombre: data.nombre,
    rfc: data.rfc.toUpperCase(),
    plan,
    databaseName,
    dbMode: 'MANAGED',
    verticalProfile: data.verticalProfile || 'CONTABLE',
    codigoPostal: data.codigoPostal || undefined,
    trialEndsAt: isTrial ? new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) : undefined,
  }
});

Queries getAllTenants y getTenantById ahora retornan:

  • verticalProfile
  • codigoPostal

2.2 Backend — tenants.controller.ts

El endpoint POST /tenants ahora acepta y pasa:

  • verticalProfile (default: 'CONTABLE')
  • codigoPostal (opcional)

2.3 Frontend — clientes/page.tsx

Nuevo campo en el formulario: Tipo de Despacho

  • Select con opciones: Contable, Jurídico, Arquitectura
  • Default: Contable
  • Se persiste al crear y se carga al editar

C.P. deliberadamente omitido: El campo codigoPostal no se incluyó en el formulario. Se obtiene automáticamente de la CSF cuando el dueño del despacho sube su FIEL por primera vez (fiel.service.tsconsultarConstancia()sincronizarDatosFiscales()).

2.4 Frontend — lib/api/tenants.ts

Tipos actualizados:

export interface Tenant {
  // ... campos existentes ...
  verticalProfile?: 'CONTABLE' | 'JURIDICO' | 'ARQUITECTURA' | null;
  codigoPostal?: string | null;
}

export interface CreateTenantData {
  // ... campos existentes ...
  verticalProfile?: 'CONTABLE' | 'JURIDICO' | 'ARQUITECTURA';
  codigoPostal?: string;
}

3. Flujo resultante

Admin global crea cliente en /clientes
  ↓
Tenant creado con:
  dbMode = 'MANAGED'
  verticalProfile = (seleccionado por admin, default CONTABLE)
  trialEndsAt = +30 días (si plan = trial)
  codigoPostal = undefined (se llenará después)
  ↓
Dueño del despacho entra a la plataforma
  ↓
Sube FIEL del despacho (primer contribuyente)
  ↓
Sistema extrae CSF automáticamente
  ↓
Tenant actualizado con codigoPostal, calle, estado, regímenes...

4. Archivos modificados

Archivo Cambio
apps/api/src/services/tenants.service.ts createTenant setea dbMode, verticalProfile, trialEndsAt, codigoPostal; queries retornan nuevos campos
apps/api/src/controllers/tenants.controller.ts Acepta verticalProfile y codigoPostal del body
apps/web/app/(dashboard)/clientes/page.tsx Formulario con selector de verticalProfile; C.P. omitido (viene de CSF)
apps/web/lib/api/tenants.ts Tipos Tenant y CreateTenantData ampliados

5. Notas

  • El campo codigoPostal del backend es opcional y se dejó en la firma por si en el futuro se quiere pasar manualmente (ej. onboarding asistido).
  • No se requirió migración de base de datos — codigoPostal ya existía como columna String? en Tenant.
  • trialEndsAt se calcula como Date.now() + 30 días para plan trial, igual que en signupDespacho().