feat: add attendance APIs
This commit is contained in:
@@ -2125,6 +2125,102 @@ func (organizationMapper) Search(tenantID types.TenantID, uid types.Uid, queryTe
|
||||
return tenantAdp.TenantOrganizationSearch(tenantID, uid, strings.TrimSpace(queryText), strings.TrimSpace(resultTypes), strings.TrimSpace(cursor), limit)
|
||||
}
|
||||
|
||||
type AttendancePersistenceInterface interface {
|
||||
Config(tenantID types.TenantID, uid types.Uid, date time.Time) (*types.AttendanceConfig, error)
|
||||
ListRecords(tenantID types.TenantID, uid types.Uid, opts types.AttendanceRecordListOptions) ([]types.AttendanceRecord, string, *types.AttendanceRecordStats, error)
|
||||
Checkin(tenantID types.TenantID, uid types.Uid, checkinID string, req types.AttendanceCheckinRequest) (*types.AttendanceRecord, *types.AttendanceCheckin, error)
|
||||
CreateAppeal(tenantID types.TenantID, uid types.Uid, appeal *types.AttendanceAppeal, idempotencyKey string) (*types.AttendanceAppeal, error)
|
||||
ListAppeals(tenantID types.TenantID, uid types.Uid, opts types.AttendanceAppealListOptions) ([]types.AttendanceAppeal, string, error)
|
||||
}
|
||||
|
||||
type attendanceMapper struct{}
|
||||
|
||||
var Attendance AttendancePersistenceInterface
|
||||
|
||||
func (attendanceMapper) Config(tenantID types.TenantID, uid types.Uid, date time.Time) (*types.AttendanceConfig, error) {
|
||||
if uid.IsZero() || date.IsZero() {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantAttendanceConfig(tenantID, uid, date)
|
||||
}
|
||||
|
||||
func (attendanceMapper) ListRecords(tenantID types.TenantID, uid types.Uid, opts types.AttendanceRecordListOptions) ([]types.AttendanceRecord, string, *types.AttendanceRecordStats, error) {
|
||||
if uid.IsZero() {
|
||||
return nil, "", nil, types.ErrMalformed
|
||||
}
|
||||
if opts.Limit <= 0 || opts.Limit > 100 {
|
||||
opts.Limit = 50
|
||||
}
|
||||
opts.Scope = strings.TrimSpace(opts.Scope)
|
||||
if opts.Scope == "" {
|
||||
opts.Scope = "mine"
|
||||
}
|
||||
if opts.Scope != "mine" && opts.Scope != "managed" {
|
||||
return nil, "", nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
return tenantAdp.TenantAttendanceRecordList(tenantID, uid, opts)
|
||||
}
|
||||
|
||||
func (attendanceMapper) Checkin(tenantID types.TenantID, uid types.Uid, checkinID string, req types.AttendanceCheckinRequest) (*types.AttendanceRecord, *types.AttendanceCheckin, error) {
|
||||
if uid.IsZero() || strings.TrimSpace(checkinID) == "" || req.Date.IsZero() || req.ClientTime.IsZero() || !validAttendanceAction(req.Action) {
|
||||
return nil, nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return tenantAdp.TenantAttendanceCheckin(tenantID, uid, strings.TrimSpace(checkinID), req)
|
||||
}
|
||||
|
||||
func (attendanceMapper) CreateAppeal(tenantID types.TenantID, uid types.Uid, appeal *types.AttendanceAppeal, idempotencyKey string) (*types.AttendanceAppeal, error) {
|
||||
if uid.IsZero() || appeal == nil || strings.TrimSpace(appeal.AppealID) == "" || strings.TrimSpace(appeal.RecordID) == "" || strings.TrimSpace(appeal.Reason) == "" {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantAttendanceAppealCreate(tenantID, uid, appeal, strings.TrimSpace(idempotencyKey))
|
||||
}
|
||||
|
||||
func (attendanceMapper) ListAppeals(tenantID types.TenantID, uid types.Uid, opts types.AttendanceAppealListOptions) ([]types.AttendanceAppeal, string, error) {
|
||||
if uid.IsZero() {
|
||||
return nil, "", types.ErrMalformed
|
||||
}
|
||||
if opts.Limit <= 0 || opts.Limit > 100 {
|
||||
opts.Limit = 50
|
||||
}
|
||||
opts.Scope = strings.TrimSpace(opts.Scope)
|
||||
if opts.Scope == "" {
|
||||
opts.Scope = "mine"
|
||||
}
|
||||
if opts.Scope != "mine" && opts.Scope != "managed" {
|
||||
return nil, "", types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return tenantAdp.TenantAttendanceAppealList(tenantID, uid, opts)
|
||||
}
|
||||
|
||||
func validAttendanceAction(action string) bool {
|
||||
switch strings.TrimSpace(action) {
|
||||
case types.AttendanceActionCheckIn, types.AttendanceActionCheckOut:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type MeetingsPersistenceInterface interface {
|
||||
Create(tenantID types.TenantID, uid types.Uid, meeting *types.Meeting, attendeeIDs []types.Uid) (*types.Meeting, error)
|
||||
List(tenantID types.TenantID, uid types.Uid, cursor string, limit int) ([]types.Meeting, string, error)
|
||||
@@ -4490,6 +4586,7 @@ func init() {
|
||||
GroupBusiness = groupBusinessMapper{}
|
||||
Workbench = workbenchMapper{}
|
||||
Organization = organizationMapper{}
|
||||
Attendance = attendanceMapper{}
|
||||
Meetings = meetingsMapper{}
|
||||
DailyReports = dailyReportsMapper{}
|
||||
MonthlyReports = monthlyReportsMapper{}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
package types
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
AttendanceActionCheckIn = "check_in"
|
||||
AttendanceActionCheckOut = "check_out"
|
||||
|
||||
AttendanceStatusNotChecked = "not_checked"
|
||||
AttendanceStatusCheckedIn = "checked_in"
|
||||
AttendanceStatusNormal = "normal"
|
||||
AttendanceStatusLate = "late"
|
||||
AttendanceStatusEarlyLeave = "early_leave"
|
||||
AttendanceStatusAbnormal = "abnormal"
|
||||
|
||||
AttendanceCheckinNormal = "normal"
|
||||
AttendanceCheckinLate = "late"
|
||||
AttendanceCheckinEarlyLeave = "early_leave"
|
||||
AttendanceCheckinOutsideRange = "outside_range"
|
||||
|
||||
AttendanceAppealPending = "pending"
|
||||
AttendanceAppealApproved = "approved"
|
||||
AttendanceAppealRejected = "rejected"
|
||||
AttendanceAppealCanceled = "canceled"
|
||||
)
|
||||
|
||||
type AttendanceRule struct {
|
||||
ID int64
|
||||
RuleID string
|
||||
Name string
|
||||
Workday bool
|
||||
LocationRequired bool
|
||||
WifiRequired bool
|
||||
AllowOutsideCheckin bool
|
||||
AppealAllowed bool
|
||||
AppealDeadline *time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type AttendanceShift struct {
|
||||
ID int64
|
||||
ShiftID string
|
||||
RuleID string
|
||||
Name string
|
||||
WorkStart string
|
||||
WorkEnd string
|
||||
CheckinStart string
|
||||
CheckoutEnd string
|
||||
SortOrder int
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type AttendanceCheckin struct {
|
||||
ID int64
|
||||
CheckinID string
|
||||
RecordID string
|
||||
UserID Uid
|
||||
Date time.Time
|
||||
Action string
|
||||
RuleID string
|
||||
ShiftID string
|
||||
ClientTime time.Time
|
||||
ServerTime time.Time
|
||||
Result string
|
||||
Location KVMap
|
||||
Wifi KVMap
|
||||
Device KVMap
|
||||
IdempotencyKey string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type AttendanceRecord struct {
|
||||
ID int64
|
||||
RecordID string
|
||||
UserID Uid
|
||||
Date time.Time
|
||||
RuleID string
|
||||
ShiftID string
|
||||
Status string
|
||||
Checkins []AttendanceCheckin
|
||||
Exceptions []string
|
||||
AppealStatus string
|
||||
Version int
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type AttendanceConfig struct {
|
||||
Date time.Time
|
||||
Timezone string
|
||||
Rule AttendanceRule
|
||||
Shifts []AttendanceShift
|
||||
AllowedActions []string
|
||||
TodayRecord *AttendanceRecord
|
||||
CanViewManaged bool
|
||||
}
|
||||
|
||||
type AttendanceRecordListOptions struct {
|
||||
Scope string
|
||||
From string
|
||||
To string
|
||||
Date string
|
||||
Status string
|
||||
DepartmentID string
|
||||
UserID string
|
||||
Cursor string
|
||||
Limit int
|
||||
}
|
||||
|
||||
type AttendanceRecordStats struct {
|
||||
ExpectedCount int
|
||||
CheckedCount int
|
||||
ExceptionCount int
|
||||
NotCheckedCount int
|
||||
}
|
||||
|
||||
type AttendanceCheckinRequest struct {
|
||||
Date time.Time
|
||||
Action string
|
||||
RuleID string
|
||||
ShiftID string
|
||||
ClientTime time.Time
|
||||
Location KVMap
|
||||
Wifi KVMap
|
||||
Device KVMap
|
||||
IdempotencyKey string
|
||||
}
|
||||
|
||||
type AttendanceAppeal struct {
|
||||
ID int64
|
||||
AppealID string
|
||||
RecordID string
|
||||
UserID Uid
|
||||
AppealType string
|
||||
Reason string
|
||||
TargetAction string
|
||||
TargetTime *time.Time
|
||||
AttachmentFileIDs []string
|
||||
Status string
|
||||
Version int
|
||||
SubmittedAt time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type AttendanceAppealListOptions struct {
|
||||
Scope string
|
||||
Status string
|
||||
Cursor string
|
||||
Limit int
|
||||
}
|
||||
Reference in New Issue
Block a user