Campos y automatizaciones del ticket
El módulo de tickets sincroniza con Zendesk pero define sus propios campos y desplegables. Esta página documenta las columnas del ticket, de dónde salen las opciones de cada desplegable, cómo se mapean con Zendesk y las automatizaciones del formulario de alta/edición.
Campos del ticket
Columnas nativas de la tabla chat_tickets (más allá de identificadores y timestamps de sistema):
| Campo | Columna | Tipo | Descripción |
|---|
| Título | title | texto | Asunto del ticket |
| Descripción | description | texto | Detalle de la incidencia |
| Estado | status | enum | created, assigned, in_progress, improvement_proposal (deprecado), resolved, closed |
| Prioridad | priority | enum | low, normal, high, urgent |
| Tipo | ticket_kind | enum | Naturaleza del ticket: incident (incidencia, default) | improvement_proposal (propuesta de mejora) |
| Propiedad | property_id | ref | Casa asociada (UUID de properties) |
| Destino | destination | enum | Zona geográfica (Baqueira, Menorca, etc.) |
| Equipo de resolución | resolution_team | enum | Equipo responsable |
| Zona | zone | enum | Zona de la propiedad donde ocurre la incidencia |
| Categoría | category | enum | Tipo de incidencia |
| Pagador | payer | enum | Quién asume el coste |
| Estado de reparación | repair_status | enum | Fase de la reparación |
| Coste estimado | estimated_cost | numérico | Importe estimado exacto (se conserva) |
| Coste estimado (rango) | estimated_cost_range | enum | Rango de coste estimado (ver abajo) |
| Coste real | actual_cost | numérico | Importe final |
| Notas internas | internal_notes | texto | Comentarios internos sobre la incidencia |
| Fecha primera respuesta | first_response_at | timestamp | Primera respuesta al cliente |
| Fecha resolución prevista | expected_resolution_at | timestamp | Fecha estimada de resolución |
| Resumen IA | ai_summary | texto | Generado por Zendesk (solo lectura) |
estimated_cost (numérico) se conserva por compatibilidad. Se añadió estimated_cost_range para capturar el coste como rango: <100, 100–500, 500–1.000, 1.000–5.000, >5.000 €.
Tipo (ticket_kind) vs Segmento (ticket_type). No confundir: ticket_kind es una columna persistida con la naturaleza del ticket (incidencia | propuesta de mejora). ticket_type (etiquetado Segmento en la lista) es una dimensión derivada de SLA (casa/experiencia/administrativo/dormido) que se computa al leer y no es una columna.
Transición del estado improvement_proposal (two-phase). “Propuesta de mejora” era un estado falso del status. Ahora es su propia dimensión ticket_kind. La migración se aplica a mano en Supabase (dev + prod) en dos fases: 162 (pre-deploy: añade la columna ticket_kind, la indexa y backfillea el kind sin tocar el status) → deploy → 163 (post-deploy: normaliza el status de las propuestas a su lifecycle real assigned/created). improvement_proposal sigue permitido en el CHECK de status hasta un follow-up (retirarlo del CHECK y del enum es la fase 3).
Las opciones de equipo de resolución, zona, categoría, estado de reparación y pagador se sirven desde ticket-options.config.ts (TICKET_OPTION_SETS), no en vivo de Zendesk. CX decidió el set final aquí, de forma que es editable sin tocar Zendesk y resiliente si la API de Zendesk falla.
El destino sí sigue viniendo en vivo de Zendesk (vía ZendeskProvider.getTicketFields()), igual que el resto de enums no cubiertos por la config.
Todo se expone en un único endpoint:
GET /chat/tickets/dropdowns
Valores finales
Equipo de resolución (resolution_team)
| value | label |
|---|
propiedades_y_mantenimiento | Properties |
promotora | Promotora |
equipo_de_limpieza | Limpieza |
manitas | Manitas |
seguro | Seguro |
Zona (zone): General, Salón, Comedor, Cocina, Dormitorio, Baños, Exterior, Lockers, Garaje.
Categoría (category): Llaves y acceso, Inventario, Electrodomésticos, Amenities o accesorios, Iluminación, Wifi, Limpieza, Fontanería, Electricidad, Daños estructurales, Daños menores, Carpintería, Diseño y estilismo (label corregida), Climatización, Mantenimiento preventivo (plagas). Se eliminó “Reservas y estancias”.
Estado de reparación (repair_status): En evaluación, En ejecución, Comunicado a propietario. Se eliminó “Programado”.
Pagador (payer): Capex, Vivla, Mejora o daño propietario, Cuota de mantenimiento, Comunidad de vecinos, Promotora, Seguro, Derrama.
Mapeo con Zendesk
El value (slug) almacenado en chat_tickets es el mismo en Vivla Tools y en Zendesk. Los slugs históricos de Zendesk se preservan tal cual para que las filas antiguas sigan resolviendo. El contrato de mapeo vive en zendesk-mappings.config.ts:
| Campo | Columna | Zendesk field id |
|---|
| Casa | property_id | 17925940459804 |
| Destino | destination | 18534461108892 |
| Equipo de resolución | resolution_team | 17926240467100 |
| Zona | zone | 17926529031708 |
| Categoría | category | 17926673594140 |
| Pagador | payer | 17926800591004 |
| Estado de reparación | repair_status | 17926767041308 |
| Coste estimado | estimated_cost | 18458778087068 |
| Coste real | actual_cost | 18458825521180 |
| Notas internas | internal_notes | 17926789994780 |
| Fecha primera respuesta | first_response_at | 19667959142428 |
| Fecha resolución prevista | expected_resolution_at | 19703173032092 |
| Resumen IA | ai_summary | 23679986610076 (solo lectura) |
Las opciones nuevas introducidas en Vivla Tools (manitas, promotora, seguro, garaje, climatizacion, mantenimiento_preventivo_plagas, y los destinos nuevos como mallorca, asturias, etc.) deben crearse como opciones en los campos correspondientes de Zendesk para que el write-back funcione. Hasta entonces, el valor se guarda en Vivla Tools pero el sync a Zendesk de esa opción falla. Ver docs/internal/specs/tickets-cx-rework/zendesk-options-to-create.md.
Qué se sincroniza en creación vs actualización
El write-back a Zendesk no es simétrico entre crear y actualizar:
- Creación (
POST /chat/tickets): se envían a Zendesk el asunto, la descripción, la prioridad, el estado y todos los campos nativos (destino, equipo, zona, categoría, pagador, costes, etc.) traducidos a sus custom fields.
- Actualización (
PATCH /chat/tickets/:id, syncTicketToZendesk): solo se re-sincronizan subject (título), status y priority. Los campos nativos (category, resolution_team, zone, destination, payer, costes…) se persisten en chat_tickets pero no se re-escriben a Zendesk tras la creación. Editarlos desde el detalle actualiza Vivla Tools pero no propaga a Zendesk.
El estado improvement_proposal nunca se escribe a Zendesk: solo existe en Tools. Si se propagara iría como pending y el eco del webhook lo devolvería como in_progress, revirtiendo el estado. shouldWriteStatusToZendesk() lo excluye del write-back y conserva el último status conocido en Zendesk.
Limitación del espejo hold. Zendesk hold no tiene estado interno propio: se mapea a in_progress (igual que pending). Por tanto, si un ticket está en hold en Zendesk y Tools reescribe su estado, Zendesk aterriza en pending, no en hold. Es una pérdida de fidelidad conocida del espejo.
Casa → Destino
Al elegir (o preseleccionar) la propiedad en el alta de un ticket, el destino se autocompleta derivando property.location → location.slug → destino (mapa LOCATION_SLUG_TO_DESTINATION). Solo aplica a creaciones futuras; no remapea tickets existentes.
GET /chat/tickets/property-destinations
Devuelve un mapa { propertyId → destino } que el formulario usa para el autocompletado.
Pagador automático según equipo
Al cambiar el equipo de resolución, si no se envía un pagador explícito, el sistema lo presugiere (suggestPayerForTeam / PAYER_BY_TEAM). El agente siempre puede sobrescribirlo.
| Equipo | Pagador sugerido |
|---|
| Limpieza · Manitas · Properties | Cuota de mantenimiento |
| Promotora | Promotora |
| Seguro | Seguro |
derrama nunca se autosugiere: es una elección exclusivamente manual.
Estado de reparación derivado del estado
El estado del ticket manda sobre el de la reparación. Al cambiar el status, si no se envía un repair_status explícito, se deriva (REPAIR_STATUS_BY_TICKET_STATUS):
| Estado del ticket | Estado de reparación |
|---|
created · assigned | En evaluación |
in_progress | En ejecución |
resolved · closed | Comunicado a propietario |
Campos eliminados
Los siguientes campos se retiraron de la UI; sus columnas se conservan en la base de datos como histórico:
- Aprobación de propietarios (
owner_approval)
- Aprobación de finanzas (
finance_approval)
- Causa de la incidencia (
incident_cause)
- Causa del bloqueo (
blocking_cause)
- Nº de horas