{"openapi":"3.1.0","info":{"title":"API Documentation","version":"1.0.0","description":"API  REST para la gestión de nóminas y conceptos asociados.\n\n  **IMPORTANTE: TODOS LOS ENDPOINTS REQUIEREN AUTENTICACIÓN BÁSICA (Basic Auth)**\n\nPara acceder a cualquier endpoint, debes incluir el header:\n`Authorization: Basic base64(usuario:contraseña)`\n\n\nEjemplo:\n`Authorization: Basic YWRtaW46YWRtaW4xMjM=`"},"servers":[{"url":"/api","description":"API Server"}],"components":{"securitySchemes":{"basicAuth":{"type":"http","scheme":"basic","description":"Autenticación básica requerida. Header: Authorization: Basic base64(usuario:contraseña)"}},"schemas":{},"parameters":{}},"paths":{"/conceptos":{"get":{"tags":["Conceptos"],"summary":"Obtener lista de conceptos","description":"Retorna todos los conceptos disponibles en el sistema","security":[{"basicAuth":[]}],"responses":{"200":{"description":"Lista de conceptos","content":{"application/json":{"schema":{"type":"object","properties":{"conceptos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"nombre":{"type":"string","example":"0001-B002"},"descripcion":{"type":"string","example":"Horas Extras"}},"required":["id","nombre"]}},"total":{"type":"integer"}},"required":["conceptos","total"]}}}},"500":{"description":"Error interno del servidor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}},"required":["success","error","message"]}}}}}}},"/empleados/codigo/{codigo}":{"get":{"tags":["Empleados"],"summary":"Buscar empleado por código","description":"Obtiene la información de un empleado específico por su código","security":[{"basicAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"0027"},"required":true,"name":"codigo","in":"path"}],"responses":{"200":{"description":"Empleado encontrado","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","nullable":true,"properties":{"EMPLEADO":{"type":"string","description":"Código del empleado"},"NOMBRE":{"type":"string","description":"Nombre completo del empleado"},"IDENTIFICACION":{"type":"string","nullable":true,"description":"Número de identificación"},"ACTIVO":{"type":"string","nullable":true,"description":"Estado activo (S/N)"},"CENTRO_COSTO":{"type":"string","nullable":true,"description":"Centro de costo"},"DEPARTAMENTO":{"type":"string","nullable":true,"description":"Departamento"},"PUESTO":{"type":"string","nullable":true,"description":"Puesto"},"FECHA_NACIMIENTO":{"type":"string","nullable":true,"description":"Fecha de nacimiento"},"SALARIO_REFERENCIA":{"type":"number","nullable":true,"description":"Salario de referencia"},"TELEFONO1":{"type":"string","nullable":true,"description":"Teléfono 1"},"TELEFONO2":{"type":"string","nullable":true,"description":"Teléfono 2"},"E_MAIL":{"type":"string","nullable":true,"description":"Correo electrónico"}},"required":["EMPLEADO","NOMBRE","IDENTIFICACION","ACTIVO","CENTRO_COSTO","DEPARTAMENTO","PUESTO","FECHA_NACIMIENTO","SALARIO_REFERENCIA","TELEFONO1","TELEFONO2","E_MAIL"]}},"required":["success","data"]}}}},"404":{"description":"Empleado no encontrado","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]}}}},"500":{"description":"Error interno del servidor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]}}}}}}},"/empleados/nombre/{nombre}":{"get":{"tags":["Empleados"],"summary":"Buscar empleados por nombre","description":"Busca empleados cuyo nombre contenga el texto especificado (búsqueda parcial)","security":[{"basicAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"Juan"},"required":true,"name":"nombre","in":"path"}],"responses":{"200":{"description":"Lista de empleados encontrados","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"EMPLEADO":{"type":"string","description":"Código del empleado"},"NOMBRE":{"type":"string","description":"Nombre completo del empleado"},"IDENTIFICACION":{"type":"string","nullable":true,"description":"Número de identificación"},"ACTIVO":{"type":"string","nullable":true,"description":"Estado activo (S/N)"},"CENTRO_COSTO":{"type":"string","nullable":true,"description":"Centro de costo"},"DEPARTAMENTO":{"type":"string","nullable":true,"description":"Departamento"},"PUESTO":{"type":"string","nullable":true,"description":"Puesto"},"FECHA_NACIMIENTO":{"type":"string","nullable":true,"description":"Fecha de nacimiento"},"SALARIO_REFERENCIA":{"type":"number","nullable":true,"description":"Salario de referencia"},"TELEFONO1":{"type":"string","nullable":true,"description":"Teléfono 1"},"TELEFONO2":{"type":"string","nullable":true,"description":"Teléfono 2"},"E_MAIL":{"type":"string","nullable":true,"description":"Correo electrónico"}},"required":["EMPLEADO","NOMBRE","IDENTIFICACION","ACTIVO","CENTRO_COSTO","DEPARTAMENTO","PUESTO","FECHA_NACIMIENTO","SALARIO_REFERENCIA","TELEFONO1","TELEFONO2","E_MAIL"]}},"total":{"type":"number"}},"required":["success","data","total"]}}}},"404":{"description":"No se encontraron empleados","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]}}}},"500":{"description":"Error interno del servidor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]}}}}}}},"/extras":{"post":{"tags":["Extras"],"summary":"Crear horas extra para empleado","security":[{"basicAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nomina":{"type":"string","minLength":1},"empleado":{"type":"string","minLength":1},"conceptos":{"type":"array","items":{"type":"object","properties":{"concepto":{"type":"string","minLength":1},"cantidad":{"type":"number","minimum":0}},"required":["concepto","cantidad"]},"minItems":1}},"required":["nomina","empleado","conceptos"]}}}},"responses":{"200":{"description":"Conceptos de nómina creados exitosamente","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"registrosInsertados":{"type":"integer"}},"required":["registrosInsertados"]}},"required":["success","message"]}}}},"400":{"description":"Error de validación","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]}}}},"500":{"description":"Error interno del servidor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]}}}}}}},"/extras-test":{"post":{"tags":["Extras"],"summary":"[TEST] Prueba de inserción con ROLLBACK automático","description":"Prueba la inserción de conceptos extras sin guardar en la BD. Útil para validar antes de hacer cambios reales.","security":[{"basicAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nomina":{"type":"string","minLength":1},"empleado":{"type":"string","minLength":1},"conceptos":{"type":"array","items":{"type":"object","properties":{"concepto":{"type":"string","minLength":1},"cantidad":{"type":"number","minimum":0}},"required":["concepto","cantidad"]},"minItems":1}},"required":["nomina","empleado","conceptos"]}}}},"responses":{"200":{"description":"Prueba exitosa (datos NO guardados)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"test_mode":{"type":"boolean"},"data":{"type":"object","properties":{"empleado":{"type":"string"},"nomina":{"type":"string"},"conceptos_procesados":{"type":"number"},"validaciones":{"type":"object","properties":{"concepto_existe":{"type":"boolean"},"nomina_inicializada":{"type":"boolean"},"cantidad_valida":{"type":"boolean"}},"required":["concepto_existe","nomina_inicializada","cantidad_valida"]}},"required":["empleado","nomina","conceptos_procesados","validaciones"]}},"required":["success","message","test_mode","data"]}}}},"400":{"description":"Error de validación","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"test_mode":{"type":"boolean"}},"required":["success","message","test_mode"]}}}},"500":{"description":"Error interno del servidor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"test_mode":{"type":"boolean"},"error":{"type":"string"}},"required":["success","message","test_mode","error"]}}}}}}},"/nominas":{"get":{"tags":["Nómina"],"summary":"Obtener lista de nóminas","security":[{"basicAuth":[]}],"responses":{"200":{"description":"Lista de nóminas","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"nomina":{"type":"string"},"descripcion":{"type":"string"},"estado":{"type":"string"},"estadoDescripcion":{"type":"string"}},"required":["nomina","descripcion","estado","estadoDescripcion"]}},"total":{"type":"integer"}},"required":["data","total"]}}}},"500":{"description":"Error interno del servidor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}},"required":["success","error","message"]}}}}}}},"/liquidacion":{"post":{"tags":["Liquidación"],"summary":"Liquidación de viáticos desde gerMan (asiento CG en Softland)","description":"\n### Integración GerMan a Softland (Diario)\n\nProcesa el desglose de rubros y genera el asiento contable correspondiente.\n\n**Lógica de Negocio:**\n* **Identificación de Cuenta:** Se busca la cuenta contable mediante el patrón: `\"Tarjeta de Crédito \" + nombre_empleado`.\n* **Validación de Integridad:** El `monto` enviado debe ser exactamente igual a la suma de los montos de cada rubro. No se permite repetir el mismo rubro (tras normalizar espacios y mayúsculas/minúsculas).\n* **Moneda en `[DIARIO]`:** Con `monedaMontos: USD` el nominal va en `*_DOLAR` y la contraparte en `*_LOCAL`; con `CRC` al revés. El `TIPO_CAMBIO` que enlaza con `[TIPO_CAMBIO_HIST]` sale de `[CUENTA_CONTABLE].[TIPO_CAMBIO]` (misma cadena en cuenta haber y en todas las de rubro; si viene vacío se usa TCVE). El factor colones/USD sigue en `[MONEDA_HIST].[MONTO]` (`MONEDA = USD`), fecha ≤ `fechaAsiento`.\n* **Total haber:** `CREDITO_LOCAL` y `CREDITO_DOLAR` se calculan aplicando ese tipo de cambio al `monto` **total** del JSON (totalizado), no solo sumando columnas sin volver a convertir el total.\n* **Orden en `[DIARIO]`:** La línea de haber (tarjeta) usa siempre el último `CONSECUTIVO` del asiento.\n* **Mapeo de Referencias:**\n    * **Líneas de rubro (debe):** Una línea en `[DIARIO]` por rubro; `[REFERENCIA]` viene de `documentos_asociados_rubro`. La cuenta se resuelve en `[CUENTA_CONTABLE]` comparando el `rubro` normalizado con `[U_RUBRO_GERMAN]` del catálogo (ese campo no se escribe en `[DIARIO]`).\n    * **Línea del total:** Una línea por el monto total contra la cuenta del empleado; `[REFERENCIA]` une los `documentos_asociados_rubro` **distintos** (sin repetir el mismo texto; orden de primera aparición), separador ` | `, máximo 249 caracteres.\n\n**Campos en Softland:**\n- `[CUENTA_CONTABLE].[U_RUBRO_GERMAN]`: solo para localizar la cuenta del debe.\n- `[DIARIO].[REFERENCIA]`: documentos por línea o concatenado en el total.\n- `[DIARIO].[FUENTE]`: formato descriptivo o, si no cabe (límite en `longitudMaximaFuenteDiarioViaticos`), prefijo de `fuenteDiarioRespaldoCortaViaticos` recortado a ese máximo (evitar 8152). Compruebe `CHARACTER_MAXIMUM_LENGTH` de la columna en su SQL Server.\n","security":[{"basicAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"monedaMontos":{"type":"string","enum":["USD","CRC"]},"rubros":{"type":"array","items":{"type":"object","properties":{"rubro":{"type":"string","minLength":1},"monto":{"type":"number","minimum":0,"exclusiveMinimum":true},"documentos_asociados_rubro":{"type":"string","minLength":1}},"required":["rubro","monto","documentos_asociados_rubro"]},"minItems":1},"monto":{"type":"number","minimum":0,"exclusiveMinimum":true},"empleado":{"type":"string","minLength":1},"fechaAsiento":{"type":"string","nullable":true}},"required":["monedaMontos","rubros","monto","empleado"]}}}},"responses":{"200":{"description":"Asiento creado","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"datos":{"type":"object","properties":{"asiento":{"type":"string"},"monedaMontos":{"type":"string","enum":["USD","CRC"]},"tipoCambioAplicado":{"type":"object","properties":{"fecha":{"type":"string"},"monto":{"type":"number"},"codigoTipoCambioHist":{"type":"string"}},"required":["fecha","monto","codigoTipoCambioHist"]},"totalCreditoLocal":{"type":"number","nullable":true},"totalCreditoDolar":{"type":"number","nullable":true},"lineas":{"type":"array","items":{"type":"object","properties":{"consecutivo":{"type":"integer"},"centroCosto":{"type":"string"},"cuentaContable":{"type":"string"},"debitoLocal":{"type":"number","nullable":true},"creditoLocal":{"type":"number","nullable":true},"debitoDolar":{"type":"number","nullable":true},"creditoDolar":{"type":"number","nullable":true},"rubro":{"type":"string"},"referenciaEnLinea":{"type":"string"}},"required":["consecutivo","centroCosto","cuentaContable","debitoLocal","creditoLocal","debitoDolar","creditoDolar"]}}},"required":["asiento","monedaMontos","tipoCambioAplicado","totalCreditoLocal","totalCreditoDolar","lineas"]}},"required":["success","message","datos"]}}}},"400":{"description":"Validación (monto vs rubros, cuadre convertido, o `TIPO_CAMBIO` distinto entre cuentas: codigo `tipo_cambio_cuenta`)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"},"codigo":{"type":"string","enum":["validacion","haber","debe","tipo_cambio","tipo_cambio_cuenta","centro_cuenta","interno"]},"descripcionBuscadaHaber":{"type":"string"},"rubrosNoEncontrados":{"type":"array","items":{"type":"string"}},"detalle":{"type":"string"}},"required":["success","message"]}}}},"404":{"description":"Cuenta, rubro, tipo de cambio o CENTRO_CUENTA no encontrados en Softland","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"},"codigo":{"type":"string","enum":["validacion","haber","debe","tipo_cambio","tipo_cambio_cuenta","centro_cuenta","interno"]},"descripcionBuscadaHaber":{"type":"string"},"rubrosNoEncontrados":{"type":"array","items":{"type":"string"}},"detalle":{"type":"string"}},"required":["success","message"]}}}},"500":{"description":"Error interno","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"},"codigo":{"type":"string","enum":["validacion","haber","debe","tipo_cambio","tipo_cambio_cuenta","centro_cuenta","interno"]},"descripcionBuscadaHaber":{"type":"string"},"rubrosNoEncontrados":{"type":"array","items":{"type":"string"}},"detalle":{"type":"string"}},"required":["success","message"]}}}}}}}}}