{
    "openapi": "3.0.0",
    "info": {
        "title": "RRHH System API",
        "description": "API de gestión de Recursos Humanos: asistencia con GPS, visitas de campo, supervisión de jefaturas, nómina y préstamos.\n *\n * Autenticación por token Bearer (Laravel Sanctum): llama a POST /api/login con email y password, luego usa el botón **Authorize** con el token recibido.",
        "contact": {
            "name": "Equipo RRHH",
            "email": "admin@rrhh.local"
        },
        "version": "1.0.0"
    },
    "servers": [
        {
            "url": "http://127.0.0.1:8000",
            "description": "Servidor local"
        },
        {
            "url": "http://127.0.0.1:8010",
            "description": "Servidor local alterno"
        }
    ],
    "paths": {
        "/api/admin/visitas-agendadas": {
            "get": {
                "tags": [
                    "Visitas Agendadas"
                ],
                "summary": "Listar la agenda de visitas",
                "description": "Listar visitas agendadas (admin)\n\nProcesa primero las visitas vencidas sin marcar (las marca como incumplidas y aplica la multa configurable).",
                "operationId": "bf200826c54040191457f389caa5e8e5",
                "parameters": [
                    {
                        "name": "estado",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "pendiente",
                                "realizada",
                                "incumplida",
                                "cancelada"
                            ]
                        }
                    },
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "desde",
                        "in": "query",
                        "description": "Fecha programada desde (Y-m-d)",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "hasta",
                        "in": "query",
                        "description": "Fecha programada hasta (Y-m-d)",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-agendar_visitas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Visitas Agendadas"
                ],
                "summary": "Agendar visita a un punto de control",
                "description": "Agendar una visita a un vendedor (admin)\n\nAsigna un punto de control GPS que el empleado debe visitar y marcar presencialmente.\nSi no se envía fecha_limite se usa el final del día programado.",
                "operationId": "9467387fc3358799aa7fa7c717dab512",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "punto_control_id",
                                    "fecha_programada"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "example": 6
                                    },
                                    "punto_control_id": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "fecha_programada": {
                                        "type": "string",
                                        "format": "date-time",
                                        "example": "2026-08-25 09:00:00"
                                    },
                                    "fecha_limite": {
                                        "type": "string",
                                        "format": "date-time",
                                        "example": "2026-08-25 17:30:00",
                                        "nullable": true
                                    },
                                    "observaciones": {
                                        "type": "string",
                                        "example": "Revisión de exhibiciones",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Visita agendada"
                    },
                    "400": {
                        "description": "Punto inactivo o fecha límite inválida"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-agendar_visitas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/visitas-agendadas/{id}": {
            "get": {
                "tags": [
                    "Visitas Agendadas"
                ],
                "summary": "Detalle de una visita agendada",
                "description": "Ver una visita agendada (admin)",
                "operationId": "5f591816466a7c8edb60f3e35575ba1c",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "404": {
                        "description": "No encontrada"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-agendar_visitas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Visitas Agendadas"
                ],
                "summary": "Cancelar visita agendada",
                "description": "Cancelar/eliminar una visita pendiente (admin)\n\nNo se puede eliminar una visita ya realizada.",
                "operationId": "48229f85868e6845be33877f35bff07f",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Visita eliminada"
                    },
                    "400": {
                        "description": "La visita ya fue realizada"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-agendar_visitas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/visitas-agendadas/mis-visitas": {
            "get": {
                "tags": [
                    "Visitas Agendadas"
                ],
                "summary": "Visitas agendadas del empleado autenticado",
                "description": "Mis visitas agendadas (vendedor)\n\nLista las visitas asignadas al empleado autenticado con su saldo de cumplimiento.",
                "operationId": "ca75809479c8bb0027646b7982500409",
                "parameters": [
                    {
                        "name": "estado",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "pendiente",
                                "realizada",
                                "incumplida",
                                "cancelada"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-marcar_visita_agendada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/visitas-agendadas/{id}/marcar": {
            "post": {
                "tags": [
                    "Visitas Agendadas"
                ],
                "summary": "Marcar asistencia en la visita (GPS)",
                "description": "Marcar asistencia en una visita agendada (vendedor)\n\nValida GPS contra el radio del punto de control y la fecha límite.\nSi está fuera del rango o la visita ya venció, no se registra.",
                "operationId": "d2c3bdfb26c03440f0039fec92ab0a08",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "lat",
                                    "lng"
                                ],
                                "properties": {
                                    "lat": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -2.19
                                    },
                                    "lng": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -79.89
                                    },
                                    "fotos": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "example": [
                                            "https://cdn.ejemplo.com/foto1.jpg"
                                        ]
                                    },
                                    "observaciones": {
                                        "type": "string",
                                        "example": "Cliente recibió pedido",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Asistencia marcada"
                    },
                    "400": {
                        "description": "Fuera del rango GPS, visita vencida o estado inválido"
                    },
                    "403": {
                        "description": "La visita pertenece a otro empleado"
                    },
                    "404": {
                        "description": "No encontrada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/mis-subordinados": {
            "get": {
                "tags": [
                    "Supervisión"
                ],
                "summary": "Subordinados directos del jefe autenticado",
                "description": "Listar mis subordinados directos",
                "operationId": "ac491da665a0f6ff69303851aab8e5d1",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "400": {
                        "description": "Perfil de empleado no encontrado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-supervisar_equipo"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/asistencias-empleado/{id}": {
            "get": {
                "tags": [
                    "Supervisión"
                ],
                "summary": "Últimas 30 asistencias de un subordinado",
                "description": "Asistencias de un subordinado\n\nValida jerarquía: el empleado objetivo debe ser subordinado directo o indirecto.",
                "operationId": "721abe587a14f5cc0a63bb1a94bf037c",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 4
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/Asistencia"
                                    }
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "No tienes autoridad sobre este empleado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/pendientes": {
            "get": {
                "tags": [
                    "Supervisión"
                ],
                "summary": "Horas extras pendientes de aprobación",
                "description": "Asistencias del equipo pendientes de aprobación",
                "operationId": "9b1ce67a040d358e97b3dc47d7519a50",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/aprobar-horas/{id}": {
            "post": {
                "tags": [
                    "Supervisión"
                ],
                "summary": "Gestionar horas extras",
                "description": "Aprobar o rechazar horas extras de una asistencia",
                "operationId": "3628c9221bf35193e79e600b51735f65",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "ID de la asistencia",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 346
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "accion"
                                ],
                                "properties": {
                                    "accion": {
                                        "type": "string",
                                        "example": "aprobar",
                                        "enum": [
                                            "aprobar",
                                            "rechazar"
                                        ]
                                    },
                                    "observacion": {
                                        "type": "string",
                                        "example": "Trabajó hasta terminar el despacho",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Registro actualizado"
                    },
                    "403": {
                        "description": "No puedes gestionar esta asistencia"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/asistencia/checkin": {
            "post": {
                "tags": [
                    "Asistencia"
                ],
                "summary": "Marcar entrada",
                "description": "Registrar entrada\n\nValida geocerca GPS según el cargo, calcula retraso/holgura y aplica reglas de penalidad.",
                "operationId": "e1a8f72cfae235d48471b539ca9e48ef",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "lat",
                                    "lng"
                                ],
                                "properties": {
                                    "lat": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -2.1894128
                                    },
                                    "lng": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -79.8890662
                                    },
                                    "fotos": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "example": [
                                            "https://cdn.ejemplo.com/foto1.jpg"
                                        ],
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Entrada registrada con detalle de holgura/penalidad"
                    },
                    "400": {
                        "description": "Fuera del rango GPS, fotos insuficientes o entrada ya registrada"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-marcar_entrada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/asistencia/checkout": {
            "post": {
                "tags": [
                    "Asistencia"
                ],
                "summary": "Marcar salida",
                "description": "Registrar salida\n\nCierra la jornada del día: calcula horas trabajadas, detecta horas extras (quedan pendientes de aprobación).",
                "operationId": "9b059249e89a38edef4fdb42fcaac4e2",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "lat",
                                    "lng"
                                ],
                                "properties": {
                                    "lat": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -2.1894128
                                    },
                                    "lng": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -79.8890662
                                    },
                                    "foto_salida": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Salida registrada. Jornada cerrada."
                    },
                    "400": {
                        "description": "Sin entrada previa, salida ya marcada o fuera de rango GPS"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-marcar_salida"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/asistencia/top10": {
            "get": {
                "tags": [
                    "Asistencia"
                ],
                "summary": "Últimas 10 asistencias propias",
                "description": "Historial de mis últimas 10 marcaciones",
                "operationId": "81785874c7931e6362fa386b8b7817b7",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/Asistencia"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Empleado no encontrado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-ver_asistencia_propia"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/auditoria": {
            "get": {
                "tags": [
                    "Auditoría"
                ],
                "summary": "Consultar auditoría del sistema (PAGINADA)",
                "description": "Registro de todas las acciones: CRUD de modelos, login/logout, cierres de nómina, sincronizaciones de roles/permisos y asignaciones masivas. Respuesta paginada estándar de Laravel.",
                "operationId": "650ae0a185458146a4c7b40ec35867c0",
                "parameters": [
                    {
                        "name": "modelo",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        },
                        "example": "Contrato"
                    },
                    {
                        "name": "modelo_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "user_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "accion",
                        "in": "query",
                        "description": "creado|actualizado|eliminado|login|login_fallido|logout|cierre_nomina|sincronizar_permisos|asignar_roles|asignacion_masiva|vencimiento_automatico",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "fecha_desde",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "fecha_hasta",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "description": "Página (default 1)",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Registros por página (default 20, máx 100)",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "{data[], current_page, last_page, per_page, total, from, to, ...} + acciones_disponibles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/login": {
            "post": {
                "tags": [
                    "Autenticación"
                ],
                "summary": "Autenticar usuario",
                "description": "Retorna un token Bearer de Sanctum junto con roles y permisos del usuario.",
                "operationId": "222b2625838e3c57e017987f73598fda",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "email",
                                    "password"
                                ],
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "format": "email",
                                        "example": "admin@rrhh.local"
                                    },
                                    "password": {
                                        "type": "string",
                                        "example": "admin123"
                                    },
                                    "device_name": {
                                        "type": "string",
                                        "example": "web-app"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Autenticación exitosa",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "properties": {
                                        "token": {
                                            "type": "string",
                                            "example": "1|xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                                        },
                                        "token_type": {
                                            "type": "string",
                                            "example": "Bearer"
                                        },
                                        "user": {
                                            "$ref": "#/components/schemas/User"
                                        },
                                        "roles": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            },
                                            "example": [
                                                "admin"
                                            ]
                                        },
                                        "permissions": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            },
                                            "example": [
                                                "rrhh-marcar_entrada",
                                                "rrhh-gestionar_nomina"
                                            ]
                                        }
                                    },
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Credenciales incorrectas"
                    },
                    "422": {
                        "description": "Datos inválidos"
                    }
                }
            }
        },
        "/api/me": {
            "get": {
                "tags": [
                    "Autenticación"
                ],
                "summary": "Perfil, permisos y menú del usuario autenticado",
                "description": "Retorna usuario, roles, is_admin, lista de permisos efectivos (union de sus roles) y un menú de opciones ya filtrado por permisos para renderizar en el frontend.",
                "operationId": "8367feff40ba10e43187792cad3132c1",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "properties": {
                                        "data": {
                                            "properties": {
                                                "user": {
                                                    "$ref": "#/components/schemas/User"
                                                },
                                                "roles": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    }
                                                },
                                                "is_admin": {
                                                    "type": "boolean",
                                                    "example": false
                                                },
                                                "permissions": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    },
                                                    "example": [
                                                        "rrhh-marcar_entrada",
                                                        "rrhh-solicitar_vacaciones"
                                                    ]
                                                },
                                                "menu": {
                                                    "description": "Ítems visibles según permisos",
                                                    "type": "array",
                                                    "items": {
                                                        "properties": {
                                                            "id": {
                                                                "type": "string",
                                                                "example": "marcar_asistencia"
                                                            },
                                                            "grupo": {
                                                                "type": "string",
                                                                "example": "Asistencia"
                                                            },
                                                            "label": {
                                                                "type": "string",
                                                                "example": "Marcar entrada/salida"
                                                            },
                                                            "ruta": {
                                                                "type": "string",
                                                                "example": "/asistencia/checkin"
                                                            },
                                                            "metodo": {
                                                                "type": "string",
                                                                "example": "POST"
                                                            }
                                                        },
                                                        "type": "object"
                                                    }
                                                },
                                                "empleado": {
                                                    "$ref": "#/components/schemas/Empleado"
                                                }
                                            },
                                            "type": "object"
                                        }
                                    },
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "No autenticado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/logout": {
            "post": {
                "tags": [
                    "Autenticación"
                ],
                "summary": "Revocar token actual",
                "description": "Cerrar sesión\n\nRevoca el token usado en la petición actual.",
                "operationId": "ad65cbbd4e9f201619eae184a5961a98",
                "responses": {
                    "200": {
                        "description": "Sesión cerrada"
                    },
                    "401": {
                        "description": "No autenticado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/cargas-familiares": {
            "get": {
                "tags": [
                    "Cargas familiares"
                ],
                "summary": "Listar cargas (filtro empleado_id)",
                "operationId": "3b216bb8ed61544639e80c0a872f3bf2",
                "parameters": [
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Cargas familiares"
                ],
                "summary": "Registrar carga familiar",
                "operationId": "0b89d32075fbc9472af83cefe8ff81f8",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "tipo"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer"
                                    },
                                    "tipo": {
                                        "type": "string",
                                        "enum": [
                                            "conyuge",
                                            "hijo",
                                            "padre"
                                        ]
                                    },
                                    "nombres": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/cargas-familiares/{id}": {
            "put": {
                "tags": [
                    "Cargas familiares"
                ],
                "summary": "Actualizar carga (ej: desactivar con activa=false)",
                "operationId": "b820ae957d71a0d2a6264dff07a6f240",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Actualizada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/cargos": {
            "get": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Listar todos los cargos con conteo de empleados",
                "description": "Listar cargos",
                "operationId": "56fa0d1d8ad94e365ba04ea7f5694b92",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_cargos"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Crear cargo",
                "description": "Crear cargo\n\nEl slug se genera automáticamente si no se envía.",
                "operationId": "e2e1b517803a1a2f985101fae24b5342",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "nombre"
                                ],
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "Supervisor de Ventas"
                                    },
                                    "es_jefe": {
                                        "type": "boolean",
                                        "example": true
                                    },
                                    "es_vendedor": {
                                        "type": "boolean",
                                        "example": false
                                    },
                                    "requiere_gps_entrada": {
                                        "type": "boolean",
                                        "example": true
                                    },
                                    "requiere_gps_salida": {
                                        "type": "boolean",
                                        "example": false
                                    },
                                    "cantidad_fotos_entrada": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "cantidad_fotos_salida": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Cargo creado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/cargos/{id}": {
            "get": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Detalle de cargo",
                "description": "Ver cargo con sus reglas de penalidad",
                "operationId": "a8904d2b082b22149b22861d3ed2fafc",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Actualizar cargo",
                "description": "Actualizar cargo",
                "operationId": "4fb147534fdb46ce7dbdd538ef63ffef",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Cargo actualizado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Eliminar cargo",
                "description": "Eliminar cargo\n\nBloqueado si tiene empleados asignados.",
                "operationId": "40efaac4aecf3f919cd5d45b98a5dea4",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Cargo eliminado"
                    },
                    "400": {
                        "description": "Tiene empleados asignados"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/cargos/{id}/visitas": {
            "put": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Configurar puntos de control (visitas) del cargo",
                "description": "Sincronizar el campo \"visitas\" del cargo (puntos de control)\n\nReemplaza la lista completa de puntos GPS que el cargo debe cubrir.",
                "operationId": "fc2ea66f6c1ffc8992a18f154eb9f579",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 6
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "punto_ids"
                                ],
                                "properties": {
                                    "punto_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            1,
                                            2
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Visitas del cargo actualizadas"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_cargos"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/chat/conversaciones": {
            "get": {
                "tags": [
                    "Chat"
                ],
                "summary": "Mis conversaciones (último mensaje + no leídos)",
                "operationId": "af027ba77b689eea9ed88c3121ff720e",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/chat/conversaciones/directa": {
            "post": {
                "tags": [
                    "Chat"
                ],
                "summary": "Abrir/obtener conversación directa con otro empleado",
                "operationId": "50a76d920791ba47b2f962d08868d3dc",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "example": 6
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Conversación existente o nueva"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/chat/conversaciones/sala": {
            "post": {
                "tags": [
                    "Chat"
                ],
                "summary": "Crear sala grupal (ej: por sucursal/equipo)",
                "operationId": "c3a448f2e50e948bb5198ba54c0449af",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "nombre",
                                    "empleado_ids"
                                ],
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "Equipo Bodega"
                                    },
                                    "empleado_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        }
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Sala creada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/chat/conversaciones/{id}/mensajes": {
            "get": {
                "tags": [
                    "Chat"
                ],
                "summary": "Historial de mensajes (paginado hacia atrás; marca leídos)",
                "operationId": "53660621701cf030acbe1936cba944c8",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "antes_de_id",
                        "in": "query",
                        "description": "Trae los anteriores a este id (scroll infinito)",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "limite",
                        "in": "query",
                        "description": "default 50",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "{mensajes[], hay_mas}"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Chat"
                ],
                "summary": "Enviar mensaje (guarda en BD + push tiempo real si Pusher activo)",
                "operationId": "5bf86b02266b84a58103550fda6f8fc3",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "mensaje"
                                ],
                                "properties": {
                                    "mensaje": {
                                        "type": "string",
                                        "example": "Hola equipo"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Mensaje enviado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/chat/autorizar": {
            "post": {
                "tags": [
                    "Chat"
                ],
                "summary": "Autorización de canales privados Pusher (endpoint /broadcasting/auth del front)",
                "operationId": "8e6dff801a9c62cf16a46335259bddbb",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "socket_id",
                                    "canal"
                                ],
                                "properties": {
                                    "socket_id": {
                                        "type": "string"
                                    },
                                    "canal": {
                                        "type": "string",
                                        "example": "private-chat.usuario.5"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "{auth}"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/comisiones/config": {
            "get": {
                "tags": [
                    "Comisiones"
                ],
                "summary": "Listar configuraciones de comisión",
                "operationId": "610c14c993ac5ea449e21a45b750457a",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Comisiones"
                ],
                "summary": "Crear/actualizar configuración de comisión de un empleado",
                "operationId": "14a0dda3c8f425fe99c6ac7b2e39924d",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "pct_comision",
                                    "regla_equipo"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer"
                                    },
                                    "pct_comision": {
                                        "description": "% sobre ventas del mes",
                                        "type": "number",
                                        "example": 5
                                    },
                                    "meta_mensual": {
                                        "description": "0 = sin meta",
                                        "type": "number",
                                        "example": 10000,
                                        "nullable": true
                                    },
                                    "regla_equipo": {
                                        "description": "individual=solo mis ventas · todos_cumplen=yó+subordinados deben cumplir · proporcional=pago × promedio de cumplimiento del equipo",
                                        "type": "string",
                                        "enum": [
                                            "individual",
                                            "todos_cumplen",
                                            "proporcional"
                                        ]
                                    },
                                    "es_remuneracional": {
                                        "description": "false=default: no carga IESS/décimos/FR",
                                        "type": "boolean",
                                        "nullable": true
                                    },
                                    "activo": {
                                        "type": "boolean",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Guardada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/comisiones/config/{id}": {
            "delete": {
                "tags": [
                    "Comisiones"
                ],
                "summary": "Eliminar configuración",
                "operationId": "8176082c525f5168702aaaaab6314ea5",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/comisiones/ventas": {
            "get": {
                "tags": [
                    "Comisiones"
                ],
                "summary": "Registro de ventas mensuales (filtros: mes, anio, empleado_id)",
                "operationId": "0549c8f31140e3ecfb32eff10d2d57d1",
                "parameters": [
                    {
                        "name": "mes",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Comisiones"
                ],
                "summary": "Registrar/actualizar total de ventas del mes de un empleado",
                "operationId": "5452119626727a4a948ebfa6a85ac641",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "mes",
                                    "anio",
                                    "total_vendido"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer"
                                    },
                                    "mes": {
                                        "type": "integer",
                                        "maximum": 12,
                                        "minimum": 1
                                    },
                                    "anio": {
                                        "type": "integer"
                                    },
                                    "total_vendido": {
                                        "type": "number",
                                        "example": 12500
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Registrado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/comisiones/ventas/{id}": {
            "delete": {
                "tags": [
                    "Comisiones"
                ],
                "summary": "Eliminar registro de ventas",
                "operationId": "3cb861bbd70e12aaae608b080f74e329",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/comisiones/previsualizar": {
            "get": {
                "tags": [
                    "Comisiones"
                ],
                "summary": "Preview de comisión por empleado en un periodo (con detalle de equipo)",
                "operationId": "d75ca0da2c7bacdfe7fd122d7f893824",
                "parameters": [
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "mes",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Detalle completo o null si no tiene esquema"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/contratos": {
            "get": {
                "tags": [
                    "Contratos"
                ],
                "summary": "Listar contratos (filtros: empleado_id, estado)",
                "operationId": "ce92e648fb04c1c0cfcba094caa0e5f8",
                "parameters": [
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "estado",
                        "in": "query",
                        "description": "activo,vencido,finalizado,cancelado",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Contratos"
                ],
                "summary": "Registrar contrato (desactiva el anterior activo del empleado)",
                "operationId": "4533934a9ee8007aef8bc2e8817e4341",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "tipo",
                                    "fecha_inicio"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer"
                                    },
                                    "tipo": {
                                        "type": "string",
                                        "enum": [
                                            "indefinido",
                                            "plazo_fijo",
                                            "obra_cierta",
                                            "eventual",
                                            "aprendizaje",
                                            "tiempo_parcial"
                                        ]
                                    },
                                    "fecha_inicio": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "fecha_fin": {
                                        "type": "string",
                                        "format": "date",
                                        "nullable": true
                                    },
                                    "salario_acordado": {
                                        "type": "number",
                                        "nullable": true
                                    },
                                    "observaciones": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/contratos/proximos-vencer": {
            "get": {
                "tags": [
                    "Contratos"
                ],
                "summary": "Alerta: contratos a plazo que vencen en N días",
                "operationId": "e0a3fe8c4de66c3b3a042bcb90614b1f",
                "parameters": [
                    {
                        "name": "dias",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        },
                        "example": 30
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/contratos/{id}": {
            "put": {
                "tags": [
                    "Contratos"
                ],
                "summary": "Actualizar contrato / renovar (cambiar fecha_fin)",
                "operationId": "48c6816565d405e8c307c9fe52f8d618",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Actualizado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Contratos"
                ],
                "summary": "Eliminar contrato (soft delete)",
                "operationId": "b1aea654b8693b64dbb34ae6c0b86275",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/contratos/{id}/documento": {
            "get": {
                "tags": [
                    "Contratos"
                ],
                "summary": "Descargar el PDF firmado del contrato",
                "operationId": "e1bde5e704a653af3f08cec9d51edd9a",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Archivo PDF (download)"
                    },
                    "404": {
                        "description": "Sin documento"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Contratos"
                ],
                "summary": "Subir PDF firmado del contrato (multipart: archivo)",
                "operationId": "3aa22961c9f2799f746f1ad21c97118a",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart/form-data": {
                            "schema": {
                                "required": [
                                    "archivo"
                                ],
                                "properties": {
                                    "archivo": {
                                        "description": "PDF firmado (máx 8MB)",
                                        "type": "string",
                                        "format": "binary"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Documento adjuntado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Contratos"
                ],
                "summary": "Eliminar el PDF adjunto",
                "operationId": "e94549f0a3784c582449146e87f831dc",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/corregir-asistencia/{id}": {
            "put": {
                "tags": [
                    "Supervisión"
                ],
                "summary": "Gestionar asistencia: aprobar, aprobar con penalidad o rechazar",
                "description": "Corregir una asistencia (jefe) con 3 decisiones\n\n- aprobado: día válido sin descuentos (revierte penalidades previas no cobradas).\n- aprobado_con_penalidad: día válido + multa según la REGLA seleccionada (regla_id);\n  el monto se calcula aplicando el porcentaje de la regla al salario del empleado.\n- rechazado: día NO trabajado → descuenta el día según parámetros\n  DESCUENTO_DIA_RECHAZADO_MODO (porcentaje|monto) y DESCUENTO_DIA_RECHAZADO_VALOR.\n\nToda penalidad/descuento genera un movimiento de nómina que se cobra en el rol mensual.\nValida jerarquía; admin puede corregir a cualquiera.",
                "operationId": "6496ea581b23ff5b62ada2a11ef2e731",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 346
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "estado_aprobacion",
                                    "justificacion"
                                ],
                                "properties": {
                                    "estado_aprobacion": {
                                        "type": "string",
                                        "example": "aprobado_con_penalidad",
                                        "enum": [
                                            "aprobado",
                                            "aprobado_con_penalidad",
                                            "rechazado"
                                        ]
                                    },
                                    "justificacion": {
                                        "type": "string",
                                        "example": "Salida anticipada sin autorización"
                                    },
                                    "hora_entrada": {
                                        "type": "string",
                                        "example": "08:20:00",
                                        "nullable": true
                                    },
                                    "hora_salida": {
                                        "type": "string",
                                        "example": "17:30:00",
                                        "nullable": true
                                    },
                                    "horas_extras_aprobadas": {
                                        "type": "number",
                                        "example": 1.5,
                                        "nullable": true
                                    },
                                    "regla_id": {
                                        "description": "Obligatorio si estado=aprobado_con_penalidad. ID de rrhh_reglas_penalidad (catálogo en GET /api/jefe/ver-reglas)",
                                        "type": "integer",
                                        "example": 3,
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Asistencia gestionada; retorna movimiento de nómina generado si aplica"
                    },
                    "400": {
                        "description": "Penalidad ya cobrada, no reversible"
                    },
                    "403": {
                        "description": "Sin autoridad sobre el empleado"
                    },
                    "422": {
                        "description": "Datos inválidos"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/aprobacion-masiva": {
            "post": {
                "tags": [
                    "Supervisión"
                ],
                "summary": "Gestionar múltiples asistencias",
                "description": "Aprobación/rechazo masivo de asistencias\n\nAl rechazar, cada día cuenta como no trabajado y genera el descuento\nconfigurado en parámetros generales (mismo criterio que la gestión individual).\nValida jerarquía sobre cada registro antes de aplicar cambios.",
                "operationId": "3e5d4fff8716ee618195d12fb36af9d1",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "asistencias_ids",
                                    "accion"
                                ],
                                "properties": {
                                    "asistencias_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            346,
                                            347,
                                            348
                                        ]
                                    },
                                    "accion": {
                                        "type": "string",
                                        "example": "aprobar",
                                        "enum": [
                                            "aprobar",
                                            "rechazar"
                                        ]
                                    },
                                    "horas_a_asignar": {
                                        "type": "number",
                                        "example": 1,
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Registros gestionados; movimientos generados si se rechazó"
                    },
                    "403": {
                        "description": "Sin autoridad sobre alguno de los empleados"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/ver-reglas": {
            "get": {
                "tags": [
                    "Supervisión"
                ],
                "summary": "Ver reglas de penalidad de los cargos subordinados",
                "description": "Reglas de penalidad aplicables a mi equipo",
                "operationId": "d9cca3e3299465ef0b46b8a284c09fac",
                "parameters": [
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "description": "Si se envía, cada regla incluye contador_actual y acumulado (ocurrencias del empleado contra la frecuencia de esa regla)",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "tipo_penalizacion",
                        "in": "query",
                        "description": "Filtro para combos: general,asistencia,administrativa,operativa,inventario (acepta lista separada por comas)",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/subordinados-de/{id}": {
            "get": {
                "tags": [
                    "Supervisión"
                ],
                "summary": "Subordinados directos con contador (para el árbol jerárquico)",
                "description": "Árbol de subordinados de un empleado",
                "operationId": "9f3175f61231437320d5c2669ad9e334",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "ID del jefe",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/dashboard/stats": {
            "get": {
                "tags": [
                    "Dashboard"
                ],
                "summary": "Datos agregados del dashboard",
                "description": "Estadísticas del dashboard\n\nLa respuesta se segmenta por roles: 'personal' para todos, 'equipo' para jefes/admin y 'admin' solo para administradores.",
                "operationId": "97f93f93be9753e12dfa48ed63db092c",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "400": {
                        "description": "Perfil de empleado no encontrado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/decimos/resumen": {
            "get": {
                "tags": [
                    "Décimos"
                ],
                "summary": "Resumen de acumuladores por empleado (saldos DT3/DC4 del año)",
                "operationId": "1999adf13f2e2d529af4def9c07d2fa6",
                "parameters": [
                    {
                        "name": "anio",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2026
                    },
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/decimos/adelantar": {
            "post": {
                "tags": [
                    "Décimos"
                ],
                "summary": "Adelanto de décimo (anticipo contra el saldo ya devengado)",
                "description": "Diferencia con préstamo: el préstamo crea DEUDA con cuotas FIFO; el adelanto descuenta dinero YA acumulado del décimo. Respeta DECIMOS_PERMITIR_ADELANTO y DECIMO_ADELANTO_PCT_MAX.",
                "operationId": "c6f92e65d3b82b5d6f640b2bd6d82af0",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_ids",
                                    "tipo"
                                ],
                                "properties": {
                                    "empleado_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            4
                                        ]
                                    },
                                    "tipo": {
                                        "type": "string",
                                        "enum": [
                                            "tercero",
                                            "cuarto"
                                        ]
                                    },
                                    "anio": {
                                        "type": "integer",
                                        "example": 2026
                                    },
                                    "monto": {
                                        "description": "Monto explícito (o usa pct)",
                                        "type": "number",
                                        "nullable": true
                                    },
                                    "pct": {
                                        "description": "% del acumulado",
                                        "type": "number",
                                        "nullable": true
                                    },
                                    "referencia": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Resultados por empleado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/decimos/pagar-anual": {
            "post": {
                "tags": [
                    "Décimos"
                ],
                "summary": "Pago anual del décimo (rol especial con el saldo acumulado)",
                "operationId": "14cb3d39215e09c22bbe7dd4aa3dba18",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "tipo"
                                ],
                                "properties": {
                                    "tipo": {
                                        "type": "string",
                                        "enum": [
                                            "tercero",
                                            "cuarto"
                                        ]
                                    },
                                    "anio": {
                                        "type": "integer",
                                        "example": 2026
                                    },
                                    "empleado_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "nullable": true
                                    },
                                    "referencia": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Resultados por empleado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/cierre-anual": {
            "post": {
                "tags": [
                    "Décimos"
                ],
                "summary": "Cierre de año: paga décimos pendientes y reporta pasivo laboral",
                "operationId": "234c1d7b214e0521710ee08bdcd7f65c",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "anio"
                                ],
                                "properties": {
                                    "anio": {
                                        "type": "integer",
                                        "example": 2026
                                    },
                                    "forzar_pagos": {
                                        "description": "Pagar aunque no se haya llegado al mes legal configurado",
                                        "type": "boolean",
                                        "nullable": true
                                    },
                                    "tipos": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "example": [
                                            "tercero",
                                            "cuarto"
                                        ],
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Resumen del cierre + pasivo laboral restante"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/pasivo-laboral": {
            "get": {
                "tags": [
                    "Décimos"
                ],
                "summary": "Reporte de pasivo laboral por décimos (lo adeudado a la fecha)",
                "operationId": "9ee5b763d3f49d0142ae80da96cdb972",
                "parameters": [
                    {
                        "name": "anio",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2026
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/empleados": {
            "get": {
                "tags": [
                    "Empleados"
                ],
                "summary": "Listar todos los empleados",
                "description": "Listar empleados",
                "operationId": "075a383fc698e805a7022999c017bf7e",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-ver_empleados"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Empleados"
                ],
                "summary": "Registrar empleado con cuenta de acceso y roles",
                "description": "Crear empleado\n\nCrea el empleado y su cuenta de usuario local (para login por token) con roles.\nSi no se envían roles se infieren del cargo: es_jefe → jefe, es_vendedor → vendedor, resto → empleado.\nSi no se envía password se asigna 'password123'.",
                "operationId": "e058e685857d29f5571728b5b211916d",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "nombre",
                                    "email",
                                    "cargo_id",
                                    "salario_mensual"
                                ],
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "Juan Pérez"
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email",
                                        "example": "juan.perez@empresa.com"
                                    },
                                    "password": {
                                        "type": "string",
                                        "example": "secret123",
                                        "nullable": true
                                    },
                                    "roles": {
                                        "description": "IDs de rrhh_roles; si se omite se infieren del cargo",
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            3
                                        ],
                                        "nullable": true
                                    },
                                    "cargo_id": {
                                        "type": "integer",
                                        "example": 4
                                    },
                                    "jefe_id": {
                                        "type": "integer",
                                        "example": 2,
                                        "nullable": true
                                    },
                                    "salario_mensual": {
                                        "type": "number",
                                        "example": 650.5
                                    },
                                    "porcentaje_cupo_prestamo": {
                                        "type": "number",
                                        "example": 100,
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Empleado registrado con su usuario"
                    },
                    "400": {
                        "description": "Email ya tiene cuenta"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-crear_empleados"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/empleados/{id}": {
            "get": {
                "tags": [
                    "Empleados"
                ],
                "summary": "Detalle de empleado con subordinados y puntos de control",
                "description": "Ver empleado",
                "operationId": "da050a531e0e9b8f480ce01678c79a1b",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "404": {
                        "description": "No encontrado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Empleados"
                ],
                "summary": "Actualizar datos del empleado",
                "description": "Actualizar empleado",
                "operationId": "79ee1e023a03a0e818ed1341169ad340",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "Juan Pérez"
                                    },
                                    "salario_mensual": {
                                        "type": "number",
                                        "example": 700
                                    },
                                    "jefe_id": {
                                        "type": "integer",
                                        "example": 2,
                                        "nullable": true
                                    },
                                    "aplica_iess": {
                                        "type": "boolean",
                                        "example": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Datos actualizados"
                    },
                    "400": {
                        "description": "Un empleado no puede ser su propio jefe"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Empleados"
                ],
                "summary": "Eliminar empleado (soft delete)",
                "description": "Eliminar empleado",
                "operationId": "b75167e2e14efaccdb6dfc44de0e960f",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Empleado eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/empleados/{id}/usuario": {
            "post": {
                "tags": [
                    "Empleados"
                ],
                "summary": "Crear usuario para un empleado",
                "description": "Crear cuenta de usuario para un empleado existente\n\nSolo aplica a empleados sin cuenta vinculada. El email se genera del nombre si no\nse envía; los roles se infieren del cargo si no se especifican.",
                "operationId": "b5813d7e88bc8b8cd155fbef0e39efdf",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "ID del empleado",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 4
                    }
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "format": "email",
                                        "example": "nuevo@empresa.com",
                                        "nullable": true
                                    },
                                    "password": {
                                        "type": "string",
                                        "example": "clave123",
                                        "nullable": true
                                    },
                                    "roles": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            3
                                        ],
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Cuenta creada y vinculada (retorna credenciales)"
                    },
                    "400": {
                        "description": "El empleado ya tiene cuenta"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-crear_empleados"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/empleados/me": {
            "get": {
                "tags": [
                    "Empleados"
                ],
                "summary": "Perfil propio con configuración GPS de la empresa",
                "description": "Perfil del empleado autenticado\n\nIncluye parámetros de geocerca de la empresa (empresa_lat, empresa_lng, empresa_radio).",
                "operationId": "8469346c4817322585e72fc69c620493",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "400": {
                        "description": "No existe perfil de empleado para este usuario"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/empleados-simple": {
            "get": {
                "tags": [
                    "Empleados"
                ],
                "summary": "Empleados para dropdowns",
                "description": "Lista simple (id + nombre) para selectores",
                "operationId": "4950400f4c6e09988a0934381059a5b0",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_nomina"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/empleados/{id}/cupo": {
            "get": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Cupo de crédito vs deuda actual",
                "description": "Cupo disponible de préstamo de un empleado",
                "operationId": "e1488318402b62c281c71e0fae9b6f3b",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "ID del empleado",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 4
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_nomina"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/evidencias": {
            "get": {
                "tags": [
                    "Evidencias"
                ],
                "summary": "Obtener una evidencia (binario o base64 con ?formato=base64)",
                "description": "Las marcaciones/visitas guardan RUTA en vez de base64. El front consulta aquí para visualizar. Registros antiguos (base64 directo) también se sirven.",
                "operationId": "a642f6c850b5ceb273204d18b538e99b",
                "parameters": [
                    {
                        "name": "ruta",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "example": "evidencias/asistencias/abc.jpg"
                    },
                    {
                        "name": "formato",
                        "in": "query",
                        "description": "base64 | binario (default)",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Imagen o {base64}"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/facturas-empleados": {
            "get": {
                "tags": [
                    "Facturas de empleados"
                ],
                "summary": "Listar facturas (filtros: empleado_id, mes, anio)",
                "operationId": "9e75fc71d24aaca744deda76c6a959e8",
                "parameters": [
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "mes",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Facturas de empleados"
                ],
                "summary": "Registrar factura de un empleado facturero",
                "operationId": "2e76177414c226a11daaa54980385fd4",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "mes",
                                    "anio",
                                    "numero",
                                    "monto"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer"
                                    },
                                    "mes": {
                                        "type": "integer",
                                        "maximum": 12,
                                        "minimum": 1
                                    },
                                    "anio": {
                                        "type": "integer"
                                    },
                                    "numero": {
                                        "type": "string",
                                        "example": "FAC-000123"
                                    },
                                    "monto": {
                                        "type": "number",
                                        "example": 800
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/facturas-empleados/{id}": {
            "put": {
                "tags": [
                    "Facturas de empleados"
                ],
                "summary": "Actualizar factura (monto, descripción...)",
                "operationId": "05a3d3af71c817e4e480edae3ca30ee2",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Actualizada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Facturas de empleados"
                ],
                "summary": "Eliminar factura",
                "operationId": "bbfb37732f5da286942a36b2340f4776",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/feriados": {
            "get": {
                "tags": [
                    "Feriados"
                ],
                "summary": "Listar feriados (filtro por año)",
                "operationId": "96098d99b9b567b4e13b463a8c8b2cb1",
                "parameters": [
                    {
                        "name": "anio",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2026
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Feriados"
                ],
                "summary": "Registrar feriado",
                "operationId": "c98c3333a5ba22b407595315fe86d42a",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "fecha",
                                    "nombre"
                                ],
                                "properties": {
                                    "fecha": {
                                        "type": "string",
                                        "format": "date",
                                        "example": "2026-12-25"
                                    },
                                    "nombre": {
                                        "type": "string",
                                        "example": "Navidad"
                                    },
                                    "tipo": {
                                        "type": "string",
                                        "example": "nacional",
                                        "enum": [
                                            "nacional",
                                            "traslado",
                                            "local"
                                        ]
                                    },
                                    "genera_recargo": {
                                        "type": "boolean",
                                        "example": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/feriados/{id}": {
            "put": {
                "tags": [
                    "Feriados"
                ],
                "summary": "Actualizar feriado",
                "operationId": "bcea7b15e96646b518fa7d0e880f4a60",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Actualizado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Feriados"
                ],
                "summary": "Eliminar feriado",
                "operationId": "53e61b0869e4798ef8e8f115da99e67b",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/reportes/gerencial": {
            "get": {
                "tags": [
                    "Reportes gerenciales"
                ],
                "summary": "Dashboard gerencial: headcount, costo laboral, ausentismo, visitas, pasivo",
                "operationId": "4aeead195f64c976b415b896a3bc39f4",
                "parameters": [
                    {
                        "name": "mes",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        },
                        "example": 8
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2026
                    }
                ],
                "responses": {
                    "200": {
                        "description": "KPIs consolidados del mes"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/reportes/gerencial/exportar/{tipo}": {
            "get": {
                "tags": [
                    "Reportes gerenciales"
                ],
                "summary": "Exportar CSV (Excel): nomina | multas | pasivo | asistencias | visitas",
                "operationId": "3cae8117c6b52c62c0b7bad0ae8b6d80",
                "parameters": [
                    {
                        "name": "tipo",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "mes",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Archivo CSV con BOM UTF-8"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/justificaciones": {
            "post": {
                "tags": [
                    "Justificaciones"
                ],
                "summary": "Solicitar justificación de ausencia (empleado autenticado)",
                "operationId": "c311b590c4da5cb9ce03f28f1cbdb42f",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "tipo",
                                    "fecha_inicio",
                                    "fecha_fin",
                                    "descripcion"
                                ],
                                "properties": {
                                    "tipo": {
                                        "type": "string",
                                        "enum": [
                                            "enfermedad",
                                            "calamidad_domestica",
                                            "permiso_con_goce",
                                            "permiso_sin_goce",
                                            "otro"
                                        ]
                                    },
                                    "fecha_inicio": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "fecha_fin": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "example": "Consulta médica con certificado"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Solicitud creada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/justificaciones/mis-solicitudes": {
            "get": {
                "tags": [
                    "Justificaciones"
                ],
                "summary": "Mis solicitudes de justificación",
                "operationId": "77aa4f384ae1f290741a574a6b01f244",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/justificaciones": {
            "get": {
                "tags": [
                    "Justificaciones"
                ],
                "summary": "Gestionar justificaciones del equipo (filtro estado, default pendientes)",
                "operationId": "5d3bb4718819b0fda3dd17ae323a5173",
                "parameters": [
                    {
                        "name": "estado",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        },
                        "example": "pendiente"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/justificaciones/{id}/gestionar": {
            "put": {
                "tags": [
                    "Justificaciones"
                ],
                "summary": "Aprobar o rechazar justificación (valida jerarquía)",
                "operationId": "fb675331d4bd3eb8ebe2aa0ab60b2e51",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "estado"
                                ],
                                "properties": {
                                    "estado": {
                                        "type": "string",
                                        "enum": [
                                            "aprobada",
                                            "rechazada"
                                        ]
                                    },
                                    "respuesta_jefe": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Gestionada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/liquidaciones/previsualizar": {
            "post": {
                "tags": [
                    "Liquidaciones"
                ],
                "summary": "Calcular liquidación sin guardar",
                "operationId": "9494cc219b0ddc481616186b34123e85",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "fecha_salida",
                                    "motivo"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "example": 4
                                    },
                                    "fecha_salida": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "motivo": {
                                        "type": "string",
                                        "enum": [
                                            "renuncia",
                                            "desahucio",
                                            "despido_intempestivo",
                                            "fin_plazo",
                                            "mutuo_acuerdo"
                                        ]
                                    },
                                    "dias_vacaciones_pendientes": {
                                        "type": "integer",
                                        "example": 10,
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Detalle de la liquidación"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/liquidaciones": {
            "get": {
                "tags": [
                    "Liquidaciones"
                ],
                "summary": "Listar liquidaciones guardadas",
                "operationId": "33fe9bb7446f2668ed5d06a63e00a459",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Liquidaciones"
                ],
                "summary": "Calcular y guardar liquidación definitiva",
                "operationId": "ce8c93c9e444af186a24c3a39c83b9bf",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "fecha_salida",
                                    "motivo"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "example": 4
                                    },
                                    "fecha_salida": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "motivo": {
                                        "type": "string",
                                        "enum": [
                                            "renuncia",
                                            "desahucio",
                                            "despido_intempestivo",
                                            "fin_plazo",
                                            "mutuo_acuerdo"
                                        ]
                                    },
                                    "dias_vacaciones_pendientes": {
                                        "type": "integer",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Guardada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/notificaciones": {
            "get": {
                "tags": [
                    "Notificaciones"
                ],
                "summary": "Mis notificaciones (no leídas primero)",
                "operationId": "4a5488228077528a278bea003da9a3cc",
                "parameters": [
                    {
                        "name": "solo_no_leidas",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "limite",
                        "in": "query",
                        "description": "default 50",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "{no_leidas, total, data[]}"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/notificaciones/{id}/leer": {
            "put": {
                "tags": [
                    "Notificaciones"
                ],
                "summary": "Marcar una notificación como leída",
                "operationId": "9dea8f9dc844782fbac96b2bf80f56ef",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/notificaciones/leer-todas": {
            "post": {
                "tags": [
                    "Notificaciones"
                ],
                "summary": "Marcar todas mis notificaciones como leídas",
                "operationId": "b59e21cb7844f2ca3ce924a9b684b69e",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/conciliaciones": {
            "get": {
                "tags": [
                    "Conciliación bancaria"
                ],
                "summary": "Listar registros de pago (filtros: pago_tipo, conciliado)",
                "operationId": "6f83b51ca15599fb146f6cc2d99ae987",
                "parameters": [
                    {
                        "name": "pago_tipo",
                        "in": "query",
                        "description": "rol|decimo|utilidades",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "conciliado",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Conciliación bancaria"
                ],
                "summary": "Registrar/upsert el pago de un rol, décimo o utilidades",
                "operationId": "8a4d51e9133e6e49f3926def4068947b",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "pago_tipo",
                                    "pago_id",
                                    "metodo",
                                    "fecha_pago"
                                ],
                                "properties": {
                                    "pago_tipo": {
                                        "type": "string",
                                        "enum": [
                                            "rol",
                                            "decimo",
                                            "utilidades"
                                        ]
                                    },
                                    "pago_id": {
                                        "type": "integer"
                                    },
                                    "metodo": {
                                        "type": "string",
                                        "enum": [
                                            "transferencia",
                                            "deposito",
                                            "cheque",
                                            "efectivo",
                                            "otro"
                                        ]
                                    },
                                    "banco": {
                                        "type": "string",
                                        "example": "Banco Pichincha",
                                        "nullable": true
                                    },
                                    "numero_comprobante": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "fecha_pago": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "monto": {
                                        "type": "number",
                                        "nullable": true
                                    },
                                    "conciliado": {
                                        "type": "boolean",
                                        "nullable": true
                                    },
                                    "observacion": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Registrado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/conciliaciones/{id}/conciliar": {
            "put": {
                "tags": [
                    "Conciliación bancaria"
                ],
                "summary": "Marcar/desmarcar como conciliado ({conciliado:true|false})",
                "operationId": "a6ca16934f6f5141a8b18cfc8350770f",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "conciliado": {
                                        "type": "boolean"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/parametros-anuales": {
            "get": {
                "tags": [
                    "Parámetros legales"
                ],
                "summary": "Listar parámetros legales por año",
                "operationId": "3ba63b232e4eb6a61e7fcd149e51f149",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Parámetros legales"
                ],
                "summary": "Crear parámetros de un año",
                "operationId": "d8460117b8e37a455791470cf61b2369",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "anio",
                                    "sbu"
                                ],
                                "properties": {
                                    "anio": {
                                        "type": "integer",
                                        "example": 2027
                                    },
                                    "sbu": {
                                        "type": "number",
                                        "example": 482
                                    },
                                    "iess_personal_pct": {
                                        "type": "number",
                                        "example": 9.45
                                    },
                                    "iess_patronal_pct": {
                                        "type": "number",
                                        "example": 11.15
                                    },
                                    "fondos_reserva_pct": {
                                        "type": "number",
                                        "example": 8.33
                                    },
                                    "ir_brackets": {
                                        "type": "array",
                                        "items": {
                                            "type": "object"
                                        },
                                        "example": [
                                            {
                                                "desde": 0,
                                                "hasta": 11610,
                                                "fraccion_basica": 0,
                                                "pct": 0
                                            }
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/parametros-anuales/{id}": {
            "put": {
                "tags": [
                    "Parámetros legales"
                ],
                "summary": "Actualizar parámetros de un año (ej: nuevo SBU publicado)",
                "operationId": "d5f5696975df9a84dc1f8185ba900868",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "sbu": {
                                        "type": "number",
                                        "example": 482
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Actualizado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/parametros": {
            "get": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Listar parámetros de la empresa",
                "description": "Listar parámetros generales",
                "operationId": "a82018309e7ff379879b051790b4a040",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_parametros"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Crear parámetro general",
                "description": "Crear parámetro",
                "operationId": "bd53285f6c336da979f8fd187de3f006",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "codigo",
                                    "valor",
                                    "descripcion",
                                    "tipo_dato"
                                ],
                                "properties": {
                                    "codigo": {
                                        "type": "string",
                                        "example": "JORNADA_DIARIA"
                                    },
                                    "valor": {
                                        "type": "string",
                                        "example": "8"
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "example": "Horas de jornada diaria laboral"
                                    },
                                    "tipo_dato": {
                                        "type": "string",
                                        "example": "numero",
                                        "enum": [
                                            "texto",
                                            "hora",
                                            "fecha",
                                            "numero",
                                            "decimales largo",
                                            "select",
                                            "fechaHora"
                                        ]
                                    },
                                    "opciones": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Parámetro creado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/parametros/{id}": {
            "get": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Detalle de un parámetro",
                "description": "Ver parámetro",
                "operationId": "083aba52359b9cacfd7a46e83673f36c",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Actualizar valor/descripción de un parámetro",
                "description": "Actualizar parámetro\n\nInvalida el caché del parámetro modificado.",
                "operationId": "d8eab825c5c3e4ab92473dbc3c776749",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "valor"
                                ],
                                "properties": {
                                    "valor": {
                                        "type": "string",
                                        "example": "8"
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "opciones": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Parámetro actualizado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Eliminar parámetro",
                "description": "Eliminar parámetro",
                "operationId": "9c32ae15a7c4b7c73035379bd2eb6f50",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Parámetro eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/reporte-mensual": {
            "get": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Reporte mensual de nómina",
                "description": "Previa/histórico de nómina mensual\n\nSi el periodo ya está cerrado retorna los datos históricos; si no, calcula la previa para todos los empleados.",
                "operationId": "5b6c92dfc121faad2e6f2ce97a61b9c1",
                "parameters": [
                    {
                        "name": "mes",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 8
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2026
                    },
                    {
                        "name": "tipo_periodo",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "Mensual",
                                "Quincenal",
                                "Semanal"
                            ]
                        },
                        "example": "Mensual"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK con data, is_closed y config_frecuencia"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_nomina"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/cerrar-periodo": {
            "post": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Cerrar periodo de nómina",
                "description": "Cerrar nómina del periodo\n\nGuarda el histórico por empleado, cobra las cuotas FIFO de préstamos/multas y actualiza saldos. Operación transaccional.",
                "operationId": "5e3c8fb79c34ff35cd2131b9ef2900c5",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "mes",
                                    "anio",
                                    "tipo_periodo"
                                ],
                                "properties": {
                                    "mes": {
                                        "type": "integer",
                                        "example": 8
                                    },
                                    "anio": {
                                        "type": "integer",
                                        "example": 2026
                                    },
                                    "tipo_periodo": {
                                        "type": "string",
                                        "example": "Mensual"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Nómina cerrada con éxito"
                    },
                    "422": {
                        "description": "El periodo ya está cerrado"
                    },
                    "500": {
                        "description": "Error interno (rollback)"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/mis-roles": {
            "get": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Histórico de nóminas cerradas propias",
                "description": "Mis roles de pago (empleado autenticado)",
                "operationId": "289ca254d6af9ba448ff4a53d1d8422c",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-ver_roles_propios"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/pdf/{id}": {
            "get": {
                "tags": [
                    "Nómina"
                ],
                "summary": "PDF del rol de pago",
                "description": "Descargar rol de pago en PDF\n\nSolo admin puede descargar roles de otros empleados.",
                "operationId": "a222deb54e63251aa1f8f3823c60f1c2",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "ID del empleado",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 4
                    },
                    {
                        "name": "mes",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 8
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2026
                    },
                    {
                        "name": "tipo_periodo",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "example": "Mensual"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Archivo PDF (stream)"
                    },
                    "403": {
                        "description": "Solo puedes descargar tus propios roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/pdf-grupal": {
            "get": {
                "tags": [
                    "Nómina"
                ],
                "summary": "PDF GRUPAL del rol de pagos del periodo (todos los empleados)",
                "operationId": "f16a912f5bfb500b89933da3ef59cf68",
                "parameters": [
                    {
                        "name": "mes",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "tipo_periodo",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Archivo PDF (stream)"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/enviar-rol": {
            "post": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Enviar rol de pago por correo (PDF adjunto)",
                "description": "Usa las credenciales MAIL_* del .env. Individual (empleado_id) o grupal (grupal=true, se envía a correo_destino o al admin).",
                "operationId": "5e89c60ce2d0e2ad4ca130471dae1a07",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "mes",
                                    "anio",
                                    "tipo_periodo"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "nullable": true
                                    },
                                    "grupal": {
                                        "type": "boolean",
                                        "nullable": true
                                    },
                                    "correo_destino": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "mes": {
                                        "type": "integer"
                                    },
                                    "anio": {
                                        "type": "integer"
                                    },
                                    "tipo_periodo": {
                                        "type": "string"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "{enviado, destino}"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/periodos-disponibles": {
            "get": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Meses/años con asistencia registrada",
                "description": "Periodos disponibles para nómina",
                "operationId": "0614783ed4907c1ed45f867a607c2342",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/pensiones-alimenticias": {
            "get": {
                "tags": [
                    "Pensiones alimenticias"
                ],
                "summary": "Listar pensiones (filtro empleado_id / activas)",
                "operationId": "439dd68a0684d4bbc7e9e8a4ea258b76",
                "parameters": [
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "activas",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Pensiones alimenticias"
                ],
                "summary": "Registrar orden judicial de pensión alimenticia",
                "operationId": "ad068ca7785a80ba2c460c5368fb331e",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "tipo_calculo",
                                    "valor",
                                    "fecha_inicio"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "example": 4
                                    },
                                    "numero_oficio": {
                                        "type": "string",
                                        "example": "JUZGADO-2026-001"
                                    },
                                    "tipo_calculo": {
                                        "type": "string",
                                        "example": "monto_fijo",
                                        "enum": [
                                            "monto_fijo",
                                            "porcentaje"
                                        ]
                                    },
                                    "valor": {
                                        "type": "number",
                                        "example": 100
                                    },
                                    "fecha_inicio": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "observaciones": {
                                        "type": "string"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/pensiones-alimenticias/{id}": {
            "put": {
                "tags": [
                    "Pensiones alimenticias"
                ],
                "summary": "Actualizar pensión (ej: desactivar con activa=false)",
                "operationId": "998362380679366ff857e9c871705a88",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Actualizada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/permissions": {
            "get": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Catálogo de permisos",
                "description": "Listar permisos con los roles que los tienen",
                "operationId": "2a86b42c70b2b82889c78c925ddedbfa",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Crear permiso",
                "description": "Crear permiso personalizado\n\nEl nombre se normaliza al patrón rrhh-slug. Útil para nuevos módulos.",
                "operationId": "86272f36fd5105e1095a899d17416fb4",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "nombre"
                                ],
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "ver_reportes_gerenciales"
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "example": "Acceso a reportes gerenciales"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Permiso creado"
                    },
                    "422": {
                        "description": "Nombre duplicado o inválido"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/permissions/{id}": {
            "get": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Detalle de permiso",
                "description": "Ver permiso",
                "operationId": "8ff9307bd5f184d580ecf6596a9eab98",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Actualizar permiso",
                "description": "Actualizar permiso (descripción o renombrar)",
                "operationId": "71ef61e3273cbbc2082d43c14809a507",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 3
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "rrhh-ver_asistencia_equipo"
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "example": "Ver asistencia de todo el equipo"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Permiso actualizado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Eliminar permiso",
                "description": "Eliminar permiso (lo desasigna de todos los roles)",
                "operationId": "5b055a17134e19f9addbd4509cbc98e2",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 9
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Permiso eliminado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/loans": {
            "get": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Listar préstamos/deudas con filtro por estado",
                "description": "Listar préstamos y deudas",
                "operationId": "7d96ea3df46cf0ce981fb8cf20156e4b",
                "parameters": [
                    {
                        "name": "estado",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "todos",
                                "pendiente",
                                "pagado",
                                "cancelado"
                            ]
                        },
                        "example": "pendiente"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_nomina"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Crear préstamo con plan de cuotas",
                "description": "Registrar préstamo/deuda\n\nGenera las N cuotas mensuales en nomina_movimientos dentro de una transacción.",
                "operationId": "3668b37a13f0b0f3fd9cba222d91f9da",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "monto_total",
                                    "numero_cuotas",
                                    "tipo",
                                    "titulo",
                                    "mes_inicio",
                                    "anio_inicio"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "example": 4
                                    },
                                    "monto_total": {
                                        "type": "number",
                                        "example": 1200
                                    },
                                    "numero_cuotas": {
                                        "type": "integer",
                                        "example": 4
                                    },
                                    "tipo": {
                                        "type": "string",
                                        "example": "prestamo",
                                        "enum": [
                                            "prestamo",
                                            "producto",
                                            "anticipo"
                                        ]
                                    },
                                    "titulo": {
                                        "type": "string",
                                        "example": "Préstamo Emergencia Médica"
                                    },
                                    "mes_inicio": {
                                        "type": "integer",
                                        "example": 9
                                    },
                                    "anio_inicio": {
                                        "type": "integer",
                                        "example": 2026
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Préstamo registrado exitosamente"
                    },
                    "422": {
                        "description": "Datos inválidos"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/loans/{id}": {
            "delete": {
                "tags": [
                    "Nómina"
                ],
                "summary": "Eliminar préstamo sin pagos",
                "description": "Eliminar préstamo\n\nSolo si no se ha cobrado ninguna cuota.",
                "operationId": "b75909f5a39c71a6e3de39c124b859a3",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Préstamo eliminado"
                    },
                    "422": {
                        "description": "Tiene pagos realizados"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/puntos-control": {
            "get": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Listar todos los puntos GPS",
                "description": "Listar puntos de control",
                "operationId": "774499a18d8e771c20e51e9da067f627",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_rutas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Asignar punto GPS a un empleado",
                "description": "Crear punto de control",
                "operationId": "35296e0a579dd764698c55f3a3e43c72",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "nombre_punto",
                                    "latitud",
                                    "longitud"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "example": 7
                                    },
                                    "nombre_punto": {
                                        "type": "string",
                                        "example": "Tienda Centro Comercial"
                                    },
                                    "latitud": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -2.19
                                    },
                                    "longitud": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -79.89
                                    },
                                    "radio_metros": {
                                        "type": "integer",
                                        "example": 50
                                    },
                                    "activo": {
                                        "type": "boolean",
                                        "example": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Punto creado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_rutas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/puntos-control/{id}": {
            "put": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Actualizar punto GPS",
                "description": "Actualizar punto de control",
                "operationId": "a819d5903d5011b73b5c4f8912a8c7c5",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "nombre_punto": {
                                        "type": "string",
                                        "example": "Tienda Norte"
                                    },
                                    "radio_metros": {
                                        "type": "integer",
                                        "example": 80
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Punto actualizado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Eliminar punto GPS",
                "description": "Eliminar punto de control",
                "operationId": "1901c9c8e02ea61791051f7b00e72cb1",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Punto eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/reglas-penalidad": {
            "get": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Listar todas las reglas",
                "description": "Listar reglas de penalidad",
                "operationId": "04f4243dba7978711d7255347ee45fa2",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-ver_reglas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Crear regla por rango de minutos de retraso",
                "description": "Crear regla de penalidad",
                "operationId": "726339176b910e8118ea885aec49710d",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "cargo_id",
                                    "nombre_regla",
                                    "minutos_retraso_inicio",
                                    "minutos_retraso_fin",
                                    "porcentaje_penalidad"
                                ],
                                "properties": {
                                    "cargo_id": {
                                        "type": "integer",
                                        "example": 4
                                    },
                                    "nombre_regla": {
                                        "type": "string",
                                        "example": "Retraso Leve"
                                    },
                                    "minutos_retraso_inicio": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "minutos_retraso_fin": {
                                        "type": "integer",
                                        "example": 15
                                    },
                                    "porcentaje_penalidad": {
                                        "type": "number",
                                        "example": 1
                                    },
                                    "frecuencia_acumulacion": {
                                        "type": "integer",
                                        "example": 3
                                    },
                                    "retraso_leve": {
                                        "type": "boolean",
                                        "example": true
                                    },
                                    "retraso_grave": {
                                        "type": "boolean",
                                        "example": false
                                    },
                                    "activo": {
                                        "type": "boolean",
                                        "example": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Regla creada"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_reglas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/reglas-penalidad/{id}": {
            "get": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Detalle de una regla",
                "description": "Ver regla",
                "operationId": "589fe0989b7638efdc75242e279c7fff",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Actualizar regla de penalidad",
                "description": "Actualizar regla",
                "operationId": "3049b2adc3f03f58e42cccbbed5be9ea",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Regla actualizada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Configuración"
                ],
                "summary": "Eliminar regla de penalidad",
                "description": "Eliminar regla",
                "operationId": "60eb6ece98bdd9d2111493b8200c5b8e",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Regla eliminada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/roles": {
            "get": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Listar roles del sistema",
                "description": "Listar roles con sus permisos y conteo de usuarios",
                "operationId": "14571799f04ccf9cf55c5b769106e385",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Crear rol",
                "description": "Crear rol",
                "operationId": "ba5d1c8c66a0e18724226615bcae101a",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "nombre"
                                ],
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "supervisor"
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "example": "Supervisa turnos nocturnos"
                                    },
                                    "permission_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            1,
                                            2,
                                            3
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Rol creado"
                    },
                    "422": {
                        "description": "Nombre duplicado o datos inválidos"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/roles/{id}": {
            "get": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Detalle de rol con permisos",
                "description": "Ver rol",
                "operationId": "e9dd6f671b6120153931f4b7d657c999",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "404": {
                        "description": "No encontrado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Actualizar rol",
                "description": "Actualizar rol\n\nEl nombre del rol admin no se puede cambiar.",
                "operationId": "4a431f127b2fd60a4985f38f540e0fe1",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "jefe_area"
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "example": "Jefatura de área"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Rol actualizado"
                    },
                    "400": {
                        "description": "El rol admin no puede renombrarse"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Eliminar rol",
                "description": "Eliminar rol\n\nBloqueado para el rol admin y para roles que aún tienen usuarios asignados.",
                "operationId": "ad53bf3a92d152c169e86f0f318e9b7f",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 5
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Rol eliminado"
                    },
                    "400": {
                        "description": "Es el rol admin o tiene usuarios asignados"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/roles/{id}/permisos": {
            "put": {
                "tags": [
                    "Roles y Permisos"
                ],
                "summary": "Asignar/reemplazar permisos de un rol",
                "description": "Sincronizar permisos del rol\n\nReemplaza la lista completa de permisos del rol.",
                "operationId": "3a82c572f2d7617142448133fd60e882",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 2
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "permission_ids"
                                ],
                                "properties": {
                                    "permission_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            1,
                                            4,
                                            7
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Permisos actualizados"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_roles"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/rubros": {
            "get": {
                "tags": [
                    "Rubros de pago"
                ],
                "summary": "Listar rubros (filtros: empleado_id, mes/anio vigentes)",
                "operationId": "1367b4fc6cfb7a598531344c0c5b6a37",
                "parameters": [
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "mes",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "anio",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "solo_vigentes",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Rubros de pago"
                ],
                "summary": "Crear rubro (fecha_fin null = indefinido)",
                "operationId": "c6b64e96e88a24fd62e03b902ce7efdc",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "nombre",
                                    "valor",
                                    "fecha_inicio"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer"
                                    },
                                    "nombre": {
                                        "type": "string",
                                        "example": "Lactancia"
                                    },
                                    "tipo_calculo": {
                                        "type": "string",
                                        "enum": [
                                            "monto_fijo",
                                            "porcentaje"
                                        ]
                                    },
                                    "valor": {
                                        "type": "number",
                                        "example": 50
                                    },
                                    "fecha_inicio": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "fecha_fin": {
                                        "type": "string",
                                        "format": "date",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/rubros/{id}": {
            "put": {
                "tags": [
                    "Rubros de pago"
                ],
                "summary": "Actualizar rubro / cambiar vigencia / desactivar",
                "operationId": "2dd049f08f4cb351e46d2fa5e660c84c",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Actualizado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Rubros de pago"
                ],
                "summary": "Eliminar rubro",
                "operationId": "8dca50c7950b26973db1ce914aa83503",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/sanciones": {
            "get": {
                "tags": [
                    "Sanciones"
                ],
                "summary": "Listar sanciones",
                "description": "Listar sanciones\n\nSanciones administrativas independientes de la asistencia (afectan el rol mensual).\nAdmin ve todas; jefe solo las de su equipo. Filtros: empleado_id, estado_pago.",
                "operationId": "a929e844008ec680be2f9a43bb94c5a0",
                "parameters": [
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 7
                    },
                    {
                        "name": "estado_pago",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "pendiente",
                                "parcial",
                                "liquidado"
                            ]
                        },
                        "example": "pendiente"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_sanciones"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Sanciones"
                ],
                "summary": "Aplicar sanción a un empleado",
                "description": "Aplicar sanción\n\nSelecciona una regla de penalidad del catálogo (GET /api/admin/reglas-penalidad o /api/jefe/ver-reglas);\nel monto se calcula aplicando el porcentaje de la regla al salario del empleado.\nCrea un movimiento de nómina categoría \"sancion\" que se descuenta en el rol del periodo.\nJefe solo puede sancionar a sus subordinados; admin a cualquiera.",
                "operationId": "6bb03918af30ef415bf05de178ca8570",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "empleado_id",
                                    "descripcion",
                                    "regla_id"
                                ],
                                "properties": {
                                    "empleado_id": {
                                        "type": "integer",
                                        "example": 7
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "example": "Incumplimiento de protocolo de bodega"
                                    },
                                    "regla_id": {
                                        "description": "ID de rrhh_reglas_penalidad; el monto se calcula con su porcentaje sobre el salario",
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "fecha_periodo": {
                                        "description": "Por defecto hoy",
                                        "type": "string",
                                        "format": "date",
                                        "example": "2026-08-22",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Sanción aplicada; retorna el movimiento con el monto calculado"
                    },
                    "400": {
                        "description": "La regla no aplica al cargo del empleado"
                    },
                    "403": {
                        "description": "Sin autoridad sobre el empleado"
                    },
                    "422": {
                        "description": "Datos inválidos"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/sanciones/{id}": {
            "delete": {
                "tags": [
                    "Sanciones"
                ],
                "summary": "Anular sanción pendiente",
                "description": "Anular sanción\n\nSolo si no fue cobrada en ningún rol cerrado.",
                "operationId": "64cac85220546afe5f6a82aae5cd1498",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "ID del movimiento de sanción",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 12
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Sanción anulada"
                    },
                    "400": {
                        "description": "Ya cobrada, no anulable"
                    },
                    "404": {
                        "description": "No encontrada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/sucursales": {
            "get": {
                "tags": [
                    "Sucursales"
                ],
                "summary": "Listar sucursales (plano, con su padre)",
                "operationId": "67f9d2c166eae0afc7acb77ff99dbcac",
                "parameters": [
                    {
                        "name": "activas",
                        "in": "query",
                        "description": "Solo activas",
                        "schema": {
                            "type": "boolean"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Sucursales"
                ],
                "summary": "Crear sucursal (parent_id null = raíz/empresa base)",
                "operationId": "a6a8e82194fbf057b73f06b4edda85d9",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "nombre"
                                ],
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "Sucursal Norte"
                                    },
                                    "codigo": {
                                        "type": "string",
                                        "example": "NOR-01",
                                        "nullable": true
                                    },
                                    "parent_id": {
                                        "description": "Sucursal padre (árbol)",
                                        "type": "integer",
                                        "nullable": true
                                    },
                                    "direccion": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "lat": {
                                        "type": "number",
                                        "example": -2.1894128,
                                        "nullable": true
                                    },
                                    "lng": {
                                        "type": "number",
                                        "example": -79.8890662,
                                        "nullable": true
                                    },
                                    "radio_metros": {
                                        "type": "integer",
                                        "example": 50
                                    },
                                    "activa": {
                                        "type": "boolean",
                                        "example": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/sucursales/arbol": {
            "get": {
                "tags": [
                    "Sucursales"
                ],
                "summary": "Sucursales anidadas en árbol (raíces = parent_id null)",
                "operationId": "56fe23567c031206f535022a765b2fbb",
                "responses": {
                    "200": {
                        "description": "Árbol jerárquico con empleados_count"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/sucursales/{id}": {
            "get": {
                "tags": [
                    "Sucursales"
                ],
                "summary": "Ver sucursal (con padre e hijas)",
                "operationId": "edba22b084168896331b47681647160c",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Sucursales"
                ],
                "summary": "Actualizar sucursal (nombre, GPS, radio, estado...)",
                "operationId": "e09708cf16bdc8927f5589874bc995a0",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "nombre": {
                                        "type": "string"
                                    },
                                    "lat": {
                                        "type": "number",
                                        "nullable": true
                                    },
                                    "lng": {
                                        "type": "number",
                                        "nullable": true
                                    },
                                    "radio_metros": {
                                        "type": "integer"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Actualizada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Sucursales"
                ],
                "summary": "Eliminar sucursal (bloqueada si tiene hijas o empleados asignados)",
                "operationId": "83ab829dbd1c7406d38cf9c6e778ea23",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminada"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/sucursales/{id}/empleados": {
            "get": {
                "tags": [
                    "Sucursales"
                ],
                "summary": "Empleados asignados a la sucursal",
                "operationId": "3100c3ce0c7f69c1c2a76deabf9b8d42",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/sucursales/{id}/asignar-empleados": {
            "post": {
                "tags": [
                    "Sucursales"
                ],
                "summary": "Asignar empleados a la sucursal ({empleado_ids:[..]})",
                "operationId": "6d79b5e2ce51dbbb1c5b45ced6577962",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "empleado_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            4,
                                            5
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Asignados"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/turnos": {
            "get": {
                "tags": [
                    "Turnos"
                ],
                "summary": "Listar turnos",
                "operationId": "bde90ed77b804604bc3ce96dc4155f6a",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Turnos"
                ],
                "summary": "Crear turno",
                "operationId": "88636d85fba31db0012c2098a0cb31b0",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "nombre",
                                    "hora_entrada",
                                    "hora_salida"
                                ],
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "example": "Nocturno"
                                    },
                                    "hora_entrada": {
                                        "type": "string",
                                        "example": "22:00"
                                    },
                                    "hora_salida": {
                                        "type": "string",
                                        "example": "06:00"
                                    },
                                    "tolerancia_min": {
                                        "type": "integer",
                                        "example": 10
                                    },
                                    "minutos_almuerzo": {
                                        "type": "integer",
                                        "example": 30
                                    },
                                    "dias_semana": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            1,
                                            2,
                                            3,
                                            4,
                                            5
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Creado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/turnos/{id}": {
            "put": {
                "tags": [
                    "Turnos"
                ],
                "summary": "Actualizar turno",
                "operationId": "87daf6178bb9b4547a9b6c5d1fc6b649",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Actualizado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Turnos"
                ],
                "summary": "Eliminar turno (los empleados vuelven al horario general)",
                "operationId": "4801b82688e56aeb4fd6d68d8213ad26",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Eliminado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/turnos/{id}/asignar": {
            "post": {
                "tags": [
                    "Turnos"
                ],
                "summary": "Asignar turno a empleados (body: {empleado_ids:[..]} o {empleado_id})",
                "operationId": "3e4aa1028af677f1c95f22610ae46b12",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "empleado_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            4,
                                            5
                                        ]
                                    },
                                    "empleado_id": {
                                        "type": "integer",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Asignados"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/users": {
            "get": {
                "tags": [
                    "Usuarios"
                ],
                "summary": "Listar usuarios del sistema",
                "description": "Listar usuarios",
                "operationId": "7dd4baaf77f85b1282854bf0aa281464",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "description": "Buscar por nombre o email",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_usuarios"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "post": {
                "tags": [
                    "Usuarios"
                ],
                "summary": "Crear usuario con roles",
                "description": "Crear usuario",
                "operationId": "389f94ca462a68bc9f573c4a08b3d5fe",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "name",
                                    "email",
                                    "password"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "example": "Juan Pérez"
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email",
                                        "example": "juan@test.com"
                                    },
                                    "password": {
                                        "type": "string",
                                        "format": "password",
                                        "example": "secreto123",
                                        "minLength": 6
                                    },
                                    "roles": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            3
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Usuario creado"
                    },
                    "422": {
                        "description": "Datos inválidos"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_usuarios"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/users/{id}": {
            "get": {
                "tags": [
                    "Usuarios"
                ],
                "summary": "Detalle de usuario",
                "description": "Ver usuario",
                "operationId": "71e44103eaa6df5095bc0af5cbe1d483",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "404": {
                        "description": "No encontrado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_usuarios"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Usuarios"
                ],
                "summary": "Actualizar usuario",
                "description": "Actualizar usuario\n\nLa contraseña es opcional (solo se cambia si se envía). Si se envían roles se reemplazan.",
                "operationId": "e2686c6d3f24049d1c98818faa091360",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "example": "Juan Pérez G."
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email",
                                        "example": "juan.nuevo@test.com"
                                    },
                                    "password": {
                                        "type": "string",
                                        "format": "password",
                                        "example": "nuevaClave1",
                                        "nullable": true
                                    },
                                    "roles": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            2
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Usuario actualizado"
                    },
                    "404": {
                        "description": "No encontrado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_usuarios"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Usuarios"
                ],
                "summary": "Eliminar usuario",
                "description": "Eliminar usuario\n\nNo permite eliminar la propia cuenta ni al último administrador.\nSi el usuario tiene perfil de empleado, este se conserva (solo se desvincula).",
                "operationId": "180f0ee009c229ee193669ddf59bb38a",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 5
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Usuario eliminado"
                    },
                    "400": {
                        "description": "Operación bloqueada (propia cuenta o último admin)"
                    },
                    "404": {
                        "description": "No encontrado"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_usuarios"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/users/{id}/roles": {
            "put": {
                "tags": [
                    "Usuarios"
                ],
                "summary": "Sincronizar roles del usuario",
                "description": "Asignar roles a un usuario\n\nReemplaza la lista completa de roles del usuario.",
                "operationId": "b93b03c7f2fec9bad9ff4b7925af56b5",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 4
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "role_ids"
                                ],
                                "properties": {
                                    "role_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "example": [
                                            2,
                                            3
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Roles actualizados"
                    },
                    "400": {
                        "description": "Quitaría el último rol admin"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_usuarios"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/utilidades": {
            "get": {
                "tags": [
                    "Utilidades"
                ],
                "summary": "Listar procesos de utilidades",
                "operationId": "083d6256a88067dca17fa0b3311d59ef",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/utilidades/procesar": {
            "post": {
                "tags": [
                    "Utilidades"
                ],
                "summary": "Procesar/calcular la distribución de utilidades de un ejercicio",
                "operationId": "9b246cfec39c339eda5bf7b14b8c0171",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "anio",
                                    "monto_declarado"
                                ],
                                "properties": {
                                    "anio": {
                                        "description": "Ejercicio económico liquidado",
                                        "type": "integer",
                                        "example": 2025
                                    },
                                    "monto_declarado": {
                                        "description": "Total utilidades para trabajadores (el 15%)",
                                        "type": "number",
                                        "example": 15000
                                    },
                                    "fecha_pago_prevista": {
                                        "type": "string",
                                        "format": "date",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Proceso en borrador con detalles por empleado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/utilidades/{id}": {
            "get": {
                "tags": [
                    "Utilidades"
                ],
                "summary": "Detalle del proceso (reparto por empleado)",
                "operationId": "0510dd288476ec77e978e0c1dd140e30",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/utilidades/{id}/preavisar": {
            "post": {
                "tags": [
                    "Utilidades"
                ],
                "summary": "Preaviso quincenal a todos los beneficiarios (art. 97)",
                "operationId": "fedb1b45f60fc8309352547ad9e803f8",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Preavisado + notificaciones enviadas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/payroll/utilidades/{id}/pagar": {
            "post": {
                "tags": [
                    "Utilidades"
                ],
                "summary": "Pagar utilidades (rol especial por empleado)",
                "operationId": "0f330a3316dcb4793db5b95efb9d70a8",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "properties": {
                                    "forzar": {
                                        "type": "boolean",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Pagado"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/vacaciones": {
            "post": {
                "tags": [
                    "Vacaciones"
                ],
                "summary": "Crear solicitud de vacaciones",
                "description": "Solicitar vacaciones (empleado autenticado)",
                "operationId": "53e23dc5bdfa62f67635b32dcc206842",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "fecha_inicio",
                                    "fecha_fin"
                                ],
                                "properties": {
                                    "fecha_inicio": {
                                        "type": "string",
                                        "format": "date",
                                        "example": "2026-09-10"
                                    },
                                    "fecha_fin": {
                                        "type": "string",
                                        "format": "date",
                                        "example": "2026-09-14"
                                    },
                                    "motivo": {
                                        "type": "string",
                                        "example": "Vacaciones familiares",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Solicitud creada (queda pendiente)"
                    },
                    "400": {
                        "description": "Saldo insuficiente o fechas se solapan con otra solicitud"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-solicitar_vacaciones"
                    },
                    "422": {
                        "description": "Fechas inválidas"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/vacaciones/mis-vacaciones": {
            "get": {
                "tags": [
                    "Vacaciones"
                ],
                "summary": "Historial y saldo de vacaciones propios",
                "description": "Mis vacaciones (historial + saldo)",
                "operationId": "0f2e1ea36f9193ceee2f0a37dbf35768",
                "responses": {
                    "200": {
                        "description": "OK con saldo e historial"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-solicitar_vacaciones"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/vacaciones/pendientes": {
            "get": {
                "tags": [
                    "Vacaciones"
                ],
                "summary": "Solicitudes pendientes de los subordinados",
                "description": "Solicitudes pendientes de mi equipo (jefe)",
                "operationId": "407b836c2ddd9f76567aef9ff6a7fbe4",
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-aprobar_vacaciones"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/vacaciones/{id}/aprobar": {
            "post": {
                "tags": [
                    "Vacaciones"
                ],
                "summary": "Aprobar una solicitud de vacaciones",
                "description": "Aprobar solicitud (jefe/admin)",
                "operationId": "562c16871da7690f5b702f2e85ee5291",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    },
                    {
                        "name": "observaciones",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Solicitud aprobada"
                    },
                    "400": {
                        "description": "Ya fue procesada o saldo insuficiente"
                    },
                    "403": {
                        "description": "Sin permiso o fuera de tu jerarquía"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/jefe/vacaciones/{id}/rechazar": {
            "post": {
                "tags": [
                    "Vacaciones"
                ],
                "summary": "Rechazar una solicitud de vacaciones",
                "description": "Rechazar solicitud (jefe/admin)",
                "operationId": "cccf01ec5e94690933dd1b50e3b42a87",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    },
                    {
                        "name": "observaciones",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Solicitud rechazada"
                    },
                    "400": {
                        "description": "Ya fue procesada"
                    },
                    "403": {
                        "description": "Sin permiso o fuera de tu jerarquía"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/vacaciones": {
            "get": {
                "tags": [
                    "Vacaciones"
                ],
                "summary": "Listar todas las solicitudes",
                "description": "Historial completo de vacaciones (admin)",
                "operationId": "8df0428aeeb9130ceed384cddaccf9ac",
                "parameters": [
                    {
                        "name": "estado",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "pendiente",
                                "aprobada",
                                "rechazada",
                                "cancelada"
                            ]
                        }
                    },
                    {
                        "name": "empleado_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-aprobar_vacaciones"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/gestion-visitas": {
            "get": {
                "tags": [
                    "Visitas"
                ],
                "summary": "Gestión administrativa de visitas",
                "description": "Listar todas las visitas (paginado)",
                "operationId": "1f837fab17c938436a2b31aea15211d5",
                "parameters": [
                    {
                        "name": "estado",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "pendiente",
                                "aprobado",
                                "rechazado",
                                "penalizado_jefe"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_visitas_admin"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/admin/gestion-visitas/{id}": {
            "put": {
                "tags": [
                    "Visitas"
                ],
                "summary": "Forzar estado de una visita",
                "description": "Corregir una visita manualmente (Admin Override)",
                "operationId": "061ff4d8c2b46f3f97523bc0510358d5",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "example": 1
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "estado"
                                ],
                                "properties": {
                                    "estado": {
                                        "type": "string",
                                        "example": "aprobado",
                                        "enum": [
                                            "pendiente",
                                            "aprobado",
                                            "rechazado",
                                            "penalizado_jefe"
                                        ]
                                    },
                                    "observacion_rechazo": {
                                        "type": "string",
                                        "example": "Validada manualmente por administración",
                                        "nullable": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Visita corregida"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-gestionar_visitas_admin"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/visitas/registrar": {
            "post": {
                "tags": [
                    "Visitas"
                ],
                "summary": "Registrar llegada del vendedor/promotor",
                "description": "Registrar visita a punto de control\n\nValida que el punto esté asignado al empleado y que el GPS esté dentro del radio del punto.",
                "operationId": "263726c9c7ee758b7bffe2e085eda8c0",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "punto_id",
                                    "lat",
                                    "lng",
                                    "fotos"
                                ],
                                "properties": {
                                    "punto_id": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "lat": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -2.19
                                    },
                                    "lng": {
                                        "type": "number",
                                        "format": "float",
                                        "example": -79.89
                                    },
                                    "fotos": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "example": [
                                            "https://cdn.ejemplo.com/visita1.jpg"
                                        ],
                                        "minItems": 1
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Visita registrada (queda pendiente de validación)"
                    },
                    "400": {
                        "description": "Punto no asignado o fuera del radio GPS"
                    },
                    "403": {
                        "description": "Sin permiso rrhh-registrar_visita"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        },
        "/api/visitas/reporte": {
            "get": {
                "tags": [
                    "Visitas"
                ],
                "summary": "Reporte mensual/personalizado de visitas",
                "description": "Reporte de visitas del rango indicado\n\nEjecuta la penalización diferida de jefes que exceden el tiempo de validación (TIEMPO_HOLGURA_VENDEDOR).",
                "operationId": "c95c0a292261277a5fce16ba13232396",
                "parameters": [
                    {
                        "name": "inicio",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "fin",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                },
                "security": [
                    {
                        "bearerAuth": []
                    }
                ]
            }
        }
    },
    "components": {
        "schemas": {
            "User": {
                "title": "Usuario",
                "properties": {
                    "id": {
                        "description": "Esquemas reutilizables de la API RRHH",
                        "type": "integer",
                        "example": 1
                    },
                    "name": {
                        "type": "string",
                        "example": "Administrador RRHH"
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "example": "admin@rrhh.local"
                    }
                },
                "type": "object"
            },
            "Cargo": {
                "title": "Cargo",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 4
                    },
                    "nombre": {
                        "type": "string",
                        "example": "Operario Bodega"
                    },
                    "slug": {
                        "type": "string",
                        "example": "bodega"
                    },
                    "es_jefe": {
                        "type": "boolean",
                        "example": false
                    },
                    "es_vendedor": {
                        "type": "boolean",
                        "example": false
                    },
                    "requiere_gps_entrada": {
                        "type": "boolean",
                        "example": true
                    },
                    "requiere_gps_salida": {
                        "type": "boolean",
                        "example": false
                    },
                    "cantidad_fotos_entrada": {
                        "type": "integer",
                        "example": 0
                    },
                    "cantidad_fotos_salida": {
                        "type": "integer",
                        "example": 0
                    }
                },
                "type": "object"
            },
            "Empleado": {
                "title": "Empleado",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 4
                    },
                    "user_id": {
                        "type": "integer",
                        "example": 5,
                        "nullable": true
                    },
                    "nombre": {
                        "type": "string",
                        "example": "OPERARIO BODEGA"
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "example": "bodega@test.com"
                    },
                    "cargo_id": {
                        "type": "integer",
                        "example": 4
                    },
                    "jefe_id": {
                        "type": "integer",
                        "example": 2,
                        "nullable": true
                    },
                    "salario_mensual": {
                        "type": "number",
                        "format": "float",
                        "example": 600
                    },
                    "porcentaje_cupo_prestamo": {
                        "type": "number",
                        "example": 100
                    },
                    "aplica_iess": {
                        "type": "boolean",
                        "example": true
                    },
                    "mensualiza_decimos": {
                        "type": "boolean",
                        "example": true
                    },
                    "aplica_fondos_reserva": {
                        "type": "boolean",
                        "example": false
                    },
                    "cargo": {
                        "$ref": "#/components/schemas/Cargo"
                    }
                },
                "type": "object"
            },
            "Asistencia": {
                "title": "Asistencia",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 346
                    },
                    "empleado_id": {
                        "type": "integer",
                        "example": 4
                    },
                    "fecha": {
                        "type": "string",
                        "format": "date",
                        "example": "2026-08-21"
                    },
                    "hora_entrada": {
                        "type": "string",
                        "example": "07:55:00"
                    },
                    "hora_salida": {
                        "type": "string",
                        "example": "17:05:00",
                        "nullable": true
                    },
                    "lat_entrada": {
                        "type": "number",
                        "format": "float",
                        "example": -2.1894128,
                        "nullable": true
                    },
                    "lng_entrada": {
                        "type": "number",
                        "format": "float",
                        "example": -79.8890662,
                        "nullable": true
                    },
                    "minutos_retraso": {
                        "type": "number",
                        "example": 0
                    },
                    "horas_trabajadas": {
                        "type": "number",
                        "example": 8.5
                    },
                    "horas_extras_calculadas": {
                        "type": "number",
                        "example": 0.5
                    },
                    "horas_extras_aprobadas": {
                        "type": "number",
                        "example": 0
                    },
                    "estado_aprobacion": {
                        "type": "string",
                        "example": "aprobado",
                        "enum": [
                            "pendiente",
                            "aprobado",
                            "rechazado"
                        ]
                    },
                    "monto_descuento": {
                        "type": "number",
                        "example": 0
                    },
                    "motivo_descuento": {
                        "type": "string",
                        "example": "Regla: Retraso Leve (15 min retraso)",
                        "nullable": true
                    }
                },
                "type": "object"
            }
        },
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "description": "Token obtenido desde POST /api/login",
                "bearerFormat": "Token Sanctum",
                "scheme": "bearer"
            }
        }
    },
    "tags": [
        {
            "name": "Auditoría",
            "description": "Registro inmutable de cambios (compliance)"
        },
        {
            "name": "Cargas familiares",
            "description": "Base del 5% de utilidades (cónyuge 1 · hijo/padre 0.5)"
        },
        {
            "name": "Chat",
            "description": "Chat interno entre empleados (tiempo real vía Pusher + historial en BD)"
        },
        {
            "name": "Comisiones",
            "description": "Comisiones por ventas: configuración por empleado, registro mensual de ventas y regla de equipo parametrizable"
        },
        {
            "name": "Contratos",
            "description": "Contratos de trabajo con control de vencimiento"
        },
        {
            "name": "Décimos",
            "description": "Motor de décimos tercero/cuarto: acumulación, adelantos, pago anual, cierre de año"
        },
        {
            "name": "Evidencias",
            "description": "Consulta de evidencias fotográficas guardadas como ruta"
        },
        {
            "name": "Facturas de empleados",
            "description": "Facturas mensuales para empleados con modalidad de pago por facturación"
        },
        {
            "name": "Feriados",
            "description": "Calendario de feriados (Ecuador)"
        },
        {
            "name": "Reportes gerenciales",
            "description": "Dashboard ejecutivo y exportaciones (CSV/Excel)"
        },
        {
            "name": "Justificaciones",
            "description": "Justificaciones de ausencias (art. 47 CT)"
        },
        {
            "name": "Liquidaciones",
            "description": "Liquidación de haberes (Código del Trabajo Ecuador)"
        },
        {
            "name": "Notificaciones",
            "description": "Bandeja in-app del usuario (email best-effort)"
        },
        {
            "name": "Conciliación bancaria",
            "description": "Registro de cómo se pagó cada rol/décimo/utilidades"
        },
        {
            "name": "Parámetros legales",
            "description": "Valores legales anuales Ecuador (SBU, IESS, tabla IR SRI)"
        },
        {
            "name": "Pensiones alimenticias",
            "description": "Órdenes judiciales de pensión (prioridad absoluta de descuento)"
        },
        {
            "name": "Rubros de pago",
            "description": "Ingresos adicionales por empleado (lactancia, enfermedad, almuerzo...) con vigencia temporal"
        },
        {
            "name": "Sucursales",
            "description": "Sucursales en árbol con geocerca GPS para validación de asistencia"
        },
        {
            "name": "Turnos",
            "description": "Turnos de trabajo (si el empleado no tiene turno se usan parámetros generales)"
        },
        {
            "name": "Utilidades",
            "description": "Reparto del 15%: 10% por salarios + 5% por cargas familiares"
        },
        {
            "name": "Visitas Agendadas",
            "description": "Visitas Agendadas"
        },
        {
            "name": "Supervisión",
            "description": "Supervisión"
        },
        {
            "name": "Asistencia",
            "description": "Asistencia"
        },
        {
            "name": "Autenticación",
            "description": "Autenticación"
        },
        {
            "name": "Configuración",
            "description": "Configuración"
        },
        {
            "name": "Dashboard",
            "description": "Dashboard"
        },
        {
            "name": "Empleados",
            "description": "Empleados"
        },
        {
            "name": "Nómina",
            "description": "Nómina"
        },
        {
            "name": "Roles y Permisos",
            "description": "Roles y Permisos"
        },
        {
            "name": "Sanciones",
            "description": "Sanciones"
        },
        {
            "name": "Usuarios",
            "description": "Usuarios"
        },
        {
            "name": "Vacaciones",
            "description": "Vacaciones"
        },
        {
            "name": "Visitas",
            "description": "Visitas"
        }
    ]
}