diff --git a/cmd/enterprise.go b/cmd/enterprise.go index eede76e..db406d9 100644 --- a/cmd/enterprise.go +++ b/cmd/enterprise.go @@ -3,12 +3,11 @@ package main import ( "enterprise/common/config" "enterprise/common/global" - "enterprise/common/model" "enterprise/server" "enterprise/worker" ) -func main() { +func main22() { config.LoadServerConfig() global.InitGlobal() @@ -21,11 +20,12 @@ func main() { } } -func main22() { +func main() { config.LoadServerConfig() global.InitGlobal() //cfg := config.GetConfig() //new(worker.Checkin).SyncCheckinDay("2024-01-17") - new(worker.Approval).Sync("202401", model.ApprovalTypeRefund) + //new(worker.Approval).Sync("202401", model.ApprovalTypeRefund) + new(worker.Staff).SyncStaffSalary("202401") } diff --git a/common/dao/approval_checkin.go b/common/dao/approval_checkin.go index e0e3c27..9bcf809 100644 --- a/common/dao/approval_checkin.go +++ b/common/dao/approval_checkin.go @@ -64,3 +64,15 @@ func (d *ApprovalCheckinDao) GetBySpNo(spNo string) (*model.ApprovalCheckin, err } return &u, nil } + +func (d *ApprovalCheckinDao) GetByUsername(username, month string) ([]*model.ApprovalCheckin, error) { + var u []*model.ApprovalCheckin + tx := GetDB().Table(d.TableName()) + tx = tx.Where("month = ?", month) + tx = tx.Where("username = ?", username) + res := tx.Find(&u) + if res.Error != nil { + return nil, res.Error + } + return u, nil +} diff --git a/common/dao/approval_vacation.go b/common/dao/approval_vacation.go index c6c5f15..97a422c 100644 --- a/common/dao/approval_vacation.go +++ b/common/dao/approval_vacation.go @@ -64,3 +64,15 @@ func (d *ApprovalVacationDao) GetBySpNo(spNo string) (*model.ApprovalVacation, e } return &u, nil } + +func (d *ApprovalVacationDao) GetByUsername(username, month string) ([]*model.ApprovalVacation, error) { + var u []*model.ApprovalVacation + tx := GetDB().Table(d.TableName()) + tx = tx.Where("month = ?", month) + tx = tx.Where("username = ?", username) + res := tx.Find(&u) + if res.Error != nil { + return nil, res.Error + } + return u, nil +} diff --git a/common/dao/checkin.go b/common/dao/checkin.go index 48b3938..71adbc7 100644 --- a/common/dao/checkin.go +++ b/common/dao/checkin.go @@ -65,3 +65,34 @@ func (d *CheckinDao) GetByDay(userId, day string) (*model.Checkin, error) { } return &u, nil } + +func (d *CheckinDao) CountUsername(month string) ([]*model.UsernameCount, error) { + var userCount []*model.UsernameCount + tx := GetDB().Table(d.TableName()) + tx = tx.Where("month = ?", month) + tx.Select("username,COUNT(1) AS count") + tx.Group("username") + + tx = tx.Find(&userCount) + if tx.Error != nil { + return nil, tx.Error + } + return userCount, nil +} + +func (d *CheckinDao) GetUsernameCount(username, month string, filterException bool) (int64, error) { + tx := GetDB().Table(d.TableName()) + tx = tx.Where("month = ?", month) + tx = tx.Where("username = ?", username) + if filterException { + tx = tx.Where("exception = ''") + } + + var count int64 + tx.Select("COUNT(1) AS count").Pluck("count", &count) + + if tx.Error != nil { + return 0, tx.Error + } + return count, nil +} diff --git a/common/model/approval_checkin.go b/common/model/approval_checkin.go index afe4d98..451dfa5 100644 --- a/common/model/approval_checkin.go +++ b/common/model/approval_checkin.go @@ -20,6 +20,11 @@ func (ac *ApprovalCheckin) From(d *qyweixin.ApproveDetail) { ac.CheckinType = value[2] } +type UsernameCount struct { + Username string `json:"username"` + Count int64 `json:"count"` +} + type ApprovalCheckin struct { Id int64 Username string diff --git a/common/model/staff_salary.go b/common/model/staff_salary.go index 42452af..760c418 100644 --- a/common/model/staff_salary.go +++ b/common/model/staff_salary.go @@ -14,6 +14,8 @@ type StaffSalary struct { AwardSalary float64 SocialInsurence float64 PersonalTax float64 + TotalDay float64 + RealDay float64 Holiday float64 CreateTime int64 UpdateTime int64 diff --git a/server/service/staff_salary.go b/server/service/staff_salary.go index e878858..eaee342 100644 --- a/server/service/staff_salary.go +++ b/server/service/staff_salary.go @@ -152,7 +152,7 @@ func (s *StaffSalary) Summary(month string, ctx *gin.Context) { panic(config.ErrDb.New().Append(err)) } - header := []string{"姓名", "身份证号", "入职日期", "转正日期", "基本工资", "出勤工资", "奖金", "社保扣除", "个税扣除", "请假天数", "实发工资"} + header := []string{"姓名", "身份证号", "入职日期", "转正日期", "基本工资", "出勤工资", "奖金", "社保扣除", "个税扣除", "应出勤天数", "实际出勤天数", "请假天数", "实发工资"} datas := make([][]string, 0) summary := new(model.StaffSalary) for _, staff := range staffSalarys { @@ -175,6 +175,8 @@ func (s *StaffSalary) Summary(month string, ctx *gin.Context) { item = append(item, cast.ToString(staff.AwardSalary)) item = append(item, cast.ToString(staff.SocialInsurence)) item = append(item, cast.ToString(staff.PersonalTax)) + item = append(item, cast.ToString(staff.TotalDay)) + item = append(item, cast.ToString(staff.RealDay)) item = append(item, cast.ToString(staff.Holiday)) item = append(item, cast.ToString(butil.FloatCut(staff.RealSalary+staff.AwardSalary-staff.SocialInsurence-staff.PersonalTax))) diff --git a/worker/staff.go b/worker/staff.go index b421360..121ac32 100644 --- a/worker/staff.go +++ b/worker/staff.go @@ -100,29 +100,42 @@ func (s *Staff) SyncStaffSalary(month string) { month = time.Now().AddDate(0, -1, 0).Format("2006-01") } month = strings.ReplaceAll(month, "-", "") - //cfg := config.GetConfig() - //hrAssiant := weixin.NewQyWeixinHR(cfg.QyWeixin.Corpid, cfg.QyWeixin.HrSecret, cfg.QyWeixin.HrSecret) staffs, err := dao.NewStaffInfoDao().Query(model.StaffInfoStatusNormal) if err != nil { log.Errorf("query staff db error :%s", err.Error()) return } - holidays, err := s.loadHoliday(month) - if err != nil { - log.Errorf("loadHoliday error :%s", err.Error()) - return - } + 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() + + // 计算应出勤天数,选择最大的一个作为应出勤天数 + userCounts, err := dao.NewCheckinDao().CountUsername(month) + if err != nil { + log.Errorf("db error :%s", err.Error()) + return + } + totalDays := int64(0) + for _, uc := range userCounts { + if uc.Count > totalDays { + totalDays = uc.Count + } + } + for _, staff := range staffs { salary, err := salaryDao.GetBy(staff.Username, month) if err != nil { log.Errorf("db error :%s", err.Error()) continue } + + 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) if salary == nil { salary = new(model.StaffSalary) salary.Month = month @@ -133,72 +146,82 @@ func (s *Staff) SyncStaffSalary(month string) { 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 + } + + approveCheckins, err := dao.NewApprovalCheckinDao().GetByUsername(staff.Username, month) + if err != nil { + log.Errorf("db error :%s", err.Error()) + continue + } + + checkinCount, err := dao.NewCheckinDao().GetUsernameCount(staff.Username, month, true) + if err != nil { + log.Errorf("db error :%s", err.Error()) + continue + } + + 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) + } extra := make(map[string]interface{}) salary.BaseSalary = cast.ToFloat64(staff.Salary) - salary.Holiday = 0 + salary.Holiday = holiday entryDate := cast.ToInt(strings.ReplaceAll(staff.EntryDate, "-", "")) officialDate := cast.ToInt(strings.ReplaceAll(staff.OfficialDate, "-", "")) - isEntryMonth := false - isOfficialMonth := false - expDays := 0 - officialDays := 0 - - if entryDate/100 == startDate/100 { - isEntryMonth = true - } - if officialDate/100 == startDate/100 { - isOfficialMonth = true - } - if entryDate%100 > 15 && isEntryMonth { // 15号以后的员工不缴社保 - socialInsurence = 0 + if discount < 1.0 && isOfficialMonth { + totalMonthDay := float64(endDate - startDate + 1) + discount = discount*float64(officialDate-startDate)/totalMonthDay + 1*float64(endDate-officialDate+1)/totalMonthDay } - if isEntryMonth { - expDays = endDate - entryDate + 1 - officialDays = 0 - } else if isOfficialMonth { - expDays = officialDate - startDate + 1 - officialDays = endDate - officialDate - } else if endDate < officialDate { - expDays = endDate - startDate + 1 - officialDays = 0 - } else { - officialDays = endDate - startDate + 1 - expDays = 0 - } - holiday := butil.FloatCut(holidays[staff.Username]) - - expSalary := cast.ToFloat64(staff.Salary) * discount / float64(endDate-startDate+1) - officalSalary := cast.ToFloat64(staff.Salary) / float64(endDate-startDate+1) - realSalary := expSalary*float64(expDays) + officalSalary*float64(officialDays) - holiday*officalSalary + realWorkDays := float64(checkinCount+int64(len(approveCheckins))) + surplusHoliday + realSalary := salary.BaseSalary * (realWorkDays / float64(totalDays)) * discount extra["discount"] = discount extra["socialInsurence"] = socialInsurence - extra["expDays"] = expDays - extra["officialDays"] = officialDays - extra["expSalary"] = butil.FloatCut(expSalary) - extra["officalSalary"] = butil.FloatCut(officalSalary) extra["days"] = endDate - startDate + 1 - extra["realDays"] = expDays + officialDays + 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) @@ -211,37 +234,3 @@ func (s *Staff) SyncStaffSalary(month string) { } } - -func (s *Staff) loadHoliday(month string) (map[string]float64, error) { - cfg := config.GetConfig() - approve := qyweixin.NewAppApprove(&qyweixin.AppConfig{ - Corpid: cfg.QyWeixin.Corpid, - Secret: cfg.QyWeixin.ApproveSecret, - Agent: cfg.QyWeixin.ApproveAgent, - }) - startTime, _ := time.ParseInLocation("200601", month, time.Local) - endTime := startTime.AddDate(0, 1, 0) - spNos, err := approve.GetList(startTime.Unix(), endTime.Unix()-1, "3WLJF6naF5jhnXvwisuPmE85wVMYcy1S1ZvYibkw") - if err != nil { - log.Errorf("approve getlist error :%s", err.Error()) - return nil, err - } - result := make(map[string]float64) - for _, spNo := range spNos { - detail, err := approve.GetDetail(spNo) - if err != nil { - log.Errorf("approve GetDetail error :%s", err.Error()) - return nil, err - } - userId := detail.GetUserid() - holidayType := detail.GetValue("请假类型") - fields := strings.SplitN(holidayType, ",", 4) - hours := float64(cast.ToInt64(fields[3])) / float64(3600*8) - if v, ok := result[userId]; ok { - result[userId] = v + hours - } else { - result[userId] = hours - } - } - return result, nil -}