package service import ( butil "enterprise/base/util" "enterprise/common/dao" "enterprise/common/model" "enterprise/common/registry" "github.com/robertkrimen/otto" log "github.com/sirupsen/logrus" "github.com/smbrave/goutil" "github.com/spf13/cast" "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, expr 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 cast.ToInt(userSalary.Base) == 0 && cast.ToInt(userSalary.Target) == 0 { return nil, nil } entryTime, _ := time.ParseInLocation("2006-01-02", s.user.EntryDate, time.Local) isEntryMonth := goutil.If(cast.ToInt(entryTime.Format("200601")) == cast.ToInt(month), true, false) isLeaveMonth := false //已离职的 if s.user.LeaveDate != "" { leaveTime, _ := time.ParseInLocation("2006-01-02", s.user.LeaveDate, time.Local) isLeaveMonth = goutil.If(cast.ToInt(leaveTime.Format("200601")) == cast.ToInt(month), true, false) //离职之后的不计算工资 if cast.ToInt(month) > cast.ToInt(leaveTime.Format("200601")) { return nil, nil } } //入职之前的工资不计算 if cast.ToInt(month) < cast.ToInt(entryTime.Format("200601")) { 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 salary.Status = model.StaffSalaryStatusWait } //已支付过的工资不能再计算了 if salary != nil && salary.Status == model.StaffSalaryStatusPayed { return salary, nil } //社保和公积金 salary.SocialDeduct = 0 salary.HouseDeduct = 0 if isEntryMonth { //入职月不买社保 salary.SocialDeduct = 0 salary.HouseDeduct = 0 } staffUser := NewStaffUser(s.user) staffUser.Load(month) salary.ShouldDay = int(staffUser.GetTotalWorkDay()) // 入职月或离职月以大多数人的出勤天数为准 if isEntryMonth || isLeaveMonth { salary.ShouldDay = int(s.getTotalWorkDayMax(s.user.CorpId, month)) } //当月的应出勤天数按22天算 if cast.ToInt(month) >= cast.ToInt(time.Now().Format("200601")) { salary.ShouldDay = 22 } salary.HolidayDay = staffUser.GetVacationDay() salary.AttendDay = staffUser.GetRealWorkDay() 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)) //计算工资 s.calculate(corp, salary, expr) s.formatFloat(salary) return salary, nil } func (s *StaffSalary) calculate(corp *model.Corp, salary *model.StaffSalary, expression string) { //获取业务数据 dataFactory := registry.NewSalaryCalculator(corp, s.user) var biz interface{} = nil if dataFactory != nil { biz = dataFactory.Calculate(salary) } data := s.getCalcData(salary) data["biz"] = biz salary.Extra = goutil.EncodeJSONIndent(data) salary.SetExtra("calculate", goutil.GetNowTime()) if expression == "" { //获取计算器表达式 calculator, _ := dao.NewSalaryCalculatorDao().Get(cast.ToInt64(s.user.GetSalary().Calculator)) if calculator == nil { log.Errorf("calculator[%s] is nil", s.user.GetSalary().Calculator) return } expression = calculator.Expression } //执行表达式 jsrun := otto.New() jsrun.Set("data", data) _, err := jsrun.Run(expression) //出勤工资 attendSalary, err := jsrun.Get("attend_salary") if err != nil { log.Errorf("attend_salary error :%s", err.Error()) } else { salary.AttendSalary, err = attendSalary.ToFloat() if err != nil { log.Errorf("attendSalary foloat is error:%s", err.Error()) } } //绩效工资 targetSalary, err := jsrun.Get("target_salary") if err != nil { log.Errorf("attend_salary error :%s", err.Error()) } else { salary.TargetSalary, err = targetSalary.ToFloat() if err != nil { log.Errorf("targetSalary foloat is error:%s", err.Error()) } } //奖金 awardSalary, err := jsrun.Get("award_salary") if err != nil { log.Errorf("attend_salary error :%s", err.Error()) } else { salary.AwardSalary, err = awardSalary.ToFloat() if err != nil { log.Errorf("awardSalary foloat is error:%s", err.Error()) } } } func (s *StaffSalary) getCalcData(mSalary *model.StaffSalary) map[string]interface{} { userSalary := s.user.GetSalary() userConfig := s.user.GetConfig() data := make(map[string]interface{}) user := make(map[string]interface{}) salary := make(map[string]interface{}) user["username"] = s.user.Username //账户名称 user["status"] = s.user.Status //状态 user["entryDate"] = s.user.EntryDate //入职时间 user["officalDate"] = s.user.OfficialDate //转正时间 user["leaveDate"] = s.user.LeaveDate //离职时间 user["baseSalary"] = cast.ToInt(userSalary.Base) //基本工资 user["targetSalary"] = cast.ToInt(userSalary.Target) //绩效工资 user["target"] = userConfig.PerftTarget //绩效目标 salary["month"] = mSalary.Month //工资月份 salary["shouldDay"] = mSalary.ShouldDay //应出勤天数 salary["attendDay"] = mSalary.AttendDay //实际出勤天数 salary["holidayDay"] = mSalary.HolidayDay //休假天数 data["user"] = user data["salary"] = salary return data } 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) 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 }