226 lines
7.0 KiB
Go
226 lines
7.0 KiB
Go
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
|
|
}
|
|
|
|
//其他按工作时长结算
|
|
if checkin.EndTime > 0 && checkin.StartTime > 0 {
|
|
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
|
|
|
|
}
|