DOC. SERVICIOS APP - SHALOM FAMILIA


Modulo Inicial

Modulo Inicial

Login de usuario - [validate_user_active]

🧾 Descripción

Valida si un usuario:

  1. Existe y su contraseña es correcta

  2. Está habilitado (enabled = 1) en el Doctype User

Es un servicio simple de autenticación básica, expuesto como endpoint público vía frappe.whitelist(allow_guest=True).


🚀 Endpoint


POST /api/method/validate_user_active

Nota: El nombre final depende del módulo donde esté definida la función.
Ejemplo típico Frappe:
/api/method/app.module.doctype.file.validate_user_active


🔐 Seguridad

⚠️ Esto implica que el endpoint debe usarse únicamente desde un frontend controlado o un gateway seguro.


📥 Request Body

Formato JSON:

{ "usr": "correo@dominio.com", "pwd": "contraseña" }

📤 Responses

200 – Usuario válido

{ "success": true, "message": "Usuario válido y activo (check_password)." }

401 – Credenciales incorrectas

(Realmente devuelve 200 con success=false, pero semánticamente es un error)

{ "success": false, "message": "Usuario o contraseña incorrectos." }

403 – Usuario deshabilitado

{ "success": false, "message": "El usuario está deshabilitado." }

🧩 Lógica Interna (resumen)

  1. Ejecuta check_password(usr, pwd)

    • Si falla → usuario o contraseña incorrectos

  2. Consulta el campo enabled:


    frappe.db.get_value("User", usr, "enabled")
  3. Devuelve éxito solo si:

    • Contraseña correcta

    • Usuario habilitado


📚 Schemas

Entrada

{ "usr": "string", "pwd": "string" }

Salida

{ "success": "bool", "message": "string" }

🧪 Ejemplo de uso (curl)

curl -X POST https://midominio.com/api/method/app.validate_user_active \ -H "Content-Type: application/json" \ -d '{"usr":"admin@example.com", "pwd":"123"}'

Modulo Inicial

Guardar usuario - [saveUsersLogeds]

🧾 Descripción

Registra y actualiza información de usuarios que inician sesión desde la aplicación móvil.
Además, valida si la versión de la app instalada es compatible con la versión mínima definida en el servidor.

Funcionalidad:

  1. Verifica la versión de la app contra versiones.json.

  2. Crea o actualiza el registro de un usuario en la base de datos mysql2.users.

  3. Devuelve mensaje de éxito o error según el proceso.


🚀 Endpoint


POST /save-users-logeds

El nombre real depende del archivo de rutas de Laravel (web.php / api.php).


🔐 Seguridad


📥 Request Body



{ "user": "string", "version": "string" }

Campos

Campo Tipo Requerido Descripción
user string Username que se registra o actualiza.
version string Versión de la app instalada en el dispositivo.

📤 Responses

❗ Importante

En tu código actual, la primera línea retorna inmediatamente:



return [ "valor"=>true, "msn"=> "Registro actualizado", ];

Por lo tanto todo el servicio está anulado.
Si esto es accidental, debes eliminar ese return.

Aun así, la documentación refleja lo que debería hacer según el resto del código.


✔️ Versión actualizada (200 OK)

Si la versión enviada es igual o mayor que la versión mínima del archivo versiones.json:



{ "valor": true, "msn": "Registro Exitoso" }

o

{ "valor": true, "msn": "Registro actualizado" }

Versión desactualizada

{ "valor": false, "msn": "Actualize su aplicacion en Play Store", "version_app": "1.0.1", "version_service": "1.0.5" }

Error al registrar o actualizar usuario

{ "valor": false, "msn": "Registre un usuario" }

o

{ "valor": false, "msn": "Registro Actualizado" }

🧩 Lógica Interna (detallada)

1. Leer versión mínima del archivo:


/public/version-app/versiones.json

Campo utilizado: familia

2. Convertir versiones a enteros

Ejemplo:
“1.2.3” → 123

Esto permite compararlas.

3. Validación:

Si intVersionApp < intVersionDefine → debe actualizar

4. Registrar usuario:

Tablas y campos usados:


users.username users.fecha_primera_s users.fecha_ultima_s

📚 Esquema del JSON de version-app/versiones.json

Se utiliza solo el campo:

{ "familia": "1.0.5" }

🗃 Schemas

Request

{ "user": "string", "version": "string" }

Response

{ "valor": "boolean", "msn": "string", "version_app": "string(optional)", "version_service": "string(optional)" }

🧪 Ejemplo de uso (curl)

curl -X POST https://midominio.com/api/save-users-logeds \ -H "Content-Type: application/json" \ -d '{"user":"jhon.doe","version":"1.0.2"}'

⚠️ Notas importantes para documentación

🔴 Problema detectado

La primera línea del método cancela toda la lógica:

return [ "valor"=>true, "msn"=> "Registro actualizado", ];

Si quieres que el servicio funcione como en la documentación, debes eliminar ese return.

Modulo Inicial

Términos y Condiciones - [setTermsAndConditions]

🧾 Descripción

Registra la aceptación de los Términos y Condiciones por parte del usuario logueado en la aplicación.
El proceso localiza al empleado asociado al user_id (email del usuario) y actualiza los campos:


🚀 Endpoint


POST /set-terms-and-conditions

La ruta exacta depende de cómo esté configurado en tus routes/api.php.


🔐 Seguridad


📥 Request Body

{ "email_logued": "string" }

Campos requeridos:

Campo Tipo Requerido Descripción
email_logued string Email del usuario con el que inició sesión en la app. Este email debe coincidir con el user_id del Employee.

📤 Responses

✔️ 200 – Términos aceptados correctamente

{ "valor": true, "msn": "Terminos y Condiciones Aceptadas Correctamente" }

❌ 400 – Falta el email

{ "valor": false, "msn": "Es necesario el email con el que ha entrado a la app" }

❌ 404 – No existe Employee asociado al usuario

Incluye ambos casos del código:

{ "valor": false, "msn": "Error al traer el empleado asociado" }

❌ 500 – Error al actualizar Employee

{ "valor": false, "msn": "Error al aceptar terminos y condiciones", "error": { ...respuesta ERP... } }

❌ 500 – Error inesperado

{ "valor": false, "msn": "Error en el servicio" }

🧩 Lógica Interna

  1. Validación inicial
    Si email_logued viene vacío → error

  2. Buscar Employee asociado al usuario
    Consulta en ERP:

     

     

    GET Employee?limit=None &fields=["name","terminos_y_condiciones_app"] &filters=[["user_id","=", email_logued]]

     

  3. Manejo de errores:

    • Respuesta sin data

    • Array vacío

  4. Actualizar Employee


    PUT Employee/{employee_name} { "terminos_y_condiciones_app": 1, "fecha_terminos_y_condiciones": "Y-m-d H:i:s" }
  5. Si el response incluye "data" → éxito
    Si no → error


📚 Schemas

Request Schema

{ "email_logued": "string" }

Response Schema

{ "valor": "boolean", "msn": "string", "error": "object (opcional)" }

🧪 Ejemplo de Uso (curl)

curl -X POST https://midominio.com/api/set-terms-and-conditions \ -H "Content-Type: application/json" \ -d '{"email_logued":"user@example.com"}'
Modulo Inicial

Obtener Usuario (1,2,3,4) - [getUser3]

🧾 Descripción

Retorna la información del usuario ingresado en la app (empleado o estudiante).
El servicio consulta primero la tabla Employee del ERP.
Si no existe o no está activo, consulta la tabla Student.
Finalmente, devuelve la información personal, laboral/educativa, permisos y datos complementarios.

Funciona como un servicio maestro de login/datos del usuario para la aplicación móvil.


🚀 Endpoint


POST /get-user3

El nombre real depende del archivo routes/api.php.


🔐 Seguridad


📥 Request Body



{ "username": "string" }

Campos

Campo Tipo Requerido Descripción
username string Email o DNI/pasaporte. Si contiene “@” se asume email, de lo contrario documento.

🧩 Lógica Interna Detallada

1️⃣ Determinar si buscar por email o documento

2️⃣ Consultar información del empleado en ERP

Consulta SQL con múltiples JOIN:

Tablas involucradas:

Si no encuentra empleado → pasa a modo estudiante.


❌ Errores de empleado antes de consultar estudiante:


3️⃣ Consultar información del estudiante (fallback)

Si el usuario no es empleado, consulta en:

Validaciones de estudiante:

{ "valor": false, "msn": "Usuario Deshabilitado...", "data": [...] }

Si todo está correcto → retorna data del estudiante.


4️⃣ Procesamiento final de empleado

Validaciones

Ajustes en la data:


5️⃣ Respuesta final (Empleado o Estudiante)

Retorna la data enriquecida del usuario.


📤 Responses

✔️ 200 – Usuario encontrado



{ "valor": true, "msn": "Si hay data", "data": [ ... ] }

❌ Usuario no es empleado ni estudiante



{ "valor": false, "msn": "Este usuario no es empleado", "data": [] }

❌ Usuario estudiante sin permisos



{ "valor": false, "msn": "Sin Estudiante: Su usuario no tiene permisos para acceder al aplicativo. Contactar con soporte.", "data": [] }

❌ Usuario deshabilitado



{ "valor": false, "msn": "Usuario Deshabilitado: Comuníquese con su administrador", "data": [ ... ] }

❌ Empleado inactivo



{ "valor": false, "msn": "Empleado Inactivo: Comuníquese con su administrador", "data": [ ... ] }

📚 Schemas

Request



{ "username": "string" }

Response (general)



{ "valor": "boolean", "msn": "string", "data": "array" }

🧪 Ejemplo de uso (curl)



curl -X POST https://midominio.com/api/get-user3 \ -H "Content-Type: application/json" \ -d '{"username":"empleado@empresa.com"}'

✔️ Servicios ERP usados internamente

1. send-query-database

Método POST que ejecuta consultas SQL personalizadas en ERPNext.

2. resource/Contrato de Trabajo

Consulta REST para obtener contratos de trabajo.


📝 Observaciones técnicas (reales)

Modulo Inicial

Obtener Version - [version]

🧾 Descripción

Obtiene la versión actual de una aplicación móvil específica.
El servicio valida si el identificador de la app existe y, de ser así, devuelve la versión correspondiente.

Este endpoint se usa para:


🚀 Endpoint


POST /version

La ruta final dependerá del archivo de rutas (routes/api.php).


🔐 Seguridad


📥 Request Body

{ "app": "string" }

Campos

Campo Tipo Requerido Descripción
app string Identificador de la aplicación cuya versión se desea consultar.

📤 Responses

✔️ 200 – App encontrada (Versión obtenida)

{ "valor": true, "msn": "Versión del app MiApp: 1.0.5", "version": "1.0.5" }

El nombre mostrado proviene de: $name_app = $this->apps[$app];

La versión proviene de: $versiones = $this->data(); $version = $versiones[$app];


❌ 404 / 200 – App no existente

 

{ "valor": false, "msn": "No existe esa app" }

Nota: El método devuelve 200 OK incluso cuando la app no existe.
(Esto es comportamiento actual del código.)


🧩 Lógica Interna

  1. Recibe el parámetro app.

  2. Obtiene todas las versiones desde $this->data()
    (método interno que no está mostrado pero retorna un array asociativo).

  3. Valida si la clave app existe en el array versiones:

    • No existe → error

    • Existe → procede

  4. Obtiene el nombre de la app desde: $this->apps[$app]

  5. Obtiene la versión asociada: $versiones[$app]

  6. Devuelve la versión actual en el message.


📚 Schema

Request

{ "app": "string" }

Response

{ "valor": "boolean", "msn": "string", "version": "string (opcional)" }

🧪 Ejemplo de Uso (curl)

curl -X POST https://midominio.com/api/version \ -H "Content-Type: application/json" \ -d '{"app":"shalom_app"}'

Respuesta esperada:

{ "valor": true, "msn": "Versión del app Shalom App: 3.1.4", "version": "3.1.4" }
Modulo Inicial

Rol de usuario - [rolUsuario]

🧾 Descripción

Valida si un usuario tiene el rol "Supervisor Nacional" dentro del ERP.
Busca en la tabla tabHas Role un registro cuya columna role = 'Supervisor Nacional' y parent = {name_usuario}.


🚀 Endpoint


POST /rol-usuario

La ruta exacta depende de tu archivo routes/api.php.


🔐 Seguridad


📥 Request Body

JSON

{ "name": "string" }

Campos

Campo Tipo Requerido Descripción
name string Nombre interno del usuario en ERPNext (us.name).

🧩 Lógica Interna del Servicio (resumen)

  1. Toma name desde el request.

  2. Construye una consulta SQL hacia ERP que busca:

    • El usuario (rol.parent)

    • El rol "Supervisor Nacional" (rol.role)

  3. Ejecuta:

    • dbErp("POST", body, method/send-query-database)

  4. Si encuentra el rol → retorna verdadero

  5. Si no lo encuentra → indica que no es supervisor

  6. Maneja errores con try/catch.


📤 Responses

✔️ 200 – Usuario es Supervisor Nacional

{ "value": true, "msn": "Listado exitoso", "data": true }

❌ 200 – Usuario NO es supervisor

{ "value": false, "msn": "Usuario no es supervisor", "data": false }

❌ 500 – Error interno al procesar

{ "value": false, "msn": "Mensaje de excepción" }

📚 Schemas

Request

{ "name": "string" }

Response

{ "value": "boolean", "msn": "string", "data": "boolean (solo en éxito o denegado)" }

🧪 Ejemplo de uso (curl)

curl -X POST https://midominio.com/api/rol-usuario \ -H "Content-Type: application/json" \ -d '{"name":"jhon.doe@empresa.com"}'
Modulo Inicial

Permisos del modulo - [permissions-module]

🧾 Descripción

Devuelve un listado de permisos de módulos habilitados para el usuario autenticado en la app.
Además, determina si el usuario tiene acceso al módulo “solicitudes_de_pagos”, validándolo contra listas internas y datos del ERP (tabla Validacion de Pagos Gerencia).


🚀 Endpoint


POST /permissions-modules

🔐 Seguridad


📥 Request Body



{ "usuario": "string" }

Campos

Campo Tipo Requerido Descripción
usuario string Email del usuario de la app.

📤 Responses

✔️ 200 – Respuesta exitosa

{ "valor": true, "msn": "lista de dni validacion módulos", "data": { "informacion_personal": true, "marcaciones": true, "otros_descuentos": true, "capacitacion": true, "contrato_de_trabajo": true, "boletas_de_pago": true, "solicitudes": true, "reconocimiento_de_deuda": true, "centro_de_ayuda": true, "supervision": true, "asistencia": true, "contratacion": true, "convocatoria": true, "documentos_internos": true, "solicitudes_de_pagos": true } }

Nota: El valor de solicitudes_de_pagos depende del usuario.


❌ 400 – Falta el usuario en la solicitud



{ "valor": false, "msn": "Debe enviar el usuario" }

🧩 Lógica Interna

1. Validar que se envíe el parámetro usuario

Si no existe → retorna error.

2. Lista inicial de usuarios con permiso en solicitudes_de_pagos

Hardcoded en el código:

[ "45738484@shalomcontrol.com", "40650120@shalomcontrol.com", "40377937@shalomcontrol.com" ]

3. Consulta al ERP

Consulta la tabla: tabValidacion de Pagos Gerencia

Utiliza: SELECT usuario FROM `tabValidacion de Pagos Gerencia`

Si la respuesta contiene valores, se agregan a la lista general.

4. Mezcla de listas

Se combinan:

5. Validación final

solicitudes_de_pagos = in_array(usuario, lista_combinada)

6. Todos los demás permisos se marcan como true


📚 Schema de Respuesta

data (permisos)

{ "informacion_personal": true, "marcaciones": true, "otros_descuentos": true, "capacitacion": true, "contrato_de_trabajo": true, "boletas_de_pago": true, "solicitudes": true, "reconocimiento_de_deuda": true, "centro_de_ayuda": true, "supervision": true, "asistencia": true, "contratacion": true, "convocatoria": true, "documentos_internos": true, "solicitudes_de_pagos": "boolean dinámico" }

🧪 Ejemplo de uso (curl)

curl -X POST https://midominio.com/api/permissions-modules \ -H "Content-Type: application/json" \ -d '{"usuario":"user@example.com"}'

Modulo Inicial

Verificar *** - [verifyDownloadSalary]

🧾 Descripción

Valida si un trabajador ha descargado su boleta de pago correspondiente al mes anterior.
La validación solo aplica del día 1 al 7 de cada mes; fuera de ese rango, se asume automáticamente como validación positiva.

El servicio consulta el registro de descargas en la tabla historial_procesos_app.


🚀 Endpoint


POST /verify-download-salary

La ruta final depende de cómo esté configurada en routes/api.php.


🔐 Seguridad

No se valida token en el controlador, pero se recomienda proteger el endpoint detrás de autenticación de la app.


📥 Request Body

{ "employee": "string", "fechaIngreso": "string (YYYY-MM-DD)" }

Campos requeridos

Campo Tipo Obligatorio Descripción
employee string Código del empleado (ID del trabajador).
fechaIngreso string Fecha de ingreso del trabajador en formato YYYY-MM-DD.

🧠 Reglas de negocio

  1. Validación por fecha
    Si la fecha actual es mayor al día 7 del mes → no corresponde validación.

  2. Obtiene el mes anterior y convierte el número en texto (ej. 01 → Enero).

  3. Si fechaIngreso >= primer día del mes actual, entonces el trabajador ingresó recientemente → no se valida descarga.

  4. Consulta en la BD (mysql2.historial_procesos_app) si existe un registro:

    • proceso = 'NOMINA'

    • empleado = <employee>

    • month y year del mes anterior

    • Registros con fecha ascendente

  5. Si existe registro → sí descargó
    Si no → debe descargar su boleta pendiente.


📤 Responses

🟦 Caso 1: Fuera del rango de fechas (después del día 7)

{ "valor": true, "msg": "No corresponde validación, fuera de fecha." }

🟥 Error: falta fecha de ingreso

{ "valor": false, "msg": "Debe enviar la fecha de ingreso del trabajador" }

🟥 Error: falta empleado

{ "valor": false, "msg": "Debe enviar el código de empleado del trabajador" }

🟦 Caso 2: Ingreso reciente (no se valida)

{ "valor": true, "msg": "No corresponde validación" }

🟩 Caso 3: El trabajador SÍ descargó su boleta

{ "valor": true, "msg": "Si descargó boleta." }

🟥 Caso 4: El trabajador NO descargó su boleta

{ "valor": false, "msg": "Tiene pendiente descargar su boleta de pago del mes de <MesTexto> <Año>, descárguelo desde el módulo Boletas de Pago." }

Ejemplo:

{ "valor": false, "msg": "Tiene pendiente descargar su boleta de pago del mes de Enero 2025, descárguelo desde el módulo Boletas de Pago." }

🔎 Ejemplo de consumo (curl)

curl -X POST https://midominio.com/api/verify-download-salary \ -H "Content-Type: application/json" \ -d '{"employee":"EMP-001","fechaIngreso":"2023-02-15"}'
Modulo Inicial

Obtener publicaciones - [obtainPosts2]

🧾 Descripción

Obtiene publicaciones (posts) asociadas a un usuario y una categoría determinada.
La lógica de filtrado, cacheo o búsqueda se realiza internamente mediante el método:

$this->postsCache($user, $category)

Este servicio únicamente recibe los parámetros, solicita la data a postsCache() y devuelve la respuesta.


🚀 Endpoint


POST /obtain-posts

El nombre final dependerá de tu archivo routes/api.php.


🔐 Seguridad

No realiza autenticación explícita.
Si requieres seguridad, debe implementarse a nivel de ruta (middleware).


📥 Request Body

{ "cookie": "string (opcional)", "user": "string", "category": "string" }

Campos

Campo Tipo Requerido Descripción
cookie string No Cookie del usuario. En este servicio no se usa, pero está recibido.
user string ID o email del usuario para obtener las publicaciones.
category string Categoría de las publicaciones a listar.

📤 Respuesta (200 OK)

Ejemplo de respuesta:

{ "data": [ // contenido devuelto por postsCache() ] }

La estructura interna depende íntegramente de lo que retorne postsCache().


🧩 Lógica Interna (resumen)

  1. Recibe cookie, user, y category.

  2. Llama a: postsCache($user, $category)

  3. Devuelve un JSON simple:

    { "data": <resultado> }

📚 Schema de Respuesta

{ "data": "array | object según postsCache()" }

🧪 Ejemplo en curl

curl -X POST https://midominio.com/api/obtain-posts \ -H "Content-Type: application/json" \ -d '{"user":"user@example.com","category":"capacitacion"}'
Modulo Inicial

Página nueva - [registerLikeForPosts]

🧾 Descripción

Permite registrar un Like o Dislike sobre una publicación del módulo Publicaciones en ERPNext.
La acción se ejecuta usando el endpoint interno frappe.desk.like.toggle_like, el cual requiere un cookie de sesión válido.


🚀 Endpoint


POST /register-like-for-posts

La ruta exacta depende de tu archivo routes/api.php.


🔐 Seguridad

Este endpoint requiere el cookie de sesión Frappe, el cual se envía desde la aplicación móvil.
Sin el cookie, el servicio rechaza la operación.


📥 Request Body

{ "cookie": "string", "name": "string", "marked": true }

Campos requeridos:

Campo Tipo Requerido Descripción
cookie string Cookie de sesión válido en ERPNext.
name string Nombre del documento Publicaciones al que se aplicará Like/Dislike.
marked boolean true = Like, false = Dislike.

📤 Responses

✔️ 200 – Like o Dislike registrado correctamente

{ "valor": true, "msn": "Like para publicación correcto", "data": [] }

(El mensaje cambia dependiendo de marked)


400 – Falta de parámetros

Falta nombre

{ "valor": false, "msn": "Es necesario el nombre de la publicación para dar like", "data": [] }

Falta marked

{ "valor": false, "msn": "Es necesario el estado del like", "data": [] }
{ "valor": false, "msn": "Es necesario el cookie para dar like", "data": "cookie_recibida" }

500 – Error desde ERPNext

{ "valor": false, "msn": "Error al generar Servicio", "data": "<detalle_del_error>" }

🧩 Lógica Interna

  1. Valida parámetros obligatorios: name, marked, cookie.

  2. Construye la propiedad add:

    • marked = true"Yes"

    • marked = false"No"

  3. Construye la llamada a ERPNext:


    POST /method/frappe.desk.like.toggle_like Headers: Cookie: <cookie> Content-Type: application/json Body: { "doctype": "Publicaciones", "name": "<nombre>", "add": "Yes/No" }
  4. ERPNext registra o quita el Like.

  5. Devuelve mensaje según operación: "Like" o "Dislike".


📚 Schemas

Request Schema

{ "cookie": "string", "name": "string", "marked": "boolean" }

Response Schema

{ "valor": "boolean", "msn": "string", "data": "array | object" }

🧪 Ejemplo de uso (curl)

curl -X POST https://midominio.com/api/register-like-for-posts \ -H "Content-Type: application/json" \ -d '{ "cookie": "sid=12345abcde", "name": "PUB-00012", "marked": true }'
Modulo Inicial

Obtener Comentarios Post (1) - [obtain-comments2]

🧾 Descripción

Obtiene los comentarios de una publicación específica del módulo Publicaciones (Frappe/ERPNext) junto con información adicional del empleado que realizó cada comentario.
El servicio:

  1. Consulta los comentarios del documento Publicaciones/{post_name}.

  2. Obtiene la lista de empleados activos desde ERP para enlazar owner → nombre_completo.

  3. Ordena todos los comentarios por fecha de creación en orden ascendente.

  4. Devuelve la lista final enriquecida con el nombre completo del usuario comentador.


🚀 Endpoint


POST /obtain-comments-by-post

(La ruta final depende de la configuración en routes/api.php)


🔐 Seguridad


📥 Request Body

{ "cookie": "string", "post_name": "string", "start": 0, "limit": 10 }

Campos

Campo Tipo Requerido Descripción
cookie string Cookie de sesión enviada por ERP para realizar consultas autenticadas.
post_name string Nombre (ID) de la publicación en ERP, ejemplo: "PUB-0001".
start number No Índice inicial para paginación de comentarios.
limit number No Cantidad máxima de comentarios a obtener.

📤 Responses

✔️ 200 – Comentarios obtenidos correctamente

{ "data": [ { "owner": "user@example.com", "name": "COM-0001", "content": "Buen trabajo equipo!", "creation": "2025-01-01 10:30:00", "nombre_completo": "Juan Pérez" } ] }

❌ 400/500 – Error en la solicitud a ERPNext

Si ocurre una excepción desde Guzzle (cookie inválida, publicación inexistente, etc.):

Respuesta directa del error de ERPNext, ejemplo:

{"exc": ["Traceback...", "..."]}

🧩 Lógica Interna (Resumen Técnico)

  1. Validación de entradas

    • Se extraen: cookie, post_name, start, limit.

  2. Consulta de comentarios

    • Endpoint Frappe llamado: GET APICAPACITACION/resource/Publicaciones/{post_name}

    • Envia parámetros:

      fields: [] filters: [] limit_start: start limit_page_length: limit
  3. Consulta de empleados activos

    • Solicita: Employee?fields=["name","nombre_completo","user_id"]&filters=[["status","=","Active"]]

    • Construye un mapa: user_id → nombre_completo

  4. Enriquecimiento de comentarios

    • A cada comentario se le agrega: nombre_completo = jsonEmployee[owner] ?? owner

  5. Ordenamiento

    • Orden ascendente por la fecha creation.

  6. Resultado final

{ "data": [ ...comentarios_ordenados... ] }

📚 Schema de respuesta final

Comentario:

{ "owner": "string", "name": "string", "content": "string", "creation": "datetime", "nombre_completo": "string" }

🧪 Ejemplo de uso (curl)

curl -X POST https://midominio.com/api/obtain-comments-by-post \ -H "Content-Type: application/json" \ -d '{ "cookie":"sid=abc123", "post_name":"PUB-0005", "start":0, "limit":20 }'
Modulo Inicial

Enviar Comentarios Post (1) - [sendComment]

🧾 Descripción

Registra un nuevo comentario dentro de una publicación del módulo de “Publicaciones” en ERP/Capacitación.

El servicio envía la información del comentario a un endpoint del ERP mediante autenticación por cookie.


🚀 Endpoint


POST /send-comment

La ruta real depende del archivo de rutas Laravel (api.php).


🔐 Seguridad


Cookie: session_id=...

📥 Request Body

{ "content": "string", "parent": "string", "cookie": "string" }

Descripción de campos

Campo Tipo Requerido Descripción
content string Texto del comentario.
parent string ID del documento Publicaciones al que pertenece el comentario.
cookie string Cookie de sesión válida del ERP.

Otros campos se envían de forma fija al backend:

{ "parenttype": "Publicaciones", "parentfield": "comments" }

📤 Responses

✔️ 200 – Comentario creado correctamente

{ "valor": true, "msn": "Creado correctamente", "data": { ... } }

400 – Error en datos del cliente

El servicio no valida explícitamente los campos, pero si backend rechaza:

{ "valor": "false", "msn": "Error de servidor", "data": "Detalle del error del ERP" }

500 – Error al procesar la solicitud

Cuando la API del ERP responde con error:

{ "valor": "false", "msn": "Error de servidor", "data": "<mensaje de error>" }

🧩 Lógica interna del servicio

  1. Crea un cliente ApiRest con manejo de cookies.

  2. Construye los datos del comentario:

    • content

    • parent (publicación)

    • parenttype = Publicaciones

    • parentfield = comments

  3. Envía un POST al endpoint del ERP:


    {APICAPACITACION}/resource/postComend2
  4. Maneja error HTTP (BadResponseException).

  5. Si la respuesta contiene data, devuelve éxito.

  6. Si no, marca error de creación.


🗃 Schemas

Request Schema

{ "content": "string", "parent": "string", "cookie": "string" }

Response Schema

{ "valor": "boolean|string", "msn": "string", "data": "object" }

🧪 Ejemplo de uso (curl)

curl -X POST https://midominio.com/api/send-comment \ -H "Content-Type: application/json" \ -d '{ "content":"Excelente publicación", "parent":"PUB-00045", "cookie":"sid=cd2312fa..." }'

Modulo Información Personal

Modulo Información Personal

Obtener Usuario (2) - [get-user3]

🧾 Descripción

Obtiene la información completa de un usuario del sistema, ya sea Empleado o Estudiante, de acuerdo al identificador enviado (email o DNI/pasaporte).
Retorna datos personales, laborales, de contrato y estado del usuario.
Si es empleado, consulta tablas de Employee —si no existe— consulta Student.


🚀 Endpoint


POST /get-user3

La ruta final depende de tus archivos api.php.


🔐 Seguridad


📥 Request Body

{ "username": "string" }

Parámetros

Campo Tipo Requerido Descripción
username string Email del usuario o número de documento/pasaporte.

📤 Respuestas

✔️ 200 – Usuario encontrado (Empleado)


{ "valor": true, "msn": "Si hay data", "data": [ { "name": "EMP000123", "employee_name": "Juan Pérez", "tipo_usuario": "Empleado", "status": "Active", "vigencia_contrato": "2024-01-01 hasta 2024-12-31", "contratacion": "primer_contrato", "pets": "0", "fecha_de_nacimiento": "05-12", "...": "otros_campos" } ] }

✔️ 200 – Usuario encontrado (Estudiante)

{ "valor": true, "msn": "Si hay data", "data": [ { "name": "STU00234", "employee_name": "Estudiante Ejemplo", "tipo_usuario": "Estudiante", "statusUser": 1, "fecha_de_nacimiento": "", "...": "otros_campos" } ] }

❌ Usuario no encontrado en Employee ni Student


{ "valor": false, "msn": "Sin Estudiante: Su usuario no tiene permisos para acceder al aplicativo. Contactar con soporte.", "data": [] }

❌ Empleado inactivo


{ "valor": false, "msn": "Empleado Inactivo: Comuníquese con su administrador para que pueda verificar el estado de su empleado.", "data": [ ... ] }

❌ Usuario estudiante deshabilitado


{ "valor": false, "msn": "Usuario Deshabilitado: Comuníquese con su administrador para que pueda verificar el estado de su empleado.", "data": [ ... ] }

🧩 Lógica del Servicio

1️⃣ Determinar tipo de búsqueda

Si el username contiene @, se busca por: Employee.user_id = username

Si no: Employee.passport_number = username


2️⃣ Consulta principal (Employee)

Usa dbErp con una consulta SQL dinámica unida a:

Si no hay resultados → se intenta en Student.


3️⃣ Consulta secundaria (Student)

Busca en:

Si no existe → usuario sin permisos.


4️⃣ Validaciones adicionales


5️⃣ Validación de contratos

Se consulta: resource/Contrato de Trabajo

Se determina:


6️⃣ Ajuste final de campos


📚 Response Schema

Para Empleado

Incluye (parcial):

Campo Descripción
name ID del Employee
employee_name Nombre completo
tipo_usuario "Empleado"
status Active, PreActivo, Inactive
vigencia_contrato Rango de fechas
contratacion primer_contrato / renovacion
pets Valor convertido a string
fecha_de_nacimiento mm-dd

Más de 40 campos adicionales según tu SQL.


Para Estudiante

Incluye:

Campo Descripción
name ID del Student
employee_name Nombre completo
tipo_usuario Estudiante
statusUser 1 ó 0
user_image Foto
gender Género
dni Documento

🧪 Ejemplo curl

curl -X POST https://midominio.com/api/get-user3 \ -H "Content-Type: application/json" \ -d '{"username": "juan.perez@empresa.com"}'
Modulo Información Personal

Actualizar Datos del Usuario (1) - [update-perfil-info]

🧾 Descripción

Actualiza la información de perfil del empleado dentro del ERP (doctype Employee) mediante una petición PUT, modificando uno o varios de los siguientes datos:

Solo actualiza los campos enviados; los no enviados no se modifican.


🚀 Endpoint


PUT /update-date-perfil

La ruta real depende del archivo routes/api.php.


🔐 Seguridad


📥 Request Body


{ "employe": "HR-EMP-001", "celular": "987654321", "correo": "example@correo.com", "direccion": "Av. Los Olivos 123" }

Campos

Campo Tipo Requerido Descripción
employe string ✔️ Sí ID del empleado en ERPNext (Employee.name).
celular string No Nuevo número de celular.
correo string No Nuevo correo personal. (Actualiza personal_email).
direccion string No Nueva dirección permanente del empleado.

🧩 Validaciones

  1. employe vacío → se devuelve error mediante responseValidate().

  2. Los demás campos son opcionales.

  3. Solo se actualizan los campos enviados.


📤 Responses

✔️ 200 – Actualización exitosa

{ "value": false, "msn": "Actualizacion Exitosa", "data": { ...respuesta del ERPNext... } }

Nota: El valor "value": false parece un bug en tu código, ya que indica éxito pero devuelve false.
Te lo dejo documentado según tu implementación real.


❌ 400 – Faltan parámetros requeridos

Ejemplo cuando no se envía employe:


{ "valor": false, "msn": "Debe enviar el empleado", "data": [] }

(Respuesta generada por responseValidate())


🧠 Lógica Interna (Resumen)

  1. Recibe parámetros del request.

  2. Si employe está vacío → error.

  3. Crea un arreglo updateKeys solo con los campos enviados.

  4. Llama a:


PUT /api/resource/Employee/{employe}

Con el body:

{ "cell_number": "...", "personal_email": "...", "permanent_address": "..." }
  1. Devuelve la respuesta del ERP.


📚 Schemas

Request


{ "employe": "string", "celular": "string (opcional)", "correo": "string (opcional)", "direccion": "string (opcional)" }

Response

{ "value": "boolean", "msn": "string", "data": "object (respuesta del ERP)" }

🧪 Ejemplo de Uso (curl)

curl -X PUT https://midominio.com/api/update-date-perfil \ -H "Content-Type: application/json" \ -d '{ "employe": "EMP-0005", "celular": "987654321", "correo": "nuevo@correo.com", "direccion": "Calle 123" }'
Modulo Información Personal

Actualizar Imagen de Perfil del Usuario (1) - [update-img-user]

🧾 Descripción

Actualiza la imagen de perfil de un usuario en ERPNext.
El proceso incluye:

  1. Recepción de un archivo enviado desde la app.

  2. Subida del archivo al endpoint de ERPNext: method/upload_file.

  3. Obtención de la URL generada del archivo.

  4. Actualización del campo user_image del User.

  5. Actualización del campo image en el Employee asociado (si existe).


🚀 Endpoint


POST /update-img-user

La ruta exacta dependerá del archivo de rutas Laravel (api.php).


🔐 Seguridad


📥 Request (Multipart / Form-Data)

Campos requeridos

Campo Tipo Requerido Descripción
file file Imagen a subir (jpg, png, etc.)
user string Nombre del usuario en ERPNext para actualizar (User.name).

Ejemplo (form-data)


file: avatar.png user: user@example.com

📤 Responses

✔️ 200 – Imagen actualizada correctamente


{ "valor": true, "msn": "Imagen de usuario actualizado correctamente", "data": { ... } }

❌ 400 – Faltan datos o error al subir archivo

Ejemplo de error al no recibir archivo:


{ "msn": "File could not be processed" }

❌ 500 – Error de carga o actualización


{ "valor": false, "msn": "Error al actualizar la imagen de usuario", "data": { ... } }

🧩 Lógica Interna

1. Lectura del archivo

$cfile = new \CURLFile($_FILES["file"]['tmp_name'], $_FILES["file"]['type'], $_FILES["file"]['name']);

2. Subida a ERPNext

⚠️ Se sube el archivo como usuario Guest.

3. Validación de respuesta

Debe existir: message.file_url

Si no existe → error.

4. Actualizar información del User

PUT resource/User/{user} { "user_image": "<file_url>" }

5. Actualizar Employee si corresponde


SELECT user_id, name FROM tabEmployee WHERE user_id = {user}

Si existe:

PUT resource/Employee/{employee_id} { "image": "<file_url>" }

📚 Request/Response Schemas

Request (multipart/form-data)


file: File user: string

Response (success)

{ "valor": true, "msn": "Imagen de usuario actualizado correctamente", "data": { "user_image": "url_file" } }

🧪 Ejemplo de uso (curl)

curl -X POST https://midominio.com/api/update-img-user \ -F "file=@/home/user/avatar.png" \ -F "user=user@example.com"

Modulo de Asistencia y Marcaciones (Marcaciones)


Modulo de Asistencia y Marcaciones (Marcaciones)

Obtiene descarga boleta de pago (1,2,3,4,5,6,7,8) - [getDownloadBoletaPago]

🧾 Descripción General

Este servicio valida si un empleado debe descargar su boleta de pago (Salary Slip) correspondiente al mes anterior.
La validación depende:

La lógica se usa para bloquear marcaciones o solicitudes cuando un trabajador tiene una boleta pendiente por descargar.


🚀 Endpoint


GET /get-download-boleta-pago/{empleado}

Parámetro Path:

Parámetro Tipo Requerido Descripción
empleado string Código del empleado (Employee.name en ERPNext).

🔐 Seguridad

No usa autenticación dentro de esta función, pero depende de endpoints internos ERPNext vía dbErp.
Se recomienda incluirlo dentro de rutas protegidas.


🧠 Flujo Lógico (Resumen Ejecutivo)

  1. Validación de fechas

    • Si el día actual es mayor a 3, no se hace validación → se retorna éxito.

  2. Consultar datos del empleado

    • Obtiene desde ERP:

      • fecha_de_ingreso_real

      • status

  3. Casos especiales por estado

    • Si el empleado está en PreActivo, no se valida.

  4. Determinar si corresponde validar

    • Calcula el último día del mes anterior.

    • Si el ingreso del trabajador es posterior a ese mes → no se valida.

  5. Validar si existe boleta generada

    • Consulta Salary Slip del mes anterior.

    • Si no existe boleta → no corresponde validar.

  6. Validar si la boleta mensual está habilitada (Estado Boleta Mensual)

    • Revisa si está habilitada para ese mes.

  7. Verificar si ya descargó boleta

    • Revisa tabla historial_procesos_app en MySQL.

    • Si no descargó → retorna mensaje de pendiente.

  8. Caso final

    • Si todo está correcto → retorna éxito.


📥 Request

Sin body.
Solo recibe el parámetro {empleado} en la URL.


📤 Responses

✔️ 200 – No corresponde validación (día mayor a 3)



{ "status": true, "msn": "No está dentro del rango de fecha de validación" }

✔️ 200 – Empleado en PreActivo



{ "status": true, "msn": "No validar descarga de boleta en PreActivo" }

✔️ 200 – No corresponde validación (ingresó después)



{ "status": true, "msn": "No tiene boleta de pago por lo tanto no se valida" }

❌ 200 – Boleta pendiente por descargar (validación negativa)



{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su boleta pendiente del mes" }

✔️ 200 – Boleta descargada previamente



{ "status": true, "msn": "Se ha descargado la boleta de pago" }

✔️ 200 – Error capturado (retorna como éxito)

{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }

Este mensaje parece incorrecto para el contexto (habla de contrato en vez de boleta), pero se documenta tal como el código lo retorna.


📚 Lógica de Consultas Usadas

1. Obtener datos del empleado

Consulta a ERP:

SELECT fecha_de_ingreso_real, status FROM `tabEmployee` WHERE name = %(name)s

2. Validar Salary Slip del mes anterior

SELECT posting_date FROM `tabSalary Slip` WHERE employee = %(employee)s AND posting_date BETWEEN %(fecha_inicio)s AND %(fecha_fin)s

3. Validar estado de boleta (habilitado)

SELECT name FROM `tabEstado Boleta Mensual` WHERE mes = %(mes)s AND año = %(año)s AND habilitado = 1

4. Validar si el empleado ya descargó su boleta

Tabla: historial_procesos_app (mysql2)
Filtro:


🧩 Posibles Errores de Diseño (para tu control interno)

(Solo informativo; no se incluye en documentación oficial si no lo deseas.)

Modulo de Asistencia y Marcaciones (Marcaciones)

Obtiene descarga Renovación de contrato (1,2,3,4,5,6,7,8) - [getRenovacionContrato]

🧾 Descripción

Valida si un trabajador tiene pendiente la descarga de su renovación de contrato, lo cual puede bloquear el registro de marcaciones o solicitudes dentro del aplicativo.
El servicio evalúa fechas, estado del trabajador y el registro interno en base MySQL donde se guarda el historial de descargas realizadas.


🚀 Endpoint


GET /get-renovacion-contrato/{empleado}

{empleado} corresponde al código del empleado (Employee.name en ERPNext).


🔐 Seguridad


📥 Parámetros

Parámetro Tipo Requerido Descripción
empleado string Código único del empleado en ERPNext.

📤 Responses

✔️ 200 – No corresponde validar renovación (fuera de fecha)

El proceso solo se ejecuta si día >= 26.
Si es antes, devuelve:



{ "status": true, "msn": "No es el día correcto para la renovación de contrato" }

✔️ 200 – Validación NO necesaria (no aplica por antigüedad)

Si el empleado ingresó después del mes previo:



{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }

❌ 200 – Debe descargar el contrato de renovación (pendiente)

El empleado tiene renovación generada y habilitada, pero no tiene registro de descarga:



{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su renovación de contrato" }

✔️ 200 – Renovación ya descargada

La base MySQL registra descarga previa:



{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }

✔️ 200 – Error controlado

Ante cualquier excepción:



{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }

🧩 Flujo del Servicio

  1. Verifica el día actual

    • Si día < 26 → no corresponde validar

  2. Obtiene datos del empleado desde ERP (fecha_de_ingreso_real)

  3. Calcula:

    • Último día del mes anterior

    • Mes actual (texto)

  4. Si el ingreso del empleado es anterior al último día del mes previo, aplica validación.

  5. Consulta en ERP:

    • Solicitudes de renovación para este empleado

    • Con criterios:

      • Mes

      • Año

      • Código del empleado

      • renueva = "Si"

      • documento validado

  6. Si tiene renovación pendiente:

    • Consulta base MySQL2 → tabla historial_procesos_app

    • Busca registro del proceso descargaContratoRenovacion

    • Si no existe → debe descargar renovación

  7. Si ya está registrado → permitir normal funcionamiento.


📚 Consultas utilizadas

A. Obtener datos del empleado



SELECT fecha_de_ingreso_real FROM `tabEmployee` WHERE name = {empleado}

B. Consulta de renovaciones

SELECT doc.name FROM `tabSolicitud de Renovaciones` doc LEFT JOIN `tabTrabajadores pendiete de renovar` tab ON doc.name = tab.parent WHERE doc.data_12 = {mes} AND doc.año = {year} AND tab.codigo = {empleado} AND tab.renueva = 'Si' AND doc.estado_de_documento = 'Validado'

C. Validación de descarga

SELECT * FROM historial_procesos_app WHERE empleado = {empleado} AND proceso IN ('descargaContratoRenovacion')


🧪 Ejemplo de consumo (HTTP)

Request:


GET /get-renovacion-contrato/EMP-00045

Response (pendiente):

{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su renovación de contrato" }

Modulo de Asistencia y Marcaciones (Marcaciones)

Consulta si existe documento del puesto (1, 2,3) - [getDocumentPuesto]

🧾 Descripción

Permite obtener el documento MOF (Manual de Organización y Funciones) asociado a un puesto específico registrado en el ERP, consultando el Doctype Designation.

Este servicio se utiliza para mostrar o validar documentación laboral relacionada al cargo del trabajador.


🚀 Endpoint


GET /get-document-puesto/{puesto}

También puede enviarse como parámetro directo según cómo se defina en routes:


GET /getDocumentPuesto?puesto=OPERADOR

🔐 Seguridad


📥 Parámetros de Entrada

Query / Path Parameter

Parámetro Tipo Requerido Descripción
puesto string Nombre del Designation cuyo MOF se desea obtener.

📤 Responses

✔️ 200 – Documento encontrado

{ "valor": true, "msn": "Documento encontrado", "data": "<url_o_contenido_del_mof>" }


404 – Documento no encontrado

Se devuelve cuando el puesto no existe o no tiene MOF asociado.

{ "valor": false, "msn": "Documento no encontrado", "data": "" }


🧠 Lógica Interna (Resumen)

  1. Verifica que se haya enviado un nombre de puesto.

  2. Construye una consulta GET hacia: resource/Designation

    Con:

    • filters: [["name","=", puesto]]

    • fields: ["mof"]

  3. Envía la solicitud mediante: ServiceErp("GET", null, body, APICAPACITACION."resource/Designation")

  4. Evalúa la respuesta:

    • Si encuentra registros → devuelve el mof.

    • Si no encuentra → error.


📚 Schema

Response

{ "valor": "boolean", "msn": "string", "data": "string" }


🧪 Ejemplo de Uso (curl)

curl -X GET "https://midominio.com/getDocumentPuesto?puesto=OPERADOR"

Respuesta esperada:

{ "valor": true, "msn": "Documento encontrado", "data": "/files/mof_operador.pdf" }

Modulo de Asistencia y Marcaciones (Marcaciones)

Verifica los documentos descargados (1, 2) - [verifyDownloadedDocuments]

Descripción

Este servicio valida si un empleado ha completado la descarga obligatoria de documentos institucionales dentro del aplicativo.
Además, verifica si el empleado ha registrado previamente sus documentos de ingreso (elección de banco, declaración de AFP/ONP, etc.).

El proceso consulta tanto ERPNext como la base de datos MySQL2 para construir un resumen de los documentos descargados y determinar si el empleado tiene todos los documentos obligatorios descargados.


Parámetros

Parámetro Tipo Descripción
$employee string Código del empleado (Employee.name) que se va a validar.

Proceso general

  1. Validación inicial de datos del empleado

    • Realiza una consulta a ERPNext para obtener los campos:

      • eleccion_banco

      • afiliado_fondo_pensiones

      • elección_fondo_pensiones

    • Si el empleado no existe, devuelve un error.

  2. Validación de documentos de ingreso

    • Antes de validar documentos descargados, se comprueba que el empleado ya subió sus documentos de ingreso.

    • Si falta alguno de estos:

      • Elección de banco

      • Si está afiliado o no al fondo de pensiones

      • Selección AFP u ONP

      → Se retorna:
      "Primero suba los documentos de ingreso"

  3. Obtención del historial de descargas

    • Consulta la tabla historial_procesos_app en MySQL2.

    • Se recuperan registros para los procesos:

      • descargaContratoTrabajo

      • descargaReglamentoInternoTrabajo

      • descargaRecomentacionesSST

      • descargaConvenioDescuento

      • descargaDeclaracionJuradaDomicilio

      • descargadeclaracionJuradaSNPSPP

      • descargaPoliticasSalariales

      • registroEPP

      • descargaPETSAlmacenamiento

      • descargaPETSManipulacion

      • descargaMOF

      • descargaPoliticasDescuentosPorDanios

  4. Construcción del resumen por empleado

    • Cada documento es asignado como:

      • 1 → descargado

      • 0 → pendiente

  5. Validación del 100% de documentos

    • Si todos los procesos están registrados → total_documentos = true

    • Si falta alguno → total_documentos = false

  6. Validación adicional: Cambio de modalidad

    • Si el empleado tiene alguna "Solicitud de Cambio de Modalidad" aprobada (docstatus != 2), se considera descargado automáticamente el contrato de trabajo.

  7. Retorno final del estado del empleado


Respuesta exitosa

{ "valor": true, "data": { "empleado": "EMP-001", "descargaContratoTrabajo": 1, "descargaReglamentoInternoTrabajo": 1, "descargaRecomendacionesSST": 0, "descargaConvenioDescuento": 1, "descargaDeclaracionJuradaDomicilio": 1, "descargaDeclaracionJuradaSNPSPP": 0, "descargaPoliticasSalariales": 1, "registroEPP": 1, "descargaPETSAlmacenamiento": 1, "descargaPETSManipulacion": 1, "descargaMOF": 1, "descargaPoliticasDescuentosPorDanios": 1, "total_documentos": false } }


Posibles respuestas con error

● Empleado no encontrado

{ "valor": false, "msn": "Empleado sin datos" }

● Documentos de ingreso no completados

{ "valor": false, "msn": "Primero suba los documentos de ingreso" }

Modulo de Asistencia y Marcaciones (Marcaciones)

Lista de marcaciones generada (1) - [listMarkingsApp45]

🧾 Descripción

Este servicio obtiene y consolida todas las marcaciones de asistencia de un empleado en una fecha específica, combinando información de:

Entrega una estructura lista para mostrar en una app móvil o web con:

El servicio también calcula dinámicamente si debe tomar estado_reporte o status, según si la fecha consultada pertenece al rango generado desde el último corte del mes.


🚀 Endpoint

POST /list-markings-app45


📥 Parámetros de Entrada (Request Body)

{ "usuario": "string", "empleado": "EMP-0001", "cookie": "token de sesión", "date": "YYYY-MM-DD" }
Campo Tipo Descripción
usuario string Usuario que solicita información (no se usa en lógica interna).
empleado string ID del empleado a consultar.
cookie string Cookie de sesión para consultas al ERP.
date string Fecha de la marcación.

🔐 Seguridad


🧠 Flujo del Servicio (Resumen Real)

1️⃣ Obtiene filtros según fecha

2️⃣ Trae las marcaciones del empleado

Consulta tabEmployee Checkin (Entrada, Refrigerio, Salida).

3️⃣ Consulta estado de asistencia

Desde tabAttendance, validando solo documentos aprobados (docstatus = 1).

4️⃣ Obtiene configuración de cortes del mes

Sirve para determinar si el estado válido es:

5️⃣ Genera un rango de fechas desde el corte hasta fin de mes

Se usa para validar cambios de lógica.

6️⃣ Procesa marcaciones y las estructura así:

 

{ "entrada": {...}, "salida_refrigerio": {...}, "llegada_refrigerio": {...}, "salida": {...}, "asistencia": {...} }

 

7️⃣ Traduce estados a texto legible

Ejemplo:

ERP Texto entregado
Present Presente
Absent Ausente
Work From Home Trabajar desde casa
Half Day Medio día

📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Lista de marcaciones generada correctamente", "data": { "entrada": { "empleado": "Juan Pérez", "hora_marcacion": "08:01 AM", "existe": 1 }, "salida_refrigerio": {...}, "llegada_refrigerio": {...}, "salida": {...}, "asistencia": { "fecha": "2025-01-15", "mes": "ENERO", "status": "PRESENTE", "nombre_fecha": "MIERCOLES 15 DE 2025" } } }

❗ Posibles Errores

1. Error al obtener marcaciones

{ "valor": false, "msn": "Error al traer asistencia", "data": [] }

2. Error al consultar Attendance o Cortes

{ "valor": false, "msn": "Fallo al traer asistencia.", "data": [] }

3. Error interno del servidor

{ "valor": false, "msn": "Error en listMarkingsApp45: <mensaje>", "error": "<stacktrace>" }


📚 Tablas / Recursos Usados

🔹 tabEmployee Checkin

Campos:

🔹 tabAttendance

🔹 tabCortes

🔹 tabShift Type


🧩 Lógica en Pseudocódigo

input: usuario, empleado, cookie, date calcular inicio y fin del día si date >= 2022-11-10: buscar checkin por fecha_consolidado else: buscar checkin por rango de horas consultar Attendance consultar Cortes del mes si cortes vacío → error generar fechas posteriores al corte determinar estado (status o estado_reporte) crear estructura de salida iterar marcaciones: si log_type == Entrada → entrada si log_type == Salida Refrigerio → salida_refrigerio etc. retornar JSON con todas las marcaciones y estado

Modulo de Asistencia y Marcaciones (Marcaciones)

Obtener Usuario (3) - [getUser3]

🧾 Descripción

Este servicio permite obtener la información completa de un usuario, ya sea Empleado o Estudiante, usando cualquiera de los siguientes identificadores:

La función consulta múltiples tablas del ERP y retorna la información enriquecida del usuario, incluyendo:

Si el usuario no es empleado, se intenta validar como estudiante.
El servicio aplica múltiples reglas de negocio internas sobre estado, tipo de usuario y permisos.


🚀 Endpoint

POST /get-user-3

📥 Body esperado

{ "username": "usuario@correo.com" }

O también:

{ "username": "12345678" }

🔐 Seguridad

Este servicio requiere autenticación interna contra el ERP mediante dbErp() y ServiceErp() con token válido del sistema.


🧠 Flujo del Servicio (Resumen Real)

1. Determinar tipo de búsqueda

Si username contiene @, se asume que es user_id.
Si no contiene, se usa como passport_number (DNI).

Se arma el filtro dinámicamente:

Caso Campo filtrado
Correo emp.user_id
DNI / Pasaporte emp.passport_number

2. Buscar al usuario como Empleado

Consulta principal: POST method/send-query-database

Incluye joins a:

Si existe un registro válido:

📌 Si todo está correcto, el servicio termina aquí retornando la data del empleado.


3. Si NO existe empleado → Buscar como Estudiante

Filtros dependen de correo o DNI.

Validaciones aplicadas:

Datos retornados incluyen:


4. Retornar la data final

Si es empleado → retorna información laboral con contratos.
Si es estudiante → retorna información básica educativa.


📤 Response 200 – Ejemplo (Empleado)

{ "valor": true, "msn": "Si hay data", "data": [{ "name": "EMP-001", "employee_name": "Juan Pérez", "user_id": "juan.perez@empresa.com", "gender": "Male", "status": "Active", "tipo_usuario": "Empleado", "vigencia_contrato": "2024-01-01 hasta 2024-12-31", "contratacion": "renovacion", "pets": "0", "bank_ac_no": "1234567890" }] }

❗ Posibles Errores

1. No existe como empleado ni estudiante

{ "valor": false, "msn": "Sin Estudiante: Su usuario no tiene permisos para acceder al aplicativo.", "data": [] }

2. Empleado Inactivo

{ "valor": false, "msn": "Empleado Inactivo: Comuníquese con su administrador...", "data": [] }

3. Usuario deshabilitado (estudiante)

{ "valor": false, "msn": "Usuario Deshabilitado...", "data": [] }

 

4. Error al consultar ERP

{ "valor": false, "msn": "Error al obtener la información", "data": [] }

📚 Tablas consultadas

Empleado

Estudiante


🗃 Resultado Final (Estructura General)

Para empleados:

{ "name": "EMP-001", "employee_name": "...", "user_id": "...", "gender": "...", "tipo_usuario": "Empleado", "contratacion": "primer_contrato | renovacion", "status": "Active | PreActivo | Inactive", "pets": "0", "vigencia_contrato": "...", "...otros campos" }

Para estudiantes:

{ "name": "ST-001", "employee_name": "...", "user_id": "...", "tipo_usuario": "Estudiante", "statusUser": 1, "...otros campos" }

🧩 Pseudocódigo del servicio

username = request.username if username contains "@": filter by user_id else: filter by passport_number employee = buscarEmpleado() if existe empleado: validar estado cargar contratos formatear datos return empleado else: student = buscarEstudiante() si no existe o está deshabilitado: error return student
Modulo de Asistencia y Marcaciones (Marcaciones)

Lista de Sucursales - [listOfErpBranchs]

🧾 Descripción

Obtiene la lista completa de sucursales registradas en el ERP, filtrando únicamente aquellas que:

El servicio consulta directamente el ERP a través del método apiService() y devuelve las sucursales ordenadas alfabéticamente por su nombre.

También realiza un post-proceso convirtiendo el campo ideentificador en string, garantizando consistencia en el frontend (evita problemas cuando el ERP envía valores numéricos).


🚀 Endpoint

GET /list-of-erp-branchs

No recibe parámetros.

Toda la data proviene del ERP mediante:

GET Branch?limit=None&order_by=name asc&fields=["name","ideentificador"]&filters=[["concesionario","=",0],["ideentificador","!=","0"]]

🔐 Seguridad

Requiere autenticación del ERP mediante apiService().
El token se gestiona internamente (servicio backend–backend).


🧠 Flujo del Servicio

  1. Llama al ERP solicitando todas las sucursales:

    • Sin límite (limit=None)

    • Ordenadas (order_by=name asc)

    • Filtradas por:

      • concesionario = 0

      • ideentificador ≠ "0"

    • Campos solicitados:

      • name

      • ideentificador

  2. Decodifica la respuesta.

  3. Valida que exista el campo "data" en la respuesta del ERP.

    • Si no existe, retorna error.

  4. Recorre cada registro y convierte ideentificador a string.

  5. Retorna la lista final de sucursales.


📥 Request Body

No tiene body.

{}


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Lista de Sucursales generado correctamente", "data": [ { "name": "Sucursal Lima", "ideentificador": "101" }, { "name": "Sucursal Arequipa", "ideentificador": "205" } ] }

❗ Posibles Errores

1. Error al obtener data del ERP

{ "valor": false, "msn": "Error al traer la lista de sucursales", "data": [] }

2. Excepción interna del servidor

{ "valor": false, "msn": "Error del servidor", "data": [] }

📚 Esquema de datos (Branch)

Branch (GET)

Campos utilizados:

{ "name": "string", "ideentificador": "string | number" }

🗃 Pseudocódigo del servicio

response = apiService("Branch?limit=None&order_by=name asc&fields=[name,ideentificador]&filters=[[concesionario,=,0],[ideentificador,!=,0]]") if !response.data: return error foreach branch in response.data: branch.ideentificador = str(branch.ideentificador) return success(branch)
Modulo de Asistencia y Marcaciones (Marcaciones)

Intento de Marcación (1) - [intentMarca]

🧾 Descripción

Registra y actualiza los intentos de marcación que realiza un empleado en una agencia durante el día.
Este servicio controla cuántas veces un colaborador intenta marcar asistencia, creando o actualizando un registro diario en el ERP.

Se basa en el Doctype:

Y utiliza los campos:


🚀 Endpoint

POST /intent-marca

El servicio recibe datos desde el body mediante Request.


📥 Request Body

{ "empleado": "EMP-0001", "agencia": "AG-001", "intento": 1 }

Campos requeridos:

Campo Tipo Obligatorio Descripción
empleado string Código del empleado
agencia string Agencia en la que intenta marcar
intento int Intento actual enviado desde la app

🔐 Seguridad

Utiliza autenticación interna del ERP a través de:

Requiere credenciales internas del sistema.


🧠 Flujo del Servicio (resumen real)

  1. Valida que existan los parámetros obligatorios: empleado, agencia e intento.
    Si falta alguno → retorna error.

  2. Determina la fecha actual (Y-m-d).
    Este valor se usa para registrar un intento por día.

  3. Consulta si el empleado ya tiene un registro de Intento de marcacion para el día actual:


    tpr.empleado = empleado AND tpr.creacion = fecha_actual
  4. Si existe un registro previo:

    • Se suma el intento nuevo al intento existente:


      intento_total = intento_enviado + intento_existente
    • Se actualiza el Doctype:


      PUT resource/Intento de marcacion/{name}
  5. Si NO existe un registro previo:

    • Se crea un nuevo documento Intento de marcacion:


      POST resource/Intento de marcacion
  6. Devuelve la respuesta directa del ERP.


📤 Response 200 – Ejemplo (actualizado)

✔ Caso actualización

{ "valor": true, "msn": "Actualizado correctamente", "data": { "name": "INT-MAR-00045", "empleado": "EMP-0001", "agencia": "AG-001", "intento": 3, "creacion": "2025-02-10" } }

✔ Caso creación

{ "valor": true, "msn": "Creado correctamente", "data": { "name": "INT-MAR-00046", "empleado": "EMP-0001", "agencia": "AG-001", "intento": 1, "creacion": "2025-02-10" } }

❗ Posibles Errores

1. Falta de parámetros requeridos

{ "valor": false, "msn": "No se encontró al empleado" }

2. Error en la consulta DB → dbErp

{ "valor": false, "msn": "Error al consultar ERP", "data": [] }

3. Error en creación o actualización en ERP

{ "valor": false, "msn": "Error al registrar intento", "data": { ...respuesta ERP... } }

📚 Doctype utilizado

Intento de marcacion

Campos usados:

{ "empleado": "string", "agencia": "string", "intento": "int", "creacion": "date" }

🗃 Lógica en pseudo-código

employee = request.empleado agencia = request.agencia intento = request.intento fecha = hoy (Y-m-d) if falta algún parámetro: return error consulta = GET Intento de marcacion where empleado = employee and creacion = fecha if existe_registro: nuevo_intento = intento + registro.intento PUT Intento de marcacion/{name} con { empleado, agencia, intento: nuevo_intento, creacion } else: POST Intento de marcacion con { empleado, agencia, intento, creacion } return respuesta
Modulo de Asistencia y Marcaciones (Marcaciones)

Validar Marcación (1) - [validar]

🧾 Descripción

Este servicio ejecuta toda la lógica de validación previa para permitir que un empleado realice una marcación (asistencia).
El servicio centraliza más de 10 validaciones críticas, verificando:

Es un servicio de control que determina si el empleado puede realizar una marcación y qué mensaje debe mostrarse al usuario.


🚀 Endpoint

POST /validar


📥 Request Body (resumen)

{ "empleado": "EMP-001", "type": "ingreso", "fecha_asistencia": "2025-02-01", "fhingreso": "2023-01-10", "status_employee": "Active", "designation": "OPERADOR", "sucursal": "LIMA-01" }

🔐 Seguridad


🧠 Flujo del Servicio (Resumen Real)

1️⃣ Validar campos obligatorios
Llama a verifyFields().
Si falta algún parámetro → retorna error inmediato.

2️⃣ Cargar datos principales

3️⃣ Validar restricciones por puesto
Si el empleado NO es "PreActivo", llama a:
validateRestrictedDesignation(designation)

4️⃣ Validar licencia activa
verifyLicencia(empleado, fechaIngreso)

5️⃣ Validar nuevos ingresos
Solo para empleados activos, ingreso reciente, y NO Express:
verifySignedNewAdmissionRegistrations()

6️⃣ Validar descarga de documentos obligatorios
Obtiene documentos descargados:
verifyDownloadedDocumentsBd()
Y valida contrato pendiente:
verifyContractDownload()

7️⃣ Validar documentos de cambio de modalidad
verifyModalityChangeDocument()

8️⃣ Validar información del empleado (horarios, jornada, etc.)
verifyEmployeeData()

9️⃣ Obtener últimas marcaciones
getMarkingsByEmployee()

🔟 Validación de “No sujeto a fiscalización”
verifyEmployeeNotSubjectToInspection()

1️⃣1️⃣ Validación de refrigerio
Si type == llegada_refrigerio:
verifyStartOfLunch()

1️⃣2️⃣ Validar coherencia del tipo de marcación
Ejemplo: que no marque salida sin marcar ingreso.
verifyTypeOfMarking()

📌 Si todas las validaciones son correctas → retorna éxito.


📤 Response 200 – Ejemplo (OK)

{ "valor": true, "msn": "Marcación permitida", "data": { "type": "ingreso", "valid": true } }

❗ Posibles Errores devueltos por este servicio

1. Campos obligatorios faltantes

{ "valor": false, "msn": "Falta el campo empleado" }

2. Puesto restringido

{ "valor": false, "msn": "Su puesto no permite realizar marcaciones" }

3. Empleado con licencia activa

{ "valor": false, "msn": "Tiene licencia activa. No puede marcar" }

4. Documentos de ingreso no firmados

{ "valor": false, "msn": "Debe firmar sus documentos de ingreso" }

5. Contrato pendiente por descargar

{ "valor": false, "msn": "Debe descargar su contrato para continuar" }

6. Error en la lógica de marcación (orden incorrecta)

{ "valor": false, "msn": "No puede marcar salida sin haber marcado ingreso" }

7. No sujeto a fiscalización

{ "valor": false, "msn": "Empleado no sujeto a fiscalización" }

🗃 Funciones internas utilizadas

Nombre Descripción
verifyFields Valida campos requeridos del request
validateRestrictedDesignation Controla puestos con restricciones
verifyLicencia Evalúa si el empleado tiene licencia activa
verifySignedNewAdmissionRegistrations Valida firmas de ingreso
verifyDownloadedDocumentsBd Valida documentos descargados
verifyContractDownload Revisa si falta descargar contrato
verifyModalityChangeDocument Valida documentos de cambios de modalidad
verifyEmployeeData Verifica datos del empleado necesarios para marcar
getMarkingsByEmployee Obtiene último registro de marcación
verifyEmployeeNotSubjectToInspection Revisa si está sujeto a fiscalización
verifyStartOfLunch Valida inicio del refrigerio
verifyTypeOfMarking Controla coherencia de marcaciones

🗃 Pseudo-código real del servicio

if !verifyFields(request): return error if puesto restringido: return error if licencia activa: return error if ingreso reciente y no Shalom Express: validar documentos de ingreso validar documentos descargados validar contrato validar cambio de modalidad validar información del empleado marcacionesPrevias = getMarkingsByEmployee() if no sujeto a fiscalización: return error if marcación es llegada_refrigerio: validar inicio refrigerio validar secuencia de tipo de marcación return OK
Modulo de Asistencia y Marcaciones (Marcaciones)

Crear Marcación (1) - [crear]

🧾 Descripción

Registra una marcación de entrada o salida para un empleado, validando previamente:

Es uno de los servicios centrales del módulo de asistencia.


🚀 Endpoint

POST /marcaciones/store

Este servicio sí recibe parámetros en el request.


📥 Request Body (Campos usados)

{ "empleado": "EMP-0001", "image": "https://.../foto.jpg", "fecha_asistencia": "2025-02-03", "type": "entrada | salida", "passport_number": "12345678", "coordinates": "-12.10, -77.05", "isOfline": 0 }

Campos relevantes

Campo Tipo Descripción
empleado string ID del empleado
image string URL base64 o imagen enviada
fecha_asistencia date Fecha de la marcación
type string “entrada” o “salida”
passport_number string Documento del empleado
coordinates string Lat/Lon opcional
isOfline int 1 si se marcó offline

🔐 Seguridad

El servicio requiere:


🧠 Flujo del Servicio (resumen real)

1. Validación de campos

Se ejecuta verifyFields($request) y si falla, retorna de inmediato.

2. Prevención de fechas inválidas

Si la marcación es online y la fecha es mayor al día actual → rechaza.

3. Validación de duplicidad

Se construye:

[ "employee" => empleado, "log_type" => type_markings[type], "fecha_de_consolidado" => fecha_asistencia ]

Luego: validateDuplicateDialing()

Si ya existe marcación → error.


4. Obtención del turno del empleado

Consulta ERP:

Si es “entrada” → valida que pase de PreActivo → Activo.


5. Cálculo de tardanza u horas extra


6. Registro en ERP

Crea documento:

Employee Checkin

[ "employee" => empleado, "time" => fecha, "coordenadas" => coordinates, "log_type" => Entrada/Salida, "urlimagen2" => image, "offline" => isOfline, "late_time" => tardanza calculada, "overtime_time" => horasExtras, ]


7. Registro en base de datos interna

Inserta en tabla marcaciones:

employee, time, log_type, fecha_de_consolidado, urlimagen2, document...

8. Generación de asistencia

Si la marcación es salida, ejecuta: storeAttendance($request)

y devuelve datos adicionales.


📤 Response 200 – Ejemplo

✔ Entrada o salida registrada correctamente

{ "valor": true, "msn": "Marcación registrada", "data": { "employee": "EMP-0001", "time": "2025-02-03 08:03:00", "late_time": "00:03", "overtime_time": "", "offline": 0 } }

✔ Al registrar salida (incluye asistencia generada)

{ "valor": true, "msn": "Marcación registrada", "data": { ...checkin ERP... }, "data2": { ...asistencia... } }


❗ Posibles Errores

1. Campos inválidos

{ "valor": false, "msn": "Falta completar campos obligatorios", "data": [] }

2. Marcación duplicada

{ "valor": false, "msn": "Error al intentar realizar una marcación duplicada" }

3. Fecha mayor al día actual

{ "valor": false, "msn": "La marcacion no puede ser mayor al día actual." }

4. Error creando Employee Checkin

{ "valor": false, "msn": "Surgió un error al insertar marcación de salida.", "data": {} }

5. Error servidor

{ "valor": false, "msn": "Error del servidor: <mensaje>" }

📚 Schemas utilizados

Employee

{ "name": string, "default_shift": string, "first_name": string, "first_last_name": string, "second_last_name": string, "passport_number": string, "id_sucursal": string }

Shift Type

{ "name": string, "start_time": "HH:MM:SS", "end_time": "HH:MM:SS" }

Employee Checkin (ERP)

{ "employee": string, "time": datetime, "log_type": string, "late_time": string, "overtime_time": string, "offline": int }

🗃 Lógica en Pseudo-código

verify = verifyFields(request) if !verify.valor → return error if fecha_asistencia > hoy AND online → return error validateDuplicateDialing() if duplicado → return error turno = GET turno del empleado en ERP if type == entrada: validarPreActive() calcular tardanza / horas extra bodyCheckin = {...} insertERPNew("Employee Checkin", bodyCheckin) insert DB marcaciones if type == salida: storeAttendance() return respuesta con asistencia return respuesta normal

Modulo de Asistencia y Marcaciones (Asistencia)

Modulo de Asistencia y Marcaciones (Asistencia)

Obtiene descarga boleta de pago (2) - [getDownloadBoletaPago]

🧾 Descripción

Este servicio valida si un empleado debe descargar obligatoriamente su boleta de pago del último mes antes de poder realizar acciones como:

El servicio evalúa:

  1. Si está dentro del rango de validación (solo del día 1 al 3 de cada mes).

  2. La fecha de ingreso del trabajador.

  3. Si tiene boleta generada el mes anterior.

  4. Si el mes correspondiente está habilitado para descarga.

  5. Si el empleado ya descargó la boleta (se revisa historial en MySQL).

  6. Si el empleado está PreActivo, no se valida la descarga.


🚀 Endpoint

GET /get-download-boleta-pago/{empleado}

📌 Parámetro obligatorio:


🔐 Seguridad


🧠 Flujo del Servicio (resumen)

1️⃣ Validación de fecha

Solo se ejecuta validación si el día actual está entre 1 y 3.
Si el día > 3 → se omite toda validación:

{ "status": true, "msn": "No está dentro del rango de fecha de validación" }

2️⃣ Obtener información del empleado

Consulta ERP:

SELECT fecha_de_ingreso_real, status FROM `tabEmployee` WHERE name = <empleado>

Si el empleado está PreActivo, no se valida boleta:

{ "status": true, "msn": "No validar descarga de boleta en PreActivo" }

3️⃣ Comparar fecha de ingreso vs fecha límite

Se calcula:

Solo se valida si el empleado ingresó antes del cierre del mes previo.


4️⃣ Verificar en MySQL si ya descargó la boleta

Consulta tabla historial_procesos_app:

WHERE empleado = ? AND proceso = 'NOMINA' AND month = <mes_anterior> AND year = <year_anterior>

Si no existe registro se sigue validación.


5️⃣ Validar si EXISTE boleta en ERP

Consulta Salary Slip del último mes:

SELECT posting_date FROM `tabSalary Slip` WHERE employee = ? AND posting_date between <primer_día_mes_anterior> AND <último_día_mes_anterior>

Si no tiene boleta:

{ "status": true, "msn": "No tiene boleta de pago por lo tanto no se valida" }

6️⃣ Validar si el mes está habilitado para descarga

Consulta:

SELECT name FROM `tabEstado Boleta Mensual` WHERE mes = <mes_texto> AND año = <year> AND habilitado = 1

Si está habilitado pero el trabajador NO la descargó, se bloquea:

{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su boleta pendiente del mes" }

7️⃣ Si pasa todas las validaciones → OK

{ "status": true, "msn": "Se ha descargado la boleta de pago" }

📥 Request

No usa body, solo el parámetro de ruta: empleado: string


📤 Response – Ejemplos

✔ Caso permitido (día fuera de rango)

{ "status": true, "msn": "No está dentro del rango de fecha de validación" }

✔ Empleado en PreActivo

{ "status": true, "msn": "No validar descarga de boleta en PreActivo" }

✔ No tiene boleta generada

{ "status": true, "msn": "No tiene boleta de pago por lo tanto no se valida" }

❌ No ha descargado la boleta y es obligatoria

{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su boleta pendiente del mes" }

✔ Todo correcto

{ "status": true, "msn": "Se ha descargado la boleta de pago" }

❗ Posibles errores

Error Descripción
Empleado no existe No se encuentra en ERP
No tiene boleta generada Salary Slip del mes anterior vacío
Boleta habilitada pero no descargada Bloquea marcación y solicitudes
Error en ERP o MySQL Respuesta capturada por el catch

🧩 Tablas consultadas

ERP (Frappe/ERPNext)

MySQL externo


🗃 Pseudocódigo del servicio

if day > 3: return OK (no validar) empleado = GET Employee if empleado.status == PreActivo: return OK if fecha_ingreso < ultimo_dia_mes_anterior: verificar si ya descargó boleta en MySQL verificar si tiene boleta en ERP if no tiene: return OK verificar si mes habilitado if habilitado y no descargado: bloquear return OK
Modulo de Asistencia y Marcaciones (Asistencia)

Obtiene descarga Renovación de contrato (2) - [getRenovacionContrato]

🧾 Descripción

Valida si un empleado debe descargar su renovación de contrato, según reglas internas de fecha y estado en el ERP.

Este servicio determina:

Se combina información del ERP y del registro histórico en MySQL2.


🚀 Endpoint

GET /get-renovacion-contrato/{empleado}

📌 El parámetro empleado es obligatorio (ID del Employee en ERP).


🔐 Seguridad

✔ Requiere autenticación interna vía dbErp() y tokens del ERP.
✔ Acceso restringido a servicios del backend.


🧠 Flujo del Servicio (Resumen)

  1. Verifica la fecha actual.

    • Si el día del mes es menor a 26 → No corresponde validar renovaciones.

  2. Obtiene datos del empleado.


    SELECT fecha_de_ingreso_real FROM tabEmployee WHERE name = {empleado}
  3. Determina si el empleado aplica para renovación:

    • Debe haber ingresado antes del último día del mes anterior.

  4. Busca renovaciones validadas del empleado:


    FROM tabSolicitud de Renovaciones doc JOIN tabTrabajadores pendiete de renovar tab WHERE doc.data_12 = <mes_actual_texto> AND doc.año = <año> AND tab.codigo = empleado AND tab.renueva = "Si" AND doc.estado_de_documento = "Validado"
  5. Si existe una renovación validada:

    • Consulta MySQL2 → tabla historial_procesos_app

    • Revisa si el usuario ya descargó su renovación:


      proceso = "descargaContratoRenovacion"
  6. Si no la descargó → bloquea ciertas funciones.

  7. Si todo está conforme → indica que la renovación fue descargada.


📥 Request

Parámetro de ruta

Campo Tipo Obligatorio Descripción
empleado string ID del Employee dentro del ERP

No tiene body.


📤 Response 200 – Ejemplos

✔ Caso 1 — No es día de validación

{ "status": true, "msn": "No es el día correcto para la renovación de contrato" }

✔ Caso 2 — Debe descargar renovación (bloqueo)

{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su renovación de contrato" }

✔ Caso 3 — Renovación descargada correctamente

{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }

✔ Caso 4 — Error controlado

{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }

❗ Posibles errores

Código Significado
status:false El empleado tiene renovación pendiente y no la descargó
status:true No aplica validación o ya cumplió con la descarga
Excepción Se devuelve un mensaje genérico indicando que el contrato fue descargado

📚 Tablas / Datos utilizados

ERP - tabEmployee

Campos usados:

ERP - tabSolicitud de Renovaciones

Campos usados:

ERP - tabTrabajadores pendiete de renovar

Campos usados:

MySQL2 - tabla historial_procesos_app

Procesos revisados:


🗃 Lógica en Pseudo-Código

if day(today) < 26: return OK("No es el día correcto") empleado = queryERP(Employee where name=empleado) if empleado.ingreso < ultimo_dia_mes_anterior: renov = queryERP(Solicitud de Renovaciones where codigo=empleado AND renueva="Si" AND estado="Validado" ) if renov exists: registro = queryMySQL(historial_procesos where proceso="descargaContratoRenovacion") if registro vacío: return ERROR("Debe descargar la renovación") return OK("Se ha descargado el contrato de trabajo")
Modulo de Asistencia y Marcaciones (Asistencia)

Lista de Asistencias (1) - [getMarkingsApp]

🧾 Descripción

Este servicio obtiene y consolida todas las asistencias de un empleado en un mes específico, calculando:

Además, toma en cuenta:

Es un endpoint fundamental para el módulo de Control de Asistencias dentro del aplicativo.


🚀 Endpoint

POST /get-markings-app

📥 Requiere parámetros obligatorios en el body:

{ "employee": "EMP-0001", "month": "02", "anio": "2025", "fechaIngreso": "2024-10-15" }


🔐 Seguridad

Requiere autenticación interna del sistema ERP mediante:


🧠 Flujo del Servicio (resumen real)

  1. Recibe parámetros del empleado y mes a consultar.

    employee, month, anio, fechaIngreso

  2. Calcula rango real del mes a evaluar, tomando en cuenta:

    • Si es el mes actual.

    • Si el empleado ingresó después del día 1.

    • Días previos al ingreso del trabajador.

  3. Carga feriados y domingos del archivo JSON:

    /public/recursos_humanos/holidays.json

  4. Determina cuántos días del mes son feriados o domingos dentro del rango permitido.

  5. Valida campos obligatorios.

  6. Consulta en el ERP todas las asistencias del empleado en el mes:

FROM tabAttendance WHERE employee = <empleado> AND attendance_date BETWEEN 1 y último día del mes AND status IN ('Present','Marcacion Incompleta','On Leave','Absent','Día de Descanso','Feriado')

  1. Recorre todas las asistencias y clasifica:

    • Present → Suma asistencia

    • On Leave → Permisos

    • Absent → Faltas

    • Feriado → Feriados

    • Día de Descanso → Descansos

    • Marcacion Incompleta → Marcaciones incompletas

  2. Calcula porcentaje de asistencia, considerando:

    • Días previos al ingreso.

    • Si el mes es el actual → hasta el día de hoy.

    • Casos especiales de permisos dominicales.

  3. Construye respuesta final con totales y fechas.


📥 Request Body

{ "employee": "EMP-0001", "month": "03", "anio": "2025", "fechaIngreso": "2024-10-10" }

📌 Todos son obligatorios.


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "LISTA DE ASISTENCIAS", "data": { "porcentage": "92.55", "dias_aistidos": "25", "dias_totales": "27", "permisos": "1", "faltas": "0", "marcacion_incompleta": "1", "fechas_asistidas": [ "2025-03-01", "2025-03-02", "2025-03-03" ], "feriados": "1", "descansos": "4", "dias_permisos": [ "2025-03-08" ], "dias_tardanzas": [ "2025-03-15" ], "dias_faltas": [], "dias_feriados": [ "2025-03-29" ], "dias_descansos": [ "2025-03-02", "2025-03-09" ] } }


❗ Posibles Errores

1. Faltan parámetros obligatorios

{ "valor": false, "msn": "Complete todos los campos" }

2. No existe asistencia registrada

{ "valor": true, "msn": "LISTA DE ASISTENCIAS", "data": { "porcentage": "0", "dias_asistidos": "0", "dias_totales": "0", ... } }

3. Error interno inesperado

{ "valor": false, "msn": "Error inesperado en el servicio", "data": [] }


📚 Estructuras usadas

Attendance (tabAttendance)

Campos consultados:

Archivo holidays.json

Estructura:

{ "Sunday": ["2025-03-02", "2025-03-09"], "Holidays": ["2025-03-29"] }


🧩 Lógica en pseudo-código

input: employee, month, anio, fechaIngreso validar campos requeridos calcular fecha_inicio y fecha_fin según: - mes actual - fecha de ingreso del empleado cargar feriados y domingos (holidays.json) contar días dentro del rango consultar asistencias en ERP: SELECT attendance_date, status FROM tabAttendance WHERE employee = employee AND status IN (...) inicializar contadores foreach asistencia in resultado: clasificar según status acumular días, permisos, faltas, descansos, feriados calcular porcentaje de asistencia return { valor: true, data: {...} }

Modulo de Asistencia y Marcaciones (Horas Extras)

Modulo de Asistencia y Marcaciones (Horas Extras)

Obtiene descarga boleta de pago (3) - [getDownloadBoletaPago]

🧾 Descripción

Valida si un empleado debe descargar su boleta de pago del mes anterior antes de poder registrar marcaciones o realizar solicitudes en el sistema.
La validación se aplica únicamente dentro de un periodo permitido (del día 1 al 3 del mes).

Este servicio combina datos entre:

Permite determinar si el usuario:


🚀 Endpoint

POST /get-download-boleta-pago

📥 Parámetros

Campo Tipo Requerido Descripción
empleado string ID del empleado (Employee.name)

🔐 Seguridad

El servicio requiere:


🧠 Flujo del Servicio (resumen real)

1️⃣ Verifica si está dentro del rango permitido

2️⃣ Obtiene datos del empleado

Consulta: 

GET tabEmployee fields = ["fecha_de_ingreso_real", "status"]

Si el empleado está PreActivo, no se valida boleta.

3️⃣ Determina el mes anterior

Se calcula:

Se verifica que el empleado haya ingresado antes del fin del mes anterior.

4️⃣ Verifica si existe boleta del mes anterior

Consulta a ERP: 

tabSalary Slip WHERE employee = empleado AND posting_date BETWEEN primer_día_mes_pasado AND último_día_mes_pasado

Si no tiene boleta, no se valida nada.

5️⃣ Valida si el mes está habilitado para descarga

Consulta: 

tabEstado Boleta Mensual WHERE mes = <mes anterior en texto> AND año = <año> AND habilitado = 1

6️⃣ Consulta si el usuario ya descargó la boleta

Busca en MySQL: 

historial_procesos_app WHERE empleado = empleado AND proceso = 'NOMINA' AND month = mes AND year = año

Si no existe descarga previa y el mes está habilitado → debe descargar.


📤 Respuestas Posibles

✔️ 1. No está en rango de validación

{ "status": true, "msn": "No está dentro del rango de fecha de validación" }

✔️ 2. Empleado PreActivo

{ "status": true, "msn": "No validar descarga de boleta en PreActivo" }

✔️ 3. No tiene boleta del mes

{ "status": true, "msn": "No tiene boleta de pago por lo tanto no se valida" }

❌ 4. Debe descargar la boleta (regla principal)

{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su boleta pendiente del mes" }

✔️ 5. Ya descargó la boleta

{ "status": true, "msn": "Se ha descargado la boleta de pago" }

✔️ 6. Error controlado

{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }


📚 Tablas y esquemas usados

🔹 Employee (ERP)

Campos utilizados:

fecha_de_ingreso_real status

🔹 Salary Slip (ERP)

Campo utilizado: posting_date

🔹 Estado Boleta Mensual (ERP)

Campos utilizados:

mes año habilitado

🔹 historial_procesos_app (MySQL)

Campos usados:

empleado proceso month year

🗃 Lógica en pseudocódigo

if dia > 3: return OK empleado = GET Employee[name] if empleado.status == PreActivo: return OK fecha_ingreso < fin_mes_anterior ? if no tiene SalarySlip en mes anterior: return OK mes_habilitado = GET EstadoBoletaMensual[mes,año] descarga = buscar en historial_procesos_app if mes_habilitado AND no descarga: return OBLIGAR DESCARGA return OK

Modulo de Asistencia y Marcaciones (Horas Extras)

Obtiene descarga Renovación de contrato (3) - [getRenovacionContrato]

🧾 Descripción

Valida si un empleado debe descargar la renovación de contrato antes de poder registrar marcaciones o realizar solicitudes dentro del aplicativo.

El servicio evalúa:

Este servicio actúa como una regla de negocio obligatoria para habilitar o bloquear el uso del aplicativo.


🚀 Endpoint

POST /get-renovacion-contrato

📌 Recibe un único parámetro:

{ "empleado": "EMP-0001" }

🔐 Seguridad


🧠 Flujo del Servicio (Resumen Real)

1️⃣ Validación inicial por fecha

{ "status": true, "msn": "No es el día correcto para la renovación de contrato" }

2️⃣ Obtener fecha real de ingreso del empleado

Consulta al ERP:

SELECT fecha_de_ingreso_real FROM `tabEmployee` WHERE name = <empleado>

Si no existe → el servicio simplemente finaliza sin error.


3️⃣ Determinar si el empleado ya debería tener renovación


4️⃣ Consultar renovación en ERP (contratos validados)

Busca registros de:

Consulta ejecutada:

SELECT doc.name FROM `tabSolicitud de Renovaciones` doc LEFT JOIN `tabTrabajadores pendiete de renovar` tab ON doc.name = tab.parent WHERE doc.data_12 = <mes_actual_texto> AND doc.año = <year> AND tab.codigo = <empleado> AND tab.renueva = 'Si' AND doc.estado_de_documento = 'Validado'

5️⃣ Validar si el empleado YA descargó la renovación

Consulta en base de datos interna:

historial_procesos_app WHERE proceso = 'descargaContratoRenovacion' AND empleado = <empleado>
{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su renovación de contrato" }

6️⃣ Si todo está correcto

Retorna éxito:

{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }

📥 Request Body

{ "empleado": "EMP-0001" }

📤 Response 200 – Ejemplos

✔ Caso correcto (ya descargó renovación)

{ "status": true, "msn": "Se ha descargado el contrato de trabajo" }

❌ Debe descargar renovación antes de usar el app

{ "status": false, "msn": "Para poder registrar su marcación o realizar alguna solicitud, descargar su renovación de contrato" }

✔ Aún no es día válido

{ "status": true, "msn": "No es el día correcto para la renovación de contrato" }

❗ Posibles Errores

Error Respuesta
Día inválido para la operación "No es el día correcto para la renovación de contrato"
Empleado sin renovación validada "Para poder registrar su marcación..."
Error inesperado en ejecución Se devuelve mensaje genérico, pero siempre con status: true
No existe el empleado El flujo simplemente finaliza sin error explícito

📚 Consultas y estructuras usadas

✔ ERP — Employee

Campos consultados:

{ "fecha_de_ingreso_real": "date" }

✔ ERP — Solicitud de Renovaciones

Consulta combinada mediante JOIN:

✔ Base interna MySQL (mysql2)

Tabla: historial_procesos_app

Campo crítico: proceso = 'descargaContratoRenovacion'


🗃 Lógica en Pseudo-código

if (dia_actual < 26) return "No es el día correcto" empleado = GET fecha_ingreso_real FROM Employee if fecha_ingreso < ultimo_dia_mes_anterior: renovacion = GET renovacion_validada FROM SolicitudRenovaciones if renovacion existe: descarga = buscar en historial_procesos_app if no hay descarga: return "Debe descargar renovación" return "OK"
Modulo de Asistencia y Marcaciones (Horas Extras)

Horas Extras del Mes (1) - [getMarkingsForEmployeePerMonth2]

🧾 Descripción

Obtiene y calcula todas las horas extras registradas para un empleado en un mes específico, detallando:

El servicio consulta información desde varios recursos del ERP:


🚀 Endpoint

POST /get-markings-employee-month

📥 Parámetros en el body

{ "employee": "EMP-0001", "month": "02", "year": "2025" }

🔐 Seguridad


🧠 Flujo del Servicio (resumen real)

1️⃣ Obtiene el corte mensual

Consulta el recurso:

GET /resource/Cortes filters: año = year, mes = month

Si no existe corte → retorna error "No hay corte mensual para este mes".


2️⃣ Obtiene las horas extras acumuladas del mes

GET /resource/Horas Extras fields: ["hhee_al_25","hhee_al_35","hhee_al_100"] filters: año, mes, empleado

3️⃣ Obtiene las marcaciones dentro del periodo del corte

GET /resource/Marcaciones filters: user_id = employee date BETWEEN corte.inicio AND corte.fin hours != 0

Si no hay marcaciones → retorna mensaje informativo.


4️⃣ Carga feriados desde archivo local

public/recursos_humanos/holidays.json

Feriados + domingos se consideran jornada al 100%.


5️⃣ Procesa cada marcación

Por cada registro:

Cada día se estructura como:

{ "fecha": "05 DE ENERO", "porcentaje": "35%", "horas_completadas": "3H" }

6️⃣ Arma la respuesta final:

Incluye:


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Lista de horas extras generado correctamente", "data": { "marcaciones": [ { "fecha": "03 DE ENERO", "porcentaje": "25%", "horas_completadas": "2H" }, { "fecha": "03 DE ENERO", "porcentaje": "35%", "horas_completadas": "1H" } ], "horas25": "12", "horas35": "4", "horas100": "2", "horas_acumuladas": "15" } }

❗ Posibles Errores

1. Corte mensual no configurado

{ "valor": false, "msn": "No hay corte mensual para este mes", "data": [] }

2. Error al traer horas extras

{ "valor": false, "msn": "Surgió un error, al obtener las horas extras", "data": [] }

3. Marcaciones vacías

{ "valor": false, "msn": "No hay horas extras registradas para este mes", "data": { "marcaciones": [], "horas25": "0", "horas35": "0", "horas100": "0", "horas_acumuladas": "0" } }

4. Error en servicio del ERP

{ "valor": false, "msn": "Surgió un error, al obtener las marcaciones.", "data": [] }

📚 Schemas utilizados

Cortes

{ "dia_inicio": "2025-01-01", "dia_final": "2025-01-31" }

Horas Extras

{ "hhee_al_25": "10", "hhee_al_35": "5", "hhee_al_100": "2" }

Marcaciones

{ "fecha": "2025-01-03", "horas": 3 }


🗃 Lógica en pseudo-código

corte = GET Cortes where año=year and mes=month if corte empty → return error hours = GET Horas Extras where año, mes, empleado markings = GET Marcaciones where user_id=employee and date between corte feriados = cargar holidays.json foreach marking: if fecha in feriados → 100% else if horas <= 2 → 25% else: agregar 2h al 25% agregar horas-2 al 35% sumar horas acumuladas return { marcaciones procesadas, horas25, horas35, horas100, horas_acumuladas }

Modulo Otros Descuentos

Modulo Otros Descuentos

Otros descuentos de Nomina (1, 2) - [listar]

🧾 Descripción

Obtiene y lista los otros descuentos de nómina registrados para un empleado en un año y mes específicos.
El servicio consulta la información en el ERP (Doctype: Otros Descuentos Nomina) y devuelve únicamente los registros que coinciden con el mes y año enviados.

Permite también filtrar por todos los meses del año enviando "TODOS" en el parámetro month.


🚀 Endpoint

POST /listar-descuentos


📥 Parámetros (Request Body)

{ "employee": "EMP-0001", "year": "2024", "month": "Marzo" }

Campos requeridos:

Campo Tipo Obligatorio Descripción
employee string ✔️ Sí Código del empleado
year string ✔️ Sí Año a filtrar
month string ✔️ Sí Mes a filtrar. Si se envía "TODOS" devuelve todos los meses del año.

🔐 Seguridad

Requiere token válido del ERP.
La comunicación se realiza mediante ServiceErp(), usando cabeceras internas de autenticación.


🧠 Flujo del Servicio (Resumen real)

  1. Valida que el parámetro employee exista.

  2. Valida que el parámetro year exista.

  3. Consulta al ERP:


GET Otros Descuentos Nomina/<employee>?fields=["table_22"]
  1. Verifica que exista información.

  2. Recorre la tabla interna table_22 (donde vienen los descuentos mensuales):

    • Compara:

      • item.mes == mes enviado

      • item.ano == año enviado

    • Si month == "TODOS", ignora el filtro del mes.

  3. Para cada coincidencia arma un objeto con:

    • motivo

    • monto

    • año

    • mes

    • creation (en formato "d de Mes")

  4. Si no hay coincidencias, retorna "Sin Descuentos".

  5. Si hay registros, los devuelve ordenados por creación.


📤 Response 200 – Ejemplo exitoso

{ "valor": true, "data": [ { "motivo": "Adelanto", "monto": 150.00, "mes": "Marzo", "anio": "2024", "creation": "05 de Marzo" }, { "motivo": "Descuento EPS", "monto": 35.00, "mes": "Marzo", "anio": "2024", "creation": "12 de Marzo" } ] }


⚠️ Respuestas de Error

1. Falta employee

{ "valor": false, "msn": "Falta employee" }

2. Falta año

{ "valor": false, "msn": "Ingrese un año" }

3. El ERP no devuelve información

{ "valor": false, "msn": "Sin Descuentos", "error": [] }

4. No existen descuentos para el filtro solicitado

{ "valor": false, "msn": "Sin Descuentos" }


🗃 Estructuras usadas (Schemas)

Otros Descuentos Nomina

Campos usados:

{ "table_22": [ { "motivo": "string", "monto": "float", "mes": "string", "ano": "string", "creation": "datetime" } ] }


🧩 Pseudocódigo

if employee is null → error if year is null → error otros_desc = GET Otros Descuentos Nomina/employee if no data → error foreach item in table_22: if (mes == month AND ano == year) OR (month == "TODOS" AND ano == year): agregar item a lista if lista vacía → error return lista formateada

Módulo Capacitación(Cursos)

Módulo Capacitación(Cursos)

Matricula Estudiante (1) - [enrollStudent]

🧾 Descripción

Este servicio matricula automáticamente a un estudiante en todos los programas de capacitación correspondientes a su puesto actual (designation).

El flujo toma como origen:

El servicio determina qué cursos pertenecen al puesto del estudiante, identifica qué programas contienen esos cursos y finalmente crea matrículas individuales para cada programa en el ERP.


🚀 Endpoint

POST /enroll-student


📥 Parámetros (Request Body)

{ "dni": "string" }
Campo Tipo Obligatorio Descripción
dni string DNI del estudiante para buscarlo en el ERP

🔐 Seguridad

Requiere autenticación interna mediante:


🧠 Flujo del Servicio (resumen)

1. Validar parámetro dni

Si no se envía DNI:
→ retorna error inmediato.


2. Buscar al estudiante en tabStudent

SELECT name, puesto, joining_date FROM tabStudent WHERE dni = <dni> ORDER BY joining_date DESC LIMIT 1

Si no existe:
→ retorna "no se encontró al estudiante".


3. Obtener todos los Programas del ERP

GET /resource/Program?fields=["name"]&limit=None

Por cada programa:


curso → [programas donde aparece]

4. Obtener todos los Cursos del ERP

GET /resource/Course?fields=["name"]

Por cada curso:


puesto → [cursos habilitados para ese puesto]

5. Validar si el puesto del estudiante tiene cursos asignados

Si no tiene cursos asociados:
→ retorna "No se encontró programas para este puesto".


6. Determinar los programas finales

Para cada curso del puesto, buscar en qué programas aparece y construir la lista final:


programas_finales = unique(programas_permitidos)

Si la lista queda vacía:
→ no existen programas asignados a este puesto.


7. Registrar las matrículas (Program Enrollment)

Para cada programa identificado:

  1. Validar si ya existe matrícula:

GET Program Enrollment?filters=[ ["student","=",<id_student>], ["program","=",<program>] ]
  1. Si existe, se almacena como encontrado.

  2. Si no existe, se crea:

POST Program Enrollment { "student": "<student_id>", "program": "<program>", "enrollment_date": "<fecha_hoy>", "academic_year": "<año>", "docstatus": 1 }

El servicio separa:


📤 Respuesta 200 – Ejemplo

{ "valor": true, "msn": "Lista de programas", "data": [ "PROG-001", "PROG-005" ], "enrollment": [ { "name": "ENR-0001" }, { "name": "ENR-0002" } ], "errors": [] }

❗ Posibles Errores

1. Falta DNI

{ "valor": false, "msn": "Falta enviar \"student\"" }

2. Estudiante no encontrado

{ "valor": false, "msn": "no se encontró al estudiante" }

3. Puesto sin cursos asociados

{ "valor": false, "msn": "No se Encontró programas para este puesto" }

4. Error al registrar un enrollment

Se devuelve en errors:

{ "errors": [ "mensaje del error interno" ] }

🗃 Esquemas usados en el ERP

Student

{ "name": "string", "dni": "string", "puesto": "string" }

Program

{ "name": "string", "courses": [ { "course": "string" } ] }

Course

{ "name": "string", "designation": [ { "designation": "string" } ] }

Program Enrollment

{ "student": "string", "program": "string", "enrollment_date": "date", "academic_year": "string", "docstatus": 1 }

🧩 Lógica en Pseudocódigo

dni = request.dni if empty(dni): return error student = query Student where dni=dni order by joining_date desc limit 1 if not found: return error designation = student.puesto programas = GET all programs mapProgramas = generar mapa curso → programas cursos = GET all courses mapCursos = generar mapa puesto → cursos if designation not in mapCursos: return error programas_final = programas donde cursos del puesto están incluidos foreach programa in programas_final: if enrollment existe: agregar a enrollments encontrados else: crear enrollment agregar respuesta a enrollments
Módulo Capacitación(Cursos)

Listar Cursos (1) - [listar]

🧾 Descripción

Este servicio obtiene todos los cursos asignados a un empleado o estudiante, basándose en su puesto (designation / puesto académico).

El flujo evalúa primero si el DNI pertenece a un Empleado, y si no, valida si pertenece a un Estudiante.
Con el puesto encontrado, se consultan los cursos vinculados y finalmente se retornan los detalles del curso desde tabCourse.

El servicio interactúa con:


🚀 Endpoint

POST /listar


📥 Request Body

{ "dni": "string" }

Campo Tipo Obligatorio Descripción
dni string DNI del empleado o estudiante para identificar su puesto.

🔐 Seguridad


🧠 Flujo del Servicio (Resumen real)

1. Buscar si el DNI pertenece a un Empleado activo

Consulta a: tabEmployee

con filtros:

Si se encuentra → extrae el designation.


2. Si no es empleado, verificar si es Estudiante activo

Consulta a: tabStudent

con filtros:

Si se encuentra → extrae el campo puesto.


3. Si no existe puesto asignado

Retorna mensaje:

"valor": false "msn": "No se encontro el puesto de empleado"


4. Buscar cursos asignados al puesto

Consulta a: tabPuesto Curso

filtrando por:

Obtiene los parent → IDs de los cursos asignados.


5. Obtener información de los cursos

Consulta a: tabCourse

Retorna campos:


6. Respuesta final

Se devuelve el listado de cursos con sus imágenes.


📤 Response 200 – Ejemplo

{ "valor": true, "data": [ { "name": "CURS-001", "hero_image": "/files/curso_001.png" }, { "name": "CURS-002", "hero_image": "/files/curso_002.png" } ] }


❗ Posibles Errores

1. No existe empleado NI estudiante con ese DNI

{ "valor": false, "msn": "No se encontro el puesto de empleado" }


2. Puesto sin cursos configurados

{ "valor": false, "msn": "Su usuario no tiene cursos asignados" }


3. Error al obtener datos del ERP

{ "valor": false, "msn": "Error al consultar datos", "data": [] }


📚 Tablas y Campos utilizados

🔸 tabEmployee

Campos:

🔸 tabStudent

Campos:

🔸 tabPuesto Curso

Campos:

🔸 tabCourse

Campos:


🗃 Lógica en pseudo-código

dni = request.dni employee = GET tabEmployee WHERE passport_number = dni AND status = 'Active' if employee exists: puesto = employee.designation else: student = GET tabStudent WHERE dni = dni AND enabled = 1 if student exists: puesto = student.puesto else: return error("No se encontro el puesto de empleado") cursosAsignados = GET tabPuesto Curso WHERE designation = puesto if cursosAsignados empty: return error("Su usuario no tiene cursos asignados") idsCursos = cursosAsignados.parents infoCursos = GET tabCourse WHERE name IN idsCursos return infoCursos

Módulo Capacitación(Cursos)

Cursos Temas (1, 2, 3, 4, 5, 6, 7) - CAPACITACIÓN ATC (II FASE) - [temas]

🧾 Descripción

Obtiene los temas (topics) de un curso específico y calcula cuántos videos y artículos contiene cada tema.

Este servicio consulta:

Está diseñado para mostrar al usuario un resumen claro del material disponible por tema.


🚀 Endpoint

GET /temas

📥 Parámetros (Request)

Se recibe un único valor desde el request:

{ "curso": "ID_DEL_CURSO" }


🔐 Seguridad

Este servicio requiere autenticación válida hacia el ERP mediante:


ServiceErp("GET", ...)

El token o cookies activos son manejados internamente por la clase general.


🧠 Flujo del Servicio (resumen real)

  1. Recibe el curso por parámetro.

  2. Consulta al ERP el recurso:


GET resource/Course/{curso}
  1. Verifica que el curso exista; si no, devuelve error:


    Su usuario no tiene cursos asignados
  2. Extrae la lista de topics del curso.

  3. Para cada topic:

    • Inicializa sus contadores:


      videos = 0 articulos = 0
    • Consulta el contenido del tópico:


      GET resource/Topic/{topic_id}
    • Recorre el contenido (topic_content):

      • Si content_type == Video → incrementa contador de videos

      • Si content_type == Article → incrementa contador de artículos

  4. Retorna la lista de temas con sus conteos.


📤 Response 200 – Ejemplo

{ "valor": true, "data": [ { "topic": "TP-001", "title": "Introducción", "videos": 3, "articulos": 1 }, { "topic": "TP-002", "title": "Conceptos Básicos", "videos": 1, "articulos": 2 } ] }


❗ Posibles Errores

1. Curso no existe o no tiene permisos

{ "valor": false, "msn": "Su usuario no tiene cursos asignados" }

2. El tópico no contiene información (se ignora sin romper el flujo)

No retorna error, simplemente no se contabiliza.

3. Fallo de conexión con ERP

{ "valor": false, "msn": "Error al consultar datos del ERP" }


📚 Schemas Consultados

Course

Campos usados:

{ "topics": [ { "topic": "string", "title": "string" } ] }

Topic

Campos usados:

{ "topic_content": [ { "content_type": "Video | Article", "content": "string" } ] }


🗃 Lógica en pseudo-código

curso = request.curso courseData = GET Course/{curso} if !courseData.exists: return error("Su usuario no tiene cursos asignados") topics = courseData.topics for each topic in topics: topic.videos = 0 topic.articulos = 0 topicContent = GET Topic/{topic.id} for content in topicContent: if content.type == "Video": topic.videos++ if content.type == "Article": topic.articulos++ return topics

Módulo Capacitación(Cursos)

Cursos Temas Contenido (1, 2, 3, 4, 5, 6, 7) - [temas_contenido]

🧾 Descripción

Obtiene todo el contenido asociado a un Tema de Capacitación, enriqueciendo la información con:

El servicio puede opcionalmente recibir el DNI del estudiante, para verificar su progreso (intentos de quiz).

Este servicio integra información desde varios recursos del ERP:


🚀 Endpoint

GET /temas-contenido

📌 Parámetros vía request:

Parámetro Tipo Obligatorio Descripción
tema string ✔️ Nombre del Topic a consultar
dni string DNI del estudiante para obtener intentos de quiz

🔐 Seguridad

Requiere autenticación interna vía:


$this->general->ServiceErp(...)

No necesita token del cliente, se usa credencial del backend.


🧠 Flujo del Servicio (Resumen real)

1️⃣ Si viene DNI → Obtener datos del estudiante

Consulta:

GET Student ?limit=None &fields=["name","puesto"] &filters=[["enabled","=",1],["dni","like","%{dni}%"]]

Guarda name del estudiante si existe.


2️⃣ Obtener el tema solicitado


GET Topic/{tema}

Debe existir; si no, devuelve: { "valor": false, "msn": "No se encontró el tema del curso" }


3️⃣ Recorrer cada elemento de “topic_content”

Para cada ítem:

📽 Si es Video:


GET Video/{content_id}

Agrega: "url": "<url del video>"


📄 Si es Article:


GET Article/{content_id}
"url": "<texto procesado o link>"


❓ Si es Quiz y hay estudiante:

GET Quiz Activity ?filters=[["quiz","=",content_id],["student","=", estudiante]]

Agrega: "quiz_attempts": <numero_de_intentos>

Si no hay estudiante o no es quiz: "quiz_attempts": 0


4️⃣ Retornar todos los contenidos enriquecidos


📥 Request Body (ejemplo)

{ "tema": "TOPIC-001", "dni": "12345678" }


📤 Response 200 – Ejemplo

{ "valor": true, "data": [ { "content_type": "Video", "content": "VID-01", "url": "https://erp/video1.mp4", "quiz_attempts": 0 }, { "content_type": "Article", "content": "ART-01", "url": "https://articulo.com/content", "quiz_attempts": 0 }, { "content_type": "Quiz", "content": "QUIZ-01", "quiz_attempts": 2 } ] }


❗ Posibles Errores

1. Tema no encontrado

{ "valor": false, "msn": "No se encontró el tema del curso" }

2. Estudiante no existe (cuando se envía DNI)

No genera error, simplemente no agrega intentos de quiz.

3. Contenido sin URL o datos incompletos

El servicio ignora valores faltantes y continúa procesando.

4. Error del servidor

{ "valor": false, "msn": "Error del servidor", "data": "<detalle>" }


📚 Recursos / Esquemas usados

Topic

{ "topic_content": [ { "content_type": "Video | Article | Quiz", "content": "string" } ] }

Video

{ "url": "string" }

Article

{ "content": "html|string" }

Student

{ "name": "string", "dni": "string", "puesto": "string" }

Quiz Activity

{ "quiz": "string", "student": "string" }


🗃 Pseudocódigo del servicio

if DNI: estudiante = GET Student by DNI topic = GET Topic/{tema} foreach content in topic.topic_content: if content_type == Video: obtener url del video if content_type == Article: obtener contenido, limpiar html, buscar link if content_type == Quiz and estudiante existe: obtener intentos realizados return lista enriquecida de contenidos

Módulo Capacitación(Cursos)

Examen del Curso (1, 2, 3) - EXAMEN ATC - Agregar contacto - [preguntas]

🧾 Descripción

Obtiene todas las preguntas de un examen (Quiz) registrado en el ERP, junto con sus opciones, respuestas correctas y metadatos.

El servicio se encarga de:


🚀 Endpoint

POST /preguntas


📥 Request Body

{ "examen": "QUIZ-0001" }

Parámetros

Campo Tipo Obligatorio Descripción
examen string ✔️ ID del cuestionario (Quiz.name)

🔐 Seguridad

Este servicio requiere acceso a la API interna del ERP a través de:


🧠 Flujo del Servicio (Explicación Real)

1. Construye consulta SQL

El servicio arma un query que une:

De esta manera obtiene:

2. Envía la consulta

Se ejecuta: POST method/send-query-database

3. Reorganiza la data

El ERP devuelve una fila por cada opción.
El servicio agrupa todo por: question.name

Generando esta estructura:

[ { question: "...", question_link: "...", options: [ { option: "...", is_correct: 0/1 } ] } ]

4. Convierte HTML → texto

Las preguntas vienen como HTML.
El servicio:

5. Construye la respuesta final

Para cada pregunta:


📤 Response 200 – Ejemplo

{ "valor": true, "data": [ { "name": "PREG-001", "owner": "admin@example", "creation": "2025-01-01", "modified": "2025-01-01", "modified_by": "admin@example", "idx": 1, "docstatus": 0, "question": "¿Cuál es la capital de Francia?", "question_type": "Opciones", "question_link": "PREG-001", "options": [ { "name": "OPT-001", "option": "Madrid", "is_correct": 0, "doctype": "Options" }, { "name": "OPT-002", "option": "París", "is_correct": 1, "doctype": "Options" } ], "imagen": "" } ] }


❗ Posibles Errores

1. Examen no encontrado

{ "valor": false, "msn": "No existe información del examen", "data": [] }

2. Error en consulta SQL

{ "valor": false, "msn": "Error al obtener preguntas", "data": "<mensaje_de_error>" }

3. Examen sin preguntas

{ "valor": true, "data": [] }


📚 Schemas Usados

🔸 Quiz

Campo Tipo
name string

🔸 Question

Campo Tipo
name string
question HTML
question_type string

🔸 Options

Campo Tipo
name string
option string
is_correct int (0 o 1)
parent question.name

🗃 Lógica en pseudo-código

examen = request.examen rows = SQL: SELECT preguntas + opciones FROM Quiz JOIN Quiz Question JOIN Question JOIN Options WHERE qz.name = examen grouped = reorganizarPorPregunta(rows) foreach pregunta in grouped: procesar HTML extraer texto e imagen return JSON(valor=true, data=preguntasProcesadas)

Módulo Capacitación(Cursos)

Evaluar Examen del Curso (1, 2, 3) - EXAMEN ATC - Agregar contacto - [guardar_examen_old]

🧾 Descripción

Este servicio registra las respuestas de un examen enviado por un estudiante.

La función:

  1. Recibe el DNI del estudiante, el identificador del examen y las respuestas.

  2. Valida que el estudiante exista en el ERP.

  3. Obtiene la definición completa del examen (Quiz) desde el ERP.

  4. Obtiene la información detallada de cada pregunta usando los question_link.

  5. Devuelve el listado de preguntas del examen, incluyendo su estructura completa.

Importante:
Este servicio no guarda las respuestas del examen.
Solo valida al estudiante y retorna las preguntas del examen consultado.


🚀 Endpoint

POST /guardar-examen-old


📥 Request Body (JSON)

{ "dni": "string", "examen": "string", "respuestas": "json_string" }

Ejemplo:

{ "dni": "12345678", "examen": "QUIZ-0001", "respuestas": "{\"P1\":\"A\",\"P2\":\"C\"}" }


🔐 Seguridad


🧠 Flujo del Servicio (Explicación detallada)

  1. Recibe datos del request:

    • $dni

    • $examen

    • $respuestas (JSON string → array)

  2. Decodifica las respuestas del examen:


    $respuestas = json_decode($respuestas, true);
  3. Busca al estudiante por DNI (solo estudiantes habilitados):

    GET Student
    filters=[["Student","enabled","=",1],["Student","dni","like","%<dni>%"]]

    • Si no encuentra coincidencias → ❌ devuelve error:


      { "valor": false, "msn": "Su usuario no tiene cursos asignados" }
  4. Obtiene la definición del examen (Quiz) desde el ERP:

    GET Quiz/<examen>

    • Trae todas las preguntas vinculadas.

  5. Por cada pregunta del examen:

    • Consulta la API:
      GET Question/{question_link}

    • Agrega la información completa al arreglo final.

  6. Devuelve todas las preguntas consultadas.


📤 Response 200 – Ejemplo

[ { "name": "QUESTION-001", "question": "¿Cuál es la capital de Perú?", "options": [ {"option": "Lima", "is_correct": 1}, {"option": "Cusco", "is_correct": 0} ] }, { "name": "QUESTION-002", "question": "Seleccione la opción correcta...", "options": [ ... ] } ]


❗ Posibles Errores

1. Estudiante no existe o no está habilitado

{ "valor": false, "msn": "Su usuario no tiene cursos asignados" }

2. Error consultando Quiz o Preguntas

(NOT IMPLEMENTED, pero puede ocurrir internamente)

{ "valor": false, "msn": "Error al obtener examen", "data": {} }

3. Respuestas mal formateadas

Si el JSON no es válido:

{ "valor": false, "msn": "Formato inválido de respuestas" }

(Nota: El código actual no valida esto, pero debería.)


📚 Schemas usados

Student (GET)

{ "name": "string", "dni": "string", "enabled": 1 }

Quiz (GET)

{ "name": "string", "question": [ { "question_link": "QUESTION-001" } ] }

Question (GET)

{ "name": "string", "question": "string", "options": [ { "option": "string", "is_correct": 0|1 } ] }


🗃 Lógica en pseudocódigo

dni = request.dni examen = request.examen respuestas = json_decode(request.respuestas) student = GET Student WHERE enabled=1 AND dni LIKE %dni% if student not found: return error quiz = GET Quiz/{examen} preguntas = [] foreach link in quiz.question: p = GET Question/{question_link} preguntas.append(p) return preguntas

Módulo Capacitación (Evaluaciones)

Módulo Capacitación (Evaluaciones)

Evaluaciones (1) - [serviceForNotesPerEmployee_old]

🧾 Descripción

Servicio que consulta y consolida los resultados de evaluaciones (exámenes) rendidos por un empleado durante un mes específico.

El servicio obtiene:

Esta es una versión antigua del servicio, mantenida por compatibilidad.


🚀 Endpoint

POST /service-for-notes-employee-old


📥 Request Body

{ "email": "usuario@empresa.com", "date": "2024-05-01" }

Parámetros

Campo Tipo Obligatorio Descripción
email string ✔️ Email corporativo del empleado (user_id).
date string (YYYY-MM-DD) ✔️ Fecha usada para identificar el mes a consultar.

🔐 Seguridad

Utiliza autenticación interna mediante apiService() (token ERP interno).

No requiere autenticación del cliente (uso interno backend → ERP).


🧠 Flujo del Servicio (Explicación Real)

1) Validación inicial

{ "valor": false, "msn": "Email necesario para la busqueda" }

2) Obtener empleado por email

Consulta al ERP:

GET Employee ?limit=None &fields=["name","passport_number","designation","fecha_de_ingreso_real"] &filters=[["user_id","=", "<email>"]]

Validaciones:


3) Obtener información del puesto (Designation)


GET Designation/<designation>

4) Rango de fechas del mes

A partir del parámetro date:

Ejemplo: 2024-05-01 to 2024-05-31


5) Obtener evaluaciones del mes

Consulta al ERP:

GET Quiz Activity ?limit=None &fields=["dni","quiz","status","score","activity_date"] &filters=[ ["dni","=", "<employee.passport_number>"], ["creation","Between", ["<firstDay>", "<lastDay>"]] ] &order_by=activity_date asc

6) Construcción del resultado


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Resultados de los examenes generado correctamente", "data": { "EXAMEN 1": { "examen": "EXAMEN 1", "puntaje": "85", "estado": "Pass" }, "EXAMEN 2": { "examen": "EXAMEN 2", "puntaje": "-", "estado": "No rindió" } }, "list_test": [ "EXAMEN 1", "EXAMEN 2" ] }

❗ Posibles Errores

1. Email vacío

{ "valor": false, "msn": "Email necesario para la busqueda" }

2. Error buscando empleado

{ "valor": false, "msn": "Error al buscar empleado" }

3. Sin puesto asignado

{ "valor": false, "msn": "El empleado no tiene un puesto asociado" }

4. Error obteniendo exámenes

{ "valor": false, "msn": "Error traer los examenes" }

5. Error obteniendo resultados

{ "valor": false, "msn": "Error traer los resultados de los examenes" }

6. Error interno del servidor

{ "valor": false, "msn": "Error al generar Servicio" }

📚 Schemas

Employee

{ "name": "string", "passport_number": "string", "designation": "string", "fecha_de_ingreso_real": "date" }

Designation

{ "exa": [ { "examen": "string" } ] }

Quiz Activity

{ "dni": "string", "quiz": "string", "status": "Pass|Fail", "score": "number", "activity_date": "date" }

🗃 Lógica en pseudo-código

email = request.email date = request.date if email is empty: return error employee = GET Employee by user_id=email if empty: return error designation = employee.designation if empty: return error exams = GET Designation/exams range = firstDayOfMonth(date), lastDayOfMonth(date) quizResults = GET QuizActivity where dni = employee.passport_number and creation between range prepare response: for each exam: set puntaje = "-" set estado = "No rindió" for each quizResult: keep best score set estado based on Pass/Fail return json

Módulo Contratación

Módulo Contratación

Documento de Ingresos (Subir Documentos de ingresos (1)) - [documentosIngreso]

🧾 Descripción

Registra y actualiza los documentos obligatorios de ingreso de un empleado dentro del ERP, así como su información bancaria y de fondo de pensiones.

Este servicio valida la información mínima necesaria antes de actualizar el documento Employee en el ERP.

👉 Es un servicio crítico para el proceso de onboarding, ya que sin este registro el empleado no continúa con otros procesos internos.


🚀 Endpoint

POST /documentos-ingreso


📥 Parámetros de entrada (Request Body)

{ "employee": "EMP-00123", "banco": "BCP", "dni": "12345678", "copia_dni_de_hijos": "url_file", "certificado_de_estudios": "url_file", "cv": "url_file", "copia_dni_de_conyuge": "url_file", "certificado_de_trabajo": "url_file", "certijoven": "url_file", "copia_de_recibo": "url_file", "fondo_pensiones": "AFP", "afiliado_fondo_pensiones": "SI" }

🔐 Seguridad

Requiere token válido del ERP (la autenticación se maneja internamente mediante ServiceErp()).


🧠 Flujo del Servicio (Resumen Real)

  1. Valida que existan campos obligatorios:

    • employee

    • banco

    • fondo_pensiones

    • afiliado_fondo_pensiones (“SI” o “NO”)

  2. Construye un arreglo con los datos a actualizar:

$data = [ "eleccion_banco" => banco, "elección_fondo_pensiones" => fondo_pensiones, "afiliado_fondo_pensiones" => afiliado_fondo_pensiones, ... ];
  1. Si el fondo de pensiones es ONP, también actualiza:


"fondo_de_pensiones" => "ONP"
  1. Si se envían documentos opcionales (DNI, copia de DNI de hijos, CV, certificado de trabajo, etc.), también se agregan al payload.

  2. Realiza la actualización del empleado:


PUT /resource/Employee/{employee}
  1. Devuelve la respuesta del ERP junto con los datos enviados.


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Documentos registrados correctamente", "data": { "eleccion_banco": "BCP", "elección_fondo_pensiones": "AFP", "afiliado_fondo_pensiones": "SI", "dni": "12345678", "cv": "url_file", "certificado_de_trabajo": "url_file" } }

❗ Posibles Errores

1. Falta el employee

{ "valor": false, "msn": "Falta key employee" }

2. Falta banco

{ "valor": false, "msn": "El banco es obligatorio" }

3. Falta fondo de pensiones

{ "valor": false, "msn": "El fondo de pensiones es obligatorio" }

4. Afiliado fondo pensiones inválido

{ "valor": false, "msn": "Valor no permitido en Afiliado a Fondo de Pensiones" }

5. Error del ERP al actualizar

{ "valor": false, "msn": "Error al actualizar documentos", "data": { ...respuesta del ERP... } }

📚 Data Model Usado

Employee (PUT)

Campos actualizables:

{ "eleccion_banco": "string", "elección_fondo_pensiones": "AFP|ONP", "afiliado_fondo_pensiones": "SI|NO", "dni": "string", "copia_dni_de_hijos": "string|fileurl", "certificado_de_estudios": "string|fileurl", "certijoven": "string|fileurl", "cv": "string|fileurl", "copia_dni_de_conyuge": "string|fileurl", "certificado_de_trabajo": "string|fileurl", "copia_de_recibo": "string|fileurl", "asignacion_familiar_2": 0|1, "fondo_de_pensiones": "AFP|ONP" }

🗃 Pseudocódigo de la lógica

if employee is empty → error if banco is empty → error if fondo_pensiones is empty → error if afiliado_fondo_pensiones not in ("SI","NO") → error data = { eleccion_banco: banco, elección_fondo_pensiones: fondo_pensiones, afiliado_fondo_pensiones: afiliado_fondo_pensiones } if fondo_pensiones == "ONP": data["fondo_de_pensiones"] = "ONP" Agregar campos opcionales si existen PUT Employee/{employee} with data return respuesta del ERP + msn "Documentos registrados correctamente"
Módulo Contratación

Documento de Ingresos (Formulario Ficha de Personal (1)) - [formFichaPersonal]

🧾 Descripción

Registra la Ficha Personal del trabajador, permitiendo actualizar:

Es un servicio utilizado por la aplicación para completar los datos obligatorios que el trabajador debe registrar para continuar con otros procesos internos.

Este servicio actualiza directamente el documento Employee en el ERP.


🚀 Endpoint


POST /form-ficha-personal

📥 Request Body (JSON)

{ "empleado": "EMP-0001", "contactoEmergencia": { "nombreCompleto": "Juan Perez", "parentesco": "Hermano", "telefono": "987654321" }, "estadoCivil": { "nombreCompleto": "Ana Torres", "fechaNacimiento": "1990-01-01", "ocupacion": "Administradora", "centroTrabajo": "Empresa X", "direccion": "Av. Los Olivos 123" }, "datosFamiliares": [...] }

Los campos contactoEmergencia y estadoCivil vienen como JSON string y se decodifican dentro del servicio.


🔐 Seguridad


🧠 Flujo del Servicio (Paso a Paso)

1️⃣ Validaciones iniciales

2️⃣ Obtiene información del empleado


GET /resource/Employee/{empleado}

Valida que el empleado exista y revisa si tiene estado civil registrado en el ERP:

3️⃣ Determina nuevo estado civil

Si el ERP no tiene estado civil registrado:

4️⃣ Construye el body para actualizar Employee

Campos incluidos:

{ "person_to_be_contacted": "...", "relation": "...", "emergency_phone_number": "...", "nombre_completo_conyugue": "...", "fecha_de_nacimiento_conyugue": "...", "ocupación_conyugue": "...", "centro_de_trabajo_conyugue": "...", "dirección_actual_conyugue": "...", "estado_civil_personal": "Casado/a" }

Todos los textos se envían en mayúsculas.

5️⃣ Actualiza Employee


PUT /resource/Employee/{empleado}

6️⃣ Registra proceso de Ficha Personal

Inserta un registro en MySQL (historial_procesos_app) con:

Sirve para el tracking de documentos obligatorios.

7️⃣ Respuesta exitosa

Devuelve:

{ "valor": true, "msg": "Se registró correctamente" }

📤 Response 200 – Ejemplo

✔️ Caso exitoso

{ "valor": true, "msg": "Se registró correctamente", "data": [] }

❌ Error: falta información del estado civil

{ "valor": false, "msg": "No tiene su información de estado civil, debe comunicarse con Soporte", "data": [] }

❌ Error: datos incompletos del cónyuge

{ "valor": false, "msg": "Complete la información del cónyugue o conviviente. Información faltante: fechaNacimiento", "data": [] }

❌ Error al actualizar en el ERP

{ "valor": false, "msg": "Ocurrió un error al actualizar la información del trabajador.", "data": { ...respuestaERP... } }

❗ Posibles Errores Detallados

Error Descripción
Missing estadoCivil No se envió estado civil o JSON inválido
Missing contactoEmergencia Falta información mínima para completar la ficha
Employee no encontrado GET Employee/{empleado} no encontró registro
Información incompleta del cónyuge Falta un campo requerido cuando el estado civil es casado/conviviente
Error de actualización PUT Employee falló
Error registrando proceso Inserción en historial_procesos_app falló

📚 Schemas (Estructuras Utilizadas)

Employee (GET y PUT)

Campos usados:

person_to_be_contacted relation emergency_phone_number nombre_completo_conyugue fecha_de_nacimiento_conyugue ocupación_conyugue centro_de_trabajo_conyugue dirección_actual_conyugue estado_civil_personal

historial_procesos_app (INSERT)

usuario empleado proceso fecha estado

🗃 Lógica en pseudo-código

empleado = request.empleado contacto = json_decode(request.contactoEmergencia) civil = json_decode(request.estadoCivil) if civil is null or empty: return error("No tiene información de estado civil") if contacto is null: return error("Falta información de contacto de emergencia") employee = GET Employee/{empleado} if civil.previous == Casado or Conviviente: validar campos completos de cónyuge newCivil = employee.estadoCivil != "" ? employee.estadoCivil : (civil.nombreCompleto ? "Casado/a" : "Soltero/a") bodyPUT = construir campos del contacto + cónyuge update = PUT Employee/{empleado} if update.ok: insertar registro en historial_procesos_app return success else: return error("Ocurrió un error al actualizar")
Módulo Contratación

Documento de Ingresos (Verificar Registro de Postulación (1)) - [validatePersonalRequirement]

🧾 Descripción

Este servicio valida si un postulante (que ya es empleado o está en proceso de contratación) cumple con las condiciones necesarias para continuar el proceso de Alta y Requerimiento de Personal.

La validación se basa en:

Este servicio permite determinar si se puede generar su trámite de contratación y qué parámetros corresponden a su modalidad de trabajo y tipo de jornada.


🚀 Endpoint

POST /validate-personal-requirement

📥 Request Body

{ "document": "12345678" }

Parámetros:


🔐 Seguridad

Requiere autenticación interna hacia el ERP mediante dbErp() y rutas definidas en APICAPACITACION.


🧠 Flujo del Servicio (Resumen)

1️⃣ Validar si el documento pertenece a un Employee

Consulta en tabEmployee:

SELECT employment_type, tipo_de_jornada FROM tabEmployee WHERE passport_number = :document

2️⃣ Buscar su postulación más reciente (Job Applicant)

Consulta:

SELECT job_title FROM tabJob Applicant WHERE numero_de_documento = :document AND docstatus != 2 ORDER BY creation DESC

3️⃣ Obtener información de la Convocatoria (Job Opening)

Consulta:

SELECT modalidad_de_trabajo, modalidad, sucursal FROM tabJob Opening WHERE name = :job_title AND docstatus != 2

4️⃣ Obtener información de la Sucursal (Branch)

Consulta:

SELECT division_nacional FROM tabBranch WHERE name = :sucursal AND docstatus != 2

5️⃣ Obtener el Requerimiento de Personal asociado a la convocatoria

SELECT tipo_de_jornada FROM {RequerimientoTabla} WHERE documento_convocatoria = :job_title AND docstatus != 2

6️⃣ Respuesta exitosa

Devuelve:


📤 Response 200 – Ejemplo

{ "valor": true, "Message": "Exito.", "data": { "tipo_jornada": "Tiempo completo", "modalidad": "Presencial", "convocatoria": "JOB-2025-00123" } }

❗ Posibles Errores

1. No existe empleado con el documento

{ "valor": false, "Message": "Surgió un error, contactar con soporte.", "data": [] }

2. No existen postulaciones válidas

{ "valor": false, "Message": "No se encontró un registró de su postulación a una de nuestras convocatorias, comuniquese con su administrador.", "data": [] }

3. Convocatoria no encontrada

{ "valor": false, "Message": "No se encontró la convocatoria vinculada a su postulación, comuniquese con su administrador.", "data": [] }

4. Sucursal/Terminal inexistente

{ "valor": false, "Message": "No existe la terminal del usuario.", "data": [] }

5. Requerimiento de Personal no creado

{ "valor": false, "Message": "La convocatoria del postulante no tiene REQUERIMIENTO DE PERSONAL creada, realizar nuevamente el proceso de contratación.", "data": [] }

6. Error del servidor

{ "valor": false, "Message": "Ocurrio un error en el servidor.", "data": [] }

📚 Esquemas utilizados

Employee

Campos consultados:

{ "employment_type": "string", "tipo_de_jornada": "string" }


Job Applicant

{ "job_title": "string" }

Job Opening

{ "modalidad_de_trabajo": "string", "modalidad": "string", "sucursal": "string" }

Branch

{ "division_nacional": "string", "name": "string" }

Requerimiento de Personal

{ "tipo_de_jornada": "string", "name": "string" }

🗃 Lógica en Pseudocódigo

employee = GET Employee WHERE passport_number = document if not employee: error("Empleado no encontrado") postulacion = GET Job Applicant WHERE document = document ORDER BY creation DESC if not postulacion: error("Postulación no encontrada") convocatoria = GET Job Opening WHERE name = postulacion.job_title if not convocatoria: error("Convocatoria no encontrada") branch = GET Branch WHERE name = convocatoria.sucursal select RP_table = Branch.zone == Lima ? RP_Lima : RP_Normal rp = GET RP_table WHERE documento_convocatoria = job_title if not rp: error("RP no creada") return { tipo_jornada: rp.tipo_de_jornada, modalidad: convocatoria.modalidad || modalidad_de_trabajo, convocatoria: job_title }
Módulo Contratación

Documento de Ingresos (Registrar Proceso de Descarga (1)) - [registerProcessApp]

🧾 Descripción

Registra en la tabla historial_procesos_app cada evento o proceso realizado por un usuario dentro de la aplicación móvil.
Además, dependiendo del tipo de proceso, realiza validaciones adicionales como:

Este servicio funciona como logger centralizado de acciones críticas del trabajador.


🚀 Endpoint

POST /register-process-app


📥 Parámetros de Entrada (Body)

{ "usuario": "string", "empleado": "string", "agencia": "string", "latitude": "string", "longitude": "string", "proceso": "string", "month": "int", "year": "int" }


🔐 Seguridad


🧠 Flujo del Servicio (Resumen Real)

1️⃣ Obtiene parámetros principales del request:


2️⃣ Si el proceso es descargaContratoReingreso

$this->validateProcessContractRenovation($request, $connection);

$this->validateProcessContractChangeModality($request,$connection);


3️⃣ Si el proceso es descargaContratoTrabajo

a) Obtiene datos del empleado en el ERP

(Documento, sucursal, nombre y puesto)

SELECT passport_number, id_sucursal, nombre_completo, designation FROM `tabEmployee`

b) Si el puesto contiene la palabra CONDUCTOR

El sistema crea un usuario conductor en un sistema externo:

POST EMPRESARIAL/api/crearUsuarioConductor { documento: DNI, ter_id: id_sucursal, nombre: nombre_completo }

Cualquier error en este paso retorna:

{ "valor": false, "msn": "Ocurrio un error al registrar el proceso." }


4️⃣ Inserta el registro del proceso en historial_procesos_app

Campos insertados:

Campo Descripción
usuario Usuario que ejecuta el proceso
empleado Código del empleado
agencia ID de la agencia
latitude Latitud
longitude Longitud
proceso Nombre del proceso ejecutado
fecha Fecha y hora actual
estado 1 (registrado)
month Mes
year Año

5️⃣ Devuelve respuesta exitosa

{ "valor": true, "msn": "Proceso registrado con éxito." }


📤 Respuestas

200 – Éxito

{ "valor": true, "msn": "Proceso registrado con éxito." }


❗ Error al insertar registro

{ "valor": false, "msn": "Ocurrio un error al registrar el proceso." }


❗ Empleado no encontrado

{ "valor": false, "msn": "No se encontró al empleado." }


❗ Error de creación de usuario conductor

{ "valor": false, "msn": "Ocurrio un error al registrar el proceso." }


📚 Estructuras utilizadas

Tabla: historial_procesos_app

{ "usuario": "string", "empleado": "string", "agencia": "string", "latitude": "string", "longitude": "string", "proceso": "string", "fecha": "datetime", "estado": 1, "month": "int", "year": "int" }

ERP: Employee

Campos usados:

{ "passport_number": "string", "id_sucursal": "string", "nombre_completo": "string", "designation": "string" }


🗃 Lógica en Pseudocódigo

leer usuario, empleado, proceso, month, year, lat, long si proceso == "descargaContratoReingreso": validar renovación de contrato validar cambio de modalidad si proceso == "descargaContratoTrabajo": traer datos del empleado si puesto incluye "CONDUCTOR": crear usuario conductor en sistema externo insertar registro en historial_procesos_app si inserción falla: retornar error retornar éxito

Módulo Contratación

Documento de Ingresos (Registrar Equipamiento (1)) - [store_equipament]

🧾 Descripción

Registra o actualiza las tallas de equipamiento de EPP (botas, polo, pantalón) para un postulante, validando previamente:

Es un servicio que integra:


🚀 Endpoint

POST /store-equipament


🔐 Seguridad

Requiere autenticación interna contra el ERP mediante:

No hace validaciones de token en el controlador; se maneja internamente por los métodos usados.


🧠 Flujo del Servicio (explicación real)

  1. Lee los parámetros enviados en la petición:

    • documento

    • botas

    • polo

    • pantalon

  2. Valida la estructura y tallas permitidas:

    Elemento Tallas permitidas
    botas 36–45
    polo S, M, L, XL
    pantalón S, M, L, XL
  3. Busca al postulante por documento:
    Llama a:


    searchPostulanteByDocument($documento)

    Si no existe → retorna error.

  4. Busca si ya existe un registro de triaje activo en el ERP:

    GET
    /resource/Triaje de Postulante 2
    con filtros:


    documento = $documento docstatus != 2
  5. Dependiendo del resultado:

    • No existe registro → crea uno (POST)

    • Sí existe → actualiza el existente (PUT)

  6. Realiza el POST o PUT correspondiente hacia el ERP.

  7. Si ERP devuelve error, intenta decodificar _server_messages para obtener error real del ERP.

  8. Retorna respuesta final indicando éxito o error.


📥 Request Body

Ejemplo:

{ "documento": "12345678", "botas": 42, "polo": "M", "pantalon": "L" }

📤 Response 200 – Ejemplos

✔️ Registro/Actualización exitosa

{ "valor": true, "msn": "Equipamiento registrado con éxito" }

❌ Documento no enviado

{ "valor": false, "msn": "Falta enviar el documento" }

❌ Talla inválida

{ "valor": false, "msn": "Ingrese una talla de botas válida" }

❌ Postulante no encontrado

{ "valor": false, "msn": "No existe postulante con ese documento" }

❌ Error del ERP

{ "valor": false, "msn": "Ocurrió un error al registrar el triaje del postulante", "data": [ "PUT", { ...body... }, "URL del recurso usado" ] }

❗ Posibles Errores del Servicio

Tipo Ejemplo
Documento no enviado "Falta enviar el documento"
Talla no válida "Ingrese una talla de botas válida"
Postulante no encontrado respuesta directa del servicio searchPostulanteByDocument
Error al crear/actualizar en ERP Mensaje del _server_messages o mensaje genérico
Error inesperado Devuelve el error capturado del ERP

🗃 ERP: Documentos involucrados

Triaje de Postulante 2 (GET / POST / PUT)

Campos usados:

Campo Tipo
documento string
botas int
polo string
pantalon string
name string (clave para PUT)

🧩 Lógica en Pseudocódigo

read document, botas, polo, pantalon validate document validate botas in [36..45] validate polo in [S,M,L,XL] validate pantalon in [S,M,L,XL] postulante = searchPostulanteByDocument(document) if postulante.invalid: return error triaje = GET TriajeDePostulante2 where documento=document and docstatus != 2 if triaje exists: method = PUT url = recurso + "/" + triaje.name else: method = POST url = recurso body = { documento, botas, polo, pantalon } result = CALL ERP with method, body, url if result.error: return readable ERP error return success

Módulo Contratación

Documento de Ingresos (Registrar Proceso de Descarga (1, 2,3,4,5)) - [registerProcessApp]

🧾 Descripción

Registra en la tabla historial_procesos_app todas las acciones (procesos) que el usuario realiza dentro del aplicativo móvil, como descargas de documentos, validación de contratos, marcaciones, entre otros.

Antes de registrar el proceso:

  1. Valida si corresponde un proceso de Reingreso o Renovación de Contrato.

  2. Procesa el registro especial para Conductores, creando su usuario en el sistema empresarial cuando descarga su contrato.

  3. Guarda la información del evento (geolocalización, mes, año, proceso, etc.) en la base de datos MySQL2.

Este servicio constituye una pieza clave para los módulos de:


🚀 Endpoint

POST /register-process-app


📥 Request Body

{ "usuario": "string", "empleado": "string", "agencia": "string", "latitude": "string|float", "longitude": "string|float", "proceso": "string", "month": "int", "year": "int" }


🔐 Seguridad


🧠 Flujo del Servicio (resumen real)

1️⃣ Obtiene los parámetros enviados desde la App

Usuario, empleado, agencia, geolocalización, proceso, mes y año.

2️⃣ Si el proceso es descargaContratoReingreso

Ejecuta:

Estas funciones validan:

3️⃣ Si el proceso es descargaContratoTrabajo

  1. Obtiene datos del empleado desde ERP:

    • DNI (passport_number)

    • Sucursal

    • Nombre completo

    • Puesto (designation)

  2. Si el puesto contiene "CONDUCTOR", registra el usuario en el sistema empresarial:


POST EMPRESARIAL/api/crearUsuarioConductor

Enviando:

{ "documento": "<passport_number>", "ter_id": "<id_sucursal>", "nombre": "<nombre_completo>" }

4️⃣ Inserta el proceso en la tabla MySQL:

Tabla: historial_procesos_app

Campos guardados:

5️⃣ Retorna la respuesta del proceso


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Proceso registrado con éxito." }


❗ Posibles Errores

1. No se puede registrar el proceso en MySQL

{ "valor": false, "msn": "Ocurrio un error al registrar el proceso." }

2. No se encuentra el empleado en el ERP

{ "valor": false, "msn": "No se encontró al empleado." }

3. Error creando usuario conductor

{ "valor": false, "msn": "Ocurrio un error al registrar el proceso." }

4. Error genérico

{ "valor": false, "msn": "Error interno del servidor." }


📚 Schemas – Objetos usados

🗂 Employee (GET ERP)

Campos usados:

{ "passport_number": "string", "id_sucursal": "string", "nombre_completo": "string", "designation": "string" }

🗂 Registro MySQL – historial_procesos_app

{ "usuario": "string", "empleado": "string", "agencia": "string", "latitude": "string|float", "longitude": "string|float", "proceso": "string", "fecha": "datetime", "estado": 1, "month": "int", "year": "int" }


🗃 Lógica en pseudo-código

leer parametros del request if proceso == "descargaContratoReingreso": validar renovación validar cambio modalidad if proceso == "descargaContratoTrabajo": traer datos del empleado desde ERP if designation contiene "CONDUCTOR": crear usuario conductor via API Empresarial insertar registro en historial_procesos_app si insert falla: devolver error return éxito

Módulo Contratación

Contrato de Trabajo(Url Contrato de trabajo PDF (1)) - [printContractPerDesignation]

🧾 Descripción

Genera y descarga el Contrato de Trabajo correspondiente a un empleado, seleccionando de forma automática el formato de contrato correcto según:

El servicio determina internamente qué plantilla PDF debe usarse y devuelve el archivo final generado.

Es un servicio interno que consulta múltiples recursos del ERP:


🚀 Endpoint

GET /print-contract-per-designation/{employee}

📥 Parámetros de ruta

Parámetro Tipo Obligatorio Descripción
employee string Código único del empleado en ERP

🔐 Seguridad

Requiere autenticación interna:


🧠 Flujo del Servicio (Resumen Real)

1️⃣ Validación del empleado

Consulta al ERP:

POST send-query-database FROM tabEmployee WHERE name = employee SELECT fecha_de_ingreso_real

Si no existe → retorna error: "No existe empleado".


2️⃣ Obtiene el contrato activo más reciente

Se buscan contratos con:

POST send-query-database FROM tabContrato de Trabajo LEFT JOIN tabEmployee

Si no existe contrato → retorna "No cuenta con Contrato".


3️⃣ Obtiene funciones asociadas (solo extranjeros)

Busca funciones del contrato:

FROM tabtabla_funcion_extranjero WHERE parent = contrato.name

Estas funciones se agregan al contrato en el PDF.


4️⃣ Determina el número de contratos previos

Solo aplica a empleados con documento PAS o CE.

Consulta cantidad de contratos registrados después del ingreso real.

Esto permite determinar si el contrato es:


5️⃣ Selección automática de la plantilla PDF

En base a reglas:

Condición Plantilla
modalidad_de_trabajo = Teletrabajo contrato_teletrabajo
labor contiene "CONDUCTOR" contrato_conductor_interprovincial
labor = "VIGILANTE" contrato_full_time_vigilante
tipo_doc PAS o CE, primer contrato contrato_extranjero
tipo_doc PAS o CE, más de 1 contrato contrato_extranjero_mas_de_segundo_contrato
tipo_contrato = PART TIME, labor=CALL CENTER ATC contrato_call_center_part_time
tipo_contrato = PART TIME contrato_part_time
tipo_contrato = FULL TIME contrato_full_time

El método retorna el PDF con:

PDF::loadView(...)->download();


📤 Response – Archivo PDF

Retorna directamente la descarga del contrato correspondiente.

Si ocurre algún error, retorna un JSON:

✔️ Empleado válido, pero sin contrato

{ "valor": false, "msn": "No cuenta con Contrato" }

❌ Empleado no encontrado

{ "valor": false, "msn": "No existe empleado" }


❗ Posibles Errores

Error Descripción
Empleado no existe No se encontró en tabEmployee
No tiene contratos vigentes No existe Contrato de Trabajo activo
Error DB ERP Respuesta inesperada en dbErp
Plantilla no encontrada Error al cargar vista PDF (muy raro)

📚 Tablas y Campos Utilizados

Employee (GET)

Campos usados:

{ "fecha_de_ingreso_real": "date" }

Contrato de Trabajo

{ "name": "string", "fecha_de_ingreso_real": "date", "empleado": "string", "labor": "string", "tipo_de_documento": "string", "modalidad_de_trabajo": "string", "tipo_de_contrato": "string" }

Funciones del Contrato (Extranjeros)

{ "funcion": "string" }


🗃 Lógica en Pseudocódigo

employeeData = GET Employee where name = employee if not exists: return error contract = GET Contrato where empleado=employee and activo if not exists: return error funciones = GET Funciones where parent=contract if doc PAS/CE: countPrevious = GET Contratos after ingreso real determinar ordinal seleccionar plantilla PDF según reglas return descargar PDF

Módulo Boletas de Pago

Módulo Boletas de Pago

Boleta Mensual(Obtener Proceso de Descarga (1)) - [obtener]

🧾 Descripción

Este servicio permite buscar y obtener información detallada de una denuncia registrada en el ERP, usando un código aleatorio generado para consulta pública.

La función:

Es un servicio de consulta directa, sin dependencias entre módulos.


🚀 Endpoint

POST /obtener

📥 Request Body

{ "codigo": "ABC12345" }

🔐 Seguridad

No requiere token especial más allá del utilizado internamente por apiService() o ServiceErp().
La autenticación se maneja dentro del sistema ERP.


🧠 Flujo del Servicio (resumen real)

  1. Recibe el parámetro: codigo = $request->codigo

  2. Construye un request hacia el ERP: GET Denuncias?fields=[...]&filters=[["codigo_aleatorio","=",codigo]]

Campos obtenidos:

  1. Si no existe la denuncia → se responde:

{ "success": false, "message": "No se encontró la denuncia" }
  1. Si existe y tiene archivo, se concatena la URL base:


archivo_denuncia = BASE_CAPACITACION . archivo_denuncia
  1. Se devuelve la primera denuncia encontrada, ya que el código es único.


📤 Response 200 – Ejemplo

{ "success": true, "message": "Encontrado", "data": { "name": "DEN-00045", "creation": "2025-01-15 09:12:20", "estado_denuncias": "Atendido", "fecha_atendido": "2025-01-20", "fecha_proceso": "2025-01-18", "archivo_denuncia": "https://servidor.com/files/denuncias/archivo.pdf", "respuesta_de_denuncia_atendido": "Se revisó la información y se procedió..." } }

❗ Posibles Errores

1. No se encuentra la denuncia

{ "success": false, "message": "No se encontró la denuncia" }

2. Error del ERP

{ "success": false, "message": "Error message from ERP" }

3. Código vacío o inválido

{ "success": false, "message": "No se encontró la denuncia" }

📚 Schemas Usados

Denuncias (GET)

Campos usados:

{ "name": "string", "creation": "datetime", "estado_denuncias": "string", "fecha_atendido": "date", "fecha_proceso": "date", "archivo_denuncia": "string|null", "respuesta_de_denuncia_atendido": "string|null" }

🗃 Lógica del Servicio (Pseudo-código)

codigo = request.codigo body = { limit = None fields = [name, creation, estado_denuncias, fecha_atendido, fecha_proceso, archivo_denuncia, respuesta...] filters = [["codigo_aleatorio", "=", codigo]] } response = GET Denuncias using ServiceErp if !response.valor or response.response is empty: return error "No se encontró la denuncia" denuncia = response.response[0] if denuncia.archivo_denuncia != "": denuncia.archivo_denuncia = BASE_CAPACITACION + denuncia.archivo_denuncia return success with denuncia
Módulo Boletas de Pago

Utilidades(Consultar Utilidades (1)) - [getYearUtilidades]

🧾 Descripción

Este servicio obtiene:

  1. La lista de años registrados en el ERP (tabla Year), ordenados de forma descendente.

  2. Valida si el empleado tiene utilidades asignadas para al menos un año (tabla Utilidades).

El objetivo es determinar si el empleado cuenta con utilidades cargadas y retornar la lista de años disponibles para consulta.


🚀 Endpoint

POST /get-year-utilidades


📥 Parámetros de entrada (Request Body)

{ "employee": "EMP-0001" }

Campos

Campo Tipo Obligatorio Descripción
employee string ID del empleado para validar si tiene utilidades.

🔐 Seguridad

Utiliza autenticación mediante ServiceErp() (token interno del ERP).
No requiere permisos adicionales, ya que solo consulta información.


🧠 Flujo del Servicio (explicación real)

1️⃣ Obtener los años disponibles (tabla Year)

Llama al ERP: GET Year?limit=None&fields=["name"]


2️⃣ Validar si el empleado tiene utilidades registradas

Consulta al ERP: GET Utilidades?limit=None&fields=["name"]&filters=[["empleado","=", employee]]


📤 Response 200 – Ejemplo

Caso 1 — El empleado NO tiene utilidades

{ "valor": false, "msn": "Hemos verificado que no tiene utilidades asignadas. Para más detalles, consultar con el área de RRHH", "data": ["2024", "2023", "2022"] }

Caso 2 — El empleado SÍ tiene utilidades

{ "valor": true, "msn": "Hemos verificado que no tiene utilidades asignadas. Para más detalles, consultar con el área de RRHH", "data": ["2024", "2023", "2022"] }

📌 Nota: El mensaje es el mismo en ambos escenarios, siguiendo el comportamiento del código original.


❗ Posibles Errores

Caso Respuesta
Error al obtener años del ERP years → [] (no rompe el flujo)
Error de conexión con el ERP years → []
El empleado no tiene utilidades "valor": false
El empleado sí tiene utilidades "valor": true"

📚 Tablas usadas (schemas)

📄 Year (GET)

Campos usados: { "name": "string" }

📄 Utilidades (GET)

Campos usados: { "name": "string" }


🗃 Lógica en pseudo-código

employee = request.employee years = GET Year years = list of names sort years desc utilidades = GET Utilidades where empleado = employee if utilidades.count == 0: return { valor: false, msn: "...", data: years } return { valor: true, msn: "...", data: years }
Módulo Boletas de Pago

Utilidades(Obtener Proceso de Descarga (1, 2, 3,4,5)) - [show]

🧾 Descripción

Este servicio permite consultar el último registro almacenado en la tabla historial_procesos_app según:

Es usado para validar si un empleado ya realizó o no un proceso específico dentro del aplicativo.


🚀 Endpoint

POST /show


📥 Parámetros de Entrada (Request Body)

{ "empleado": "EMP-0001", "proceso": "descargaContratoTrabajo", "anio": 2025, "mes": 1 }

🔎 Descripción de parámetros

Parámetro Tipo Obligatorio Descripción
empleado string Código del empleado a consultar
proceso string Nombre del proceso a buscar
anio int Año del proceso (filtrado opcional)
mes int Mes del proceso (filtrado opcional)

🔐 Seguridad

Utiliza conexión directa a la base de datos dbapp.
No requiere token ERP, pero depende de la autenticación interna del backend.


🧠 Flujo del Servicio (Resumen real)

  1. Validar parámetros obligatorios

    • Si no se envía empleado → retorna error

    • Si no se envía proceso → retorna error

  2. Construir filtros dinámicos

    • Base: empleado + proceso

    • Si llega año → se agrega al WHERE

    • Si llega mes → se agrega al WHERE

  3. Consultar la tabla interna
    Query sobre:


    historial_procesos_app ORDER BY fecha DESC LIMIT 1

    Utiliza first() para obtener el último registro.

  4. Validar si existe registro

    • Si no existe, devuelve mensaje informando que no se encontró el proceso.

  5. Retornar información del proceso encontrado
    Incluye toda la fila obtenida desde la base de datos.


📤 Response 200 – Ejemplos

✅ Caso exitoso

{ "valor": true, "msn": "Proceso encontrado.", "data": { "id": 1524, "empleado": "EMP-0001", "proceso": "descargaContratoTrabajo", "year": 2025, "month": 1, "fecha": "2025-01-03 09:32:11" } }

❌ Faltan parámetros

{ "valor": false, "msn": "Falta empleado." }

{ "valor": false, "msn": "Falta proceso." }

❌ No existe el proceso

{ "valor": false, "msn": "No se encontró el proceso." }


❗ Posibles Errores

  1. No se envía empleado

    { "valor": false, "msn": "Falta empleado." }

  2. No se envía proceso

    { "valor": false, "msn": "Falta proceso." }

  3. No se encontró el registro

    { "valor": false, "msn": "No se encontró el proceso." }

  4. Error interno de base de datos
    (Puede retornar error 500 desde DB, manejado por Laravel)


📚 Estructura usada (historial_procesos_app)

{ "empleado": "string", "proceso": "string", "year": "int", "month": "int", "fecha": "datetime" }


🗃 Lógica en Pseudo-código

if empleado is empty → return error if proceso is empty → return error where = [ empleado = input.empleado, proceso = input.proceso ] if anio present: where.year = input.anio if mes present: where.month = input.mes result = DB.historial_procesos_app .where(where) .orderBy(fecha desc) .first() if result is null: return error "No se encontró el proceso" return success + result

Módulo Boletas de Pago

CTS(Url CTS PDF (1)) - [pdfCTS]

🧾 Descripción

Genera el PDF de la Compensación por Tiempo de Servicios (CTS) de un empleado para un periodo específico (mes y año).
El servicio consulta la información almacenada en el ERP y retorna el archivo PDF ya renderizado desde una vista Blade (pdf/cts).

También valida si la descarga está habilitada según la fecha definida por la empresa:

Si el usuario intenta descargar antes de esas fechas, el servicio lo bloquea.


🚀 Endpoint

GET /pdf-cts/{employee}/{month}/{year}

Parámetros

Parámetro Tipo Descripción
employee string ID del empleado
month string/int 5 ó 11 (Mayo / Noviembre)
year string/int Año del cálculo CTS

🔐 Seguridad

Este servicio requiere una autenticación interna mediante apiService() para consumir los datos del ERP.
No necesita token del cliente, pero sí credenciales válidas para el ERP.


🧠 Flujo del Servicio (resumen real)

1️⃣ Validación del Mes

Convierte el mes recibido:

Valor recibido Se interpreta como
"5" "MAYO"
"11" "NOVIEMBRE"

2️⃣ Validación de Fecha de Bloqueo

El servicio verifica si la fecha actual está dentro del periodo permitido:

Si aún no llega la fecha → se retorna:

{ "valor": false, "msn": "CTS no habilitado" }

3️⃣ Obtiene la CTS del ERP

Se consulta la API del ERP:

Compensacion por Tiempo de Servicios ?limit=None &order_by=creation desc &filters=[ ["empleado","=","<employee>"], ["mes","=","<MAYO/NOVIEMBRE>"], ["año","=","<year>"] ] &fields=[ ...campos... ]

Se recuperan campos como:

Si no existen registros → retorna:

{ "valor": false, "msn": "No cuenta con CTS para ese Periodo" }

4️⃣ Genera el PDF

Si existe el registro, el servicio envía la información a la vista:

resources/views/pdf/cts.blade.php

Luego devuelve el PDF:

return PDF::loadView("pdf/cts", $dataPdf) ->setPaper('a4', 'wrapper') ->stream();

📥 Request Body

No utiliza body.


📤 Response – Ejemplo exitoso

El servicio no retorna JSON cuando es exitoso, sino un PDF vía stream, por lo que la respuesta es un archivo.

Ejemplo conceptual: <PDF STREAM - CTS Mayo 2024>


❗ Posibles Errores

1. CTS no habilitado por fecha

{ "valor": false, "msn": "CTS no habilitado" }

2. CTS inexistente para el periodo

{ "valor": false, "msn": "No cuenta con CTS para ese Periodo" }

3. Parámetros mal enviados

{ "valor": false, "msn": "Parametros No Validos" }

4. Error interno del ERP

Retorna el error capturado del servicio apiService().


📚 Schemas involucrados

Compensación por Tiempo de Servicios (CTS)

Campos usados:

{ "dias_ausencias": int, "dias_de_licencia_sin_goce": int, "dias_de_descanso_medico": int, "descuento_de_dias_de_ausencia": number, "promedio_remunerativo": number, "name": string, "nombre_de_compañia": string, "ruc": string, "ubicacion": string, "nombre_completo": string, "mes": "MAYO/NOVIEMBRE", "año": string, "cuenta_de_banco": string, "nombre_de_banco": string, "asignacion_familiar": number, "gratificacion_entre_seis": number, "horas_extras_entre_seis": number, "horas_nocturnas_entre_seis": number, "remuneracion_computable_cts": number, "meses_computables_cts": number, "pago_meses": number, "dias_computables_cts": number, "pago_dias": number, "cts_total_a_pagar": number, "tipo_de_documento": string, "dni": string }

🗃 Lógica en pseudo-código

convert month to MAYO/NOVIEMBRE fechaBloqueo = (month == MAYO) ? "year-05-15" : "year-11-15" if hoy <= fechaBloqueo: return CTS no habilitado data = GET CTS where empleado, mes, año if data empty: return no CTS available pdf = render view pdf/cts with data return pdf stream
Módulo Boletas de Pago

Reconocimiento de deuda( Url Reconocimiento de deuda PDF (1) ) - [debtRecognition]

🧾 Descripción

Este servicio valida si un empleado tiene un Reconocimiento de Deuda pendiente de firma, y en caso afirmativo, genera y descarga el archivo PDF del documento, incluyendo el detalle de cuotas asociadas.

El servicio consume directamente información del ERP, consultando tanto el documento principal como sus tablas hijas (detalles de deuda por mes).


🚀 Endpoint

POST /debt-recognition

📥 Parámetros

Recibe como parámetro directo el ID del empleado:

{ "employee": "EMP-0001" }

🔐 Seguridad

El servicio requiere autenticación interna vía dbErp() para consultas SQL y usa PDF::loadView() para generar el documento final.


🧠 Flujo del Servicio (resumen real)

1. Verifica si existe un Reconocimiento de Deuda pendiente

Consulta en el ERP:

Si no encuentra ningún registro:

{ "valor": false, "msn": "Usted no cuenta con un reconocimiento de deuda pendiente de firmar." }

2. Obtiene los datos del Reconocimiento de Deuda

Si existe un documento pendiente:


3. Obtiene el detalle (tabla hija) del reconocimiento

Consulta:

Los campos recuperados:

{ "ano": "", "mes": "", "monto": "" }

4. Construye la data final

Une:


5. Genera el documento PDF

Renderiza la vista:

pdf/Doctype/ReconocimientoDeDeuda/reconocimiento_de_deuda.blade.php

Y retorna la descarga del PDF.


📤 Response – Archivo PDF

El servicio retorna directamente un PDF generado con domPDF:


Content-Type: application/pdf Content-Disposition: attachment; filename="ReconocimientoDeDeuda.pdf"

No devuelve un JSON en caso de éxito, sino una descarga directa del documento.


❗ Posibles Errores

1. No existe reconocimiento pendiente

{ "valor": false, "msn": "Usted no cuenta con un reconocimiento de deuda pendiente de firmar." }

2. Error en la consulta ERP

{ "valor": false, "msn": "Error al obtener datos" }

3. Error inesperado en PDF o datos

{ "valor": false, "msn": "Error inesperado" }

📚 Schemas usados

Reconociemientos de Deuda (principal)

{ "name": "string", "empleado": "string", "monto_total": "decimal", "fecha": "date", "reconocimiento_escaneado_firmado": "string|null" }

table_reconocimiento_deuda (detalle)

{ "ano": "number", "mes": "string", "monto": "decimal" }

🗃 Pseudocódigo del Servicio

filters = { docstatus: 0, empleado: employee } recognition = GET ReconociemientosDeDeuda WHERE sin archivo firmado if recognition vacío: return error detail = GET table_reconocimiento_deuda WHERE parent = recognition.name dataComplete = { dataEmployee: recognition, dataTable: detail } return PDF(dataComplete)

Módulo de Solicitudes

Módulo de Solicitudes

Solicitud de Adelanto( Solicitar de adelanto de sueldo (1) ) - [guardarAdelantosMensual]

🧾 Descripción

Registra la solicitud de adelanto salarial mensual para un empleado, validando una serie de reglas de negocio relacionadas con:

El servicio crea o actualiza el registro correspondiente al empleado dentro del documento mensual de adelantos.


🚀 Endpoint

POST /guardar-adelantos-mensual/{employee}/{amount}

Recibe:


🔐 Seguridad

Requiere autenticación del ERP (realizada internamente vía ServiceErp()).


🧠 Flujo del Servicio (lógica real)

1️⃣ Validación inicial del monto

2️⃣ Obtiene la ficha del empleado


GET Employee/{employee}

Se validan:

3️⃣ Validaciones por fecha

4️⃣ Validaciones por tipo de trabajo

5️⃣ Validación de asistencia

Se verifica si hoy está con licencia:

GET Attendance?filters=[ employee=..., status="On Leave", attendance_date=hoy, docstatus=1 ]

Si está con licencia → no puede solicitar adelanto.

6️⃣ Ubica o crea el documento mensual tipo "Solicitud de Adelanto Mensual"

Se busca:

GET Solicitud de Adelanto Mensual?filters=[ ["id","=",employee.id_sucursal], ["mes","=",mesTexto], ["anio","=",anio] ]

7️⃣ Registra o actualiza al trabajador dentro de la tabla interna table_12

8️⃣ Devuelve la respuesta con todos los registros procesados.


📥 Request Body

No recibe body (los parámetros son por URL).


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Solicitud de adelanto registrado correctamente.", "data": { "SAL-MENS-0001": { "id_empleado": "EMP-001", "monto": 150, "from_app": 1 } } }

❗ Posibles Errores

1. Monto inválido

{ "valor": false, "msn": "Seleccione un monto valido." }

2. Empresa no permitida

{ "valor": false, "msn": "Solo se pueden solicitar los trabajadores de la compañia Shalom Empresarial" }

3. Empleado deshabilitado

{ "valor": false, "msn": "Su empleado se encuentra deshabilitado" }

4. Fecha fuera de rango

{ "valor": false, "msn": "Solo se pueden realizar solicitudes desde el día 01 hasta el 14 del mismo mes." }

5. Restricción por área o tipo de empleado

{ "valor": false, "msn": "Los conductores no pueden solicitar adelanto salarial." }

6. Empleado con licencia

{ "valor": false, "msn": "Usted se encuentra de licencia, no puede solicitar adelanto salarial." }

7. Error al crear documento mensual

{ "valor": false, "msn": "Ocurrió un error al registrar su solicitud de adelanto" }

📚 Schemas utilizados

Employee (GET Employee/{id})

Campos relevantes:

{ "company": "string", "status": "string", "employment_type": "string", "department": "string", "designation": "string", "tipo_de_empleado": "string", "id_sucursal": "int", "passport_number": "string", "employee_name": "string", "branch": "string", "fecha_de_ingreso_real": "Y-m-d" }

Solicitud de Adelanto Mensual (GET/POST)

Campos usados:

{ "id": "int", "mes": "string", "anio": "int", "sucursal": "string", "departamento": "string (opcional)" }

Registro en tabla interna (table_12)

{ "id_empleado": "string", "dni": "string", "nombre_completo": "string", "fecha_de_ingreso": "Y-m-d", "monto": "int", "sucursal": "string", "from_app": 1 }

🧠 Lógica en pseudo-código

if amount == "Seleccionar": return error employeeData = GET Employee/{employee} validar empresa, estado, fecha, tipo, área, puesto... if falla alguna regla: return error validar licencia del día buscar documento mensual de adelantos if no existe: crear nuevo documento obtener tabla interna del documento si empleado no existe en table_12: crear registro else: actualizar monto return éxito + registros modificados
Módulo de Solicitudes

Solicitud de Adelanto(Estado solicitud (1,2,3,4) - Adelante de sueldo) - [show]

🧾 Descripción

Este servicio permite obtener el estado actual de distintos procesos vinculados a un trabajador, tales como:

El servicio analiza dinámicamente el tipo de proceso solicitado.
Si se envía un tipo de proceso específico, consulta su última solicitud pendiente.
Si no se envía proceso, valida automáticamente si el trabajador tiene adelanto salarial en el mes actual y devuelve su estado.

📌 Es un servicio que depende totalmente de la API del ERP para obtener la información.


🚀 Endpoint

POST /estado-solicitud


📥 Request Body

{ "empleado": "EMP-0001", "proceso": "licencia" }

Parámetros

Campo Tipo Obligatorio Descripción
empleado string ✔️ Código del empleado en ERP
proceso string opcional Tipo de solicitud a consultar (“cambio de cuenta”, “licencia”, “asignación familiar”). Si no se envía, se valida “adelanto salarial”.

🔐 Seguridad

Requiere autenticación interna y comunicación con el ERP vía dbErp() y ServiceErp().


🧠 Flujo del Servicio (resumen real)

🔸 1. Validación Inicial

Obtiene:

Define tablas ERP según el proceso solicitado.


🔸 2. Cuando se envía un proceso específico

Los procesos admitidos son:

Proceso enviado Tabla consultada Campo de relación
"cambio de cuenta" tabCambio de Cuenta Bancaria empleado
"licencia" tabSolicitud de Licencias id_empleado
"asignación familiar" tabSolicitud Asignacion Familiar id_empleado

El servicio:

  1. Construye los filtros del ERP.

  2. Busca la última solicitud activa (docstatus < 2).

  3. Si no encuentra registros → devuelve un mensaje indicando que no existe solicitud.

  4. Si existe:

    • Lee motivo

    • Lee validacion_solicitud

    • Lee docstatus

    • Devuelve estado traducido a texto.

Estados interpretados:

docstatus Estado
0 En proceso
1 Aprobado
2 Pagado
3 Rechazado

🔸 3. Cuando NO se envía proceso: Validación de adelanto salarial

  1. Obtiene el adelanto salarial del mes (tabSolicitud de Adelanto Mensual + tabla interna hija).

  2. Si no existe solicitud → devuelve mensaje correspondiente.

  3. Si existe, continúa:

    • Revisa si existe Solicitud de Pagos pagada relacionada al mes.

    • Si se encuentra, asigna estado "Pagado".

    • Si docstatus = 0 y el día es >= 17, se marca como "Rechazado".

    • Caso contrario usa el estado según docstatus.


📤 Response 200 – Ejemplo de solicitud por proceso

{ "valor": true, "msn": "Estado de la solicitud encontrado", "data": { "motivo": "Actualización de datos", "validacion_solicitud": "Pendiente", "fecha": "2025-01-22 12:30:00", "estado": "En proceso" } }


📤 Response 200 – Ejemplo para adelanto salarial

{ "valor": true, "msn": "Estado de la solicitud encontrado", "data": { "monto": 300, "fecha": "2025-01-18 15:04:22", "estado": "Pagado" } }


❗ Posibles Errores

1. Proceso enviado no existe

{ "valor": false, "msn": "Usted no cuenta con una solicitud" }

2. No existen solicitudes del tipo indicado

{ "valor": false, "msn": "Usted no cuenta con una solicitud de licencia" }

3. No existe adelanto salarial para el mes

{ "valor": false, "msn": "Usted no ha solicitado un adelanto salarial para este mes" }

4. Falla consultando al ERP

{ "valor": false, "msn": "Hubo un inconveniente al consultar los datos." }


📚 Schemas (Estructuras utilizadas)

Solicitud de Licencias

{ "name": "string", "modified": "datetime", "docstatus": 0, "motivo": "string", "validacion_solicitud": "string" }

Solicitud Adelanto Mensual

{ "mes": "string", "anio": "string", "docstatus": 0, "modified": "datetime", "monto": 0 }


🗃 Lógica en pseudo-código simplificada

if request.proceso exists: tabla, where = procesos_config[proceso] data = dbErp(tabla, where) if empty(data): return sin solicitud estado = traducir_docstatus(data.docstatus) return estado, motivo, fecha else: adelanto = dbErp(Solicitud Adelanto Mensual) if no adelanto: return "no ha solicitado" if solicitud_pagos_pagada AND adelanto.docstatus == 1: estado = Pagado else if docstatus==0 AND día >=17: estado = Rechazado else: estado = según tabla return monto, fecha, estado

Módulo de Solicitudes

Cambio de cuenta bancaria(Solicitar cambio de cuenta (1)) - [store]

🧾 Descripción

Registra una nueva solicitud de cambio de cuenta bancaria para un empleado, validando previamente:

Si todo es correcto, crea un nuevo documento en el ERP: Cambio de Cuenta Bancaria


🚀 Endpoint

POST /cambio-cuenta-bancaria/store


📥 Request Body

{ "empleado": "EMP-0001", "nuevo_banco": "Banco de Crédito del Perú", "nueva_cuenta_bancaria": "12345678901234", "documento_cuenta": "/files/archivo.pdf" }

Campos requeridos

Campo Tipo Obligatorio Descripción
empleado string ✔️ ID del empleado
nuevo_banco string ✔️ Nuevo banco elegido
nueva_cuenta_bancaria string ✔️ Número de cuenta del nuevo banco
documento_cuenta string ✔️ Archivo previamente cargado en ERP

🔐 Seguridad

Requiere autenticación interna mediante ServiceErp() y dbErp() hacia el ERP corporativo.


🧠 Flujo del Servicio (resumen real)

1. Validaciones iniciales

Banco Longitudes válidas
BCP 14 o 20
BBVA 16, 18 o 20
Interbank 18 o 20
Otros 20

Si no cumple → devuelve error.


2. Verifica si el empleado ya tiene una solicitud en estado Borrador

Se consulta en el ERP:

GET Cambio de Cuenta Bancaria filters = [["empleado","=", empleado],["docstatus","=",0]]

Si ya existe un documento en borrador → error.


3. Registrar la nueva solicitud

Si no existe borrador, crea el documento:

POST resource/Cambio de Cuenta Bancaria { "empleado": empleado, "nombre_de_banco_nuevo": nuevo_banco, "nuevo_num_de_cuenta_bancaria": nueva_cuenta_bancaria, "documento_cuenta": documento_cuenta }

📤 Response 200 – Éxitoso

{ "valor": true, "msn": "Registrado con éxito", "response": { "name": "CCB-000123", "empleado": "EMP-0001", "nombre_de_banco_nuevo": "Banco de Crédito del Perú", "nuevo_num_de_cuenta_bancaria": "12345678901234" } }

❗ Posibles Errores

1. Falta un dato obligatorio

{ "valor": false, "msn": "Debe adjuntar un documento de acreditación de cuenta bancaria" }

2. Número de cuenta inválido

{ "valor": false, "msn": "Cantidad de dígitos de número de cuenta incorrecto" }

3. Ya existe solicitud en borrador

{ "valor": false, "msn": "Ya cuenta con una solicitud en Borrador pendiente de validar" }

4. Error al registrar en ERP

{ "valor": false, "msn": "Ocurrió un error al registrar el cambio de cuenta bancaria", "error": { ... } }

📚 Schemas utilizados

Cambio de Cuenta Bancaria (POST)

{ "empleado": "string", "nombre_de_banco_nuevo": "string", "nuevo_num_de_cuenta_bancaria": "string", "documento_cuenta": "string" }

Consulta de solicitudes

{ "name": "string" }

🗃 Lógica en pseudo-código

if faltan_datos: return error validar_longitud_segun_banco() buscar_borrador = GET CambioCuentaBancaria where empleado and docstatus=0 if existe_borrador: return error "Ya cuenta con una solicitud" crear_documento = POST CambioCuentaBancaria { empleado, banco, cuenta, documento } return éxito
Módulo de Solicitudes

Solicitud de Licencias(Combo tipos de licencias (1)) - [combos]

🧾 Descripción

Servicio que devuelve los valores preconfigurados para el combo tipos_licencias, utilizado por el frontend o aplicación móvil para poblar listas desplegables relacionadas a licencias.

Este servicio no realiza operaciones en base de datos, no consume ERP ni APIs externas.
Simplemente retorna valores estáticos cargados en la propiedad $this->tipos_licencias.


🚀 Endpoint

POST /combos

No requiere parámetros.


🔐 Seguridad

No requiere validación adicional.
El servicio solo retorna data estática, sin acceso a información sensible del ERP.


🧠 Flujo del Servicio (resumen real)

  1. Obtiene el array interno $this->tipos_licencias, previamente definido en el controlador.

  2. Construye un arreglo combos con la estructura:

$combos["tipos_licencias"] = $this->tipos_licencias;
  1. Retorna una respuesta JSON estándar:

{ "valor": true, "data": { "tipos_licencias": [...] } }

📥 Request Body

No requiere parámetros.
Ejemplo:


{}

📤 Response 200 – Ejemplo

{ "valor": true, "data": { "tipos_licencias": [ "LICENCIA A1", "LICENCIA A2A", "LICENCIA A2B", "LICENCIA A3A", "LICENCIA A3B", "LICENCIA A3C" ] } }

(La estructura real depende del contenido de $this->tipos_licencias.)


❗ Posibles Errores

Este servicio no genera errores internos, pues no consulta APIs externas.
Solo pueden ocurrir fallas del servidor:

1. Error por variable no definida

{ "valor": false, "msn": "Error interno: tipos_licencias no declarado", "data": [] }

2. Error inesperado del servidor

{ "valor": false, "msn": "Error del servidor: <mensaje>", "data": [] }

📚 Schemas (estructuras usadas)

Response

{ "valor": true|false, "data": { "tipos_licencias": "array" } }

🗃 Lógica en pseudo-código

function combos(request): combos = {} combos["tipos_licencias"] = this.tipos_licencias return { valor: true, data: combos }
Módulo de Solicitudes

Solicitud de Licencias(Solicitar solicitud de licencia (1)) - [store]

🧾 Descripción

Crea una Solicitud de Licencias para un empleado, validando previamente:

El servicio registra en el ERP un nuevo documento "Solicitud de Licencias" si cumple todas las reglas definidas.


🚀 Endpoint

POST /solicitud-licencias/store


📥 Request Body – Parámetros

Campo Tipo Obligatorio Descripción
empleado string ID del empleado
tip_licencia string Tipo de licencia (validado contra $this->tipos_licencias)
fecha_ini date Fecha de inicio de la licencia
fecha_fin date Fecha fin de la licencia
declaracion_jurada file/url depende Obligatorio si tip_licencia = "Familiar Enfermo"
hoja_hospitalizacion file/url depende Obligatorio si tip_licencia = "Familiar Enfermo"
uci file/url depende Obligatorio si tip_licencia = "Familiar Enfermo"
acta_nacimiento file/url depende Obligatorio si tip_licencia = "Paternidad"
acta_defuncion file/url depende Obligatorio si tip_licencia = "Licencia Por Luto"

🧠 Flujo del Servicio (resumen real)

  1. Validación de campos obligatorios

    • Verifica empleado, tipo de licencia válido, fecha_ini y fecha_fin.

  2. Cálculo de días de licencia


    $dias = (new DateTime(fecha_ini))->diff(new DateTime(fecha_fin))->days;
  3. Validaciones específicas por tipo de licencia

    Tipo de licencia Requisitos Máximo días
    Familiar Enfermo declaracion_jurada, hoja_hospitalizacion, uci 7
    Paternidad acta_nacimiento 10
    Licencia Por Luto acta_defuncion 5
    Licencia sin goce 30
  4. Validación: El empleado no debe tener una solicitud en borrador

    GET Solicitud de Licencias filters: [["id_empleado","=",empleado],["docstatus","=",0]]
  5. Construcción del body para enviar al ERP

    • Incluye campos adicionales dependiendo del tipo de licencia.

  6. Creación de la solicitud

    POST resource/Solicitud de Licencias
  7. Retorno de respuesta estándar


📤 Response 200 – Ejemplo exitoso

{ "valor": true, "msn": "Solicitud de licencias enviada", "data": [] }

(El campo data retorna el borrador encontrado, si existía.)


⚠️ Posibles Errores

1. Falta de parámetros

{ "valor": false, "msn": "Envie el empleado" }

2. Tipo de licencia inválido

{ "valor": false, "msn": "Envie el tipo de licencia válido" }

3. Fechas incompletas

{ "valor": false, "msn": "Envie la fecha de inicio" }

4. Exceso de días permitidos

{ "valor": false, "msn": "El rango de fecha no debe sobrepasar los 7 dias" }

5. Documentación obligatoria faltante

{ "valor": false, "msn": "Suba su hoja de hospitalizacion" }

6. Solicitud duplicada en borrador

{ "valor": true, "msn": "No se puede crear, Ya tiene una solicitud en borrador" }

7. Error al registrar en ERP

{ "valor": false, "msn": "Ocurrió un error al crear la Solicitud de Licencias", "error": { ... } }

🗃 Lógica en Pseudocódigo

if empleado vacío → error if tipo no permitido → error if fechas vacías → error dias = fecha_fin - fecha_ini switch tipo_licencia: Familiar Enfermo: validar documentos validar dias <= 7 Paternidad: validar acta_nacimiento validar dias <= 10 Luto: validar acta_defuncion validar dias <= 5 Licencia sin goce: validar dias <= 30 buscar borradores: GET Solicitud de Licencias where empleado & docstatus=0 si existe → error body = { empleado, tipo, fechas, documentos } crear solicitud: POST Solicitud de Licencias si ERP responde error → retornar error retornar éxito


📚 Estructuras usadas

Solicitud de Licencias (POST)

Campos enviados:

{ "id_empleado": "string", "tip_licencia": "string", "fecha_ini": "YYYY-mm-dd", "fecha_fin": "YYYY-mm-dd", "declaracion_jurada": "url (opcional)", "hoja_hospitalizacion": "url (opcional)", "uci": "url (optional)", "acta_nacimiento": "url (optional)", "acta_defuncion": "url (optional)" }
Módulo de Solicitudes

Asignación Familiar(Buscar dni empleado (1)) - [searchJobApplicant]

🧾 Descripción

Este servicio consulta información de un postulante (Job Applicant) enviando su número de documento a un endpoint externo.
El servicio actúa como un proxy directo: recibe un documento, llama por cURL al endpoint de EMPRESARIAL y retorna la respuesta tal cual viene de la API.

No realiza validaciones ni transformaciones adicionales.


🚀 Endpoint interno

POST /search-job-applicant


📥 Parámetros de entrada (Request Body)

{ "document": "string" }

Campo | Tipo | Obligatorio | Descripción

---|---|---|---
document | string | Sí | Número de documento del postulante a buscar.


🔐 Seguridad

No usa autenticación interna ni tokens propios.
El servicio simplemente reenvía el dato al endpoint: POST {EMPRESARIAL}/api/search_job_applicant


🧠 Flujo del Servicio (Resumen Real)

  1. Recibe el campo document desde la solicitud.

  2. Prepara una petición cURL hacia:


    {EMPRESARIAL}/api/search_job_applicant
  3. Envía el documento como parámetro form-data:


    document = <valor recibido>
  4. Ejecuta la llamada.

  5. Decodifica la respuesta JSON.

  6. Retorna la data al cliente sin modificaciones.


📤 Respuesta 200 – Ejemplo

Respuesta depende totalmente del servicio externo.
Un ejemplo típico puede ser:

{ "valor": true, "data": { "name": "JOB-00045", "first_name": "Carlos", "last_name": "Rojas", "status": "Open", "document": "74581236" } }

❗ Posibles Errores

1. No se puede conectar con EMPRESARIAL

{ "valor": false, "msn": "No se pudo conectar con el servicio externo", "data": [] }

2. EMPRESARIAL devuelve error interno

{ "valor": false, "msn": "Error desde API Empresarial", "data": { ...detalle del error... } }

3. Respuesta no válida o JSON corrupto

{ "valor": false, "msn": "Respuesta inesperada del servidor externo", "data": "<response>" }

📚 Esquema esperado desde el API externo (referencial)

El API no está documentado en tu código, pero normalmente una estructura de Job Applicant incluye:

{ "name": "string", "first_name": "string", "last_name": "string", "status": "string", "document": "string" }

La estructura real depende 100% del sistema EMPRESARIAL.


🗃 Lógica en pseudo-código

document = request.document curl = init() curl.url = EMPRESARIAL + "api/search_job_applicant" curl.method = POST curl.postfields = { document: document } response = curl.execute() return json_decode(response)


🧩 Código documentado

/** * Servicio: searchJobApplicant * * Descripción: * Busca información de un postulante enviando su documento al API externo EMPRESARIAL. * Este servicio actúa como un puente: manda el documento vía cURL y retorna la respuesta * sin transformaciones adicionales. * * Endpoint interno: * POST /search-job-applicant * * Parámetros: * - document (string): Documento de identidad del postulante. * * Flujo: * 1. Recibe el documento del request. * 2. Ejecuta cURL hacia EMPRESARIAL/api/search_job_applicant enviando el documento. * 3. Obtiene y decodifica la respuesta JSON. * 4. Retorna directamente la respuesta del servicio externo. * * Posibles errores: * - Fallo en la conexión cURL * - Respuesta inválida del servidor externo */ public function searchJobApplicant(Request $request) { $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => EMPRESARIAL.'api/search_job_applicant', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => array('document' => $request->document), )); $response = curl_exec($curl); curl_close($curl); return json_decode($response,true); }
Módulo de Solicitudes

Asignación Familiar(Solicitar asignacion familiar (1)) - [store]

🧾 Descripción

Este servicio registra una Solicitud de Asignación Familiar para un empleado, validando previamente que:

  1. Se hayan enviado las dos imágenes del DNI (anverso y reverso).

  2. El empleado tenga un género válido y registrado.

  3. No exista ya una asignación familiar duplicada para el mismo hijo (DNI del menor).

  4. No existan más de dos solicitudes asociadas al mismo DNI de hijo (límite máximo permitido).

El registro se almacena directamente en el ERP mediante el recurso Solicitud Asignacion Familiar.


🚀 Endpoint

POST /solicitud-asignacion-familiar


📥 Request Body

{ "dni": "string", "fecha_hijo": "YYYY-MM-DD", "edad": 10, "empleado": "EMP-0001", "img_dni": "ruta/archivo1.png", "reverso": "ruta/archivo2.png", "nombre": "Nombre del hijo", "afiliacion_al_essalud": "SI" }

🔐 Seguridad

✔ Requiere autenticación interna vía ServiceErp() del ERP.
✔ Se validan datos del empleado antes de crear la solicitud.


🧠 Flujo del Servicio (Resumen)

  1. Validación de archivos obligatorios
    Verifica que se envíen img_dni y reverso.
    Si falta uno → retorna error.

  2. Obtiene datos del empleado
    Usa el método verifyEmployeeGender($empleado) para traer:

    • género

    • fecha de ingreso real

  3. Revisa si ya existe una solicitud similar
    Busca solicitudes para:

    • el mismo DNI del hijo

    • la misma fecha de ingreso del empleado


    GET Solicitud Asignacion Familiar filters: dni_hijo, fecha_ingreso
  4. Valida duplicidades según reglas

    • Si existe 1 solicitud previa, compara géneros:

      • Si el género coincide → ❌ ya tiene asignación familiar.

    • Si existen 2 solicitudes previas → ❌ no puede registrar más.

  5. Crea la nueva solicitud
    Realiza un POST hacia: POST /resource/Solicitud Asignacion Familiar

    Con los campos:

    { "id_empleado": "...", "nombre_hijo": "...", "dni_hijo": "...", "edad_hijo": "...", "fecha_hijo": "...", "dni_doc": "...", "reverso": "...", "afiliacion_al_essalud": "..." }
  6. Retorna respuesta final


📤 Response 200 – Ejemplos

✔ Registro exitoso

{ "valor": true, "msn": "Asignacion familiar registrada con exito" }

❌ Faltan imágenes del DNI

{ "valor": false, "msn": "Debe de enviar la 2 imagenes del DNI" }

❌ Asignación ya existente para el DNI del menor

{ "valor": false, "msn": "Este dni ya cuenta con una asignacion familiar" }

❌ DNI ya usado en dos asignaciones previas

{ "valor": false, "msn": "Este dni ya cuenta con dos asignaciones familiares" }

❌ Error al registrar en el ERP

{ "valor": false, "msn": "Ocurrió un error al registrar la solicitud de asignacion familiar" }

📚 Schemas utilizados

🔹 Solicitud Asignacion Familiar (POST)

{ "id_empleado": "string", "nombre_hijo": "string", "dni_hijo": "string", "edad_hijo": number, "fecha_hijo": "YYYY-MM-DD", "dni_doc": "string", "reverso": "string", "afiliacion_al_essalud": "SI/NO" }

🔹 Solicitud Asignacion Familiar (GET/FILTER)

{ "name": "string", "id_empleado": "string", "dni_hijo": "string", "fecha_ingreso": "YYYY-MM-DD" }

🔹 Datos del empleado (verifyEmployeeGender)

{ "gender": "M/F", "fecha_de_ingreso_real": "YYYY-MM-DD" }

🗃 Lógica en pseudocódigo

if falta img_dni o reverso: return error genderEmployee = verifyEmployeeGender(empleado) solicitudesPrevias = Buscar solicitudes por dni_hijo y fecha_ingreso if count == 1: otherGender = verifyEmployeeGender(solicitudesPrevias.id_empleado) if same gender: return error: ya tiene asignación if count >= 2: return error: límite alcanzado body = datos de asignación familiar guardar = POST Solicitud Asignacion Familiar if error: return error return éxito
Módulo de Solicitudes

Solicitudes de Pagos(Obtener Lista de Solicitudes (1)) - [paymentRequestList]

🧾 Descripción

Este servicio obtiene la lista de solicitudes de pago realizadas en el ERP, aplicando restricciones dependientes del usuario, su departamento y reglas de validación definidas por el área de Gerencia.

El módulo:

Si el usuario no está autorizado, el módulo devuelve un mensaje de bloqueo.


🚀 Endpoint

POST /payment-request-list


📥 Request Body

Ejemplo:

{ "department": "LOGISTICA", "concepto": "Compras abastecimiento interno", "usuario": "usuario@empresa.com", "status": "Validado" }

Campos:

Campo Tipo Descripción
department string Departamento del usuario
concepto string Concepto filtrado (opcional)
usuario string User ID
status string Estado de validación (opcional). Si es vacío, se excluyen "No requiere" y "Rechazado".

🔐 Seguridad

Requiere conexión válida con el ERP vía dbErp() y ServiceErp().


🧠 Flujo del Servicio (resumen funcional)

1️⃣ Validación de permisos del usuario

Se consulta: tabValidacion de Pagos Gerencia

Si no existe configuración para ese usuario:

{ "valor": false, "msn": "El modulo esta inhabilitado para su departamento", "data": [] }

2️⃣ Construcción de filtros principales

Si existen reglas personalizadas:

3️⃣ Filtrado por estado

4️⃣ Filtrado por concepto

Si el body incluye un concepto → se agrega un WHERE concepto = X.

5️⃣ Consulta principal

Se obtiene:

name, fecha, estado_de_validación, moneda, departamento, proveedor, ruc, concepto, monto, number_factura, voucher

Desde: tabSolicitud de Pagos

6️⃣ Obtención de archivos transados

Por cada solicitud encontrada se consultan los archivos: tabArchivos Transados

Clasifica:

Y asigna nombres:

Imagen 1 Documento 1 Archivo 1

7️⃣ Construcción de la respuesta final

Cada solicitud incluye:

{ "archivos_transados": [...], "documento_factura": "url o vacío", ... }

📤 Response 200 – Ejemplo exitoso

{ "valor": true, "msn": "Lista de Solicitudes generada correctamente", "data": [ { "name": "SP-0001", "fecha": "2025-01-10", "estado": "Validado", "moneda": "PEN", "departamento": "LOGISTICA", "proveedor": "Proveedor SAC", "ruc": "20123456789", "concepto": "Transacción / Compensaciones", "monto": 1500, "numero": "F001-12345", "documento_factura": "/files/factura.pdf", "archivos_transados": [ { "name": "ARCH-001", "parent": "SP-0001", "url": "/file-download/123.jpg", "nombre_archivo": "Imagen 1" } ] } ] }

❌ Posibles Errores

1️⃣ Usuario sin permisos para usar el módulo

{ "valor": false, "msn": "El modulo esta inhabilitado para su departamento", "data": [] }

2️⃣ Error al cargar solicitudes

{ "valor": false, "msn": "Surgió un error al cargar la lista de solicitudes, intente nuevamente", "data": { ... } }

3️⃣ No existen solicitudes dentro de los filtros

{ "valor": true, "msn": "No existen solicitudes", "data": [] }

📚 Tablas / Recursos Usados

tabValidacion de Pagos Gerencia

Campos usados:

tabSolicitud de Pagos

Campos:

tabArchivos Transados

Campos:


🗃 Lógica en pseudo-código

usuario_rules = GET ValidacionPagos where usuario = X if empty(usuario_rules): return módulo inhabilitado build base filters: estado_documento NOT IN ('Pago Rechazado') fecha >= hoy - 6 meses if usuario_rules exist: for each rule: add OR (concepto = rule.concepto AND monto > rule.monto) if status enviado: add estado_de_validación = X else: exclude ['No requiere', 'Rechazado'] if concepto enviado: add concepto = X requests = query SolicitudPagos with filters if no requests: return lista vacía get archivos_transados for all requests group and classify archivos by type return lista final con archivos agrupados
Módulo de Solicitudes

Solicitudes de Pagos(Obtener Combos Conceptos (1)) - [getComboSolicitudPago]

🧾 Descripción

Obtiene la lista de conceptos permitidos para un usuario específico, basándose en la tabla del ERP "Validación de Pagos Gerencia".

El servicio filtra los registros por el usuario ingresado y retorna un array único de conceptos asociados a dicho usuario.
Se utiliza para validar qué tipos de pagos puede solicitar un trabajador.


🚀 Endpoint

POST /get-combo-solicitud-pago


📥 Request Body

Debe incluir el campo:

{ "usuario": "correo_o_user_id" }

❗ Validación

Si no se envía usuario, responde:

{ "valor": true, "msn": "Debe de ingresar el usuario correctamente", "data": [] }


🔐 Seguridad

El servicio usa el método interno dbErp() que requiere autenticación interna vía ERPNext.
Por ello, se asume que el cliente ya cuenta con token/credenciales válidas.


🧠 Flujo del Servicio (Explicación Real)

  1. Validar parámetro usuario

    • Si está vacío → responde error de validación.

  2. Construir filtros para ERP


    WHERE usuario = <usuario>
  3. Consultar al ERP
    Usando:


    tabValidacion de Pagos Gerencia

    con el SQL:

    • SELECT concepto

    • FROM tabValidacion de Pagos Gerencia

    • WHERE usuario = %(usuario)s

  4. Obtener resultados

    • Se extrae la columna concepto de la respuesta.

    • Se eliminan duplicados mediante array_unique.

  5. Retornar los conceptos permitidos.


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Se encontró los conceptos", "data": [ "Bonificación", "Viáticos", "Movilidad", "Pago Extraordinario" ] }


❗ Posibles Errores

1. Usuario no enviado

{ "valor": true, "msn": "Debe de ingresar el usuario correctamente", "data": [] }

2. Usuario sin conceptos asignados

{ "valor": true, "msn": "Se encontró los conceptos", "data": [] }

(El servicio no devuelve error — solo retorna lista vacía.)

3. Error del ERP

Si dbErp() falla internamente, el servicio responderá una lista vacía debido a su estructura actual.


📚 Tablas y Estructuras Usadas

Tabla: tabValidacion de Pagos Gerencia

Campos utilizados:

{ "usuario": "string", "concepto": "string" }


🗃 Lógica en Pseudocódigo

IF usuario está vacío: return error filtros = { usuario: usuario } data = ERP.dbErp( table = "Validacion de Pagos Gerencia", select = "concepto", where usuario = usuario ) conceptos = extraer columna "concepto" conceptos = eliminar duplicados return { valor: true, data: conceptos }

Módulo de Solicitudes

Solicitudes de Pagos(Validar Solicitud (1)) - [validatePaymentRequest]

🧾 Descripción

Servicio encargado de validar o rechazar una Solicitud de Pagos en el ERP.
Actualiza el campo estado_de_validación del documento Solicitud de Pagos y devuelve una respuesta indicando si la operación fue exitosa.

El servicio no procesa lógica adicional más allá de actualizar el estado del documento y devolver el resultado.


🚀 Endpoint

PUT /validate-payment-request

📩 Recibe parámetros mediante el body del Request (Laravel Request):

{ "name": "SP-00012", "status": "Validado" }

🔐 Seguridad

Requiere autenticación contra el ERP, manejada internamente mediante: $this->general->ServiceErp()

No requiere headers adicionales desde el lado del cliente.


🧠 Flujo del Servicio (explicación real)

  1. Recibe:

    • name → ID del documento (Solicitud de Pagos)

    • status → Puede ser "Validado" o "Rechazado"

  2. Determina internamente mensajes para usuario según status:

    • "Validado" → aprobar

    • "Rechazado" → rechazar

  3. Construye el body con el nuevo estado:


    ["estado_de_validación" => $request->status]
  4. Envía:


    PUT /resource/Solicitud de Pagos/{name}
  5. Si el ERP responde con error → devuelve mensaje indicando fallo al aprobar o rechazar.

  6. Si la operación es correcta → responde con:

    • valor = true

    • mensaje: "Solicitud de Pago Aprobado/Rechazado correctamente"

    • data → respuesta del ERP


📥 Request Body (Laravel)

{ "name": "string (ID del documento)", "status": "Validado | Rechazado" }

📤 Response 200 – Ejemplo (Aprobado)

{ "valor": true, "msn": "Solicitud de Pago Aprobado correctamente", "data": { "name": "SP-00012", "estado_de_validación": "Validado" } }

Ejemplo (Rechazado)

{ "valor": true, "msn": "Solicitud de Pago Rechazado correctamente", "data": { "name": "SP-00012", "estado_de_validación": "Rechazado" } }

❗ Posibles Errores

1. Error durante el PUT

{ "valor": false, "msn": "Surgió un error al aprobar la Solicitud de Pago", "data": {} }

2. El ERP responde con "valor = false"

{ "valor": false, "msn": "Surgió un error al rechazar la Solicitud de Pago", "data": { ...respuesta del ERP... } }

3. Excepción inesperada

{ "valor": false, "msn": "Surgió un error al aprobar la Solicitud de Pago", "data": "ErrorException detail" }

📚 Schema del documento afectado

Solicitud de Pagos (PUT)

Campos utilizados: { "estado_de_validación": "string" }


🗃 Lógica en pseudo-código

name = request.name status = request.status body = { estado_de_validación: status } try: response = PUT "Solicitud de Pagos/{name}" with body except: return error message if response.valor == false: return error message return success response with custom message
Módulo de Solicitudes

Cambio Salarial Administrativo(Empleados Activos (1)) - [getEmployeeActive]

🧾 Descripción

Servicio que obtiene el listado completo de empleados activos desde el ERP.
Solo devuelve empleados cuyo status = "active" y expone información básica:

Este servicio se utiliza para obtener la lista de empleados habilitados dentro del sistema.


🚀 Endpoint

POST /get-employee-active

📌 El método es POST, pero internamente realiza una consulta GET al ERP.


📥 Request Body

El servicio no requiere parámetros en el body.


{}

Todo se obtiene directamente del ERP mediante ServiceErp().


🔐 Seguridad

Requiere conexión autorizada al ERP.
La autenticación se maneja internamente mediante: $this->general->ServiceErp(...)


🧠 Flujo del Servicio (Resumen Real)

  1. Construye la solicitud hacia el ERP:

GET Employee ?limit=None &fields=["nombre_completo","passport_number","name"] &filters=[["status","=","active"]]
  1. Envía la solicitud al ERP mediante: 

$this->general->ServiceErp('GET', null, $body, APICAPACITACION . 'resource/Employee');


  1. Verifica:

    • Si el ERP respondió con error.

    • Si no existen registros de empleados activos.

  2. En caso de éxito:

    • Devuelve la lista completa de empleados encontrados.


📤 Response 200 – Ejemplo

✅ Caso exitoso

{ "valor": true, "msn": "Busqueda Existosa", "data": [ { "nombre_completo": "Juan Pérez López", "passport_number": "45382910", "name": "HR-EMP-00231" }, { "nombre_completo": "Ana Torres", "passport_number": "72839201", "name": "HR-EMP-00412" } ] }

❗ Error interno del ERP

{ "valor": false, "msn": "Error interno, cominique con soporte", "data": [] }

❗ Sin registros encontrados

{ "valor": false, "msn": "No se encontraron Registros", "data": [] }

❗ Posibles Errores

1. Error en la llamada al ERP

Ocurre cuando ServiceErp() devuelve valor = false.

{ "valor": false, "msn": "Error interno, cominique con soporte", "data": [] }

2. No existen empleados activos

{ "valor": false, "msn": "No se encontraron Registros", "data": [] }

3. Error inesperado del servidor

(si se implementara un try/catch)

{ "valor": false, "msn": "Error del servidor: <detalle>", "data": [] }

📚 Schemas utilizados

Employee (GET)

Campos usados:

{ "name": "string", "nombre_completo": "string", "passport_number": "string" }


🗃 Lógica en Pseudo-Código

body = { limit = none fields = ["nombre_completo","passport_number","name"] filters = [["status","=","active"]] } response = GET ERP Employee with body if response.valor == false: return error if response.data.count == 0: return "No se encontraron registros" return { valor: true, msn: "Busqueda Existosa", data: response.data }
Módulo de Solicitudes

Cambio Salarial Administrativo(Obtener Salario (1)) - [getEmployeeActive]

🧾 Descripción

Este servicio obtiene todos los empleados activos desde el ERP, retornando únicamente la información básica necesaria para listarlos:

Es un servicio de consulta que solo consume los datos de la API del ERP usando ServiceErp().


🚀 Endpoint

GET /get-employee-active

No recibe parámetros en el body; todo se obtiene del ERP.


🔐 Seguridad

Requiere autenticación válida hacia el ERP (manejada internamente por ServiceErp()).


🧠 Flujo del Servicio (Resumen Real)

  1. Construye el body de consulta para el ERP:

    { "limit": "none", "fields": ["nombre_completo", "passport_number", "name"], "filters": [["status", "=", "active"]] }
  2. Realiza el request: GET Employee

  3. Valida:

    • Si hubo error en el ERP → retorna error.

    • Si la respuesta está vacía → retorna mensaje "No se encontraron registros".

  4. Si hay resultados, retorna:

    • valor = true

    • msn = "Busqueda Exitosa"

    • data = lista de empleados activos


📥 Request Body

Este endpoint no recibe body.


{}

📤 Response 200 – Ejemplo

✔️ Con empleados encontrados

{ "valor": true, "msn": "Busqueda Existosa", "data": [ { "nombre_completo": "Juan Pérez", "passport_number": "12345678", "name": "EMP-0001" }, { "nombre_completo": "Ana Torres", "passport_number": "87654321", "name": "EMP-0002" } ] }

❗ Sin registros

{ "valor": false, "msn": "No se encontraron Registros", "data": [] }

❌ Error interno

{ "valor": false, "msn": "Error interno, cominique con soporte", "data": [] }

❗ Posibles Errores

1️⃣ Error del ERP

Ocurre cuando ServiceErp() retorna "valor" => false

{ "valor": false, "msn": "Error interno, cominique con soporte", "data": [] }

2️⃣ No hay registros activos

{ "valor": false, "msn": "No se encontraron Registros", "data": [] }

3️⃣ Error inesperado en servidor

{ "valor": false, "msn": "Error del servidor", "data": [] }

📚 Schemas Usados

📄 Employee (GET)

Campos utilizados:

{ "name": "string", "nombre_completo": "string", "passport_number": "string" }

🗃 Lógica en Pseudo-código

body = { limit: none fields: ["nombre_completo", "passport_number", "name"] filters: [["status","=","active"]] } response = GET ERP Employee if response.valor == false: return error if response.data is empty: return no registros return { valor: true msn: "Busqueda Exitosa" data: response.data }
Módulo de Solicitudes

Cambio Salarial Administrativo(Actualizar Salario (1)) - [updateSalarialbyEmployee]

🧾 Descripción

Este servicio registra una solicitud de actualización salarial para un empleado.
Envía al ERP los nuevos valores de:

El servicio solo valida la estructura y los datos requeridos, mientras que el proceso interno de aprobación o registro es manejado por el ERP a través del recurso Cambio Salarial Administrativo.


🚀 Endpoint

POST /update-salarial-by-employee


📥 Request Body (JSON)

Todos los campos son obligatorios.

Campo Tipo Descripción
empleado string ID del empleado
sueldo number Nuevo sueldo propuesto
movilidad number Nuevo monto de movilidad
bono_nocturno number Monto de bono nocturno
fecha string (YYYY-MM-DD) Fecha de aplicación del cambio salarial

Ejemplo de entrada

{ "empleado": "EMP-00123", "sueldo": "1500", "movilidad": "200", "bono_nocturno": "150", "fecha": "2025-01-15" }

🔐 Seguridad

Requiere token válido del ERP (interno), administrado desde:

$this->general->ServiceErp()

🧠 Flujo del Servicio (resumen real)

  1. Valida que se hayan enviado todos los campos requeridos.
    Si falta alguno, retorna error.

  2. Valida formato de fecha usando validateDate().

  3. Construye el body que será enviado al ERP:

{ "empleado": "<id>", "nuevo_sueldo": "<sueldo>", "nueva_movilidad": "<movilidad>", "nuevo_bono_nocturno": "<bono nocturno>", "fecha_de_actualizacion_date": "<fecha>" }
  1. Envía la solicitud al ERPPOST resource/Cambio Salarial Administrativo

  1. Devuelve al cliente el resultado, incluyendo la respuesta del ERP.


📤 Response 200 – Ejemplo exitoso

{ "valor": true, "msn": "¡Excelente! Se ha registrado exitosamente tu solicitud.", "data": { "name": "CSA-00045", "empleado": "EMP-00123", "nuevo_sueldo": "1500", "nueva_movilidad": "200", "nuevo_bono_nocturno": "150", "fecha_de_actualizacion_date": "2025-01-15" } }

❗ Posibles Errores

1. Campos faltantes

{ "valor": false, "msn": "Ingrese los campos requeridos" }

2. Empleado vacío

{ "valor": false, "msn": "Ingrese el empleado" }

3. Sueldo vacío

{ "valor": false, "msn": "Ingrese el sueldo" }

4. Movilidad vacío

{ "valor": false, "msn": "Ingrese la movilidad" }

5. Bono nocturno vacío

{ "valor": false, "msn": "Ingrese el Bono Nocturno" }

6. Fecha inválida

{ "valor": false, "msn": "Ingrese la fecha de actualizacion" }

📚 Schemas

Cambio Salarial Administrativo (ERP)

Body enviado:

{ "empleado": "string", "nuevo_sueldo": "number", "nueva_movilidad": "number", "nuevo_bono_nocturno": "number", "fecha_de_actualizacion_date": "YYYY-MM-DD" }

🗃 Lógica en Pseudocódigo

required = [empleado, sueldo, movilidad, bono_nocturno, fecha] if falta alguno: return error if fecha no válida: return error body = { empleado, nuevo_sueldo: sueldo, nueva_movilidad: movilidad, nuevo_bono_nocturno: bono_nocturno, fecha_de_actualizacion_date: fecha } response = POST ERP Cambio Salarial Administrativo return success with response

Módulo de Solicitudes

Cambio de Sistema Pensionario(Sistema de Pension Combos (1)) - [combos]

🧾 Descripción

Este servicio retorna un conjunto de listas predefinidas utilizadas en la aplicación móvil, específicamente los tipos de AFP disponibles para selección en formularios o procesos del sistema.

No realiza consultas a base de datos ni al ERP; solo devuelve información estática utilizada para poblar combos (selects) en la interfaz.

Es un servicio simple y de uso general dentro del módulo de onboarding o actualización de datos personales.


🚀 Endpoint

POST /combos

Este servicio no requiere parámetros en el body ni en la URL.


🔐 Seguridad

Utiliza el flujo regular del controlador.
No solicita autenticación directa dentro de la función, pero su acceso depende de la configuración del backend (middleware del módulo).

No realiza llamadas externas al ERP.


🧠 Flujo del Servicio (resumen real)

  1. Define internamente una lista fija con los tipos de AFP:

    • AFP Habitat

    • AFP Profuturo

    • AFP Prima

    • AFP Integra

  2. Organiza los datos dentro de un arreglo asociado a la clave "tipos_afp".

  3. Retorna un JSON con:

    • valor: true

    • data: { "tipos_afp": [...] }


📥 Request Body

Este servicio no recibe parámetros.


{}

📤 Response 200 – Ejemplo

{ "valor": true, "data": { "tipos_afp": [ "AFP Habitat", "AFP Profuturo", "AFP Prima", "AFP Integra" ] } }

❗ Posibles Errores

Este servicio no genera errores, dado que devuelve datos estáticos.
Sin embargo, errores genéricos podrían producirse por:

  1. Error interno del servidor

    { "valor": false, "msn": "Error interno del servidor", "data": [] }

📚 Schemas usados

Respuesta del servicio

{ "valor": "boolean", "data": { "tipos_afp": ["string", ...] } }

🗃 Lógica en pseudo-código

combos = { "tipos_afp": [ "AFP Habitat", "AFP Profuturo", "AFP Prima", "AFP Integra" ] } return { valor: true, data: combos }
Módulo de Solicitudes

Cambio de Sistema Pensionario(Enviar solicitud cambio AFP (1)) - [store]

🧾 Descripción

Este servicio registra una solicitud de cambio de sistema pensionario para un empleado, validando previamente:

El servicio crea un nuevo documento en el ERP: Solicitud de Cambio de Sistema Pensionario


🚀 Endpoint

POST /cambio-sistema-pensionario/store


🔐 Seguridad


🧠 Flujo del Servicio (resumen real)

1. Validación de parámetros

El servicio valida:

2. Trae los datos del empleado


GET Employee/{empleado}

Si el empleado no existe → error.

3. Determina si el cambio es permitido

Reglas del negocio:

4. Verifica si ya existe una solicitud "Borrador"

Consulta a la base ERP:

SELECT name FROM `tabSolicitud de Cambio de Sistema Pensionario` WHERE id_empleado = <empleado> AND docstatus = 0

Si existe una, retorna error.

5. Crea la solicitud de cambio

POST resource/Solicitud de Cambio de Sistema Pensionario { "id_empleado": <empleado>, "sistema_pensionario": "AFP"|"ONP", "tipo_de_afp": "...", "tipo_cambio": "...", "cuspp": "..." // cuando aplica }


📥 Request Body (ejemplo)

{ "empleado": "EMP-0001", "sistema_pensionario": "AFP", "tipo_afp": "AFP Integra", "cuspp": "123456789012", "tipo_cambio": "DE ONP A AFP" }


📤 Response 200 – Ejemplo

✔ Cambio enviado correctamente

{ "valor": true, "msn": "Solicitud de cambio de sistema pensionario enviada" }

❌ Tipo de cambio inválido

{ "valor": false, "msn": "La opción del tipo de cambio no es una opción valida (\"ENTRE AFP\",\"DE ONP A AFP\",\"DE AFP A ONP\")" }

❌ Ya existe solicitud en borrador

{ "valor": false, "msn": "Ya cuenta con una solicitud en Borrador pendiente de validar" }

❌ No puede cambiar al mismo sistema

{ "valor": false, "msn": "No puede hacer el cambio al mismo sistema pensionario" }

❌ Error al crear solicitud

{ "valor": false, "msn": "Ocurrió un error al crear la solicitud de cambio de sistema pensionario", "error": { ... } }


📚 Validaciones importantes del servicio

✔ Validación de CUSPP

✔ Validación de sistema pensionario

✔ Regla especial ONP → AFP

Si el empleado está en ONP, solo puede migrar a AFP Integra:

if($employee["response"]["fondo_de_pensiones"] == "ONP" && $sistema_pensionario == "AFP" && $tipo_afp != "AFP Integra")


🗃 Lógica en pseudo-código

validar parámetros employee = GET Employee/{empleado} si no existe -> error si cambio no permitido -> error buscar solicitudes en Borrador para el empleado si existe -> error validar CUSPP si aplica crear documento: POST Solicitud de Cambio de Sistema Pensionario retornar éxito

Módulo Centro de Ayuda

Módulo Centro de Ayuda

Denuncias(Consultar Sucursal (1,2)) - [getBranchsDesignations]

🧾 Descripción

Servicio que obtiene dinámicamente:

dependiendo del parámetro type recibido en la solicitud.

Este servicio consulta directamente al ERP mediante los métodos internos dbErp() y ServiceErp().


🚀 Endpoint

POST /get-branchs-designations


📥 Request Body

{ "type": "Sucursal" | "Puesto" }

Valores permitidos:

type Acción
"Sucursal" Retorna sucursales con empleados asociados.
"Puesto" Retorna todos los puestos (Designation).

🔐 Seguridad


🧠 Flujo del Servicio

✔️ Si type = "Sucursal"

  1. Construye la consulta SQL:

    • Selecciona sucursales (tabBranch).

    • Hace JOIN con empleados (tabEmployee).

    • Agrupa y retorna solo sucursales con más de 1 empleado registrado.

  2. Ejecuta la consulta vía:


    dbErp("POST", body, /method/send-query-database)
  3. Si encuentra resultados:

    • Devuelve solo el nombre de la sucursal (br.name).

  4. Si ocurre error:

    • Retorna mensaje de error controlado.


✔️ Si type = "Puesto"

  1. Solicita al ERP la lista completa de Designations:


    GET resource/Designation?limit=None
  2. Extrae solo el nombre del puesto (name).

  3. Devuelve la lista al cliente.


❌ Si type ≠ “Sucursal” ni “Puesto”

Retorna error indicando que la opción no es válida.


📤 Response 200 – Ejemplos

✔️ Respuesta para type = "Sucursal"

{ "valor": true, "msg": "Se encontraron sucursales", "data": [ "Sucursal Lima", "Sucursal Arequipa", "Sucursal Trujillo" ] }

✔️ Respuesta para type = "Puesto"

{ "valor": true, "msg": "Se encontraron puestos", "data": [ "Asistente Administrativo", "Operario de Almacén", "Jefe de Sucursal" ] }

❌ Opción no válida

{ "valor": false, "msg": "Opcion no valida", "data": [] }

❌ Error del servidor

{ "valor": false, "msn": "Error de servidor", "data": "<detalle_del_error>" }


📚 Schemas que utiliza

Branch (SQL ERP)

Campos relevantes:

br.name

Employee

Relacionada solo para contar empleados por sucursal:

emp.branch emp.name

Designation

Campos relevantes:

{ "name": "string" }


🗃 Lógica en Pseudocódigo

tipo = request["type"] if tipo == "Sucursal": response = SQL: SELECT br.name FROM Branch br LEFT JOIN Employee emp ON emp.branch = br.name GROUP BY br.name HAVING COUNT(emp.name) > 1 return nombres de sucursales else if tipo == "Puesto": response = GET Designation return lista de name else: return error "Opción no válida"

Módulo Centro de Ayuda

Denuncias(Crear demanda (1)) - [store]

🧾 Descripción

Este servicio crea un registro oficial de una denuncia interna realizada por un colaborador o usuario del sistema.
Permite registrar denuncias anónimas o identificadas, incluir detalles del hecho, denunciados, fechas, archivos adjuntos y otros campos relevantes.

La información se almacena directamente en el ERP, creando un nuevo documento del tipo:


DocType: Denuncias

Incluye reglas de validación para asegurar que los datos enviados cumplan los requisitos mínimos según la normativa interna del área de cumplimiento.


🚀 Endpoint

POST /denuncias/store


🔐 Seguridad

Requiere autenticación interna:


🧠 Flujo del Servicio (Resumen Real)

  1. Lee parámetros del request:

    • Identificación del denunciante

    • Datos de contacto (si aplica)

    • Motivo de denuncia

    • Fechas del hecho

    • Sucursal

    • Denunciados (en JSON)

    • Archivo adjunto

    • Otros detalles relacionados

  2. Valida que el JSON de denunciados sea correcto.

  3. Ejecuta múltiples validaciones obligatorias:

    • Si se identifica → celular y correo son obligatorios.

    • Campos motivo, sucursal, desde, hasta, detalle deben existir.

    • Si conoce involucrados → mínimo 1 y máximo 3 denunciados.

    • Cada denunciado debe tener nombre, sucursal y área.

  4. Valida y arma estructura del archivo adjunto si se envía.

  5. Genera un código aleatorio único que identificará la denuncia.

  6. Crea el documento Denuncias en el ERP:


    POST /resource/Denuncias
  7. Guarda los denunciados como tabla hija (table_16).

  8. Devuelve confirmación y el código de seguimiento.


📥 Request Body (Ejemplo)

{ "identificar": 1, "celular": "987654321", "correo": "user@example.com", "motivo": "Acoso laboral", "continua_ocurriendo": 0, "sucursal": "SUC-001", "desde": "2025-01-01", "hasta": "2025-01-15", "conoce_involucrados": 1, "denunciados": "[{\"nombre\":\"Juan Perez\",\"sucursal\":\"Lima\",\"area\":\"Operaciones\"}]", "detalle": "Descripción detallada del hecho...", "compromiso": "Ninguno", "archivo": "codigo-archivo.pdf" }

🧪 Validaciones Importantes

Campo Requerido Condición
identificar Debe ser 0 o 1
celular, correo Obligatorios si identificar = 1
motivo
sucursal
continua_ocurriendo Debe ser 0 o 1
desde / hasta Fechas del hecho
conoce_involucrados 0 o 1
denunciados Condicional 1 a 3 registros si conoce_involucrados = 1
detalle

Si el archivo existe, se formatea a: https://fileserver.shalomcontrol.com/file-view/<archivo>


📤 Response 200 – Ejemplo exitoso

{ "success": true, "message": "Se registró correctamente", "data": { "codigo": "ABC123" } }


❗ Posibles Errores

1. JSON malformado en denunciados

{ "success": false, "message": "El campo denunciados debe ser un json codificado" }

2. Campos obligatorios faltantes

{ "success": false, "message": "Debe ingresar un celular" }

3. Número incorrecto de denunciados

{ "success": false, "message": "Solo puede ingresar hasta 3 denunciados como máximo" }

4. Error al registrar en el ERP

{ "success": false, "message": "Ocurrió un error al registrar", "response": { ... } }

5. Error inesperado del servidor

{ "success": false, "message": "Ocurrió un error al registrar", "exception": "<mensaje>" }

📚 Esquema del DocType Denuncias (Campos usados)

{ "identificar": "0|1", "celular": "string|null", "correo": "string|null", "motivo": "string", "continua_ocurriendo": "0|1", "sucursal": "string", "desde": "date", "hasta": "date", "conoce_involucrados": 0, "detalle": "string", "compromiso": "string|null", "archivo": "string|null", "estado_denuncias": "PENDIENTE", "doctype": "Denuncias", "table_16": [], "codigo_aleatorio": "string" }

🗃 Lógica en Pseudocódigo

leer todos los campos del request validar denunciados (JSON) validar campos uno por uno si identificar == 1: validar celular & correo si conoce_involucrados == 1: validar entre 1 a 3 denunciados si hay archivo: generar url pública generar codigo aleatorio armar payload del ERP insert = POST /resource/Denuncias si insert falla: retornar error retornar success + codigo
Módulo Centro de Ayuda

Denuncias(Url Demanda PDF (1)) - [pdf]

🧾 Descripción

Este servicio obtiene la información completa de una denuncia registrada en el ERP (Frappe/ERPNext), validando primero que exista una denuncia cuyo código aleatorio coincida con el parámetro enviado.

Una vez encontrada:

  1. Obtiene la información principal de la denuncia.

  2. Consulta nuevamente la denuncia para traer sus tablas hijas (por ejemplo table_16).

  3. Construye un array final con los datos completos.

  4. Genera un PDF oficial de la denuncia usando una plantilla Blade.

  5. Retorna el archivo descargable Demanda.pdf.

Este servicio se utiliza para permitir a los usuarios descargar un reporte o constancia oficial de la denuncia registrada.


🚀 Endpoint

GET /pdf/{codigo}

📌 El parámetro {codigo} corresponde al campo codigo_aleatorio de la denuncia.


📥 Parámetros

URL Params

Parámetro Tipo Obligatorio Descripción
codigo string Código aleatorio que identifica la denuncia

📌 No recibe parámetros en el body.


🔐 Seguridad

El servicio realiza llamadas internas al ERP a través de ServiceErp(), por lo que requiere autenticación válida configurada internamente.
No necesita token desde el cliente.


🧠 Flujo del Servicio (Resumen real)

1️⃣ Buscar denuncia por código aleatorio

Realiza un GET al recurso: GET Denuncias?filters=[["codigo_aleatorio","=",<codigo>]]

Si no encuentra coincidencias → retorna error.


2️⃣ Para cada denuncia encontrada

Hace un GET para traer la información completa del documento con sus tablas hijas: GET Denuncias/{name}

Guarda el contenido de la tabla table_16 y arma un arreglo final.


3️⃣ Generar el PDF

Usa: PDF::loadView("pdf/demanda", ["data" => $demandas_final[0]])

Lo genera en tamaño A5, orientación portrait, y lo retorna como descarga: Demanda.pdf


📤 Response – Ejemplo exitoso (PDF descargable)

El navegador descargará directamente: Demanda.pdf

Con el contenido renderizado desde la vista pdf/demanda.blade.php.


❗ Posibles Errores

1. No existe la denuncia

{ "success": false, "message": "No se encontró la denuncia" }

2. Error consultando el ERP

{ "success": false, "message": "<mensaje de la excepción>" }

3. La denuncia existe, pero falla la obtención completa

(No rompe el flujo; simplemente ignora la denuncia afectada.)


📚 Schemas utilizados

Denuncias (GET)

Campos utilizados:

{ "name": "string", "codigo_aleatorio": "string", "table_16": [ ... ], ...otros campos }

PDF Output

Basado en la vista: resources/views/pdf/demanda.blade.php


🗃 Lógica en Pseudo-código

body = { filters: [["codigo_aleatorio", "=", codigo]], fields: ["*"] } demandas = GET Denuncias WHERE codigo_aleatorio=codigo if demandas is empty: return error foreach denuncia in demandas: detalle = GET Denuncias/{name} agregar table_16 al resultado final generar PDF usando vista "pdf/demanda" retornar archivo: Demanda.pdf
Módulo Centro de Ayuda

Denuncias(Consultar demanda (1)) - [obtener]

🧾 Descripción

Permite consultar una denuncia registrada en el ERP usando un código aleatorio como identificador de búsqueda.

El servicio:

Es un servicio utilizado para que un usuario pueda revisar:


🚀 Endpoint

POST /obtener


📥 Request Body

{ "codigo": "string" }

Parámetros

Campo Tipo Obligatorio Descripción
codigo string ✔️ Sí Código aleatorio generado al registrar la denuncia

🔐 Seguridad

Requiere autenticación interna mediante
$this->general->ServiceErp()
(usa cookies o token ya configurado en el backend).


🧠 Flujo del Servicio (resumen real)

  1. Obtiene el código enviado en el request.

  2. Construye el body para consultar la denuncia en el ERP:

    • fields: name, creation, estado_denuncias, fechas, archivo, respuesta.

    • filters: [["codigo_aleatorio","=", $codigo]]

  3. Llama al ERP:
    GET resource/Denuncias

  4. Si no existe denuncia, retorna error.

  5. Si existe:

    • Verifica si archivo_denuncia no está vacío.

    • Si tiene archivo, le agrega la URL base del servidor.

  6. Retorna toda la información encontrada.


📤 Response 200 – Ejemplo exitoso

{ "success": true, "message": "Encontrado", "data": { "name": "DEN-00012", "creation": "2025-01-10 12:40:15", "estado_denuncias": "Atendido", "fecha_atendido": "2025-01-18", "fecha_proceso": "2025-01-15", "archivo_denuncia": "https://dominio.com/files/denuncia_12.pdf", "respuesta_de_denuncia_atendido": "Se realizó la evaluación correspondiente." } }


❗ Posibles Errores

1️⃣ Denuncia no encontrada

{ "success": false, "message": "No se encontró la denuncia" }

2️⃣ Error en la comunicación con el ERP

{ "success": false, "message": "Error del servidor: <detalle>" }

3️⃣ Respuesta vacía del ERP

{ "success": false, "message": "No se encontró la denuncia" }

📚 Esquema utilizado (Denuncias – GET)

Campos usados:

{ "name": "string", "creation": "datetime", "estado_denuncias": "string", "fecha_atendido": "date", "fecha_proceso": "date", "archivo_denuncia": "string", "respuesta_de_denuncia_atendido": "string" }

🗃 Lógica en pseudo-código

codigo = request.codigo body = { limit: None, fields: [name, creation, estado_denuncias, fecha_atendido, fecha_proceso, archivo_denuncia, respuesta_de_denuncia_atendido], filters: [["codigo_aleatorio", "=", codigo]] } response = GET Denuncias(body) if response is error or empty: return error "No se encontró la denuncia" denuncia = response[0] if denuncia.archivo_denuncia != "": denuncia.archivo_denuncia = BASE_CAPACITACION + denuncia.archivo_denuncia return success data = denuncia

Módulo Convocatorias

Módulo Convocatorias

Lista de convocatorias internas (1) - [getInternalCalls]

🧾 Descripción

Obtiene todas las convocatorias internas vigentes dentro del ERP, incluyendo información del puesto, sede y su archivo adjunto (PDF u otro documento del Job Opening).
El servicio cruza información entre:

Solo trae convocatorias internas activas (status = "Open") y marcadas como convocatoria interna = 1.


🚀 Endpoint

GET /get-internal-calls

No recibe parámetros.
Toda la información se obtiene mediante apiService() hacia el ERP.


🔐 Seguridad

Requiere conexión autorizada vía apiService(), usando token interno del ERP.


🧠 Flujo del Servicio (Resumen)

  1. Obtener todos los Job Openings internos activos

    GET Job Opening?limit=None &fields=["name","designation","sucursal"] &filters=[ ["convocatoria_interna","=",1], ["status","=","Open"] ]

  2. Obtener todos los archivos relacionados al Job Opening

    GET File?limit=None &fields=["name","attached_to_name","file_url"] &filters=[["attached_to_doctype","=","Job Opening"]]

  3. Si alguno de los endpoints devuelve error, se retorna:

    { "valor": false, "msn": "Error al buscar las convocatorias internas." }

  4. Si no hay convocatorias abiertas:

    { "valor": true, "msn": "En este momento no hay convocatorias internas..." }

  5. Para cada convocatoria se agrega:

    • La descripción de la sede: "PARA LA SEDE {sucursal}"

    • El archivo correspondiente (file_url), si existe.

  6. Se retorna listado de convocatorias internas enriquecidas.


📥 Request Body

No tiene body.


{}

📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Convocatorias internas encontradas", "data": [ { "name": "JOB-0001", "designation": "Analista de Operaciones", "sucursal": "LIMA", "sede": "PARA LA SEDE LIMA", "file": "https://dominio.com/files/job_0001.pdf" } ] }


❗ Posibles Errores

1. Error en consulta de Job Opening

{ "valor": false, "msn": "Error al buscar las convocatorias internas.", "data": {} }

2. Error en consulta de archivos File

{ "valor": false, "msn": "Error al buscar las convocatorias internas.", "data": {} }

3. No existen convocatorias internas activas

{ "valor": true, "msn": "En este momento no hay convocatorias internas, Estar atento a las proximas convocatorias", "data": [] }

4. Error inesperado del servidor

{ "valor": false, "msn": "Error del servidor", "data": "<error completo>" }


📚 Esquemas (estructuras utilizadas)

Job Opening

Campos usados:

{ "name": "string", "designation": "string", "sucursal": "string" }

File

Campos usados:

{ "name": "string", "attached_to_name": "string", "file_url": "string" }


🗃 Pseudo-código de la lógica

jobs = GET Job Opening internas y abiertas if jobs vacío → return no hay convocatorias files = GET File adjuntos a Job Opening for job in jobs: job.sede = "PARA LA SEDE " + job.sucursal job.file = "" for file in files: if file.attached_to_name == job.name: job.file = BASE_CAPACITACION + file.file_url return lista de jobs con su archivo si existe

Módulo Convocatorias

Obtiene combos (1) - [combosJobApplicant]

🧾 Descripción

Este servicio obtiene y devuelve todos los combos (listas de valores) necesarios para el registro o postulación de un Job Applicant (Postulante) dentro del sistema.

Los datos se obtienen directamente desde el ERP mediante el método interno getCombo(), que consulta tablas maestras como Country, Branch, Department y Gender.

Además, incluye una lista estática de tipos de documentos admitidos (DNI, Pasaporte, Carnet de Extranjería).


🚀 Endpoint

GET /combos-job-applicant

No requiere parámetros.


🔐 Seguridad

Requiere autenticación válida en la API del ERP, ya que las consultas internas se realizan mediante: $this->getCombo("<Doctype>")


🧠 Flujo del Servicio (resumen real)

  1. Inicializa un arreglo vacío $combo.

  2. Obtiene desde el ERP las siguientes listas:

    • Países → Doctype: Country

    • Sucursales → Doctype: Branch

    • Departamentos → Doctype: Department

    • Género → Doctype: Gender

  3. Agrega una lista fija de tipos de documentos:


    ["DNI", "Pasaporte", "Carnet de Extranjeria"]
  4. Retorna la estructura completa con todos los combos.

  5. En caso de error, devuelve una respuesta controlada.


📥 Request Body

Este servicio no recibe body, ni parámetros.


{}

📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Combos generados correctamente", "data": { "paises": [ { "name": "Peru" }, { "name": "Chile" } ], "sucursales": [ { "name": "Lima" } ], "departamento": [ { "name": "Recursos Humanos" } ], "genero": [ { "name": "Masculino" }, { "name": "Femenino" } ], "documentos": [ "DNI", "Pasaporte", "Carnet de Extranjeria" ] } }

❗ Posibles Errores

1. Error de ejecución o conexión con el ERP

{ "valor": false, "msn": "Error del servidor", "data": { "message": "detalle del error" } }

📚 Schemas (estructuras usadas)

Resultado de getCombo()

El servicio asume que getCombo() devuelve una estructura similar a:

[ { "name": "string" } ]

Lista fija de tipos de documentos:

[ "DNI", "Pasaporte", "Carnet de Extranjeria" ]

🗃 Lógica en pseudo-código

combo = {} combo["paises"] = getCombo("Country") combo["sucursales"] = getCombo("Branch") combo["departamento"] = getCombo("Department") combo["genero"] = getCombo("Gender") combo["documentos"] = ["DNI", "Pasaporte", "Carnet de Extranjeria"] return { valor: true, msn: "Combos generados correctamente", data: combo }
Módulo Convocatorias

Aplicar convocatoria (1) - [setJobApplicantPerApp]

🧾 Descripción

Registra una nueva solicitud de postulación (Job Applicant) desde la aplicación móvil, validando previamente:

Este servicio crea un documento Job Applicant en el ERP y también registra un Error Log con la data enviada al ERP (para auditoría).


🚀 Endpoint

POST /set-job-applicant-per-app


📥 Parámetros requeridos (Request Body)

{ "email_logued": "string (obligatorio)", "job_title": "string (obligatorio)", "email_id": "string (obligatorio, debe contener @)", "direccion": "string", "adjuntar_copia_de_documento": "string (file url)", "sucursal": "string", "resume_attachment": "string (file url)", "grado_instruccion": "string", "phone_number": "string (opcional)", "country": "string (opcional)", "ciudad": "string (opcional)", "nacionalidad": "string (opcional)", "carrera_profesional": "string (opcional)" }

🔐 Seguridad


🧠 Flujo del Servicio (Explicación Detallada)

1️⃣ Validaciones iniciales

2️⃣ Verifica si ya existe una postulación previa

Consulta en el ERP:

GET Job Applicant ?limit=None &filters=[["email_logued","=","<email_logued>"], ["job_title","=","<job_title>"]]

Si ya existe un registro → retorna error.

3️⃣ Obtiene datos del empleado

Busca el empleado vinculado al email logueado:

GET Employee ?fields=["*"] &filters=[["user_id","=","<email_logued>"]]

Si no existe → retorna error.

4️⃣ Calcula la edad del postulante

Usando la fecha de nacimiento del empleado mediante DateTime::diff.

5️⃣ Construye el cuerpo del nuevo Job Applicant

Incluye:

6️⃣ Crea el registro Job Applicant

POST Job Applicant BODY: { ...data }

7️⃣ Registra error interno en Error Log (auditoría)

La respuesta del ERP se envía también a: POST Error Log

8️⃣ Retorna la respuesta al cliente

Si se creó correctamente:

{ "valor": true, "msn": "Solicitud insertada correctamente", "data": { ... } }

Si falló:

{ "valor": false, "msn": "Solicitud no se puede insertar correctamente", "data": { ... } }

📤 Respuesta 200 – Ejemplo (Éxito)

{ "valor": true, "msn": "Solicitud insertada correctamente", "data": { "name": "JOB-APP-000123", "status": "Open", "applicant_name": "Juan Pérez", "job_title": "VAC-2025-005", "email_logued": "empleado@empresa.com" } }

❌ Respuesta 200 – Ejemplo (Error)

{ "valor": false, "msn": "Ya existe una solicitud para su usuario", "data": [] }

❗ Posibles Errores Comunes

1. Falta email_logued

{ "valor": false, "msn": "Es necesario el email con el que ha entrado a la app" }

2. Email sin “@”

{ "valor": false, "msn": "El email debe contener @" }

3. Empleado no existe

{ "valor": false, "msn": "Error al traer el empleado asociado" }

4. Solicitud duplicada

{ "valor": false, "msn": "Ya existe una solicitud para su usuario" }

5. Error al crear Job Applicant

{ "valor": false, "msn": "Solicitud no se puede insertar correctamente", "data": { ...ERP response... } }

🗃 Estructuras usadas (Schemas)

▶ Employee (GET)

Campos consultados:

{ "first_name": "string", "middle_name": "string", "first_last_name": "string", "second_last_name": "string", "nombre_completo": "string", "gender": "string", "passport_number": "string", "date_of_birth": "date", "place_of_issue": "string" }

▶ Job Applicant (POST)

Campos enviados:

{ "grado": "string", "job_title": "string", "applicant_name": "string", "numero_de_documento": "string", "email_id": "string", "sucursal": "string", "resume_attachment": "string", "status": "Open", "email_logued": "string" }

🧩 Pseudocódigo del Servicio

if !email_logued: error // validar duplicados list = GET Job Applicant by email_logued & job_title if list > 0: error employee = GET Employee by user_id=email_logued if not exists: error validar campos obligatorios edad = calcular edad(employee.date_of_birth) body = construir Job Applicant createJob = POST Job Applicant registrar Error Log con createJob if createJob.data: return success else: return error

Módulo Documentos Internos

Módulo Documentos Internos

Lista de categorias - documentos (1) - [getInternalDocuments]

🧾 Descripción

Obtiene todos los documentos internos del ERP, los agrupa por categoría y devuelve cuáles corresponden a un puesto específico (si aplica).

Este servicio combina información procedente de:

También determina dinámicamente qué archivo debe adjuntarse para la categoría IPERC, según el puesto del trabajador.

📌 Es un servicio de consulta sin paginación.
📌 No requiere parámetros en el body (solo el parámetro $puesto en la URL).


🚀 Endpoint

GET /internal-documents/{puesto}


🔐 Seguridad

Requiere autenticación válida vía dbErp usando el token del ERP.
El servicio accede directamente a vistas y tablas internas del ERP.


🧠 Flujo del Servicio

1. Consulta documentos internos

Ejecuta la sentencia SQL:

SELECT di.name, di.nombre_del_archivo, di.categoria, di.campo_para_adjuntar, de.puesto, de.adjuntar FROM `tabDocumentos Internos` di LEFT JOIN `tabDocumentos especificos` de ON di.name = de.parent

Si falla la consulta → devuelve error 500 del servicio.


2. Normaliza categorías

Si un documento no tiene categoría, se asigna por defecto: categoria = "POLITICAS"


3. Agrupa documentos por categoría

Genera una estructura como:

{ "POLITICAS": [...], "IPERC": [...], "MOF": [...], ... }

4. Caso especial: categoría IPERC

Para IPERC:

Ejemplo lógica:

adjunto = campo_para_adjuntar_default foreach item in detalles: if item.puesto == puesto AND item.adjuntar != "": adjunto = item.adjuntar

5. Construye la respuesta final

La respuesta incluye:


📤 Response 200 – Ejemplo Real

{ "valor": true, "msn": "Lista de categorias generado correctamente", "data": { "categorias": [ "POLITICAS", "IPERC", "MOF" ], "categorias_registro": { "POLITICAS": [ { "name": "DOC-001", "nombre_del_archivo": "reglamento_interno.pdf", "campo_para_adjuntar": "/files/reglamento_interno.pdf" } ], "IPERC": [ { "name": "IPERC-001", "nombre_del_archivo": "iperc_almacen.pdf", "campo_para_adjuntar": "/files/iperc_almacen.pdf" } ] } } }

❗ Posibles errores

1. Error de servicio ERP

{ "valor": false, "msn": "Error de servicio", "data": [...] }

2. Error interno

{ "valor": false, "msn": "Error de servidor", "data": "<mensaje>" }

📚 Estructuras de datos utilizadas

Documentos Internos (tabDocumentos Internos)

Campos utilizados:

{ "name": "string", "nombre_del_archivo": "string", "categoria": "string|null", "campo_para_adjuntar": "string" }

Documentos Específicos (tabDocumentos especificos)

Campos utilizados:

{ "puesto": "string|null", "adjuntar": "string|null" }

🗃 Pseudocódigo del servicio

sql = SELECT documentos internos + documentos especificos docs = dbErp(sql) foreach doc in docs: if categoria is null: categoria = "POLITICAS" grouped = group docs by categoria foreach categoria in grouped: group by name (padre) if categoria == 'IPERC': adjunto = campo_para_adjuntar_default if puesto matches child: adjunto = child.adjuntar else: adjunto = campo_para_adjuntar return { categorias: keys(grouped), categorias_registro: grouped }
Módulo Documentos Internos

Guardar documento (1) - [saveInternalDocuments]

🧾 Descripción

Registra internamente un documento aceptado o gestionado por un usuario dentro de una terminal específica.

Este servicio guarda un log en la tabla documentos_internos, permitiendo rastrear:

Es utilizado para auditoría y trazabilidad dentro del sistema.


🚀 Endpoint

POST /save-internal-documents


📥 Parámetros (Request Body)

{ "usuario": "string", "terminal": "string", "tipo": "string" }

Campos:

Campo Tipo Requerido Descripción
usuario string ✔️ Sí ID o username del usuario que realiza la acción
terminal string ✔️ Sí Código de la terminal donde se ejecuta la acción
tipo string ❌ No Tipo de documento o acción registrada

🔐 Seguridad

No requiere token de ERP.
Acceso interno del backend usando conexión directa a la base de datos mysql2.


🧠 Flujo del Servicio (resumen)

  1. Valida que usuario y terminal existan en la solicitud.

  2. Establece zona horaria America/Lima.

  3. Inserta un registro en la tabla documentos_internos con:

    • usuario

    • terminal

    • tipo

    • fecha actual

  4. Si el registro falla, retorna un error.

  5. Si todo es exitoso, responde confirmación de inserción.


🗃 Base de Datos Utilizada

Tabla: documentos_internos (BD: mysql2)

Campo Tipo Descripción
usuario varchar Usuario que registra
terminal varchar Terminal desde donde registra
tipo varchar Tipo de documento
fecha datetime Fecha y hora del registro

🔎 Pseudocódigo

if usuario vacío → retornar error “te olvidaste el usuario” if terminal vacío → retornar error "te olvidaste la terminal" fecha = now() insert into documentos_internos (usuario, terminal, tipo, fecha) if insert falla → retornar "Ocurrió un error" else → retornar "Insertado con éxito"

📤 Respuestas del Servicio

200 – Inserción exitosa

{ "valor": true, "msg": "Insertado con éxito" }

❗ Error: Falta usuario

{ "valor": false, "msg": "te olvidaste el usuario" }

❗ Error: Falta terminal

{ "valor": false, "msg": "te olvidaste la terminal" }

❗ Error al insertar

{ "valor": false, "msg": "Ocurrio un error" }

📚 Ejemplo completo de Request

{ "usuario": "user@example.com", "terminal": "236", "tipo": "descarga_politicas" }
Módulo Documentos Internos

Examen Medico (1) - [obtain]

🧾 Descripción

Este servicio permite consultar los resultados del examen EMO (Evaluación Médica Ocupacional) de un empleado utilizando su DNI (passport_number).

El servicio valida que el DNI haya sido enviado, busca la información correspondiente mediante el método interno getExamenEmo() y retorna los resultados si existen.

Es un servicio de consulta rápida y directa.


🚀 Endpoint

POST /obtain


📥 Request Body

{ "passport_number": "12345678" }

Campos:

Campo Tipo Obligatorio Descripción
passport_number string ✔️ DNI del empleado para consultar su examen EMO

🔐 Seguridad

Este servicio no requiere autenticación externa, pero su funcionamiento depende de un método interno:


🧠 Flujo del Servicio (Explicación)

  1. Validación inicial del DNI

    • Si el parámetro passport_number no está presente, el servicio responde con error.

  2. Consulta del examen EMO

    • Se llama al método interno getExamenEmo($passport_number).

  3. Validación del resultado

    • Si el método no retorna datos, se responde con un mensaje indicando que no se encontraron resultados.

  4. Respuesta exitosa

    • Si sí existen resultados, se retorna el contenido del examen EMO.


📤 Response 200 – Ejemplos

✔️ Caso exitoso

{ "valor": true, "msn": "Se encontraron resultados", "data": { "resultado": "Apto", "fecha": "2025-01-12", "observaciones": "Ninguna" } }

❗ Error: DNI no enviado

{ "valor": false, "msn": "El dni del empelado es obligatorio" }

❗ Error: Sin resultados EMO

{ "valor": false, "msn": "No se encontraron resultados" }

❗ Posibles Errores

Código Motivo Descripción
400 DNI faltante No se envió el passport_number
404 Sin resultados El empleado no tiene examen EMO registrado
500 Error en método interno Fallo en getExamenEmo()

📚 Schemas

Request Schema

{ "passport_number": "string" }

Response Schema (éxito)

{ "valor": true, "msn": "Se encontraron resultados", "data": { ...examen_emo } }

Response Schema (error)

{ "valor": false, "msn": "Descripción del error" }

🗃 Lógica en pseudocódigo

if !passport_number: return error("El dni del empleado es obligatorio") examen = getExamenEmo(passport_number) if !examen: return error("No se encontraron resultados") return success(examen)

Módulo QR

Módulo QR

Verificar QR (1) - [verifyQR]

🧾 Descripción

Este servicio permite validar si un empleado tiene permitido registrarse (por ejemplo, marcar asistencia) en función del último escaneo de QR del bus registrado en el ERP.

La lógica se basa en verificar si el empleado escaneó su QR dentro de las últimas 4 horas (14400 segundos).

El servicio consulta la tabla:

Mediante dbErp() para obtener el escaneo más reciente disponible.


🚀 Endpoint

POST /verify-qr


📥 Request Body (Ejemplo)

{ "employee": "HR-EMP-00045" }

Parámetros

Campo Tipo Obligatorio Descripción
employee string ✔️ Código de empleado a validar

🔐 Seguridad

El servicio usa comunicación interna con ERP mediante:

No requiere autenticación adicional desde el cliente.


🧠 Flujo del Servicio (Explicación real)

  1. Validación inicial del parámetro

    • Si employee está vacío → se devuelve error.

  2. Consulta del último escaneo registrado en ERP

    Se ejecuta:

    SELECT tpr.name, teas.empleado, teas.fecha FROM `tabRegistro de Escaneres de Bus` tpr LEFT JOIN `tabTabla Lista Blanca` teas ON teas.parent = tpr.name WHERE teas.empleado = employee ORDER BY teas.fecha DESC LIMIT 1
  3. Si no existen registros

    • Se retorna mensaje indicando que no se encontró escaneo.

  4. Cálculo de la diferencia de tiempo

    Se obtiene el tiempo transcurrido entre:

    • Fecha del escaneo (fecha)

    • Fecha actual

    Se obtiene con:

    $diff = $fechaEscaneoCarbon->diffInSeconds(now());
  5. Aplicación de la regla de validación

    • Si la diferencia es menor a 4 horas (14400 segundos)permitido

    • Si es mayor → denegado

  6. Manejo de excepciones
    Si ocurre un error interno, se retorna el mensaje de error.


📤 Response 200 – Ejemplos

✔️ Caso permitido (último escaneo dentro de 4 horas)

{ "status": true, "msn": "permitido" }

✔️ Caso denegado (más de 4 horas sin escanear)

{ "status": true, "msn": "denegado" }

❌ No existe escaneo asociado al empleado

{ "status": false, "msn": "No se ha encontrado un escaner de bus para el empleado" }

❌ Parámetro inválido

{ "status": false, "msn": "El empleado no puede estar vacio" }

❌ Error interno

{ "status": false, "msn": "Error interno: <mensaje>" }

📚 Schemas utilizados

Registro de Escaneres de Bus (consulta)

Campos consultados:

{ "name": "string", "empleado": "string", "fecha": "datetime" }

🗃 Lógica en Pseudo-código

if employee is empty: return error("El empleado no puede estar vacio") data = GET ultimo registro de escaneo del bus para employee if no data: return error("No se ha encontrado un escaneo") fechaEscaneo = data.fecha diferencia = now() - fechaEscaneo (en segundos) if diferencia < 14400: return permitido else: return denegado
Módulo QR

Leer QR (1) - [leerCodigoQR]

🧾 Descripción

Este servicio valida un código QR de acceso a buses internos y determina si un empleado puede registrar un nuevo escaneo.
El flujo consulta los registros previos, controla tiempos de reescaneo (mínimo 4 horas) y registra un nuevo ingreso si corresponde.

El servicio interactúa con:


🚀 Endpoint

POST /leer-codigo-qr


📥 Request Body

{ "qr": "string", "employee": "string" }

Parámetros

Campo Tipo Obligatorio Descripción
qr string ✔️ Código QR escaneado
employee string ✔️ Código del empleado que intenta registrar el escaneo

🔐 Seguridad

Requiere autenticación interna del ERP (vía dbErp() y ServiceErp()).


🧠 Flujo del Servicio (resumen real)

1️⃣ Validaciones iniciales

Si falla, retorna error inmediato.


2️⃣ Buscar el documento del QR

Consulta el ERP:

GET Registro de Escaneres de Bus JOIN Tabla Lista Blanca WHERE qr = <qr> ORDER BY fecha DESC

Campos devueltos:

Si no hay resultados: QR inválido.


3️⃣ Filtrar último registro por empleado

Construye una lista de empleados únicos y toma el último escaneo para cada uno.

Si el empleado actual tiene un registro:

{ "status": true, "msn": "denegado" }

4️⃣ Registrar nuevo escaneo

Si cumple la validación, inserta un registro en la tabla:

POST Tabla Lista Blanca { fecha, parent, empleado, parentlink: Registro de Escaneres de Bus }

Si falla el registro → error
Si se registra correctamente → "permitido"


📤 Response 200 – Ejemplos

✔️ Permitido

{ "status": true, "msn": "permitido" }

⛔ Denegado por escaneo reciente

{ "status": true, "msn": "denegado" }

❌ QR sin registros

{ "status": false, "msn": "No se encontraron registros para el QR escaneado" }

❌ Error interno

{ "status": false, "msn": "Error interno: <mensaje>" }

❗ Posibles Errores

  1. QR vacío

{ "status": false, "msn": "El QR no puede estar vacio" }
  1. Empleado vacío

{ "status": false, "msn": "El empleado no puede estar vacio" }
  1. QR inexistente en ERP

{ "status": false, "msn": "No se encontraron registros para el QR escaneado" }
  1. Error al insertar registro

{ "status": false, "msn": "No se pudo registrar el escaner de bus" }
  1. Error interno (try–catch)

{ "status": false, "msn": "Error interno: <mensaje>" }

🗃 Tablas / Schemas utilizados

Registro de Escaneres de Bus (tpr)

Campos usados:

{ "name": "string", "qr": "string" }

Tabla Lista Blanca (teas)

Campos usados:

{ "empleado": "string", "fecha": "datetime", "parent": "string" }

Registro Insertado

{ "fecha": "datetime", "parent": "string", "empleado": "string", "parentfield": "table_1", "parenttype": "Registro de Escaneres de Bus" }

🧩 Pseudocódigo del flujo

if qr is empty → error if employee is empty → error // Buscar registros del QR dataQR = SELECT * FROM RegistroEscaneresBus JOIN TablaListaBlanca WHERE qr = qr ORDER BY fecha DESC if dataQR is empty → error // Obtener últimos registros por empleado empleadosUnicos = agrupar_por_empleado(dataQR) if empleadosUnicos[employee] existe: diffHoras = horas_entre(último registro, ahora) if diffHoras < 4: return "denegado" // Registrar nuevo escaneo insert = POST TablaListaBlanca { fecha: now, empleado, parent: documentoPrincipal } if insert.error: return error return "permitido"

Módulo Supervision

Módulo Supervision

Lista Sucursales (1) - [listSucursalSupervition]

🧾 Descripción

Este servicio obtiene todas las supervisiones realizadas por un Supervisor Nacional, junto con información adicional relacionada a:

El servicio consolida datos procedentes de:

y devuelve una lista enriquecida de supervisiones.


🚀 Endpoint

POST /list-sucursal-supervition


📥 Parámetros de Entrada (Request)

Body / FormData

Parámetro Tipo Obligatorio Descripción
Employe string ✔️ Código del empleado supervisor cuyo historial de supervisiones será consultado.

Ejemplo:

{ "Employe": "EMP-001245" }

🔐 Seguridad


🧠 Flujo del Servicio (Resumen Detallado)

1️⃣ Validar parámetro recibido

Si Employe viene vacío, se retorna un mensaje de validación.

2️⃣ Listar supervisiones creadas por el supervisor

Consulta en el ERP:

GET resource/Check List del Supervisor Nacional 2 Filters: supervisor = Employe Fields: sucursal, fecha, name

3️⃣ Obtener la relación con Tabla Supervisores

Con los name obtenidos, se consulta:

POST send-query-database FROM tabCheck List del Supervisor Nacional 2 spr LEFT JOIN tabTabla supervisores tab ON spr.name = tab.id_doctype WHERE spr.name IN (...) SELECT spr.name, tab.parent

Construye:

4️⃣ Obtener programación de supervisores

Si existen supervisiones relacionadas, consulta:

POST send-query-database FROM tabProgramacion de Supervisores WHERE name IN parents SELECT name, prog_supervisores, fecha_real_de_la_supervicion

Se agrega esta información a cada supervisión detectada.

5️⃣ Unir los datos

Cada supervisión final contendrá:


📤 Response (200 – Ejemplo)

{ "valor": true, "msn": "Lista de Sucursales", "data": [ { "sucursal": "SUC-014", "fecha": "2024-10-03", "name": "CHK-SUP-00045", "supervision": "SUP-NACIONAL-05", "fechaSupervision": "2024-10-04" } ] }

❗ Posibles Errores

1. Supervisor no enviado

{ "valor": false, "msn": "El campo empleado es obligatorio", "data": [] }

2. Error del servicio ERP

{ "valor": false, "msn": "Ocurrio un error al listar", "data": [] }

3. Supervisor sin supervisiones registradas

{ "valor": false, "msn": "No hay ningun registro creado", "data": [] }

📚 Tablas / Recursos involucrados

Check List del Supervisor Nacional 2

Campos usados:

{ "sucursal": "string", "fecha": "date", "name": "string", "supervisor": "string" }

Tabla supervisores

Relación entre registros checklist y programaciones.

Programación de Supervisores

Campos utilizados:

{ "name": "string", "prog_supervisores": "string", "fecha_real_de_la_supervicion": "date" }

🗃 Pseudocódigo del Servicio

if Employe is empty: return error listName = GET Check List supervisor where supervisor=Employe if listName empty: return sin registros names = extract "name" from listName relations = QUERY tabla supervisores WHERE spr.name IN names parents = extract unique parent programaciones = QUERY programacion supervisores WHERE name IN parents merge programaciones into listName return listName enriched
Módulo Supervision

Informacion de sucursal (1) - [infosupervitionName]

🧾 Descripción

Obtiene la información general de un checklist del Supervisor Nacional, incluyendo:

El servicio combina información proveniente de:


🚀 Endpoint

POST /infosupervition-name

🔸 Recibe un parámetro obligatorio en el body:

{ "name": "ID del checklist" }

🔐 Seguridad

Requiere autenticación interna mediante ServiceErp() y dependencias del módulo general.


🧠 Flujo del Servicio (resumen real)

  1. Valida parámetro name
    Si viene vacío, retorna error utilizando responseValidate().

  2. Obtiene todas las categorías asociadas al checklist
    Usa:


    listCategory($request)
  3. Valida respuesta de categorías

    • Si ocurre error → retorna mensaje de fallo.

    • Si la data viene vacía → indica que no existen registros creados.

  4. Calcula progresos y puntajes totales
    Recorre cada categoría para:

    • Sumar section_puntaje

    • Sumar progreso

    • Contar categorías

    Luego obtiene:

    • all_progress = total_progreso / cantidad_categorias

    • all_point = round(total_puntaje)

  5. Consulta información de cabecera del checklist en ERP

    Realiza:


    GET Check List del Supervisor Nacional 2?filters=[["name","=",<name>]]

    Campos obtenidos:

    • sucursal

    • fecha

    • name

  6. Agrega métricas calculadas al resultado:

    • all_progress

    • all_point

  7. Retorna respuesta final con la información consolidada


📥 Request Body

{ "name": "CHK-00045" }

📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Informacion obtenida", "data": { "sucursal": "LIMA-01", "fecha": "2025-01-15", "name": "CHK-00045", "all_progress": 82.5, "all_point": 120 } }

❗ Posibles Errores

1. name vacío

{ "valor": false, "msn": "Campo requerido vacío" }

2. Error al obtener categorías

{ "valor": false, "msn": "Error al obtener la informacion", "error": { ... } }

3. No existen registros en categorías

{ "valor": false, "msn": "No hay ningun registro creado", "data": [] }

4. Error consultando al ERP

{ "valor": false, "msn": "Error al obtener informacion", "data": [] }

📚 Schemas usados

Categoría (respuesta de listCategory)

{ "section_puntaje": "number", "progreso": "number" }

Check List del Supervisor Nacional 2 (ERP)

{ "sucursal": "string", "fecha": "date", "name": "string" }

🗃 Lógica en pseudo-código

if name == "": return error categorias = listCategory(request) if categorias.error: return error if categorias.data empty: return no registros for categoria in categorias: total_puntaje += categoria.section_puntaje total_progreso += categoria.progreso cantidad += 1 GET checklistHeader FROM ERP WHERE name = <name> header.all_progress = total_progreso / cantidad header.all_point = round(total_puntaje) return header
Módulo Supervision

Puntajes de las categorias (1) - [listCategory]

🧾 Descripción

Obtiene y procesa dinámicamente todas las categorías, preguntas y porcentajes de avance del Check List del Supervisor Nacional 2, basándose en su estructura de campos del DocType y los valores registrados en un documento específico.

Este servicio:

  1. Lee la estructura del DocType para identificar:

    • Secciones (categorías).

    • Preguntas tipo Check, Data, Attach Image.

  2. Recupera los valores reales del documento filtrado por name.

  3. Agrupa los campos por categoría.

  4. Calcula el avance (%) y puntaje por sección.

  5. Devuelve un resumen por categoría con:

    • Total de campos.

    • Campos completados.

    • Progreso (%).

    • Puntaje asignado.


🚀 Endpoint

POST /list-category


📥 Request Body

{ "name": "<id del documento Check List del Supervisor Nacional 2>" }

Parámetros

Campo Tipo Requerido Descripción
name string ID del documento cuyo checklist se evaluará

🔐 Seguridad

El servicio utiliza autenticación interna mediante: $this->general->ServiceErp()

Por lo tanto, requiere credenciales válidas para consumir el ERP.


🧠 Flujo del Servicio (Explicación Técnica Real)

1️⃣ Obtener estructura del DocType

Se consulta: GET resource/DocType/Check List del Supervisor Nacional 2

Esto trae todos los campos del formulario.
El servicio filtra únicamente:

También omite los campos de puntaje global:


2️⃣ Construcción dinámica de categorías y preguntas

Ejemplo de agrupación generada:

{ "Gestión Documentaria": [ "documentos_autoridades", "imagen_14", "comentario_14", ... ], "Presentación del almacén": [ "foto_area", "check_orden", "comentario_orden" ] }

3️⃣ Recuperar valores del documento

Se unen todos los fields encontrados y se hace:

GET resource/Check List del Supervisor Nacional 2 ?fields=[...fields] &filters=[["name","=",name]]

Esto trae los valores registrados del documento.


4️⃣ Agrupar los valores por categoría

El servicio arma una estructura:

{ "Gestión Documentaria": { "documentos_autoridades": 1, "imagen_14": "/files/img.png", "comentario_14": "OK" } }

5️⃣ Calcular puntajes y progreso

Para cada categoría:


progreso = (complete_fields / total_fields_categoria) * 100

⚠ Nota: El servicio divide el total de campos entre 3 ($maxFields = $maxFields / 3) para compensar que cada pregunta tiene 3 tipos de fields (check, data, image).


📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Lista De Categorias", "data": [ { "category": "Gestión Documentaria", "progreso": 67, "total_fields": 6, "complete_fields": 4, "section_puntaje": 7.28 }, { "category": "Áreas Críticas", "progreso": 50, "total_fields": 4, "complete_fields": 2, "section_puntaje": 3.64 } ] }


❗ Posibles Errores

1. No se puede obtener el DocType

{ "value": false, "msn": "Ocurrio un error al consular" }

2. Documento no encontrado

(El servicio devolverá valores vacíos por categoría)


🗃 Estructuras Utilizadas

DocType (GET)

Campos analizados:

{ "fieldname": "string", "label": "string", "fieldtype": "Section Break | Check | Data | Attach Image" }

🧩 Lógica en pseudocódigo

doctype = GET DocType fields categorias = {} foreach field in doctype.fields: if field is Section Break: categoria_actual = field.label if field is Check/Data/Image: categorias[categoria_actual].append(field.fieldname) # Obtener valores reales del documento values = GET Check List del Supervisor Nacional 2 where name = request.name # Agrupar valores por categoría foreach categoria in categorias: newQuestions[categoria] = tomar valores según fieldname # Calcular porcentaje y puntaje foreach categoria in newQuestions: total = count(fields) / 3 completos = fields con valor 1 puntaje = completos * 1.82 agregar resultado al response
Módulo Supervision

Respuestas formulario (1) - [missing_questions_form]

🧾 Descripción

Este servicio identifica qué preguntas no han sido completadas dentro de un formulario del DocType:

Check List del Supervisor Nacional 2

El servicio analiza:

Se usa principalmente para:

✔ Validar formularios incompletos
✔ Mostrar al usuario qué preguntas faltan llenar
✔ Controlar flujos de supervisión/inspecciones


🚀 Endpoint

POST /missing-questions-form


📥 Parámetros del Request

Campo Tipo Obligatorio Descripción
category string ✔ Sí Nombre de la sección del formulario (label del Section Break).
name string ✔ Sí ID del documento del Doctype "Check List del Supervisor Nacional 2".

Ejemplo de request:

{ "category": "Limpieza y Orden", "name": "CHK-SUP-00015" }


🔐 Seguridad

Utiliza autenticación interna a través de:


$this->general->ServiceErp()

No requiere autenticación externa del usuario final.
Toda la data se obtiene desde el ERP.


🧠 Flujo del Servicio (Resumen Técnico)

1️⃣ Validaciones iniciales

Si falta un campo → retorna error inmediato.


2️⃣ Obtiene estructura del formulario

GET al Doctype: GET /resource/DocType/Check List del Supervisor Nacional 2

De ahí obtiene:

Y construye un arreglo organizado por secciones:

{ "Nombre de Sección": { "fields_name": { fieldname : label }, "data_name": { fieldname : label }, "img_name": { fieldname : label } } }

Se excluyen automáticamente:


3️⃣ Filtra solo la categoría solicitada

Busca dentro de todas las secciones y selecciona solo: questions[category]

Si no existe → retorna vacío.


4️⃣ Obtiene valores del documento filtrado por name


GET /resource/Check List del Supervisor Nacional 2?filters=[["name","=",<name>]]

Aquí obtiene los valores reales del formulario.


5️⃣ Determina qué preguntas faltan completar

Compara para cada campo: si campo == 0 → está incompleto → se agrega a la lista

Guarda:


6️⃣ Retorna solo las preguntas faltantes


📤 Response 200 – Ejemplo Real

{ "valor": true, "msn": "Missing Questions", "data": { "Limpieza y Orden": [ "pregunta_1", "pregunta_3" ], "questions": [ "¿Los ambientes se encuentran limpios?", "¿El personal cumple con el orden establecido?" ] } }


❗ Posibles Errores

1️⃣ category vacío

{ "valor": false, "msn": "El campo category es requerido" }


2️⃣ name vacío

{ "valor": false, "msn": "El campo name es requerido" }


3️⃣ El Doctype no responde

{ "valor": false, "msn": "Ocurrio un error al consular" }


4️⃣ Error en consulta de valores del documento

{ "valor": false, "msn": "Ocurrio un error durante el proceso, intente de nuevo." }


🗃 Estructuras Usadas

📌 DocType: Check List del Supervisor Nacional 2

Campos analizados:

Se ignoran:


🧩 Algoritmo en Pseudocódigo

validar(category) validar(name) doctype = GET DocType structure preguntas = extraer_secciones_y_campos(doctype) selectedCategory = preguntas[category] campos = obtener_fieldnames(selectedCategory) valores = GET Documento ERP con esos campos missing = [] para cada campo en selectedCategory: si valor == 0: agregar a missing return missing

Módulo Supervision

Respuestas (1) - [missing_questions]

🧾 Descripción

Este servicio obtiene las preguntas incompletas y completas de una categoría específica del Doctype “Check List del Supervisor Nacional 2”, basándose en un registro identificado por su name.

El servicio:

  1. Obtiene toda la estructura de campos del Doctype.

  2. Identifica qué campos pertenecen a cada categoría (Section Break).

  3. Filtra únicamente los campos tipo:

    • Check

    • Data (comentado actualmente)

    • Attach Image (comentado actualmente)

  4. Consulta los valores reales del formulario (0 o 1).

  5. Determina qué preguntas están completas o incompletas.

  6. Devuelve solo la categoría solicitada.

Es un servicio orientado a auditorías y evaluación operacional.


🚀 Endpoint

POST /missing-questions


📥 Parámetros (Request Body)

Campo Tipo Obligatorio Descripción
name string ✔️ Identificador del documento del Doctype “Check List del Supervisor Nacional 2”.
category string ✔️ Nombre de la categoría (Section Break) a analizar.

Ejemplo:


{ "name": "CHK-SUP-00045", "category": "Gestión Documentaria" }

🔐 Seguridad

Requiere autenticación ERP válida, manejada internamente por ServiceErp().


🧠 Flujo del Servicio (Resumen)

  1. Validación de parámetros
    Si name o category vienen vacíos → error inmediato.

  2. Obtener estructura del Doctype
    GET /resource/DocType/Check List del Supervisor Nacional 2

    • Extrae los campos agrupados por sección (Section Break).

    • Identifica solo campos tipo Check.

  3. Agrupar preguntas por categoría

    • Mapea category → lista de campos (fieldname → label).

  4. Construir lista total de fields para consultar sus valores
    Ejemplo:


    ["documentos_autoridades", "imagen_14", "comentario_14", ...]
  5. Consultar valores reales del registro
    GET /resource/Check List del Supervisor Nacional 2?fields=[...]&filters=[["name","=",name]]

  6. Clasificar por categoría:

    • Si campo = 0Incompleta

    • Si campo = 1Completa

  7. Retornar solo la categoría solicitada.


📤 Response 200 – Ejemplo


{ "valor": true, "msn": "Missing Questions", "data": { "Incompletas": [ "Falta documento de autoridades", "Informe integrado no subido" ], "Completas": [ "Imagen de fachada", "Checklist SST completado" ] } }

❗ Posibles Errores

1. Parámetro vacío


{ "valor": false, "msn": "El campo name es obligatorio" }

2. Error al consultar el DocType


{ "value": false, "msn": "Ocurrio un error al consultar" }

3. Error consultando los valores del registro


{ "valor": false, "msn": "Ocurrio un error durante el proceso", "error": { ... } }

📚 Estructuras utilizadas

✔️ Doctype: Check List del Supervisor Nacional 2

Campos relevantes:

Tipo Uso
Section Break Agrupar preguntas por categoría
Check Representa preguntas de Sí/No
Data (comentado, no procesado actualmente)
Attach Image (comentado, no procesado actualmente)

Ejemplo de estructura procesada:


[ "Gestión Documentaria" => [ "documentos_autoridades" => "1. Documentos de autoridades", "informativo_integrado" => "2. Informativo integrado", ], "Seguridad Operacional" => [ "extintores" => "1. Extintores en regla", ] ]

🧠 Pseudocódigo Real


validate name, category doctypeFields = GET DocType Check List questions = group fields by Section Break (only Check fields) allFields = extract all fieldnames used in questions values = GET Check List record where name = request.name For each category: For each field: if value == 0 → add to Incompletas if value == 1 → add to Completas return data of selected category
Módulo Supervision

Adjuntar imagen (1) - [uploadFileErp]

🧾 Descripción

Este servicio permite subir un archivo al ERP utilizando el endpoint interno method/upload_file.

Funciona enviando el archivo recibido desde el request PHP ($_FILES["file"]) mediante cURL hacia el servicio de carga del ERP y devuelve los metadatos del archivo subido:

Es un servicio auxiliar utilizado por funcionalidades que requieren cargar documentos o imágenes hacia el servidor del ERP.


🚀 Endpoint

POST /upload-file-erp

📌 Requiere enviar un archivo en el campo file del formulario.


🔐 Seguridad

No utiliza el token del usuario.
El servicio realiza la subida como Guest, usando los headers de cookie:

Cookie: full_name=Guest; sid=Guest; system_user=no; user_id=Guest; user_image=

➡️ Esto significa que la API de ERP ya está configurada para permitir carga de archivos desde clientes externos bajo permisos Guest.


🧠 Flujo del Servicio (resumen)

  1. Captura el archivo enviado en $_FILES["file"].

  2. Crea un objeto CURLFile con:

    • ruta temporal (tmp_name)

    • tipo MIME

    • nombre original

  3. Envía el archivo al endpoint:


    POST /method/upload_file
  4. Espera la respuesta del ERP.

  5. Decodifica la respuesta JSON.

  6. Retorna un objeto con:

    • url del archivo

    • fecha de creación

    • nombre

    • tamaño


📥 Request Body

Debe enviarse como multipart/form-data.

Ejemplo (form-data):

Campo Tipo Descripción
file File Archivo a subir

Ejemplo en HTML:

<form method="POST" enctype="multipart/form-data"> <input type="file" name="file"> </form>


📤 Response 200 – Ejemplo

{ "url": "/files/documento.pdf", "creation": "2025-01-14 09:43:55.12893", "file_name": "documento.pdf", "file_size": 120394 }

❗ Posibles Errores

1. Error al procesar el archivo

{ "msn": "Failed to open stream..." }

2. Error en cURL

{ "msn": "cURL Error #:Timeout..." }

3. El ERP no devuelve estructura válida

{ "msn": "Error al procesar respuesta del ERP" }

📚 Estructura de respuesta del ERP

El ERP retorna algo como:

{ "message": { "file_url": "/files/image.png", "creation": "2025-01-15 10:45:00.12584", "file_name": "image.png", "file_size": 48204 } }

🗃 Lógica en pseudo-código

try: file = new CURLFile(tmp, type, name) catch error: return error send file to ERP via cURL → POST /method/upload_file if error in curl: return error parse response return { url: response.message.file_url, creation: response.message.creation, file_name: response.message.file_name, file_size: response.message.file_size }
Módulo Supervision

Actualizar terminos de supervision (1) - [updatequestion]

🧾 Descripción

Actualiza los campos (preguntas) de un documento del Doctype “Check List del Supervisor Nacional 2” dentro del ERP, permitiendo modificar dinámicamente cualquier grupo de preguntas o valores enviados desde la aplicación.

El servicio solo actualiza los campos enviados, y valida previamente que realmente existan cambios antes de ejecutar la operación.


🚀 Endpoint

POST /updatequestion


📥 Request Body

{ "questions": "{...}", "name": "CHK-LIST-0001" }

📌 Parámetros

Campo Tipo Obligatorio Descripción
questions string (JSON-stringified) ✔️ Objeto JSON con los campos a modificar.
name string ✔️ ID del documento del check list que se actualizará.

Ejemplo del campo questions:

{ "pregunta_1": "SI", "pregunta_2": "NO", "observacion": "Todo conforme" }

🔐 Seguridad

Requiere autenticación interna mediante: $this->general->ServiceErp(...)

➡️ Se usa el token y contexto configurado internamente para comunicarse con el ERP.


🧠 Flujo del Servicio (resumen real)

  1. Valida parámetros obligatorios
    Si questions o name viene vacío, retorna error de validación.

  2. Valida que existan cambios reales
    Si questions == '{}', se considera que no hubo modificación.

  3. Convierte a array el JSON recibido


    $questions = json_decode($questionsForm, true);
  4. Genera el payload a actualizar
    Todos los campos recibidos se envían directamente al ERP.

  5. Realiza la actualización mediante API ERP


    PUT resource/Check List del Supervisor Nacional 2/{name}
  6. Retorna el resultado de la operación


📤 Response 200 – Ejemplos

✅ Actualización correcta

{ "valor": true, "msn": "Actualizado Correctamente" }

⚠️ No hubo cambios enviados

{ "valor": false, "msn": "Usted no realizo ningun cambio" }

❌ Error de validación

{ "valor": false, "msn": "El campo questions es obligatorio" }

❌ Falla en el PUT

{ "valor": false, "msn": "Error al actualizar" }

❗ Posibles Errores

Error Descripción
Parámetros vacíos Si questions o name está vacío.
Sin cambios Cuando el JSON está vacío ({}).
Error en ERP Si el PUT falla por permisos, campos inexistentes o problemas del servidor.
Error inesperado Respuesta falsa o nula desde ServiceErp.

📚 Schemas (datos usados)

✔ Check List del Supervisor Nacional 2 (PUT)

Campos dinámicos según las preguntas.
Ejemplo:

{ "pregunta_1": "SI", "pregunta_2": "NO", "observacion": "Correcto" }

🗃 Lógica en pseudo-código

questionsForm = request.questions name = request.name if questionsForm empty → return error if name empty → return error if questionsForm == "{}" → return "no hizo cambios" questions = decode(questionsForm) fields = questions update = PUT /resource/Check List del Supervisor Nacional 2/{name} with fields if update fails → return error return success

Módulo Auth

Módulo Auth

Autenticacion por dos (1) - [generateCodeAuthenticator]

🧾 Descripción

Genera un código de verificación de 6 dígitos para un usuario y lo envía al servicio externo encargado del sistema de autenticación de doble factor (2FA).

Este servicio:

  1. Recibe el número de documento del usuario.

  2. Genera un código aleatorio numérico de 6 dígitos.

  3. Envía ese código al servicio https://sistema.shalomcontrol.com/api/generate_code_two_factor.

  4. Devuelve la respuesta del servicio externo.

Es usado para validar la identidad del usuario durante procesos de autenticación reforzada.


🚀 Endpoint

POST /generate-code-authenticator


📥 Request Body

{ "username": "12345678" }

Parámetros

Campo Tipo Obligatorio Descripción
username string ✔️ DNI, pasaporte o documento del usuario

🔐 Seguridad

No requiere token del ERP.
Sin embargo, el envío del código es gestionado mediante una llamada a un servicio externo con autenticación interna del cliente Piero().


🧠 Flujo del Servicio (resumen real)

  1. Valida que el request incluya username.

    • Si no existe, retorna error.

  2. Genera un código numérico aleatorio de 6 dígitos, cada uno seleccionado de "0123456789".

  3. Envía el código al servicio:


    POST https://sistema.shalomcontrol.com/api/generate_code_two_factor

    Con los parámetros:


    document = <username> code = <6-digit code>
  4. Recibe y retorna la respuesta proporcionada por el servicio externo.

  5. Si ocurre un error en la solicitud HTTP (BadResponseException), devuelve:

{ "valor": false, "msn": "Error al enviar al servicio", "msn2": "<detalle del error>" }

📤 Response 200 – Ejemplo

{ "valor": true, "msn": "Código generado y enviado correctamente", "data": { "document": "12345678", "success": true } }

(La estructura exacta depende del servicio externo sistema.shalomcontrol.com.)


❗ Posibles Errores

1. Falta el número de documento

{ "valor": false, "msn": "Enviar numero de documento" }

2. Error del servicio externo

{ "valor": false, "msn": "Error al enviar al servicio", "msn2": "<mensaje del servidor externo>" }

3. Error inesperado (validación interna)

{ "valor": false, "msn": "Error inesperado" }

📚 Código que genera el servicio (resumen simplificado)

if(!$document) return error; code = random_numeric(6); POST https://sistema.shalomcontrol.com/api/generate_code_two_factor { document: <username>, code: <6-digit code> } return response_from_service;