This commit is contained in:
jiangyong27 2024-11-04 23:00:55 +08:00
parent 73a3e853df
commit bbc9c78499
16 changed files with 513 additions and 277 deletions

View File

@ -55,11 +55,12 @@ type WxPay struct {
} }
type Config struct { type Config struct {
Server *Server `toml:"server"` Server *Server `toml:"server"`
Mysql *Mysql `toml:"mysql"` Mysql *Mysql `toml:"mysql"`
Redis *Redis `toml:"redis"` UnifyMysql *Mysql `toml:"unify_mysql"`
QyWeixin *QyWeixin `toml:"qyweixin"` Redis *Redis `toml:"redis"`
WxPay *WxPay `toml:"wxpay"` QyWeixin *QyWeixin `toml:"qyweixin"`
WxPay *WxPay `toml:"wxpay"`
} }
func GetEnv() string { func GetEnv() string {

View File

@ -6,5 +6,7 @@ var (
) )
var ( var (
ContextParam = "context_params" ContextParam = "context_params"
SalarySocialInsurence float64 = 462.7
SalaryHouseFund float64 = 105
) )

View File

@ -3,13 +3,18 @@ package dao
import "gorm.io/gorm" import "gorm.io/gorm"
var ( var (
db *gorm.DB db *gorm.DB
unifyDB *gorm.DB
) )
func SetDB(d *gorm.DB) { func SetDB(d *gorm.DB) {
db = d db = d
} }
func SetUnifyDB(d *gorm.DB) {
unifyDB = d
}
func GetDB() *gorm.DB { func GetDB() *gorm.DB {
return db return db
} }

View File

@ -14,16 +14,16 @@ func NewUserConfigDao() *UserConfigDao {
} }
func (d *UserConfigDao) TableName() string { func (d *UserConfigDao) TableName() string {
return "user_config" return "staff_config"
} }
func (d *UserConfigDao) Create(o *model.UserConfig) (int64, error) { func (d *UserConfigDao) Create(o *model.StaffConfig) (int64, error) {
o.CreateTime = time.Now().Unix() o.CreateTime = time.Now().Unix()
res := GetDB().Table(d.TableName()).Create(o) res := GetDB().Table(d.TableName()).Create(o)
return o.Id, res.Error return o.Id, res.Error
} }
func (d *UserConfigDao) Update(o *model.UserConfig) error { func (d *UserConfigDao) Update(o *model.StaffConfig) error {
o.UpdateTime = time.Now().Unix() o.UpdateTime = time.Now().Unix()
tx := GetDB().Table(d.TableName()) tx := GetDB().Table(d.TableName())
res := tx.Save(o) res := tx.Save(o)
@ -31,12 +31,12 @@ func (d *UserConfigDao) Update(o *model.UserConfig) error {
} }
func (d *UserConfigDao) Delete(id int64) error { func (d *UserConfigDao) Delete(id int64) error {
res := GetDB().Table(d.TableName()).Delete(&model.UserConfig{}, id) res := GetDB().Table(d.TableName()).Delete(&model.StaffConfig{}, id)
return res.Error return res.Error
} }
func (d *UserConfigDao) Get(id int64) (*model.UserConfig, error) { func (d *UserConfigDao) Get(id int64) (*model.StaffConfig, error) {
var u model.UserConfig var u model.StaffConfig
tx := GetDB().Table(d.TableName()) tx := GetDB().Table(d.TableName())
tx = tx.Where("id = ?", id) tx = tx.Where("id = ?", id)
res := tx.First(&u) res := tx.First(&u)
@ -50,8 +50,8 @@ func (d *UserConfigDao) Get(id int64) (*model.UserConfig, error) {
return &u, nil return &u, nil
} }
func (d *UserConfigDao) GetByUsername(username string) (*model.UserConfig, error) { func (d *UserConfigDao) GetByUsername(username string) (*model.StaffConfig, error) {
var u model.UserConfig var u model.StaffConfig
tx := GetDB().Table(d.TableName()) tx := GetDB().Table(d.TableName())
tx = tx.Where("username = ?", username) tx = tx.Where("username = ?", username)
res := tx.First(&u) res := tx.First(&u)
@ -65,8 +65,8 @@ func (d *UserConfigDao) GetByUsername(username string) (*model.UserConfig, error
return &u, nil return &u, nil
} }
func (d *UserConfigDao) Query(status int) ([]*model.UserConfig, error) { func (d *UserConfigDao) Query(status int) ([]*model.StaffConfig, error) {
var u []*model.UserConfig var u []*model.StaffConfig
tx := GetDB().Table(d.TableName()) tx := GetDB().Table(d.TableName())
if status != 0 { if status != 0 {

View File

@ -0,0 +1,43 @@
package dao
import (
"enterprise/common/model"
"gorm.io/gorm"
)
type UnifyAdData struct {
}
func NewUnifyAdData() *UnifyAdData {
return &UnifyAdData{}
}
func (d *UnifyAdData) TableName() string {
return "unify_ad_data"
}
func (d *UnifyAdData) QueryOwnerData(owner, startDay, endDay string) ([]*model.UnifyAdData, error) {
tx := unifyDB.Table(d.TableName())
var o []*model.UnifyAdData
tx = tx.Where("data_type = ?", "account_report")
tx = tx.Where("owner = ?", owner)
if startDay != "" {
tx = tx.Where("day >= ?", startDay)
}
if endDay != "" {
tx = tx.Where("day <= ?", endDay)
}
tx.Order("day DESC")
tx = tx.Find(&o)
if tx.Error == gorm.ErrRecordNotFound {
return o, nil
}
if tx.Error != nil {
return nil, tx.Error
}
return o, nil
}

View File

@ -69,6 +69,16 @@ func initDB() error {
} }
db.Logger = &DBLogger{threshold: int64(2000)} db.Logger = &DBLogger{threshold: int64(2000)}
dao.SetDB(db) dao.SetDB(db)
unifyDsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", cfg.UnifyMysql.User,
cfg.UnifyMysql.Pass, cfg.UnifyMysql.Host, cfg.UnifyMysql.Port, cfg.UnifyMysql.Db)
db, err = gorm.Open(mysql.Open(unifyDsn), &gorm.Config{})
if err != nil {
log.Errorf("open dsn[%s] error[%s]", dsn, err)
return err
}
db.Logger = &DBLogger{threshold: int64(2000)}
dao.SetUnifyDB(db)
return nil return nil
} }

View File

@ -13,7 +13,8 @@ type StaffInfo struct {
StaffType string StaffType string
Phone string Phone string
Idno string Idno string
Salary string BaseSalary string
PerfSalary string
EntryDate string EntryDate string
OfficialDate string OfficialDate string
LeaveDate string LeaveDate string

View File

@ -1,6 +1,11 @@
package model package model
import butil "enterprise/base/util" import (
"encoding/json"
butil "enterprise/base/util"
"github.com/spf13/cast"
"strings"
)
var ( var (
StaffSalaryStatusNormal = 1 StaffSalaryStatusNormal = 1
@ -12,10 +17,12 @@ type StaffSalary struct {
Username string Username string
Month string Month string
BaseSalary float64 BaseSalary float64
PerfSalary float64
AttendSalary float64 AttendSalary float64
RealSalary float64 RealSalary float64
AwardSalary float64 AwardSalary float64
SocialInsurence float64 SocialInsurence float64
HouseFund float64
PersonalTax float64 PersonalTax float64
TotalDay float64 TotalDay float64
RealDay float64 RealDay float64
@ -26,5 +33,28 @@ type StaffSalary struct {
} }
func (s *StaffSalary) GetRealSalary() float64 { func (s *StaffSalary) GetRealSalary() float64 {
return butil.FloatCut(s.AttendSalary + s.AwardSalary - s.SocialInsurence - s.PersonalTax) return butil.FloatCut(s.AttendSalary + s.PerfSalary + s.AwardSalary - s.SocialInsurence - s.PersonalTax - s.HouseFund)
}
func (s *StaffSalary) GetShouldSalary() float64 {
return butil.FloatCut(s.AttendSalary + s.PerfSalary + s.AwardSalary)
}
type StaffSalarySort []*StaffSalary
func (s StaffSalarySort) Len() int {
return len(s)
}
func (s StaffSalarySort) Less(i, j int) bool {
var iExtra map[string]string
var jExtra map[string]string
json.Unmarshal([]byte(s[i].Extra), &iExtra)
json.Unmarshal([]byte(s[j].Extra), &jExtra)
return cast.ToInt64(strings.ReplaceAll(iExtra["entryDate"], "-", "")) < cast.ToInt64(strings.ReplaceAll(jExtra["entryDate"], "-", ""))
}
func (s StaffSalarySort) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
} }

View File

@ -0,0 +1,27 @@
package model
type UnifyAdData struct {
Id int64 `json:"id"`
AppId int64 `json:"appId"`
Day string `json:"day"`
AccountType string `json:"accountType"`
AccountName string `json:"accountName"`
AccountId string `json:"accountId"`
Owner string `json:"owner"`
Balance int64 `json:"balance"`
DataType string `json:"dataType"`
DataName string `json:"dataName"`
DataId string `json:"dataId"`
Cost int64 `json:"cost"`
ReturnCost int64 `json:"return_cost"`
PayAmount int64 `json:"payAmount"`
Impression int64 `json:"impression"`
Click int64 `json:"click"`
Download int64 `json:"download"`
Active int64 `json:"active"`
Register int64 `json:"register"`
Pay int64 `json:"pay"`
CreateTime int64 `json:"createTime"`
UpdateTime int64 `json:"updateTime"`
Raw string `json:"raw"`
}

View File

@ -1,23 +1,25 @@
package model package model
import "encoding/json" import (
"encoding/json"
"github.com/smbrave/goutil"
)
var ( var (
CheckinOndutyMoneyEnable = "checkin.onduty.money.enable" //上班打卡红包
CheckinOffdutyMoneyEnable = "checkin.offduty.money.enable" //下班打卡红包
CheckinOndutyMoney = "checkin.onduty.money" //上班打卡金额
CheckinOffdutyMoney = "checkin.offduty.money" //下班打卡金额
StaffSalaryExpDiscount = "staff.salary.exp.discount" //试用期薪资折扣 StaffSalaryExpDiscount = "staff.salary.exp.discount" //试用期薪资折扣
StaffSalarySocialInsurence = "staff.salary.social.insurence" //社保扣除金额 StaffSalarySocialInsurence = "staff.salary.social.insurence" //社保扣除金额
StaffSalaryHouseFund = "staff.salary.house.fund" //住房公积金
StaffSalaryPerDay = "staff.salary.per.day" //按天计算的工资 StaffSalaryPerDay = "staff.salary.per.day" //按天计算的工资
StaffSalaryNotify = "staff.salary.notify" //是否发送工资单 StaffSalaryNotify = "staff.salary.notify" //是否发送工资单
StaffSalaryProfitDeduct = "staff.salary.profit.deduct" //广告收益提成
StaffSalaryProfitTarget = "staff.salary.profit.target" //广告收益目标
) )
var ( var (
UserConfigStatusNormal = 1 StaffConfigStatusNormal = 1
UserConfigStatusDisable = 2 StaffConfigStatusDisable = 2
) )
type UserConfig struct { type StaffConfig struct {
Id int64 Id int64
Username string Username string
Config string Config string
@ -26,8 +28,14 @@ type UserConfig struct {
UpdateTime int64 UpdateTime int64
} }
func (u *UserConfig) Get(key string) interface{} { func (u *StaffConfig) Get(key string) interface{} {
config := make(map[string]interface{}) config := make(map[string]interface{})
json.Unmarshal([]byte(u.Config), &config) json.Unmarshal([]byte(u.Config), &config)
return config[key] return config[key]
} }
func (u *StaffConfig) Exist(key string) bool {
config := make(map[string]interface{})
json.Unmarshal([]byte(u.Config), &config)
return goutil.If(config[key] == nil, false, true)
}

View File

@ -10,6 +10,14 @@ user = "root"
pass = "ZW5aaGVuMIIBIj" pass = "ZW5aaGVuMIIBIj"
db = "enterprise" db = "enterprise"
[unify_mysql]
host = "192.168.2.50"
port = 13307
user = "unify"
pass = "MDE2LCJIYXNoSWQiOjY"
db = "unify"
threshold = 5000
[redis] [redis]
addr="192.168.2.50:6379" addr="192.168.2.50:6379"
db=0 db=0

View File

@ -10,6 +10,14 @@ user = "root"
pass = "ZW5aaGVuMIIBIj" pass = "ZW5aaGVuMIIBIj"
db = "enterprise" db = "enterprise"
[unify_mysql]
host = "10.0.2.157"
port = 3307
user = "unify"
pass = "MDE2LCJIYXNoSWQiOjY"
db = "unify"
threshold = 5000
[redis] [redis]
addr="127.0.0.1:6379" addr="127.0.0.1:6379"
db=0 db=0

2
go.mod
View File

@ -3,7 +3,7 @@ module enterprise
go 1.21.6 go 1.21.6
require ( require (
git.u8t.cn/open/gosdk v0.0.0-20240927033033-8d021096f778 git.u8t.cn/open/gosdk v0.0.0-20241104101317-10492bab9fd7
github.com/ArtisanCloud/PowerWeChat/v3 v3.2.27 github.com/ArtisanCloud/PowerWeChat/v3 v3.2.27
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0

View File

@ -12,6 +12,7 @@ import (
"github.com/spf13/cast" "github.com/spf13/cast"
excelize "github.com/xuri/excelize/v2" excelize "github.com/xuri/excelize/v2"
"os" "os"
"sort"
"time" "time"
"net/http" "net/http"
@ -33,7 +34,7 @@ func (s *StaffSalary) Agent(month string, ctx *gin.Context) {
panic(config.ErrDb.New().Append(err)) panic(config.ErrDb.New().Append(err))
} }
header := []string{"姓名", "身份证号", "电话", "基本工资", "出勤工资", "奖金", "社保扣除", "个税扣除", "应发工资"} header := []string{"姓名", "身份证号", "电话", "应发工资", "社保扣除", "公积金扣除", "个税扣除", "实发工资"}
datas := make([][]string, 0) datas := make([][]string, 0)
for _, staff := range staffSalarys { for _, staff := range staffSalarys {
baseInfo, err := dao.NewStaffInfoDao().GetByUsername(staff.Username) baseInfo, err := dao.NewStaffInfoDao().GetByUsername(staff.Username)
@ -51,10 +52,9 @@ func (s *StaffSalary) Agent(month string, ctx *gin.Context) {
item = append(item, baseInfo.Realname) item = append(item, baseInfo.Realname)
item = append(item, cast.ToString(baseInfo.Idno)) item = append(item, cast.ToString(baseInfo.Idno))
item = append(item, cast.ToString(baseInfo.Phone)) item = append(item, cast.ToString(baseInfo.Phone))
item = append(item, cast.ToString(staff.BaseSalary)) item = append(item, cast.ToString(staff.GetShouldSalary()))
item = append(item, cast.ToString(staff.AttendSalary))
item = append(item, cast.ToString(staff.AwardSalary))
item = append(item, cast.ToString(staff.SocialInsurence)) item = append(item, cast.ToString(staff.SocialInsurence))
item = append(item, cast.ToString(staff.HouseFund))
item = append(item, cast.ToString(staff.PersonalTax)) item = append(item, cast.ToString(staff.PersonalTax))
item = append(item, cast.ToString(staff.GetRealSalary())) item = append(item, cast.ToString(staff.GetRealSalary()))
@ -152,8 +152,9 @@ func (s *StaffSalary) Summary(month string, ctx *gin.Context) {
if err != nil { if err != nil {
panic(config.ErrDb.New().Append(err)) panic(config.ErrDb.New().Append(err))
} }
sort.Sort(model.StaffSalarySort(staffSalarys))
header := []string{"姓名", "身份证号", "入职日期", "转正日期", "基本工资", "出勤工资", "奖金", "社保扣除", "个税扣除", "应出勤天数", "实际出勤天数", "补卡天数", "请假天数", "实发工资", "状态"} header := []string{"姓名", "身份证号", "入职日期", "转正日期", "基本工资", "绩效工资", "出勤工资", "奖金", "社保扣除", "公积金扣除", "个税扣除", "应出勤天数", "实际出勤天数", "出勤率", "补卡天数", "请假天数", "实发工资", "状态"}
datas := make([][]string, 0) datas := make([][]string, 0)
summary := new(model.StaffSalary) summary := new(model.StaffSalary)
for _, staff := range staffSalarys { for _, staff := range staffSalarys {
@ -173,12 +174,15 @@ func (s *StaffSalary) Summary(month string, ctx *gin.Context) {
item = append(item, cast.ToString(baseInfo.EntryDate)) item = append(item, cast.ToString(baseInfo.EntryDate))
item = append(item, cast.ToString(baseInfo.OfficialDate)) item = append(item, cast.ToString(baseInfo.OfficialDate))
item = append(item, cast.ToString(staff.BaseSalary)) item = append(item, cast.ToString(staff.BaseSalary))
item = append(item, cast.ToString(staff.AttendSalary)) item = append(item, cast.ToString(butil.FloatCut(staff.PerfSalary)))
item = append(item, cast.ToString(staff.AwardSalary)) item = append(item, cast.ToString(butil.FloatCut(staff.AttendSalary)))
item = append(item, cast.ToString(butil.FloatCut(staff.AwardSalary)))
item = append(item, cast.ToString(staff.SocialInsurence)) item = append(item, cast.ToString(staff.SocialInsurence))
item = append(item, cast.ToString(staff.HouseFund))
item = append(item, cast.ToString(staff.PersonalTax)) item = append(item, cast.ToString(staff.PersonalTax))
item = append(item, cast.ToString(staff.TotalDay)) item = append(item, cast.ToString(staff.TotalDay))
item = append(item, cast.ToString(staff.RealDay)) item = append(item, cast.ToString(staff.RealDay))
item = append(item, fmt.Sprintf("%d%%", int(100*staff.RealDay/staff.TotalDay)))
item = append(item, cast.ToString(extra["approvalCheckinDay"])) item = append(item, cast.ToString(extra["approvalCheckinDay"]))
item = append(item, cast.ToString(staff.Holiday)) item = append(item, cast.ToString(staff.Holiday))
item = append(item, cast.ToString(staff.GetRealSalary())) item = append(item, cast.ToString(staff.GetRealSalary()))
@ -190,21 +194,26 @@ func (s *StaffSalary) Summary(month string, ctx *gin.Context) {
datas = append(datas, item) datas = append(datas, item)
summary.BaseSalary += staff.BaseSalary summary.BaseSalary += staff.BaseSalary
summary.PerfSalary += staff.PerfSalary
summary.AttendSalary += staff.AttendSalary summary.AttendSalary += staff.AttendSalary
summary.AwardSalary += staff.AwardSalary summary.AwardSalary += staff.AwardSalary
summary.SocialInsurence += staff.SocialInsurence summary.SocialInsurence += staff.SocialInsurence
summary.PersonalTax += staff.PersonalTax summary.PersonalTax += staff.PersonalTax
summary.Holiday += staff.Holiday summary.Holiday += staff.Holiday
summary.HouseFund += staff.HouseFund
} }
summary.Holiday = butil.FloatCut(summary.Holiday) summary.Holiday = butil.FloatCut(summary.Holiday)
summary.BaseSalary = butil.FloatCut(summary.BaseSalary) summary.BaseSalary = butil.FloatCut(summary.BaseSalary)
summary.PerfSalary = butil.FloatCut(summary.PerfSalary)
summary.AttendSalary = butil.FloatCut(summary.AttendSalary) summary.AttendSalary = butil.FloatCut(summary.AttendSalary)
summary.AwardSalary = butil.FloatCut(summary.AwardSalary) summary.AwardSalary = butil.FloatCut(summary.AwardSalary)
summary.SocialInsurence = butil.FloatCut(summary.SocialInsurence) summary.SocialInsurence = butil.FloatCut(summary.SocialInsurence)
summary.HouseFund = butil.FloatCut(summary.HouseFund)
summary.PersonalTax = butil.FloatCut(summary.PersonalTax) summary.PersonalTax = butil.FloatCut(summary.PersonalTax)
datas = append(datas, []string{"合计", "-", "-", "-", datas = append(datas, []string{"合计", "-", "-", "-",
cast.ToString(summary.BaseSalary), cast.ToString(summary.AttendSalary), cast.ToString(summary.AwardSalary), cast.ToString(summary.SocialInsurence), cast.ToString(summary.BaseSalary), cast.ToString(summary.PerfSalary), cast.ToString(summary.AttendSalary), cast.ToString(summary.AwardSalary), cast.ToString(summary.SocialInsurence),
cast.ToString(summary.PersonalTax), "-", "-", "-", cast.ToString(summary.Holiday), cast.ToString(summary.HouseFund),
cast.ToString(summary.PersonalTax), "-", "-", "-", "-", cast.ToString(summary.Holiday),
cast.ToString(butil.FloatCut(summary.GetRealSalary())), "-"}) cast.ToString(butil.FloatCut(summary.GetRealSalary())), "-"})
if xls != "" { if xls != "" {

289
service/staff.go Normal file
View File

@ -0,0 +1,289 @@
package service
import (
butil "enterprise/base/util"
"enterprise/common/config"
"enterprise/common/dao"
"enterprise/common/model"
log "github.com/sirupsen/logrus"
"github.com/smbrave/goutil"
"github.com/spf13/cast"
"math"
"strings"
"time"
)
type Staff struct {
info *model.StaffInfo
config *model.StaffConfig
}
func NewStaff(info *model.StaffInfo, config *model.StaffConfig) *Staff {
return &Staff{
info: info,
config: config,
}
}
func (s *Staff) CalcSalary(salary *model.StaffSalary, month string) (*model.StaffSalary, error) {
staff := s.info
if salary == nil {
salary = new(model.StaffSalary)
salary.Month = month
salary.Username = s.info.Username
}
entryTime, _ := time.ParseInLocation("2006-01-02", staff.EntryDate, 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)
isLeaveMonth := goutil.If(cast.ToInt(leaveTime.Format("200601")) == cast.ToInt(month), true, false)
// 试用期折扣
discount := s.getDiscount(month)
//社保和公积金
socialInsurence := goutil.If(s.config.Exist(model.StaffSalarySocialInsurence), cast.ToFloat64(s.config.Get(model.StaffSalarySocialInsurence)), config.SalarySocialInsurence)
//houseFund := goutil.If(s.config.Exist(model.StaffSalaryHouseFund), cast.ToFloat64(s.config.Get(model.StaffSalaryHouseFund)), config.SalaryHouseFund)
houseFund := cast.ToFloat64(s.config.Get(model.StaffSalaryHouseFund))
if isEntryMonth { //入职月不买社保
socialInsurence = 0
houseFund = 0
}
holiday, surplusHoliday := s.getRealVacationDay(staff.Username, month)
totalDays := s.getTotalWorkDay(staff.Username, month)
realWorkDays := s.getRealWorkDay(staff.EntryDate, staff.LeaveDate, staff.Username, month)
approvalCheckinDay := s.getApprovalCheckinDay(staff.Username, month)
// 入职月或离职月以大多数人的出勤天数为准
if isEntryMonth || isLeaveMonth {
totalDays = s.getTotalWorkDayMax(month)
}
salary.BaseSalary = cast.ToFloat64(staff.BaseSalary)
realWorkDays = realWorkDays + surplusHoliday
atttendRate := float64(realWorkDays) / float64(totalDays)
attendSalary := salary.BaseSalary * atttendRate * discount
staffSalaryPerDay := cast.ToFloat64(s.config.Get(model.StaffSalaryPerDay))
if staffSalaryPerDay > 0 {
attendSalary = staffSalaryPerDay * realWorkDays
}
extra := make(map[string]interface{})
extra["approvalCheckinDay"] = approvalCheckinDay //展示依赖
extra["entryDate"] = staff.EntryDate //展示排序依赖
awardSalay, perfSalary := s.getExtraSalary(month)
salary.Holiday = holiday
salary.PerfSalary = perfSalary
salary.AwardSalary = awardSalay
salary.AttendSalary = butil.FloatCut(attendSalary)
salary.RealSalary = salary.GetRealSalary()
salary.SocialInsurence = socialInsurence
salary.HouseFund = houseFund
salary.Holiday = holiday
salary.TotalDay = float64(totalDays)
salary.RealDay = realWorkDays
salary.Extra = goutil.EncodeJSONIndent(extra)
return salary, nil
}
func (s *Staff) getExtraSalary(month string) (float64, float64) {
monthTime, _ := time.ParseInLocation("200601", month, time.Local)
startDay := monthTime.Format("2006-01-02")
endDay := monthTime.AddDate(0, 1, -1).Format("2006-01-02")
datas, err := dao.NewUnifyAdData().QueryOwnerData(s.info.Username, startDay, endDay)
if err != nil {
log.Errorf("db error :%s", err.Error())
return 0, 0
}
sumProfitAmount := int64(0)
for _, data := range datas {
sumProfitAmount += data.PayAmount - data.Cost
}
totalProfit := cast.ToFloat64(goutil.FormatMoney(sumProfitAmount))
//1算提成
awardSalary := float64(0)
if s.config.Exist(model.StaffSalaryProfitDeduct) {
deductRate := cast.ToFloat64(s.config.Get(model.StaffSalaryProfitDeduct))
awardSalary = totalProfit * deductRate
if awardSalary < 0 {
awardSalary = 0
}
}
//2算绩效
perfSalary := cast.ToFloat64(s.info.PerfSalary)
if s.config.Exist(model.StaffSalaryProfitTarget) {
profitTarget := cast.ToFloat64(s.config.Get(model.StaffSalaryProfitTarget))
if totalProfit < 0 {
perfSalary = 0
awardSalary = 0
} else if totalProfit < profitTarget {
perfSalary = perfSalary * (totalProfit / profitTarget)
awardSalary = 0
}
}
return awardSalary, perfSalary
}
func (s *Staff) getDiscount(month string) float64 {
officalTime, _ := time.ParseInLocation("2006-01-02", s.info.OfficialDate, time.Local)
monthTime, _ := time.ParseInLocation("200601", month, time.Local)
startDate := cast.ToInt(monthTime.Format("20060102"))
endDate := cast.ToInt(monthTime.AddDate(0, 1, -1).Format("20060102"))
officialDate := cast.ToInt(strings.ReplaceAll(s.info.OfficialDate, "-", ""))
isOfficialMonth := goutil.If(cast.ToInt(officalTime.Format("200601")) == cast.ToInt(month), true, false)
// 试用期折扣
discount := cast.ToFloat64(s.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
}
if discount < 1.0 && isOfficialMonth {
totalMonthDay := float64(endDate - startDate + 1)
discount = discount*float64(officialDate-startDate)/totalMonthDay + 1*float64(endDate-officialDate+1)/totalMonthDay
}
return discount
}
func (s *Staff) getRealVacationDay(username, month string) (float64, float64) {
// 休假申请
approveVacations, err := dao.NewApprovalVacationDao().GetByUsername(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 *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(entryDate, leaveDate, 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
//入职当天算工作日
entryTime, _ := time.ParseInLocation("2006-01-02", entryDate, time.Local)
if entryTime.Format("200601") == month {
realWorkdays += 1
}
//离职当天算工作日
leaveTime, _ := time.ParseInLocation("2006-01-02", leaveDate, time.Local)
if leaveTime.Format("200601") == month {
realWorkdays += 1
}
for _, checkin := range userCheckins {
//入职离职当天已经算过了
if entryTime.Format("2006-01-02") == checkin.Day || leaveTime.Format("2006-01-02") == checkin.Day {
continue
}
if checkin.Exception == "" {
realWorkdays += 1
continue
}
//有补卡申请就直接算出勤
approvalCheckin, _ := dao.NewApprovalCheckinDao().GetByUsernameDay(username, checkin.Day)
if approvalCheckin != nil {
realWorkdays += 1
approvalCheckinDay += 1
continue
}
////有请假申请的不算出勤
//approvalVacation, _ := dao.NewApprovalVacationDao().GetByUsernameDay(username, checkin.Day)
//if approvalVacation != nil {
// 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
}

View File

@ -1,17 +1,16 @@
package worker package worker
import ( import (
butil "enterprise/base/util"
"enterprise/common/config" "enterprise/common/config"
"enterprise/common/dao" "enterprise/common/dao"
"enterprise/common/global" "enterprise/common/global"
"enterprise/common/model" "enterprise/common/model"
"enterprise/service"
"fmt" "fmt"
"git.u8t.cn/open/gosdk/qyweixin" "git.u8t.cn/open/gosdk/qyweixin"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/smbrave/goutil" "github.com/smbrave/goutil"
"github.com/spf13/cast" "github.com/spf13/cast"
"math"
"strings" "strings"
"time" "time"
) )
@ -44,7 +43,8 @@ func (s *Staff) MontorWorkAge() {
message = append(message, fmt.Sprintf("【员工半年提醒】[%s]", staff.Realname)) message = append(message, fmt.Sprintf("【员工半年提醒】[%s]", staff.Realname))
message = append(message, fmt.Sprintf("入职时间:%s", staff.EntryDate)) message = append(message, fmt.Sprintf("入职时间:%s", staff.EntryDate))
message = append(message, fmt.Sprintf("入职年限:%.1f", float64(spanMonth)/12)) message = append(message, fmt.Sprintf("入职年限:%.1f", float64(spanMonth)/12))
message = append(message, fmt.Sprintf("基本工资:%s", staff.Salary)) message = append(message, fmt.Sprintf("基本工资:%s", staff.BaseSalary))
message = append(message, fmt.Sprintf("绩效工资:%s", staff.PerfSalary))
message = append(message, fmt.Sprintf("身份证号:%s", staff.Idno)) message = append(message, fmt.Sprintf("身份证号:%s", staff.Idno))
if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil { if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil {
@ -99,7 +99,7 @@ func (s *Staff) SyncStaffInfo() {
Agent: cfg.QyWeixin.EnterpriseAgent, Agent: cfg.QyWeixin.EnterpriseAgent,
}) })
userConfigs, err := dao.NewUserConfigDao().Query(model.UserConfigStatusNormal) userConfigs, err := dao.NewUserConfigDao().Query(model.StaffConfigStatusNormal)
if err != nil { if err != nil {
log.Errorf("query staff db error :%s", err.Error()) log.Errorf("query staff db error :%s", err.Error())
return return
@ -120,15 +120,16 @@ func (s *Staff) SyncStaffInfo() {
} }
staff.Username = staffInfo.UserName staff.Username = staffInfo.UserName
staff.Realname = staffInfo.RealName staff.Realname = staffInfo.RealName
staff.Idno = staffInfo.Idno staff.Idno = staffInfo.Extra["11015"]
staff.StaffType = staffInfo.StaffType staff.StaffType = staffInfo.Extra["12003"]
staff.Salary = cast.ToString(staffInfo.Salary) staff.BaseSalary = staffInfo.Extra["20001"]
staff.EntryDate = staffInfo.EntryDate staff.PerfSalary = staffInfo.Extra["20005"]
staff.OfficialDate = staffInfo.OfficialDate staff.EntryDate = time.Unix(cast.ToInt64(staffInfo.Extra["12018"]), 0).Format("2006-01-02")
staff.BirthDate = staffInfo.BirthDate staff.OfficialDate = time.Unix(cast.ToInt64(staffInfo.Extra["12023"]), 0).Format("2006-01-02")
staff.BankName = staffInfo.BankName staff.BirthDate = time.Unix(cast.ToInt64(staffInfo.Extra["11005"]), 0).Format("2006-01-02")
staff.BankCard = staffInfo.BankCard staff.BankName = staffInfo.Extra["13001"]
staff.AlipayUid = staffInfo.AlipayUid staff.BankCard = staffInfo.Extra["13002"]
staff.AlipayUid = staffInfo.Extra["20004"]
if staff.Id == 0 { if staff.Id == 0 {
_, err = dao.NewStaffInfoDao().Create(staff) _, err = dao.NewStaffInfoDao().Create(staff)
@ -147,11 +148,6 @@ func (s *Staff) SyncStaffSalary(month string) {
month = time.Now().AddDate(0, -1, 0).Format("2006-01") month = time.Now().AddDate(0, -1, 0).Format("2006-01")
} }
month = strings.ReplaceAll(month, "-", "") 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) staffs, err := dao.NewStaffInfoDao().Query(model.StaffInfoStatusNormal)
if err != nil { if err != nil {
@ -160,128 +156,33 @@ func (s *Staff) SyncStaffSalary(month string) {
} }
for _, staff := range staffs { 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 { if staff.LeaveDate != "" {
continue leaveTime, _ := time.ParseInLocation("2006-01-02", staff.LeaveDate, time.Local)
} isLeaveMonth := goutil.If(cast.ToInt(leaveTime.Format("200601")) == cast.ToInt(month), true, false)
if !isLeaveMonth {
salary, err := salaryDao.GetBy(staff.Username, month) continue
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 {
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)
} }
} }
// 打卡正常天数+补卡天数 为正常出勤天数 config, err := dao.NewUserConfigDao().GetByUsername(staff.Username)
totalDays := s.getTotalWorkDay(staff.Username, month) if err != nil || config == nil {
realWorkDays := s.getRealWorkDay(staff.EntryDate, staff.LeaveDate, staff.Username, month) log.Errorf("username[%s] not config,skip!!", staff.Username)
approvalCheckinDay := s.getApprovalCheckinDay(staff.Username, month) continue
extra := make(map[string]interface{}) }
salary.BaseSalary = cast.ToFloat64(staff.Salary) salary, err := dao.NewStaffSalaryDao().GetBy(staff.Username, month)
salary.Holiday = holiday if err != nil {
entryDate := cast.ToInt(strings.ReplaceAll(staff.EntryDate, "-", "")) log.Errorf("db error :%s", err.Error())
officialDate := cast.ToInt(strings.ReplaceAll(staff.OfficialDate, "-", "")) continue
if discount < 1.0 && isOfficialMonth {
totalMonthDay := float64(endDate - startDate + 1)
discount = discount*float64(officialDate-startDate)/totalMonthDay + 1*float64(endDate-officialDate+1)/totalMonthDay
} }
// 入职月或离职月以大多数人的出勤天数为准 staffService := service.NewStaff(staff, config)
if isEntryMonth || isLeaveMonth { salary, err = staffService.CalcSalary(salary, month)
totalDays = maxTotalDays if err != nil {
log.Errorf("username[%s] staffService.CalcSalary error :%s", staff.Username, err.Error())
continue
} }
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 { if salary.Id == 0 {
_, err = dao.NewStaffSalaryDao().Create(salary) _, err = dao.NewStaffSalaryDao().Create(salary)
} else { } else {
@ -293,109 +194,3 @@ func (s *Staff) SyncStaffSalary(month string) {
} }
} }
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(entryDate, leaveDate, 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
//入职当天算工作日
entryTime, _ := time.ParseInLocation("2006-01-02", entryDate, time.Local)
if entryTime.Format("200601") == month {
realWorkdays += 1
}
//离职当天算工作日
leaveTime, _ := time.ParseInLocation("2006-01-02", leaveDate, time.Local)
if leaveTime.Format("200601") == month {
realWorkdays += 1
}
for _, checkin := range userCheckins {
if checkin.Exception == "" {
realWorkdays += 1
continue
}
//入职离职当天已经算过了
if entryTime.Format("2006-01-02") == checkin.Day || leaveTime.Format("2006-01-02") == checkin.Day {
continue
}
//有补卡申请就直接算出勤
approvalCheckin, _ := dao.NewApprovalCheckinDao().GetByUsernameDay(username, checkin.Day)
if approvalCheckin != nil {
realWorkdays += 1
approvalCheckinDay += 1
continue
}
//有请假申请的不算出勤
approvalVacation, _ := dao.NewApprovalVacationDao().GetByUsernameDay(username, checkin.Day)
if approvalVacation != nil {
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
}