enterprise/worker/staff.go

329 lines
9.9 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 worker
import (
butil "enterprise/base/util"
"enterprise/common/config"
"enterprise/common/dao"
"enterprise/common/global"
"enterprise/common/model"
"fmt"
"git.u8t.cn/open/gosdk/qyweixin"
log "github.com/sirupsen/logrus"
"github.com/smbrave/goutil"
"github.com/spf13/cast"
"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
}
userConfig, err := dao.NewUserConfigDao().GetByUsername(staffSalary.Username)
if err != nil {
log.Errorf("db error :%s", err.Error())
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.AttendSalary))
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", staffSalary.GetRealSalary()))
if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil {
log.Errorf("send message error :%s", err.Error())
}
if userConfig != nil && cast.ToBool(userConfig.Get(model.StaffSalaryNotify)) == true {
if err := global.SendMessage([]string{userConfig.Username}, 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, "-", "")
maxTotalDays := s.getTotalWorkDayMax(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 {
entryTime, _ := time.ParseInLocation("2006-01-02", staff.EntryDate, time.Local)
officalTime, _ := time.ParseInLocation("2006-01-02", staff.OfficialDate, time.Local)
leaveTime, _ := time.ParseInLocation("2006-01-02", staff.LeaveDate, 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)
isLeaveMonth := goutil.If(cast.ToInt(leaveTime.Format("200601")) == cast.ToInt(month), true, false)
// 已离职的员工不处理
if staff.LeaveDate != "" && !isLeaveMonth {
continue
}
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
}
config, err := dao.NewUserConfigDao().GetByUsername(staff.Username)
if err != nil {
log.Errorf("db error :%s", err.Error())
continue
}
if config == nil {
log.Errorf("username[%s] not config,skip!!", staff.Username)
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 {
if isEntryMonth { //入职月不买社保
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)
}
// 打卡正常天数+补卡天数 为正常出勤天数
totalDays := s.getTotalWorkDay(staff.Username, month)
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
}
// 入职月或离职月以大多数人的出勤天数为准
if isEntryMonth || isLeaveMonth {
totalDays = maxTotalDays
}
realWorkDays = realWorkDays + surplusHoliday
attendSalary := salary.BaseSalary * (realWorkDays / float64(totalDays)) * discount
staffSalaryPerDay := cast.ToFloat64(config.Get(model.StaffSalaryPerDay))
if staffSalaryPerDay > 0 {
attendSalary = 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.AttendSalary = butil.FloatCut(attendSalary)
salary.RealSalary = salary.GetRealSalary()
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点算
if later > 8 {
later = 8
}
realWorkdays += (8 - later) / 8
continue
}
}
return realWorkdays
}
func (s *Staff) getTotalWorkDay(username, month string) int64 {
checkins, _ := dao.NewCheckinDao().Query(username, month, false)
return int64(len(checkins))
}
func (s *Staff) getTotalWorkDayMax(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
}