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" "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 } corp, _ := dao.NewCorpDao().Get(s.user.CorpId) for _, checkin := range userCheckins { //入职离职当天已经算过了 if entryTime.Format("2006-01-02") == checkin.Day || leaveTime.Format("2006-01-02") == checkin.Day { continue } //有请假申请的不算出勤 approvalVacation, _ := dao.NewApprovalVacationDao().GetByUsernameDay(s.user.CorpId, s.user.Username, checkin.Day) if approvalVacation != nil { continue } if checkin.Exception == "" { realWorkdays += 1 continue } //有补卡申请就直接算出勤 approvalCheckin, _ := dao.NewApprovalCheckinDao().GetByUsernameDay(s.user.CorpId, s.user.Username, checkin.Day) if approvalCheckin != nil { realWorkdays += 1 approvalCheckinDay += 1 continue } //其他按工作时长结算 duration := float64(checkin.EndTime-checkin.StartTime) / cast.ToFloat64(corp.GetConfig().WorkerHouer) realWorkdays += goutil.If(duration > 1, 1, duration) } 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 }