Skip to main content

Scan Points Computation Documentation

This code provides functions to compute scan points for attendance summaries. It processes scan logs and applies rules to determine check-in, check-out, and break times.

Constants

const (
SCAN_CHECK_IN ScanPointEvent = "CheckIn"
SCAN_CHECK_OUT ScanPointEvent = "CheckOut"
SCAN_BREAK ScanPointEvent = "Break"
SCAN_BREAK_IN ScanPointEvent = "BreakIn-" // always have index, even though only 1 break
SCAN_BREAK_OUT ScanPointEvent = "BreakOut-" // always have index, even though only 1 break
)

const (
DEFAULT_TRESHOLD float64 = 120 // not used
DEFAULT_NO_INDEX int = -1
DEFAULT_TRESHOLD_MULTIPLIER float64 = 0.75
MINIMUM_TRESHOLD float64 = 45
MAX_FLOAT float64 = 1500 // for function findMinimum, we need to start with large number. 1500 minutes is already sufficient, it's more than 24 hours
TRESHOLD_COUNT_EQUAL bool = true // if this is not true then all checking about threshold is < or > instead of <= and >=
SCAN_POINT_FULL_SCORE int = 1000 // just for scoring

SUMMARY_NO_SCHEDULE = "NoSchedule"
SUMMARY_NO_SHIFT = "NoShift"
SUMMARY_CANNOT_COMPUTE = "CannotCompute"
SUMMARY_INCOMPLETE = "Incomplete" // incomplete scans

SUMMARY_DAY_NO_WORK = "NoWork"
SUMMARY_DAY_WORK = "Work"
)

ScanPointStruct struct

type ScanPointStruct struct {
ScanDateTime time.Time
Treshold float64 // depends on the duration of CI-CO * DEFAULT_TRESHOLD_MULTIPLIER
WinnerLogID string // Don't need this, can get it from WinnerLogPtr.Id
WinnerRuleID string
WinnerLogPtr *entity.AttendanceLogTable // if winner, then this is the log address (from global &AllScanLogs[ID])
UseThisTime time.Time // from Winner or overwrite , can be different from WinnerLogPtr.TimeStamp
WinnerLogDistance float64
WinnerFromLogs bool
WinnerFromRule bool
WinnerFromOverwrite bool
}
  • ScanDateTime time.Time: The date and time of the scan point.
  • Treshold float64: The threshold for matching scan logs.
  • WinnerLogID string: The ID of the winning scan log.
  • WinnerRuleID string: The ID of the winning rule.
  • WinnerLogPtr *entity.AttendanceLogTable: Pointer to the winning scan log.
  • UseThisTime time.Time: The time to use for this scan point.
  • WinnerLogDistance float64: The distance of the winning scan log.
  • WinnerFromLogs bool: Indicates if the winner is from scan logs.
  • WinnerFromRule bool: Indicates if the winner is from a rule.
  • WinnerFromOverwrite bool: Indicates if the winner is from an overwrite.

Functions

GetScanPointsFromShift

func GetScanPointsFromShift(iShift *entity.ShiftTable, calcDate string, cache *caching.AllCacheStruct) (ScanPointMap, []ScanPointEvent)

Generates scan points from a shift for a given calculation date.

  • iShift *entity.ShiftTable: The shift table.
  • calcDate string: The calculation date in yyyy-mm-dd format.
  • cache *caching.AllCacheStruct: The cache structure.

Returns a map of scan points and an order of scan point events.

GetTresholdFromIntDuration

func GetTresholdFromIntDuration(dur float64, cache *caching.AllCacheStruct) float64

Calculates the threshold duration in minutes with checks on MINIMUM_TRESHOLD.

  • dur float64: The duration in minutes.
  • cache *caching.AllCacheStruct: The cache structure.

Returns the threshold duration.

FindMinimumAbsolute

func FindMinimumAbsolute(scanLogs []*entity.AttendanceLogTable, eventIdx string) (*entity.AttendanceLogTable, int)

Finds the minimum absolute distance for an event index.

  • scanLogs []*entity.AttendanceLogTable: The scan logs.
  • eventIdx string: The event index.

Returns a pointer to the minimum scan log and its index.

ScanLogsHasDate

func ScanLogsHasDate(calcDate string, scanLogs []*entity.AttendanceLogTable, summary *AttendanceSummariesCompute) bool

Checks if the scan logs contain the calculation date.

  • calcDate string: The calculation date in yyyy-mm-dd format.
  • scanLogs []*entity.AttendanceLogTable: The scan logs.
  • summary *AttendanceSummariesCompute: The attendance summary.

Returns true if the scan logs contain the date, otherwise false.

GetScanPointCandidateFromScanLogs

func GetScanPointCandidateFromScanLogs(scanpoints ScanPointMap, scanLogs []*entity.AttendanceLogTable, order []ScanPointEvent)

Gets candidates of scan logs for each scan point.

  • scanpoints ScanPointMap: The scan points.
  • scanLogs []*entity.AttendanceLogTable: The scan logs.
  • order []ScanPointEvent: The order of scan point events.

ResetScanLogsUsed

func ResetScanLogsUsed(scanLogs []*entity.AttendanceLogTable)

Resets the Used and UsedAs fields of the scan logs.

  • scanLogs []*entity.AttendanceLogTable: The scan logs.

CheckScanPointComplete

func (scanpoints ScanPointMap) CheckScanPointComplete() (bool, []ScanPointEvent)

Checks if the scan points are complete.

  • scanpoints ScanPointMap: The scan points.

Returns true if the scan points are complete, otherwise false, and a list of incomplete scan point events.

GetAllDistancesFromCandidates

func (s ScanPointMap) GetAllDistancesFromCandidates() float64

Gets the total distance from all scan point candidates.

  • s ScanPointMap: The scan points.

Returns the total distance.

Example Usage

package main

import (
"fio-backend/entity"
"fio-backend/utils/caching"
"fio-backend/utils/compute"
"fmt"
"time"
)

func main() {
// Create a sample shift table
shift := &entity.ShiftTable{
StartTime: "08:00:00",
EndTime: "17:00:00",
ShiftBreaks: []entity.ShiftBreakTable{
{
OrderNum: 1,
BreakID: "break_id_1",
Break: entity.BreakTable{
StartTime: "12:00:00",
EndTime: "12:30:00",
DurationMinutes: 30,
},
},
},
}

// Create a sample cache
cache := &caching.AllCacheStruct{
Summaries: &caching.LocalSummaries{
Threshold: 0.75,
},
}

// Get scan points from shift
calcDate := "2024-05-01"
scanPoints, order := compute.GetScanPointsFromShift(shift, calcDate, cache)

// Print the scan points
for event, sp := range scanPoints {
fmt.Printf("Event: %s, ScanPoint: %+v\n", event, sp)
}

// Create sample scan logs
scanLogs := []*entity.AttendanceLogTable{
{
Id: "log_id_1",
UserProfileID: "user_id_123",
Timestamp: "2024-05-01T08:00:00Z",
},
{
Id: "log_id_2",
UserProfileID: "user_id_123",
Timestamp: "2024-05-01T17:00:00Z",
},
{
Id: "log_id_3",
UserProfileID: "user_id_123",
Timestamp: "2024-05-01T12:00:00Z",
},
{
Id: "log_id_4",
UserProfileID: "user_id_123",
Timestamp: "2024-05-01T12:30:00Z",
},
}

// Get scan point candidates from scan logs
compute.GetScanPointCandidateFromScanLogs(scanPoints, scanLogs, order)

// Print the updated scan points
for event, sp := range scanPoints {
fmt.Printf("Event: %s, ScanPoint: %+v\n", event, sp)
}

// Check if scan points are complete
complete, incomplete := scanPoints.CheckScanPointComplete()
fmt.Printf("Complete: %v, Incomplete: %+v\n", complete, incomplete)
}

Improvements and Considerations

  • Error Handling: Improve error handling by returning errors instead of just logging them.
  • Code Clarity and Comments: Improve code comments to explain complex logic more clearly.
  • Unit Tests: Add unit tests to ensure the functions work correctly with various inputs and edge cases.
  • Performance Optimization: Optimize the functions for performance, especially when processing large numbers of scan logs and breaks.
  • Modularization: Break down the functions into smaller, more modular functions to improve readability and maintainability.

This comprehensive documentation provides a detailed understanding of the scan points computation functions and their functionalities. By addressing the suggested improvements, you can create a more robust and maintainable solution for calculating scan points in attendance summaries.