enterprise/service/staff_salary.go

232 lines
7.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
butil "enterprise/base/util"
"enterprise/common/dao"
"enterprise/common/model"
"enterprise/common/registry"
log "github.com/sirupsen/logrus"
"github.com/smbrave/goutil"
"github.com/spf13/cast"
"math"
"strings"
"time"
)
type StaffSalary struct {
user *model.StaffUser
}
func NewStaffSalary(user *model.StaffUser) *StaffSalary {
return &StaffSalary{
user: user,
}
}
func (s *StaffSalary) CalcSalary(salary *model.StaffSalary, month string) (*model.StaffSalary, error) {
corp, err := dao.NewCorpDao().Get(s.user.CorpId)
if err != nil {
return nil, err
}
userSalary := s.user.GetSalary()
userConfig := s.user.GetConfig()
corpConfig := corp.GetConfig()
if userSalary.Base == "" && userSalary.Target == "" {
return nil, nil
}
if salary == nil {
salary = new(model.StaffSalary)
salary.Month = month
salary.CorpId = s.user.CorpId
salary.UserId = s.user.Id
salary.UserName = s.user.Username
}
entryTime, _ := time.ParseInLocation("2006-01-02", s.user.EntryDate, time.Local)
leaveTime, _ := time.ParseInLocation("2006-01-02", s.user.LeaveDate, time.Local)
isEntryMonth := goutil.If(cast.ToInt(entryTime.Format("200601")) == cast.ToInt(month), true, false)
isLeaveMonth := goutil.If(cast.ToInt(leaveTime.Format("200601")) == cast.ToInt(month), true, false)
//社保和公积金
salary.SocialDeduct = 0
salary.HouseDeduct = 0
if isEntryMonth { //入职月不买社保
salary.SocialDeduct = 0
salary.HouseDeduct = 0
}
salary.ShouldDay = int(s.getTotalWorkDay(s.user.CorpId, s.user.Username, month))
// 入职月或离职月以大多数人的出勤天数为准
if isEntryMonth || isLeaveMonth {
salary.ShouldDay = int(s.getTotalWorkDayMax(s.user.CorpId, month))
}
holiday, surplusHoliday := s.getRealVacationDay(month)
realWorkDays := s.getRealWorkDay(month)
approvalCheckinDay := s.getApprovalCheckinDay(s.user.CorpId, s.user.Username, month)
salary.HolidayDay = holiday
salary.AttendDay = realWorkDays + surplusHoliday
salary.Salary = cast.ToFloat64(userSalary.Base) + cast.ToFloat64(userSalary.Target)
salary.SocialDeduct = goutil.If(userConfig.SocialDeduct != "", cast.ToFloat64(userConfig.SocialDeduct), cast.ToFloat64(corpConfig.SocialDeduct))
salary.HouseDeduct = goutil.If(userConfig.HouseDeduct != "", cast.ToFloat64(userConfig.HouseDeduct), cast.ToFloat64(corpConfig.HouseDeduct))
extra := make(map[string]interface{})
extra["approvalCheckinDay"] = approvalCheckinDay //展示依赖
extra["entryDate"] = s.user.EntryDate //展示排序依赖
extra["leaveDate"] = s.user.LeaveDate //展示排序依赖
extra["baseSalary"] = userSalary.Base
extra["targetSalary"] = userSalary.Target
salary.Extra = goutil.EncodeJSONIndent(extra)
calculator := registry.NewSalaryCalculator(corp, s.user)
if calculator != nil {
calculator.Calculate(salary)
}
s.formatFloat(salary)
return salary, nil
}
func (s *StaffSalary) formatFloat(salary *model.StaffSalary) {
salary.AwardSalary = butil.FloatCut(salary.AwardSalary)
salary.AttendSalary = butil.FloatCut(salary.AttendSalary)
salary.TargetSalary = butil.FloatCut(salary.TargetSalary)
salary.OtherSalary = butil.FloatCut(salary.OtherSalary)
salary.AttendDay = butil.FloatCut(salary.AttendDay)
salary.HolidayDay = butil.FloatCut(salary.HolidayDay)
}
func (s *StaffSalary) getRealVacationDay(month string) (float64, float64) {
// 休假申请
approveVacations, err := dao.NewApprovalVacationDao().GetByUsername(s.user.CorpId, s.user.Username, month, "")
if err != nil {
log.Errorf("db error :%s", err.Error())
return 0, 0
}
holiday := float64(0)
surplusHoliday := float64(0)
for _, vac := range approveVacations {
startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", vac.VacationStartTime, time.Local)
endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", vac.VacationEndTime, time.Local)
//同一天请假时长大于8小时算一天
if startTime.Format("2006-01-02") == endTime.Format("2006-01-02") && vac.VacationDuration > 1 {
holiday += 1
} else {
holiday += vac.VacationDuration
//不是整天数,把剩余的算上
span := vac.VacationDuration - math.Floor(vac.VacationDuration)
surplusHoliday += goutil.If(math.Abs(span) < 0.000001, 0, 1-span)
}
}
return holiday, surplusHoliday
}
func (s *StaffSalary) getApprovalCheckinDay(corpId int64, username, month string) int {
approvalDay := int(0)
userCheckins, err := dao.NewCheckinDao().Query(corpId, username, month, false)
if err != nil {
log.Errorf("db error :%s", err.Error())
return approvalDay
}
for _, checkin := range userCheckins {
approvalCheckin, _ := dao.NewApprovalCheckinDao().GetByUsernameDay(corpId, username, checkin.Day)
if approvalCheckin != nil {
approvalDay += 1
}
}
return approvalDay
}
func (s *StaffSalary) getRealWorkDay(month string) float64 {
realWorkdays := float64(0)
userCheckins, err := dao.NewCheckinDao().Query(s.user.CorpId, s.user.Username, month, false)
if err != nil {
log.Errorf("db error :%s", err.Error())
return realWorkdays
}
approvalCheckinDay := 0
//入职当天算工作日
entryTime, _ := time.ParseInLocation("2006-01-02", s.user.EntryDate, time.Local)
if entryTime.Format("200601") == month {
realWorkdays += 1
}
//离职当天算工作日
leaveTime, _ := time.ParseInLocation("2006-01-02", s.user.LeaveDate, time.Local)
if leaveTime.Format("200601") == month {
realWorkdays += 1
}
for _, checkin := range userCheckins {
//入职离职当天已经算过了
if entryTime.Format("2006-01-02") == checkin.Day || leaveTime.Format("2006-01-02") == checkin.Day {
continue
}
if checkin.Exception == "" {
realWorkdays += 1
continue
}
//有请假申请的不算出勤
approvalVacation, _ := dao.NewApprovalVacationDao().GetByUsernameDay(s.user.CorpId, s.user.Username, checkin.Day)
if approvalVacation != nil {
continue
}
//有补卡申请就直接算出勤
approvalCheckin, _ := dao.NewApprovalCheckinDao().GetByUsernameDay(s.user.CorpId, s.user.Username, checkin.Day)
if approvalCheckin != nil {
realWorkdays += 1
approvalCheckinDay += 1
continue
}
// 迟到的按时间折算
if strings.Contains(checkin.Exception, "上班打卡:时间异常") {
stTime := time.Unix(checkin.StartTime, 0)
later := float64(stTime.Hour() - 8) //迟到小时数从9点算
if later > 8 {
later = 8
}
realWorkdays += (8 - later) / 8
continue
}
}
return realWorkdays
}
func (s *StaffSalary) getTotalWorkDay(corpId int64, username, month string) int64 {
checkins, _ := dao.NewCheckinDao().Query(corpId, username, month, false)
return int64(len(checkins))
}
func (s *StaffSalary) getTotalWorkDayMax(corpId int64, month string) int64 {
// 最多人数的应出勤天数 为真正的出勤天数
userCounts, err := dao.NewCheckinDao().CountUsername(corpId, month)
if err != nil {
log.Errorf("db error :%s", err.Error())
return 0
}
mp := make(map[int64]int)
totalDays := int64(0)
for _, uc := range userCounts {
mp[uc.Count] += 1
}
minCount := 0
for k, v := range mp {
if v > minCount {
minCount = v
totalDays = k
}
}
return totalDays
}