226 lines
6.6 KiB
Go
226 lines
6.6 KiB
Go
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
|
|
}
|