Files
autoficher/README.md
omar 365f676a1f feat: comando /proximos con la prevision de los proximos dias
Muestra que dias se fichara y cuales no (festivo, vacaciones, override o
ausencia de Google Calendar), con el saldo acumulado al final.

Para los dias futuros no se inventa una hora exacta: el instante se sortea esa
madrugada y la costumbre deriva de un dia al siguiente, asi que se muestra el
RANGO en que caera cada fichaje, que si es exacto. Para hoy se muestra el plan
real con su estado.

De paso, nombres de dia en castellano en /hoy y /proximos: dependian del locale
del sistema y salian en ingles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-24 18:57:48 +02:00

4.3 KiB
Raw Blame History

Autoficher para Timenet

Ficha y desficha automáticamente en Timenet, controlado desde Telegram.

Cómo calcula Timenet (y por qué importa)

Verificado sobre 6 meses de historial (104 días laborables, 376 fichajes):

trabajado = Σ  min(salida, fin_teórico) − max(entrada, inicio_teórico)

Timenet recorta a la ventana teórica. La API guarda dos horas por fichaje: HR (la que fichaste) y H (la que te cuentan). De 376 fichajes, 136 llevaban ajuste: todos salidas, todos recortados hacia atrás. Ninguna entrada ajustada jamás.

Consecuencias, y son todo el diseño de este programa:

  • Sólo importan las entradas. Llegar tarde se debita al minuto; salir tarde no acredita nada. Por eso las entradas se fichan antes de la hora y las salidas después.
  • Acabar el mes en positivo es imposible. 0 días con saldo positivo en 108, y timeExtraHours: false en todos los tipos de jornada. El objetivo es 0 clavado.
  • El calendario laboral (festivos, vacaciones, horarios) lo da cp/calendar. No hay que adivinarlo. Google Calendar queda sólo para ausencias personales.

Servicio (recomendado)

pip install -r requirements.txt          # requiere python-telegram-bot >= 22
cp sample.config.json config.json        # y edítalo
echo "TIMENET_PIN=1234" > .env && chmod 600 .env

cp deploy/autoficher.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now autoficher.service
sudo loginctl enable-linger $USER        # para que sobreviva al logout y al reinicio
systemctl --user status autoficher        # estado
journalctl --user -u autoficher -f        # logs en vivo
systemctl --user restart autoficher       # recargar tras tocar config

Comandos de Telegram

Se registran solos en el menú del chat al arrancar.

comando qué hace
/hoy plan y estado de hoy, con lo que Timenet ha registrado de verdad
/saldo saldo del mes y acumulado
/plan plan de hoy, con botón para re-tirar los dados
/proximos [n] previsión de los próximos días laborables y sus rangos
/fichar /desfichar fichaje manual inmediato
/off [hoy|dd/mm|dd/mm-dd/mm] no fichar esos días
/on [fecha] volver a fichar ese día
/pausa /reanudar parar o retomar el servicio
/log últimos eventos

Doce minutos antes de cada fichaje llega un aviso con killswitch:

⏳ ENTRADA programada a las 08:59:22 (en 12 min)
[🛑 Cancelar hoy]  [⏭ +15 min]  [✅ Fichar ya]

El bot sólo atiende al chat_id de config.json; cualquier otro chat se ignora.

Configuración

Lo esencial va en config.json (ver sample.config.json). Los valores por defecto del jitter están en app/settings.py:

perfil entry_before / exit_after (s) presencia extra colchón mínimo
holgado 40-150 / 30-130 5,67 min/día 30 s
equilibrado (por defecto) 30-100 / 20-70 3,55 min/día 20 s
ajustado 20-70 / 15-45 2,70 min/día 15 s

Los tres dan saldo 0; cambia cuánta presencia real cuestan y cuánto retraso del daemon aguantan antes de perder un minuto.

geo_jitter_meters desplaza la posición dentro de un disco de ese radio. Sin él, las coordenadas salen idénticas al sexto decimal en todos los fichajes.

Herramientas

./venv/bin/python3 tools/tn_inspect.py     # calendario y saldo, contra la API real
./venv/bin/python3 tools/dryrun.py         # simula el año y verifica que no pierde minutos
./venv/bin/python3 tools/test_daemon.py    # 19 pruebas con reloj simulado, sin red

Modo antiguo (CLI de un disparo)

main.py sigue funcionando para fichajes puntuales desde consola o cron:

python3 main.py -p <pin> [-t <0=Entrada, 1=Salida> | -bt] [-f] [-d]

No aplica la corrección del sesgo ni consulta el calendario de Timenet: pierde de 3 a 5 minutos al día. Úsalo sólo como respaldo manual.

Google Calendar

Para ausencias personales. Descarga el OAuth de la API de Google y déjalo en la raíz como googleoauth_grant.json; el token se guarda en googleoauth.json. Se consulta el calendario autoficher: si un evento cubre el día, no se ficha.