product_attendance_record.go 7.5 KB
package domain

import (
	"errors"
	"fmt"
	"time"

	"github.com/linmadan/egglib-go/utils/xtime"
	"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/infrastructure/utils"
	"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/log"
)

const (
	AttendanceNotApprove   = 1 // 未审核
	AttendanceApproved     = 2 // 已审核
	AttendanceAutoApproved = 3 // 自动审核
)

// 生产考勤记录
type ProductAttendanceRecord struct {
	// 考勤记录ID
	ProductAttendanceId int `json:"productAttendanceId,omitempty"`
	// 企业id
	CompanyId int `json:"companyId,omitempty"`
	// 组织ID
	OrgId int `json:"orgId,omitempty"`
	// 考勤类型 1.正常 2.支援
	AttendanceType int `json:"attendanceType,omitempty"`
	// 生产工人
	ProductWorker *User `json:"productWorker,omitempty"`
	// 工作位置
	WorkStation *WorkStation `json:"workStation,omitempty"`
	// 签到
	SignIn time.Time `json:"signIn,omitempty"`
	// 签退
	SignOut time.Time `json:"signOut,omitempty"`
	// 考勤状态 1.未审核 2:已审核 3.自动审核
	AttendanceStatus int `json:"attendanceStatus,omitempty"`
	// 工时(审核前)
	WorkTimeBefore float64 `json:"workTimeBefore,omitempty"`
	// 工时(审核后)
	WorkTimeAfter float64 `json:"workTimeAfter,omitempty"`
	// 创建时间
	CreatedAt time.Time `json:"createdAt,omitempty"`
	// 更新时间
	UpdatedAt time.Time `json:"updatedAt,omitempty"`
	// 删除时间
	DeletedAt time.Time `json:"deletedAt,omitempty"`
	// 扩展数据
	Ext *Ext `json:"ext,omitempty"`
	// 生产日期
	ProductDate time.Time `json:"productDate,omitempty"`
}

type ProductAttendanceRecordRepository interface {
	Save(productAttendanceRecord *ProductAttendanceRecord) (*ProductAttendanceRecord, error)
	Remove(productAttendanceRecord *ProductAttendanceRecord) (*ProductAttendanceRecord, error)
	FindOne(queryOptions map[string]interface{}) (*ProductAttendanceRecord, error)
	Find(queryOptions map[string]interface{}) (int64, []*ProductAttendanceRecord, error)
}

func (productAttendanceRecord *ProductAttendanceRecord) Identify() interface{} {
	if productAttendanceRecord.ProductAttendanceId == 0 {
		return nil
	}
	return productAttendanceRecord.ProductAttendanceId
}

func (productAttendanceRecord *ProductAttendanceRecord) Update(data map[string]interface{}) error {
	return nil
}

// 计算审核前工时
func (productAttendanceRecord *ProductAttendanceRecord) ComputeWorkTimeBefore(productCalendar *ProductCalendar) float64 {
	if productAttendanceRecord.SignIn.IsZero() {
		return 0
	}
	if productAttendanceRecord.SignOut.IsZero() {
		return 0
	}
	if !productAttendanceRecord.SignOut.After(productAttendanceRecord.SignIn) {
		return 0
	}
	signIn := roundTime(productAttendanceRecord.SignIn)
	signOut := roundTime(productAttendanceRecord.SignOut)
	wt := utils.Round(signOut.Sub(signIn).Hours(), 2)
	if productCalendar == nil {
		return roundWorkTime(wt)
	}
	wt = wt - productAttendanceRecord.AttendanceBreakTime(productCalendar)
	if wt < 0 {
		return 0
	}
	return roundWorkTime(wt)
}

// roundWorkTime 工时取整[0:0.167]=> 0 \ [0.167,0.667]=> 0.5 \ [0.667,1]=>1
// 10/60 = 0.167  40/60 = 0.667
func roundWorkTime(wt float64) float64 {
	i := float64(int(wt))
	f := wt - i
	if f < 0.167 {
		return i
	}
	if f >= 0.167 && f < 0.667 {
		return i + 0.5
	}
	if f >= 0.667 {
		return i + 1
	}
	return i
}

func roundTime(t time.Time) time.Time {
	hour, min, _ := t.Local().Clock()
	y, m, d := t.Local().Date()
	newTime := time.Date(y, m, d, hour, 0, 0, 0, time.Local)
	if min < 11 {
		min = 0
	} else if min >= 11 && min < 41 {
		min = 30
	} else {
		min = 60
	}
	return newTime.Add(time.Minute * time.Duration(min))
}

func (productAttendanceRecord *ProductAttendanceRecord) SetProductTimeByProductCalendar(productCalendar *ProductCalendar) error {
	now := xtime.New(productAttendanceRecord.SignIn)
	productAttendanceRecord.ProductDate = now.BeginningOfDay()
	if productCalendar == nil {
		return nil
	}
	overDay, err := productCalendar.CheckOverDay(productAttendanceRecord.SignIn)
	if err != nil {
		return nil
	}
	newNow := now.BeginningOfDay().Add(-time.Hour * 24)
	if overDay { //&& productCalendar.MatchCalendarSelected(newNow)
		productAttendanceRecord.ProductDate = newNow
	}
	return nil
}

func (productAttendanceRecord *ProductAttendanceRecord) Approve(approveUser *User, workTimeAfter float64, status int) error {
	if productAttendanceRecord.AttendanceStatus == AttendanceApproved || productAttendanceRecord.AttendanceStatus == AttendanceAutoApproved {
		return errors.New("已审核")
	}
	productAttendanceRecord.AttendanceStatus = status
	productAttendanceRecord.WorkTimeAfter = workTimeAfter
	if productAttendanceRecord.Ext != nil {
		if productAttendanceRecord.Ext.AttendanceExt == nil {
			productAttendanceRecord.Ext.AttendanceExt = &ProductAttendanceRecordExt{}
		}
		productAttendanceRecord.Ext.AttendanceExt.ApproveUserId = approveUser.UserId
		productAttendanceRecord.Ext.AttendanceExt.ApproveUserName = approveUser.UserName
		productAttendanceRecord.Ext.AttendanceExt.ApproveAt = time.Now().Unix()
	}
	return nil
}

func (productAttendanceRecord *ProductAttendanceRecord) ProductTime() time.Time {
	attendanceExt := productAttendanceRecord.Ext.AttendanceExt
	if attendanceExt != nil && !xtime.IsZero(productAttendanceRecord.ProductDate) {
		return productAttendanceRecord.ProductDate
	}
	return productAttendanceRecord.SignIn
}

func (productAttendanceRecord *ProductAttendanceRecord) GroupName() string {
	if productAttendanceRecord.Ext == nil {
		return ""
	}
	if productAttendanceRecord.Ext.AttendanceExt == nil {
		return ""
	}
	return productAttendanceRecord.Ext.AttendanceExt.GroupName
}

func (productAttendanceRecord *ProductAttendanceRecord) ApproveUser() *User {
	if productAttendanceRecord.Ext == nil {
		return nil
	}
	if productAttendanceRecord.Ext.AttendanceExt == nil {
		return nil
	}
	if productAttendanceRecord.Ext.AttendanceExt.ApproveUserId == 0 {
		return nil
	}
	return &User{
		UserId:   productAttendanceRecord.Ext.AttendanceExt.ApproveUserId,
		UserName: productAttendanceRecord.Ext.AttendanceExt.ApproveUserName,
	}
}

// 计算考勤休息时间
//
// 考勤打卡时间内有休息时间进行累计
func (productAttendanceRecord *ProductAttendanceRecord) AttendanceBreakTime(productCalendar *ProductCalendar) float64 {
	var (
		signIn  = productAttendanceRecord.SignIn
		signOut = productAttendanceRecord.SignOut
	)
	if signIn.IsZero() {
		return 0
	}
	if signOut.IsZero() {
		return 0
	}
	if productCalendar == nil {
		return 0
	}
	var bt float64
	for _, v := range productCalendar.BreakTimePeriods {
		var (
			checkSignIn, checkSignOut time.Time
		)
		checkSignIn = v.GetCheckBeginTime(signIn.Local())
		checkSignOut = v.GetCheckEndTime(signIn.Local())
		if xtime.BeforeEqual(signIn.Local(), checkSignIn) && xtime.AfterEqual(signOut.Local(), checkSignIn) {
			if xtime.AfterEqual(signOut.Local(), checkSignOut) {
				bt += v.BreakTime
			} else {
				bt += utils.Round(signOut.Local().Sub(checkSignIn).Hours(), 2)
			}
		}
		log.Logger.Debug(fmt.Sprintf("range(%v,%v)  actual(%v,%v) break_time:%v", checkSignIn, checkSignOut, signIn.Local(), signOut.Local(), bt))
	}
	if productAttendanceRecord.Ext != nil && productAttendanceRecord.Ext.AttendanceExt != nil {
		productAttendanceRecord.Ext.AttendanceExt.BreakTime = bt
	}
	return bt
}

//计算上岗到 离岗之间的工作时间,
//breakTime 休息时间(小时)
func (productAttendanceRecord *ProductAttendanceRecord) ComputeWorkTime(breakTime float64) float64 {
	signIn := roundTime(productAttendanceRecord.SignIn)
	signOut := roundTime(productAttendanceRecord.SignOut)
	wt := utils.Round(signOut.Sub(signIn).Hours()-breakTime, 2)
	return roundWorkTime(wt)
}