package worker import ( butil "enterprise/base/util" "enterprise/common/config" "enterprise/common/dao" "enterprise/common/global" "enterprise/common/model" "fmt" log "github.com/sirupsen/logrus" "github.com/smbrave/goutil" "github.com/spf13/cast" "gitlab.batiao8.com/open/gosdk/qyweixin" "strings" "time" ) type Staff struct { } func (s *Staff) SendStaffSalaryBill(month string) { staffSalarys, err := dao.NewStaffSalaryDao().Query(month) if err != nil { log.Errorf("db error :%s", err.Error()) return } for _, staffSalary := range staffSalarys { if staffSalary.BaseSalary < 0.1 { continue } message := make([]string, 0) message = append(message, fmt.Sprintf("【工资单】[%s][%s]", staffSalary.Username, month)) message = append(message, fmt.Sprintf("基本工资:%.2f", staffSalary.BaseSalary)) message = append(message, fmt.Sprintf("出勤工资:%.2f", staffSalary.RealSalary)) if staffSalary.AwardSalary >= 0.1 { message = append(message, fmt.Sprintf("额外工资:%.2f", staffSalary.AwardSalary)) } message = append(message, fmt.Sprintf("社保扣除:%.2f", staffSalary.SocialInsurence)) message = append(message, fmt.Sprintf("个税扣除:%.2f", staffSalary.PersonalTax)) message = append(message, fmt.Sprintf("实发工资:%.2f", butil.FloatCut(staffSalary.RealSalary+staffSalary.AwardSalary-staffSalary.SocialInsurence-staffSalary.PersonalTax))) if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil { log.Errorf("send message error :%s", err.Error()) } } } func (s *Staff) SyncStaffInfo() { cfg := config.GetConfig() hrAssiant := qyweixin.NewAppHr(&qyweixin.AppConfig{ Corpid: cfg.QyWeixin.Corpid, Secret: cfg.QyWeixin.EnterpriseSecret, Agent: cfg.QyWeixin.EnterpriseAgent, }) userConfigs, err := dao.NewUserConfigDao().Query(model.UserConfigStatusNormal) if err != nil { log.Errorf("query staff db error :%s", err.Error()) return } for _, user := range userConfigs { staffInfo, err := hrAssiant.GetStaffInfo(user.Username) if err != nil { log.Errorf("getstaff info username[%s] error :%s", user.Username, err.Error()) continue } staff, err := dao.NewStaffInfoDao().GetByUsername(user.Username) if err != nil { log.Errorf("db error :%s", err.Error()) continue } if staff == nil { staff = new(model.StaffInfo) } staff.Username = staffInfo.UserName staff.Realname = staffInfo.RealName staff.Idno = staffInfo.Idno staff.StaffType = staffInfo.StaffType staff.Salary = cast.ToString(staffInfo.Salary) staff.EntryDate = staffInfo.EntryDate staff.OfficialDate = staffInfo.OfficialDate staff.BirthDate = staffInfo.BirthDate staff.BankName = staffInfo.BankName staff.BankCard = staffInfo.BankCard if staff.Id == 0 { _, err = dao.NewStaffInfoDao().Create(staff) } else { err = dao.NewStaffInfoDao().Update(staff) } if err != nil { log.Errorf("db error :%s", err.Error()) } } } func (s *Staff) SyncStaffSalary(month string) { if month == "" { month = time.Now().AddDate(0, -1, 0).Format("2006-01") } month = strings.ReplaceAll(month, "-", "") totalDays := s.getTotalWorkDay(month) monthTime, _ := time.ParseInLocation("200601", month, time.Local) startDate := cast.ToInt(monthTime.Format("20060102")) endDate := cast.ToInt(monthTime.AddDate(0, 1, -1).Format("20060102")) salaryDao := dao.NewStaffSalaryDao() staffs, err := dao.NewStaffInfoDao().Query(model.StaffInfoStatusNormal) if err != nil { log.Errorf("query staff db error :%s", err.Error()) return } for _, staff := range staffs { salary, err := salaryDao.GetBy(staff.Username, month) if err != nil { log.Errorf("db error :%s", err.Error()) continue } if salary == nil { salary = new(model.StaffSalary) salary.Month = month salary.Username = staff.Username } entryTime, _ := time.ParseInLocation("2006-01-02", staff.EntryDate, time.Local) officalTime, _ := time.ParseInLocation("2006-01-02", staff.OfficialDate, time.Local) isEntryMonth := goutil.If(cast.ToInt(entryTime.Format("200601")) == cast.ToInt(month), true, false) isOfficialMonth := goutil.If(cast.ToInt(officalTime.Format("200601")) == cast.ToInt(month), true, false) config, err := dao.NewUserConfigDao().GetByUsername(staff.Username) if err != nil { log.Errorf("db error :%s", err.Error()) continue } // 试用期折扣 discount := cast.ToFloat64(config.Get(model.StaffSalaryExpDiscount)) if discount == 0.0 { discount = 0.8 } if cast.ToInt(monthTime.Format("200601")) > cast.ToInt(officalTime.Format("200601")) { discount = 1.0 } //社保 socialInsurence := cast.ToFloat64(config.Get(model.StaffSalarySocialInsurence)) if isEntryMonth && entryTime.Day() >= 15 { socialInsurence = 0 } // 休假申请 approveVacations, err := dao.NewApprovalVacationDao().GetByUsername(staff.Username, month) if err != nil { log.Errorf("db error :%s", err.Error()) continue } holiday := float64(0) surplusHoliday := float64(0) for _, vac := range approveVacations { holiday += vac.VacationDuration surplusHoliday += goutil.If(vac.VacationDuration < 1, 1-vac.VacationDuration, 0) } // 打卡正常天数+补卡天数 为正常出勤天数 realWorkDays := s.getRealWorkDay(staff.Username, month) approvalCheckinDay := s.getApprovalCheckinDay(staff.Username, month) extra := make(map[string]interface{}) salary.BaseSalary = cast.ToFloat64(staff.Salary) salary.Holiday = holiday entryDate := cast.ToInt(strings.ReplaceAll(staff.EntryDate, "-", "")) officialDate := cast.ToInt(strings.ReplaceAll(staff.OfficialDate, "-", "")) if discount < 1.0 && isOfficialMonth { totalMonthDay := float64(endDate - startDate + 1) discount = discount*float64(officialDate-startDate)/totalMonthDay + 1*float64(endDate-officialDate+1)/totalMonthDay } realWorkDays = realWorkDays + surplusHoliday realSalary := salary.BaseSalary * (realWorkDays / float64(totalDays)) * discount staffSalaryPerDay := cast.ToFloat64(config.Get(model.StaffSalaryPerDay)) if staffSalaryPerDay > 0 { realSalary = staffSalaryPerDay * realWorkDays } extra["discount"] = discount extra["approvalCheckinDay"] = approvalCheckinDay //展示依赖 extra["socialInsurence"] = socialInsurence extra["days"] = endDate - startDate + 1 extra["startDate"] = startDate extra["totalDays"] = totalDays extra["realDays"] = realWorkDays extra["startDate"] = startDate extra["endDate"] = endDate extra["officialDate"] = officialDate extra["entryDate"] = entryDate extra["isEntryMonth"] = isEntryMonth extra["isOfficialMonth"] = isOfficialMonth extra["surplusHoliday"] = surplusHoliday salary.RealSalary = butil.FloatCut(realSalary) salary.SocialInsurence = socialInsurence salary.Holiday = holiday salary.TotalDay = float64(totalDays) salary.RealDay = realWorkDays salary.Extra = goutil.EncodeJSONIndent(extra) if salary.Id == 0 { _, err = dao.NewStaffSalaryDao().Create(salary) } else { err = dao.NewStaffSalaryDao().Update(salary) } if err != nil { log.Errorf("db error :%s", err.Error()) } } } func (s *Staff) getApprovalCheckinDay(username, month string) int { approvalDay := int(0) userCheckins, err := dao.NewCheckinDao().Query(username, month, false) if err != nil { log.Errorf("db error :%s", err.Error()) return approvalDay } for _, checkin := range userCheckins { approvalCheckin, _ := dao.NewApprovalCheckinDao().GetByUsernameDay(username, checkin.Day) if approvalCheckin != nil { approvalDay += 1 } } return approvalDay } func (s *Staff) getRealWorkDay(username, month string) float64 { realWorkdays := float64(0) userCheckins, err := dao.NewCheckinDao().Query(username, month, false) if err != nil { log.Errorf("db error :%s", err.Error()) return realWorkdays } approvalCheckinDay := 0 for _, checkin := range userCheckins { if checkin.Exception == "" { realWorkdays += 1 continue } approvalCheckin, _ := dao.NewApprovalCheckinDao().GetByUsernameDay(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点算 realWorkdays += (8 - later) / 8 continue } } return realWorkdays } func (s *Staff) getTotalWorkDay(month string) int64 { // 最多人数的应出勤天数 为真正的出勤天数 userCounts, err := dao.NewCheckinDao().CountUsername(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 }