Skip to main content

Overview

The Attendance Record model stores location-based check-in data for employees. Records are stored in data/registros.json as a JSON array, with each entry representing a single location submission.

Schema

usuario
string
required
Username of the employee who submitted the location. Automatically set to current_user.id from the authenticated session.Source: Extracted from Flask-Login sessionExample: "empleado1"
lat
number
required
Latitude coordinate of the employee’s location at check-in time.Format: Decimal degreesRange: -90 to 90Example: 19.432608
lon
number
required
Longitude coordinate of the employee’s location at check-in time.Format: Decimal degreesRange: -180 to 180Example: -99.133209
fecha
string
required
Date of the attendance record. Automatically generated server-side when location is submitted.Format: YYYY-MM-DDExample: "2026-03-05"Generation: datetime.datetime.now().strftime("%Y-%m-%d")
hora
string
required
Time of the attendance record. Automatically generated server-side when location is submitted.Format: HH:MM:SS (24-hour format)Example: "08:15:30"Generation: datetime.datetime.now().strftime("%H:%M:%S")

JSON Structure

{
  "usuario": "empleado1",
  "lat": 19.432608,
  "lon": -99.133209,
  "fecha": "2026-03-05",
  "hora": "08:15:30"
}

Complete Example

Sample data/registros.json file with multiple records:
[
  {
    "usuario": "empleado1",
    "lat": 19.432608,
    "lon": -99.133209,
    "fecha": "2026-03-05",
    "hora": "08:15:30"
  },
  {
    "usuario": "empleado1",
    "lat": 19.432615,
    "lon": -99.133201,
    "fecha": "2026-03-05",
    "hora": "10:22:45"
  },
  {
    "usuario": "empleado1",
    "lat": 19.432601,
    "lon": -99.133215,
    "fecha": "2026-03-06",
    "hora": "08:45:12"
  }
]

Record Creation

Attendance records are created via the /update-location endpoint. Implementation (app.py:116-132):
@app.route('/update-location', methods=['POST'])
@login_required
def update_location():
    data = request.json
    registros = leer_json(REGISTROS_FILE)
    ahora = datetime.datetime.now()
    
    nuevo = {
        "usuario": current_user.id,
        "lat": data['lat'],
        "lon": data['lon'],
        "fecha": ahora.strftime("%Y-%m-%d"),
        "hora": ahora.strftime("%H:%M:%S")
    }
    registros.append(nuevo)
    guardar_json(REGISTROS_FILE, registros)
    return jsonify({"status": "OK"})

Client Provides

  • lat (number)
  • lon (number)

Server Generates

  • usuario (from session)
  • fecha (current date)
  • hora (current time)

Attendance Status

Records are evaluated for tardiness based on the hora field:
PUNTUAL
status
Record submitted at or before 08:30:00Condition: hora <= "08:30:00"Display: Shown as “PUNTUAL” in monitor dashboard and PDF reports
RETARDO
status
Record submitted after 08:30:00Condition: hora > "08:30:00"Display: Shown as “RETARDO” in monitor dashboard and PDF reports
Status evaluation logic (app.py:148-149):
hora_reg = reg.get('hora', '00:00:00')
es_retardo = hora_reg > "08:30:00"
The comparison is performed as a string comparison, which works correctly for the HH:MM:SS format.

Usage in Monitoring

The monitor dashboard uses attendance records to display:

All Attendance Records

Shows every record with computed status:
asistencia.append({
    "usuario": reg.get('usuario', 'S/N'),
    "fecha": reg.get('fecha', 'S/F'),
    "hora": hora_reg,
    "status": "RETARDO" if es_retardo else "PUNTUAL"
})

Active Users

Displays the most recent location for each user:
for u in usuarios:
    if u['username'] == 'admin': continue
    reg_user = [r for r in todos_registros if r['usuario'] == u['username']]
    if reg_user:
        activos.append(reg_user[-1])  # Last record

Today’s Absences

Identifies users without records for the current date:
hoy = datetime.datetime.now().strftime("%Y-%m-%d")
quienes_registraron_hoy = set()

for reg in todos_registros:
    if reg.get('fecha') == hoy:
        quienes_registraron_hoy.add(reg.get('usuario'))

for u in usuarios:
    if u['username'] == 'admin': continue
    if u['username'] not in quienes_registraron_hoy:
        faltantes.append(u['username'])

Usage in Reports

PDF reports include all attendance records and compute tardiness statistics:
stats = {}

for r in registros:
    hora = r.get('hora', '00:00:00')
    estado = "RETARDO" if hora > "08:30:00" else "PUNTUAL"
    
    # Display in table
    p.drawString(100, y, str(r.get('usuario', 'S/N')))
    p.drawString(200, y, str(r.get('fecha', 'S/F')))
    p.drawString(300, y, str(hora))
    p.drawString(400, y, estado)
    
    # Count tardiness
    if estado == "RETARDO":
        usr = r.get('usuario', 'S/N')
        stats[usr] = stats.get(usr, 0) + 1
The summary section shows total tardiness per user:
RESUMEN TOTAL DE RETARDOS ACUMULADOS:
• empleado1: 3 retardos.
• empleado2: 1 retardos.

Multiple Records Per Day

The system allows multiple location submissions per day:
  • Each submission creates a new record
  • No deduplication or updating of existing records
  • All records are preserved in chronological order
  • The monitor dashboard shows all records, not just the first of the day
This enables tracking employee movement throughout the workday.

Data Persistence

Records are stored using JSON file operations:
def leer_json(archivo):
    try:
        if not os.path.exists(archivo) or os.stat(archivo).st_size == 0:
            return []
        with open(archivo, 'r') as f:
            return json.load(f)
    except (json.decoder.JSONDecodeError, FileNotFoundError):
        return []

def guardar_json(archivo, datos):
    with open(archivo, 'w') as f:
        json.dump(datos, f, indent=4)
The file is:
  • Created empty on first run (app.py:37-39)
  • Read entirely into memory for each operation
  • Written entirely back to disk after modifications
  • Formatted with 4-space indentation for readability

Coordinate Precision

The system accepts and stores coordinate values with arbitrary precision:
  • No rounding or truncation applied
  • Stored as JSON numbers (float)
  • Standard GPS coordinates have ~7 decimal places (~11mm precision)
Example high-precision coordinates:
{
  "lat": 19.4326080123456,
  "lon": -99.1332091234567,
  "fecha": "2026-03-05",
  "hora": "08:15:30"
}

Build docs developers (and LLMs) love