Configuración y entornos — Control de Asistencia¶
Toda la configuración vive en config.ini en la raíz del proyecto. Se lee al
arrancar, por lo que cualquier cambio exige reiniciar el servicio.
Credenciales
config.ini está en .gitignore y nunca se sube al repositorio. Usa
config.example.ini como plantilla.
Secciones de config.ini¶
| Sección | Clave | Descripción |
|---|---|---|
[sync] |
interval_minutes |
Frecuencia de la corrida (default 5) |
exit_hour |
Hora local desde la que un punch cuenta como salida (17) |
|
auto_close_hour |
Hora local de cierre de asistencias abiertas (17) |
|
utc_offset_hours |
Offset UTC de la zona local (Panamá -5) |
|
exclude_zk_ids |
IDs sin empleado en ninguna instancia de Odoo | |
log_file / unmatched_log |
Rutas de log | |
[zk.<n>] |
name, ip, port, password |
Conexión al reloj |
[odoo.<n>] |
label, url, db, user, api_key |
Credenciales de la instancia |
exclude_zk_ids |
IDs inexistentes en esta instancia |
Los exclude_zk_ids se separan por espacio o coma. Para agregar otro reloj u
otra instancia de Odoo, se duplica la sección con otro sufijo.
API Key de Odoo
Sigue la guía Generar una API Key en Odoo.
La IP del reloj es DHCP — reserva pendiente
Hoy el F22 toma su IP por DHCP, así que cada vez que se reinicia puede
quedarse con una dirección distinta y romper la conexión hasta que alguien
actualice ip a mano con utils/find_zk.py y reinicie el servicio.
Lo correcto es asignarle una IP estática por reserva DHCP en el router (atando su MAC a una dirección fija). Esa configuración está pendiente — ver Troubleshooting → El reloj cambió de IP.
Ejemplo¶
[zk.principal]
name = Oficina Principal
ip = 192.168.68.121
port = 4370
password = 0
[odoo.main]
label = Produccion
url = https://<instancia>.odoo.com
db = <nombre-base-de-datos>
user = usuario@empresa.com
api_key = <api-key-de-odoo>
[sync]
interval_minutes = 5
exit_hour = 17
auto_close_hour = 17
utc_offset_hours = -5
exclude_zk_ids =
log_file = C:\ruta\al\proyecto\logs\sync.log
unmatched_log = C:\ruta\al\proyecto\logs\unmatched.log
Producción vs. staging¶
sync.py no acepta un flag --config: el destino lo determina el
config.ini activo. La estrategia es mantener un archivo por entorno y copiar el
que corresponda.
| Archivo | Uso | En git |
|---|---|---|
config.ini |
Config activa (la que usa el servicio) | No |
config.production.ini |
Credenciales de producción | No |
config.staging.ini |
Credenciales de staging | No |
config.example.ini |
Plantilla sin credenciales | Sí |
El procedimiento de cambio de entorno está en Instalar y operar el servicio de Windows.
CLI¶
python sync.py # modo servicio (scheduler)
python sync.py --dry-run # imprime el payload, no envía
python sync.py --desde 2026-05-01 # mueve watermark y arranca
python sync.py --desde 2026-05-01 --device sucursal # solo un dispositivo
--desde pide confirmación interactiva (s/n) mostrando el watermark actual y
el nuevo valor de cada dispositivo afectado.
Utilidades (utils/)¶
Todas leen del config.ini de la raíz.
| Script | Qué hace |
|---|---|
status.py |
Conectividad por dispositivo, última sync, pendientes y últimos errores |
match_report.py |
Cruza usuarios del reloj con empleados de Odoo: quién tiene zk_user_id, quién no, y qué nombres difieren |
close_open_attendances.py |
Cierra manualmente asistencias abiertas de días anteriores |
marcaciones_hoy.py |
Marcaciones del día leídas directo del reloj, sin pasar por Odoo |
delete_attendance.py |
Elimina asistencias de Odoo por empleado y fecha (--empleado, --fecha, --instancia, --dry-run) |
fix_attendance.py |
Compara Odoo contra el reloj y corrige check_in / check_out (--fix-entradas, --fix-salidas) |
find_zk.py |
Escanea la subred para localizar el reloj cuando DHCP le cambia la IP, y ofrece actualizar config.ini |
users.py |
Exporta usuarios del reloj a data/zk_users.csv |
rename_users.py |
Edita nombres de usuarios directamente en el dispositivo, de forma interactiva |
delete_users.py |
Elimina usuarios del dispositivo con backup previo en data/deleted_users_<ts>.json |
restore_users.py |
Restaura usuarios desde un backup generado por delete_users.py |
Casi todos aceptan --dry-run
Los scripts que escriben (en Odoo o en el dispositivo) soportan --dry-run
para simular sin aplicar cambios. Úsalo siempre primero.