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.)

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" }

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" }

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" }

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

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

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)

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

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

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