zkteco 1.0.0

A pure-Rust client for ZKTeco biometric attendance / access-control terminals (TCP/UDP protocol). A faithful port of the Python `pyzk` library.
Documentation
//! The [`Attendance`] record returned by [`crate::Zk::get_attendance`] and live
//! capture.

use chrono::NaiveDateTime;
use std::fmt;

/// A single attendance punch read from the device.
///
/// Mirrors `pyzk`'s `Attendance`. `status` and `punch` are kept as raw integers
/// because their exact meaning varies across ZKTeco firmware/models; helper
/// accessors interpret the common cases.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Attendance {
    /// Internal device user index. Kept for compatibility; prefer [`Self::user_id`].
    pub uid: u32,
    /// The user's own ID / PIN (the value shown on the device keypad).
    pub user_id: String,
    /// When the punch happened, as reported by the device clock.
    pub timestamp: NaiveDateTime,
    /// Verification status / method code (raw device value).
    pub status: u8,
    /// Punch state code: typically 0 = check-in, 1 = check-out, etc. (raw value).
    pub punch: u8,
}

impl Attendance {
    /// Construct a record. Normally produced by the crate, but exposed for tests
    /// and callers building synthetic data.
    pub fn new(
        user_id: impl Into<String>,
        timestamp: NaiveDateTime,
        status: u8,
        punch: u8,
        uid: u32,
    ) -> Self {
        Attendance {
            uid,
            user_id: user_id.into(),
            timestamp,
            status,
            punch,
        }
    }

    /// Human-readable label for the common [`Self::punch`] codes.
    ///
    /// Codes beyond the well-known set are returned as `"punch <n>"`.
    pub fn punch_label(&self) -> String {
        match self.punch {
            0 => "check-in".into(),
            1 => "check-out".into(),
            2 => "break-out".into(),
            3 => "break-in".into(),
            4 => "overtime-in".into(),
            5 => "overtime-out".into(),
            other => format!("punch {other}"),
        }
    }
}

impl fmt::Display for Attendance {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "<Attendance>: {} : {} ({}, {})",
            self.user_id, self.timestamp, self.status, self.punch
        )
    }
}