Contratos y previsualización

REST requiere Starter o Pro activo. contracts:read permite listar, consultar y previsualizar sin persistir; contracts:write permite mutar e incluye lectura. No requiere resources:write para gestionar contratos de un recurso existente.

Endpoints

Método y ruta Parámetros Éxito
GET /api/v1/contracts Query opcional resource_id ID positivo, limit entero 1–100 (50), offset entero ≥0 (0) 200 array data, meta con limit/offset/total
GET /api/v1/contracts/:id ID positivo obligatorio 200 {"data": contrato}
POST /api/v1/contracts JSON creación 201 {"data":{"contract": contrato}}
PATCH /api/v1/contracts/:id ID obligatorio, JSON parcial 200 {"data":{"contract": contrato}}
PUT /api/v1/contracts/:id Igual que PATCH, conserva omitidos 200 mismo envelope
DELETE /api/v1/contracts/:id ID obligatorio; conflict_policy opcional 200 {"data":{"contract": contrato}} eliminado
POST /api/v1/contracts/preview JSON con operation: "create" (por defecto sin id) 200 resultado de preview
POST /api/v1/contracts/:id/preview ID obligatorio; operation: "update" (defecto con id) o "delete" 200 resultado de preview

Lista por ID ascendente; no admite filtro de fechas ni nombre. GET individual acepta include=monthly_hours y from/to (ISO juntos, ordenados, ≤3660 días), pero no añade matriz al contrato.

Atributos de contrato

Campo Tipo Crear Actualizar
resource_id ID positivo Obligatorio Opcional, solo puede ser el mismo recurso
start_date date string YYYY-MM-DD Obligatorio Opcional
end_date date string o null Opcional, null = indefinido Opcional; null elimina fecha de fin
daily_hours entero 1–8 Obligatorio Opcional
annual_convention_hours entero 1–2500 o null por REST Opcional Opcional
cost_per_hour decimal string no negativo Obligatorio Opcional
conflict_policy reject o resolve Opcional, reject por defecto Opcional, reject por defecto
entry_ids array no vacío de IDs positivos Condicional: resolver conflictos Condicional: resolver conflictos

Campos planos, sin attrs, hours ni organization_id. Los omitidos se conservan en actualización. {} es una actualización válida si supera las validaciones/conflictos actuales; no es un preview. Las fechas deben estar ordenadas, sin solapes incompatibles. Un contrato contiguo con misma jornada y convenio puede rechazarse como duplicado: actualiza el existente. El convenio opcional permite usar la configuración de organización cuando corresponde. MCP exige número para jornada/convenio y no admite null en convenio; usa enteros para cumplir el dominio.

Un sucesor de un contrato indefinido anterior cierra automáticamente ese anterior el día previo a start_date. Esta operación es atómica, respeta capacidad del plan y puede afectar asignaciones y costes: previsualiza primero.

Preview de creación, actualización y borrado

Todos los ejemplos llevan Bearer y JSON Content-Type.

POST /api/v1/contracts/preview
Content-Type: application/json

{"operation":"create","resource_id":7,"start_date":"2027-01-01","end_date":null,"daily_hours":6,"annual_convention_hours":1800,"cost_per_hour":"50.00"}

El preview de creación valida el flujo real, incluido cierre de predecesor, y revierte la simulación: no persiste contratos, cierres ni asignaciones y no emite cambios. Con éxito devuelve data.valid: true, closes_contract_id (ID o null) y contract propuesto (id/timestamps pueden ser null). Si encuentra conflictos del predecesor devuelve 200 con valid: false, conflicts (asignaciones) y closes_contract_id.

POST /api/v1/contracts/5/preview
Content-Type: application/json

{"operation":"update","daily_hours":4}

Actualización sin conflictos: {"data":{"valid":true,"conflicts":[]}}. Con conflictos: {"data":{"valid":false,"conflicts":[...]}}, donde cada elemento es una asignación. El preview no resuelve aunque envíes conflict_policy: "resolve".

POST /api/v1/contracts/5/preview
Content-Type: application/json

{"operation":"delete"}

Borrado permitido: {"data":{"valid":true,"id":5}}. Borrado bloqueado devuelve error HTTP, no necesariamente valid: false. operation solo es parámetro de preview. La variante sin ID también acepta id en el cuerpo para update/delete; usa preferentemente la ruta con ID.

Guardar y resolver explícitamente

POST /api/v1/contracts
Content-Type: application/json

{"resource_id":7,"start_date":"2027-01-01","end_date":null,"daily_hours":6,"annual_convention_hours":1800,"cost_per_hour":"50.00"}
PATCH /api/v1/contracts/5
Content-Type: application/json

{"daily_hours":4,"conflict_policy":"resolve","entry_ids":[42]}

reject no autoriza resolver asignaciones. Con resolve, selecciona IDs actualmente conflictivos, obtenidos del preview; el array no puede estar vacío cuando hay conflictos. El resolver solo puede modificar las asignaciones seleccionadas. Si necesita cambiar otras, quedan conflictos, o hay bloqueos archivados, la transacción se revierte. Si no hay conflictos no hace falta selección. El preview no reserva estado: los conflictos se vuelven a comprobar al escribir.

GET /api/v1/contracts?resource_id=7&limit=50&offset=0
GET /api/v1/contracts/5
DELETE /api/v1/contracts/5

DELETE acepta opcionalmente conflict_policy, pero resolve no fuerza el borrado. No admite entry_ids, fechas, jornada ni operation. El borrado debe superar sus comprobaciones y devuelve el contrato eliminado, no deleted: true ni 204.

Representación y errores

Contrato: id, start_date, end_date nullable, daily_hours entero, annual_convention_hours entero nullable, cost_per_hour decimal string, inserted_at, updated_at ISO 8601. Solo listar/GET individual añaden resource_id; el objeto bajo data.contract no lo incluye.

400 invalid_params para parámetros/políticas/selecciones inválidos; 404 not_found; 409 conflict con asignaciones en errors.assignments cuando procede. 422 validation_error (solapes, duplicados, fechas/costes), plan_limit, archived_project_conflict u otros rechazos de dominio. Los errores usan errors.code, errors.detail y detalles adicionales. valid: false de un preview exitoso es HTTP 200, no un error del transporte. También 401/403 comunes.

MCP Pro: kordia_search (entity: "contracts"), kordia_get (entity: "contract"), kordia_manage_contract (action: "create", "update", "delete") y kordia_preview_contract_change (operation). No enviar operation a manage ni filtros ajenos a la operación, aunque aparezcan en el esquema agregado de la herramienta.