package service import ( butil "enterprise/base/util" "enterprise/common/config" "enterprise/common/dao" "enterprise/common/model" "enterprise/server/api" "enterprise/server/session" CommonService "enterprise/service" "fmt" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "github.com/spf13/cast" excelize "github.com/xuri/excelize/v2" "os" "sort" "time" "net/http" ) var ( StaffSalaryTypeBank = "bank" StaffSalaryTypeSummary = "summary" StaffSalaryTypeAgent = "agent" ) type StaffSalary struct { } func NewStaffSalary() *StaffSalary { return &StaffSalary{} } func (s *StaffSalary) List(sess *session.AdminSession, req *api.ListSalaryReq) (int64, interface{}, interface{}) { if !sess.GetAdmin().GetConfig().IsFinance() { return 0, nil, nil } salarys, total, err := dao.NewStaffSalaryDao().QueryAdmin(1, -1, sess.GetCorpId(), req.StaffId, req.StartMonth, req.EndMonth, req.Status) session.CheckDBError(err) start := (req.Page - 1) * req.Size end := start + req.Size items := make([]*api.Salary, 0) summary := new(api.Salary) for pos, m := range salarys { staffSalary := new(api.Salary) staffSalary.From(m) staffUser, err := dao.NewStaffUserDao().Get(m.UserId) session.CheckDBError(err) if staffUser != nil { userSalary := staffUser.GetSalary() staffSalary.Realname = staffUser.Realname staffSalary.TargetSalary = userSalary.Target staffSalary.BaseSalary = userSalary.Base } summary.Add(staffSalary) if pos < start || pos >= end { continue } items = append(items, staffSalary) } return total, summary, items } func (s *StaffSalary) Create(sess *session.AdminSession, req *api.CreateSalaryReq) { users, _, err := dao.NewStaffUserDao().Query(1, -1, sess.GetCorpId(), 0, req.Username, "", "", "") session.CheckDBError(err) salaryLast := cast.ToInt(config.GetCorpConfig(sess.GetCorpId(), "salary_latest", 31)) lastMonth := cast.ToInt(time.Now().AddDate(0, 0, -time.Now().Day()).Format("200601")) if cast.ToInt(req.Month) < lastMonth || (cast.ToInt(req.Month) == lastMonth && time.Now().Day() > salaryLast) { panic(config.ErrTimeExceed.New().Append(fmt.Sprintf("salaryLast=%d", salaryLast))) } for _, user := range users { //离职的且离职时间不在当月的不在计算工资 if user.Status == model.StaffUserStatusOffline { leaveDate, _ := time.ParseInLocation("2006-01-02", user.LeaveDate, time.Local) if leaveDate.Month() != time.Now().Month() { continue } } salary, err := dao.NewStaffSalaryDao().GetBy(sess.GetCorpId(), user.Id, req.Month) session.CheckDBError(err) salaryServ := CommonService.NewStaffSalary(user) salary, err = salaryServ.CalcSalary(salary, req.Month, "") if err != nil { log.Errorf("CalcSalary error :%s", err.Error()) continue } if salary == nil { continue } if salary.Id == 0 { _, err = dao.NewStaffSalaryDao().Create(salary) } else { err = dao.NewStaffSalaryDao().Update(salary) } session.CheckDBError(err) } return } func (s *StaffSalary) Delete(sess *session.AdminSession, id int64) { salary, err := dao.NewStaffSalaryDao().Get(id) session.CheckDBError(err) session.CheckNilError(salary, "工资段不存在") if salary.Status == model.StaffSalaryStatusPayed { panic("已支付的不能删除") } } func (s *StaffSalary) Update(sess *session.AdminSession, req *api.UpdateSalaryReq) { salary, err := dao.NewStaffSalaryDao().Get(cast.ToInt64(req.Id)) session.CheckDBError(err) session.CheckNilError(salary, "工资单不存在") if req.OtherIncome != "" { salary.OtherSalary = cast.ToFloat64(req.OtherIncome) } if req.OtherDeduct != "" { salary.OtherDeduct = cast.ToFloat64(req.OtherDeduct) } if req.PersonalDeduct != "" { salary.PersonalDeduct = cast.ToFloat64(req.PersonalDeduct) } if req.Status != "" { salary.Status = cast.ToInt(req.Status) } err = dao.NewStaffSalaryDao().Update(salary) session.CheckDBError(err) } func (s *StaffSalary) Pay(sess *session.AdminSession, req *api.PaySalaryReq) { salary, err := dao.NewStaffSalaryDao().Get(cast.ToInt64(req.SalaryId)) session.CheckDBError(err) session.CheckNilError(salary, "工资单") if salary.Status == model.StaffSalaryStatusPayed { panic("工资单已支付") } corp, err := dao.NewCorpDao().Get(sess.GetCorpId()) session.CheckDBError(err) session.CheckNilError(corp, "企业不存在") user, err := dao.NewStaffUserDao().Get(salary.UserId) session.CheckDBError(err) session.CheckNilError(user, "用户不存在") title := fmt.Sprintf("%s工资", salary.Month) salary.Status = model.StaffSalaryStatusPayed dao.NewStaffSalaryDao().Update(salary) if err = CommonService.NewPay().Pay(corp, user, title, req.PayType, int64(salary.GetRealSalary()*100), salary.GetOutTradeNo()); err != nil { panic(config.ErrInternal.New().Append(err)) } } func (s *StaffSalary) Agent(cid int64, month string, ctx *gin.Context) { xls := ctx.Query("xls") staffSalarys, err := dao.NewStaffSalaryDao().QueryAll(cid, month, model.StaffSalaryStatusWait) if err != nil { panic(config.ErrDb.New().Append(err)) } header := []string{"姓名", "身份证号", "电话", "应发工资", "社保扣除", "公积金扣除", "个税扣除", "实发工资"} datas := make([][]string, 0) for _, staff := range staffSalarys { userInfo, err := dao.NewStaffUserDao().Get(staff.UserId) if err != nil { log.Errorf("db error :%s", err.Error()) continue } if userInfo == nil { continue } if userInfo.GetConfig().PayChannel != model.StaffSalaryPaymentBank { continue } userSalary := userInfo.GetSalary() if userSalary.Base == "" { continue } item := make([]string, 0) item = append(item, userInfo.Realname) item = append(item, cast.ToString(userInfo.Idno)) item = append(item, cast.ToString(userInfo.Phone)) item = append(item, cast.ToString(staff.GetShouldSalary())) item = append(item, cast.ToString(staff.SocialDeduct)) item = append(item, cast.ToString(staff.HouseDeduct)) item = append(item, cast.ToString(staff.PersonalDeduct)) item = append(item, cast.ToString(staff.GetRealSalary())) datas = append(datas, item) } if xls != "" { filename := fmt.Sprintf("agent_%s.xlsx", time.Now().Format("20060102_150405")) s.toExcel(filename, header, datas, ctx) os.Remove(filename) } else { links := make([]map[string]string, 0) links = append(links, map[string]string{ "url": "/staff/salary?type=agent&xls=1&cid=" + cast.ToString(cid), "name": "下载", }) links = append(links, map[string]string{ "url": "/staff/salary?type=bank&cid=" + cast.ToString(cid), "name": "银行", }) links = append(links, map[string]string{ "url": "/staff/salary?type=summary&cid=" + cast.ToString(cid), "name": "汇总", }) ctx.HTML(http.StatusOK, "salary.html", gin.H{ "title": month + "工资汇总", "header": header, "data": datas, "link": links, }) } } func (s *StaffSalary) Bank(cid int64, month string, ctx *gin.Context) { xls := ctx.Query("xls") staffSalarys, err := dao.NewStaffSalaryDao().QueryAll(cid, month, model.StaffSalaryStatusWait) if err != nil { panic(config.ErrDb.New().Append(err)) } header := []string{"账号", "户名", "金额", "开户行", "开户地", "收款备注"} datas := make([][]string, 0) for _, staff := range staffSalarys { userInfo, err := dao.NewStaffUserDao().Get(staff.UserId) if err != nil { log.Errorf("db error :%s", err.Error()) continue } if userInfo == nil { continue } if userInfo.GetConfig().PayChannel != model.StaffSalaryPaymentBank { continue } userSalary := userInfo.GetSalary() userPayee := userInfo.GetPayee() if userSalary.Base == "" { continue } item := make([]string, 0) item = append(item, userPayee.BankCard) item = append(item, userInfo.Realname) item = append(item, cast.ToString(staff.GetRealSalary())) item = append(item, cast.ToString(userPayee.BankName)) item = append(item, "重庆市") item = append(item, fmt.Sprintf("%s工资", month)) datas = append(datas, item) } if xls != "" { filename := fmt.Sprintf("bank_%s.xlsx", time.Now().Format("20060102_150405")) s.toExcel(filename, header, datas, ctx) os.Remove(filename) } else { links := make([]map[string]string, 0) links = append(links, map[string]string{ "url": "/staff/salary?type=bank&xls=1&cid=" + cast.ToString(cid), "name": "下载", }) links = append(links, map[string]string{ "url": "/staff/salary?type=summary&cid=" + cast.ToString(cid), "name": "汇总", }) links = append(links, map[string]string{ "url": "/staff/salary?type=agent&cid=" + cast.ToString(cid), "name": "代理", }) ctx.HTML(http.StatusOK, "salary.html", gin.H{ "title": month + "工资汇总", "header": header, "data": datas, "link": links, }) } } func (s *StaffSalary) Summary(cid int64, month string, ctx *gin.Context) { xls := ctx.Query("xls") staffSalarys, err := dao.NewStaffSalaryDao().QueryAll(cid, month, 0) if err != nil { panic(config.ErrDb.New().Append(err)) } sort.Sort(model.StaffSalarySort(staffSalarys)) var header []string if cid == 1002 { header = []string{"姓名", "入职日期", "转正日期", "基本工资", "绩效工资", "出勤收入", "绩效收入", "奖金收入", "其他收入", "应出勤天数", "实际出勤天数", "请假天数", "实发工资", "状态"} } else { header = []string{"姓名", "入职日期", "转正日期", "基本工资", "绩效工资", "出勤收入", "绩效收入", "奖金收入", "其他收入", "社保扣除", "公积金扣除", "个税扣除", "应出勤天数", "实际出勤天数", "请假天数", "实发工资", "状态"} } datas := make([][]string, 0) summary := new(model.StaffSalary) totalCount := 0 for _, salary := range staffSalarys { userInfo, err := dao.NewStaffUserDao().Get(salary.UserId) if err != nil { log.Errorf("db error :%s", err.Error()) continue } if userInfo == nil { continue } userSalary := userInfo.GetSalary() //extra := make(map[string]interface{}) //json.Unmarshal([]byte(salary.Extra), &extra) item := make([]string, 0) item = append(item, userInfo.Realname) item = append(item, cast.ToString(userInfo.EntryDate)) item = append(item, cast.ToString(userInfo.OfficialDate)) item = append(item, userSalary.Base) item = append(item, userSalary.Target) item = append(item, cast.ToString(butil.FloatCut(salary.AttendSalary))) item = append(item, cast.ToString(butil.FloatCut(salary.TargetSalary))) item = append(item, cast.ToString(butil.FloatCut(salary.AwardSalary))) item = append(item, cast.ToString(butil.FloatCut(salary.OtherSalary))) if cid != 1002 { item = append(item, cast.ToString(butil.FloatCut(salary.SocialDeduct))) item = append(item, cast.ToString(butil.FloatCut(salary.HouseDeduct))) item = append(item, cast.ToString(butil.FloatCut(salary.PersonalDeduct))) } item = append(item, cast.ToString(salary.ShouldDay)) item = append(item, cast.ToString(butil.FloatCut(salary.AttendDay))) item = append(item, cast.ToString(butil.FloatCut(salary.HolidayDay))) item = append(item, cast.ToString(salary.GetRealSalary())) if cast.ToFloat64(salary.ShouldDay) != cast.ToFloat64(salary.AttendDay)+cast.ToFloat64(salary.HolidayDay) { item = append(item, "【异常】") } else { item = append(item, "") } totalCount += 1 datas = append(datas, item) summary.Salary += salary.Salary summary.TargetSalary += salary.TargetSalary summary.AttendSalary += salary.AttendSalary summary.AwardSalary += salary.AwardSalary summary.OtherSalary += salary.OtherSalary summary.SocialDeduct += salary.SocialDeduct summary.HouseDeduct += salary.HouseDeduct summary.PersonalDeduct += salary.PersonalDeduct summary.OtherDeduct += salary.OtherDeduct summary.AttendDay += salary.AttendDay summary.HolidayDay += salary.HolidayDay } summary.HolidayDay = butil.FloatCut(summary.HolidayDay) summary.Salary = butil.FloatCut(summary.Salary) summary.TargetSalary = butil.FloatCut(summary.TargetSalary) summary.AttendSalary = butil.FloatCut(summary.AttendSalary) summary.AwardSalary = butil.FloatCut(summary.AwardSalary) summary.SocialDeduct = butil.FloatCut(summary.SocialDeduct) summary.HouseDeduct = butil.FloatCut(summary.HouseDeduct) summary.PersonalDeduct = butil.FloatCut(summary.PersonalDeduct) summary.OtherDeduct = butil.FloatCut(summary.OtherDeduct) if cid != 1002 { datas = append(datas, []string{"合计", cast.ToString(totalCount), "-", cast.ToString(summary.Salary), "-", cast.ToString(summary.AttendSalary), cast.ToString(summary.TargetSalary), cast.ToString(summary.AwardSalary), cast.ToString(summary.OtherSalary), cast.ToString(summary.SocialDeduct), cast.ToString(summary.HouseDeduct), cast.ToString(summary.PersonalDeduct), "-", "-", cast.ToString(summary.HolidayDay), cast.ToString(butil.FloatCut(summary.GetRealSalary())), "-"}) } else { datas = append(datas, []string{"合计", cast.ToString(totalCount), "-", cast.ToString(summary.Salary), "-", cast.ToString(summary.AttendSalary), cast.ToString(summary.TargetSalary), cast.ToString(summary.AwardSalary), cast.ToString(summary.OtherSalary), "-", "-", cast.ToString(summary.HolidayDay), cast.ToString(butil.FloatCut(summary.GetRealSalary())), "-"}) } if xls != "" { filename := fmt.Sprintf("summary_%s.xlsx", time.Now().Format("20060102_150405")) s.toExcel(filename, header, datas, ctx) os.Remove(filename) } else { links := make([]map[string]string, 0) links = append(links, map[string]string{ "url": "/staff/salary?type=bank&cid=" + cast.ToString(cid), "name": "银行", }) links = append(links, map[string]string{ "url": "/staff/salary?type=agent&cid=" + cast.ToString(cid), "name": "代理", }) ctx.HTML(http.StatusOK, "salary.html", gin.H{ "title": month + "工资汇总", "header": header, "data": datas, "link": links, }) } } func (s *StaffSalary) toExcel(filePath string, header []string, datas [][]string, ctx *gin.Context) { f := excelize.NewFile() //声明工作表的名称 sheetName := "工资单" f.SetSheetName("Sheet1", sheetName) f.SetSheetRow(sheetName, "A1", &header) for i, data := range datas { f.SetSheetRow(sheetName, fmt.Sprintf("A%d", i+2), &data) } if err := f.SaveAs(filePath); err != nil { panic(config.ErrInternal.New().Append(err)) } ctx.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filePath)) ctx.Writer.Header().Add("Content-Type", "application/msexcel") ctx.File(filePath) } func (s *StaffSalary) Bill(id int64, ctx *gin.Context) { salary, err := dao.NewStaffSalaryDao().Get(id) session.CheckDBError(err) session.CheckNilError(salary, "工资单不存在") corp, err := dao.NewCorpDao().Get(salary.CorpId) session.CheckDBError(err) session.CheckNilError(corp, "企业不存在") user, err := dao.NewStaffUserDao().Get(salary.UserId) session.CheckDBError(err) session.CheckNilError(user, "用户不存在") datas := make([]*model.SalaryBillSection, 0) baseDetail := make([]*model.SalaryBillLine, 0) baseDetail = append(baseDetail, &model.SalaryBillLine{Label: "员工姓名", Value: fmt.Sprintf("%s", user.Realname)}) baseDetail = append(baseDetail, &model.SalaryBillLine{Label: "基本工资", Value: fmt.Sprintf("%s", user.GetSalary().Base)}) baseDetail = append(baseDetail, &model.SalaryBillLine{Label: "绩效工资", Value: fmt.Sprintf("%s", user.GetSalary().Target)}) datas = append(datas, &model.SalaryBillSection{ Name: "基本信息", Line: baseDetail, }) salaryDetail := make([]*model.SalaryBillLine, 0) salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "出勤收入", Value: fmt.Sprintf("%.2f 元", salary.AttendSalary)}) salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "绩效收入", Value: fmt.Sprintf("%.2f 元", salary.TargetSalary)}) if salary.AwardSalary != 0 { salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "奖金收入", Value: fmt.Sprintf("%.2f 元", salary.AwardSalary)}) } if salary.OtherSalary != 0 { salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "其他收入", Value: fmt.Sprintf("%.2f 元", salary.OtherSalary)}) } if salary.SocialDeduct != 0 { salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "社保扣除", Value: fmt.Sprintf("%.2f 元", salary.SocialDeduct)}) } if salary.HouseDeduct != 0 { salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "公积金扣除", Value: fmt.Sprintf("%.2f 元", salary.HouseDeduct)}) } salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "个税扣除", Value: fmt.Sprintf("%.2f 元", salary.PersonalDeduct)}) if salary.OtherSalary != 0 { salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "其他扣除", Value: fmt.Sprintf("%.2f 元", salary.OtherSalary)}) } datas = append(datas, &model.SalaryBillSection{ Name: "工资明细", Line: salaryDetail, }) attendDetail := make([]*model.SalaryBillLine, 0) attendDetail = append(attendDetail, &model.SalaryBillLine{Label: "应出勤", Value: fmt.Sprintf("%d 天", salary.ShouldDay)}) attendDetail = append(attendDetail, &model.SalaryBillLine{Label: "休假天数", Value: fmt.Sprintf("%.2f 天", salary.HolidayDay)}) attendDetail = append(attendDetail, &model.SalaryBillLine{Label: "缺勤天数", Value: fmt.Sprintf("%.2f 天", float64(salary.ShouldDay)-salary.AttendDay-salary.HolidayDay)}) attendDetail = append(attendDetail, &model.SalaryBillLine{Label: "实际出勤", Value: fmt.Sprintf("%.2f 天", salary.AttendDay)}) datas = append(datas, &model.SalaryBillSection{ Name: "出勤信息", Line: attendDetail, }) ctx.HTML(http.StatusOK, "salary_bill.html", gin.H{ "title": "工资单", "salary": fmt.Sprintf("%.2f 元", salary.GetRealSalary()), "datas": datas, }) }