517 lines
16 KiB
Go
517 lines
16 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"dubbo.apache.org/dubbo-go/v3/common/logger"
|
|
"dubbo.apache.org/dubbo-go/v3/config"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/fonchain_enterprise/fonchain-main/api/account"
|
|
"github.com/fonchain_enterprise/fonchain-main/api/artwork"
|
|
"github.com/fonchain_enterprise/fonchain-main/api/collections"
|
|
"github.com/fonchain_enterprise/fonchain-main/api/employee"
|
|
"github.com/fonchain_enterprise/fonchain-main/api/oa"
|
|
"github.com/fonchain_enterprise/fonchain-main/api/order"
|
|
backendSeries "github.com/fonchain_enterprise/fonchain-main/api/series"
|
|
"github.com/fonchain_enterprise/fonchain-main/api/shopbrand"
|
|
config1 "github.com/fonchain_enterprise/fonchain-main/pkg/config"
|
|
"github.com/fonchain_enterprise/fonchain-main/pkg/e"
|
|
"github.com/fonchain_enterprise/fonchain-main/pkg/model"
|
|
"github.com/fonchain_enterprise/fonchain-main/pkg/model/vo/turnstile"
|
|
"github.com/fonchain_enterprise/fonchain-main/pkg/utils"
|
|
"github.com/google/uuid"
|
|
"github.com/robfig/cron/v3"
|
|
"os"
|
|
"path"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
func Task(c *cron.Cron) {
|
|
/*if config.GetConsumerService("ArtworkClientImpl") != nil {
|
|
_, _ = c.AddFunc("@every 5m", CheckCopyright)
|
|
}*/
|
|
//发送周报短信
|
|
if config.GetConsumerService("OrderClientImpl") != nil {
|
|
_, _ = c.AddFunc("0 15 * * 0", SendAReportToBoss)
|
|
}
|
|
//重启打卡机设备
|
|
if config.GetConsumerService("AccountClientImpl") != nil {
|
|
_, _ = c.AddFunc("0 0 4 * *", RebootClockDevice)
|
|
}
|
|
//更新考勤组绑定
|
|
//if config.GetConsumerService("EmployeeClientImpl") != nil {
|
|
// _, _ = c.AddFunc("1 4 * * *", UpdateAttendanceRegularly)
|
|
//}
|
|
//更新在职状态
|
|
if config.GetConsumerService("EmployeeClientImpl") != nil {
|
|
_, _ = c.AddFunc("0 23 * * *", UpdateWorkingStatus)
|
|
}
|
|
//创建到期消息提醒
|
|
if config.GetConsumerService("EmployeeClientImpl") != nil {
|
|
_, _ = c.AddFunc("0 1 * * *", CreateAReminderMessage)
|
|
}
|
|
//创建假期余额
|
|
if config.GetConsumerService("EmployeeClientImpl") != nil {
|
|
_, _ = c.AddFunc("0 0 1 1 *", CreateLeaveBalance)
|
|
//_, _ = c.AddFunc("10 10 * * *", CreateLeaveBalance)
|
|
}
|
|
//添加补充年假
|
|
if config.GetConsumerService("EmployeeClientImpl") != nil {
|
|
_, _ = c.AddFunc("1 0 * * *", AddSupplementaryAnnualLeave)
|
|
}
|
|
/*if config.GetConsumerService("SeriesClientImpl") != nil && config.GetConsumerService("BrandClientImpl") != nil && config.GetConsumerService("CollectionsClientImpl") != nil {
|
|
_, _ = c.AddFunc("@every 5m", CheckSeries)
|
|
}*/
|
|
|
|
if err := DelayDeleteFileTask.AddTimerTask(c); err != nil {
|
|
panic("添加定时任务失败,错误:" + err.Error())
|
|
}
|
|
|
|
if config.GetConsumerService("AccountClientImpl") != nil && config.GetConsumerService("ApprovalClientImpl") != nil {
|
|
_, _ = c.AddFunc("* 9 * * *", SendPromotionMsg) // 23:50 执行
|
|
}
|
|
//更新打卡机用户状态
|
|
if config.GetConsumerService("AccountClientImpl") != nil {
|
|
_, _ = c.AddFunc("0 12 * * 1", UpdateClockUserStatus)
|
|
}
|
|
}
|
|
func UpdateClockUserStatus() {
|
|
fmt.Println("更新打卡机用户状态")
|
|
list, err := AccountProvider.ClockDeviceBatchList(context.Background(), &account.ClockBatchBindRequest{})
|
|
if err != nil {
|
|
fmt.Println("查询打卡机用户失败")
|
|
return
|
|
}
|
|
userList := []*account.ClockUserDeviceBatch{}
|
|
//整合数据
|
|
if len(list.Data) == 0 {
|
|
return
|
|
}
|
|
for _, i := range list.Data {
|
|
if i.WorkStatus == "notactive" {
|
|
continue
|
|
}
|
|
userList = append(userList, &account.ClockUserDeviceBatch{
|
|
UserId: i.UserId,
|
|
DeviceId: i.DeviceId,
|
|
JobNum: i.JobNum,
|
|
DeviceNum: i.DeviceNum,
|
|
DeviceName: i.DeviceName,
|
|
WorkStatus: i.WorkStatus,
|
|
})
|
|
}
|
|
data, clockDeviceBatchUntie := DeviceNumToJobNums(userList)
|
|
//下发数据
|
|
err = DelBatchDeviceAccount(data)
|
|
if err != nil {
|
|
fmt.Println("下发数据失败", err)
|
|
}
|
|
//删除关联
|
|
_, err = AccountProvider.ClockDeviceBatchUntie(context.Background(), clockDeviceBatchUntie)
|
|
if err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func DelBatchDeviceAccount(req map[string][]uint64) (err error) {
|
|
for deviceNum, jobNums := range req {
|
|
uuidObj := uuid.New()
|
|
stringSlice := make([]string, len(jobNums))
|
|
for i, num := range jobNums {
|
|
stringSlice[i] = strconv.FormatUint(num, 10)
|
|
}
|
|
synReq := turnstile.TurnStile{
|
|
Cmd: "to_device",
|
|
From: "Message1",
|
|
To: deviceNum,
|
|
Extra: uuidObj.String(),
|
|
Data: turnstile.TurnData{
|
|
Cmd: e.DelMultiUser,
|
|
UserIds: stringSlice,
|
|
UserType: 0,
|
|
},
|
|
}
|
|
err, _ = utils.IssueTheCardPunchData(synReq, deviceNum, uuidObj)
|
|
if err != nil {
|
|
return errors.New("下发数据失败")
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
func DeviceNumToJobNums(data []*account.ClockUserDeviceBatch) (deviceNum map[string][]uint64, ClockDeviceBatchUntie *account.ClockBatchBindRequest) {
|
|
deviceNumToJobNums := make(map[string][]uint64)
|
|
ClockDeviceBatchUntie = &account.ClockBatchBindRequest{}
|
|
for _, batch := range data {
|
|
ClockDeviceBatchUntie.UserId = append(ClockDeviceBatchUntie.UserId, batch.UserId)
|
|
if _, exists := deviceNumToJobNums[batch.DeviceNum]; exists {
|
|
deviceNumToJobNums[batch.DeviceNum] = append(deviceNumToJobNums[batch.DeviceNum], batch.UserId)
|
|
} else {
|
|
deviceNumToJobNums[batch.DeviceNum] = []uint64{batch.UserId}
|
|
}
|
|
}
|
|
// 提取所有设备号并去重
|
|
deviceIdSet := make(map[uint64]bool)
|
|
for _, batch := range data {
|
|
// 检查设备 ID 是否已存在,去重
|
|
if !deviceIdSet[batch.DeviceId] {
|
|
ClockDeviceBatchUntie.DeviceId = append(ClockDeviceBatchUntie.DeviceId, batch.DeviceId)
|
|
deviceIdSet[batch.DeviceId] = true
|
|
}
|
|
}
|
|
return deviceNumToJobNums, ClockDeviceBatchUntie
|
|
}
|
|
|
|
// AddSupplementaryAnnualLeave 添加补充年假
|
|
func AddSupplementaryAnnualLeave() {
|
|
if time.Now().Month() == time.January && time.Now().Day() == 1 {
|
|
return
|
|
}
|
|
WorkingConditionId, err := GrpcEmployeeProvider.SearchDictionaryList(context.Background(), &employee.SearchDictionaryRequest{
|
|
Name: "在职",
|
|
Tag: "workingCondition",
|
|
})
|
|
if err != nil || WorkingConditionId.WorkingCondition == nil {
|
|
fmt.Println("查询工作状态失败!")
|
|
return
|
|
}
|
|
currentMonthDay := time.Now().Format("01-02")
|
|
// 根据在职状态和入职日期模糊查询员工档案
|
|
employeeFileList, err := GrpcEmployeeProvider.FindEmployeeFileList(context.Background(), &employee.FindEmployeeFileListRequest{
|
|
WorkingConditionId: WorkingConditionId.WorkingCondition[0].Id,
|
|
BlurDateOfEntry: currentMonthDay,
|
|
})
|
|
if err != nil || len(employeeFileList.EmployeeFileList) == 0 {
|
|
fmt.Println("无人员需要添加假期余额")
|
|
return
|
|
}
|
|
for _, i := range employeeFileList.EmployeeFileList {
|
|
replenishment := supplementaryLeave(i.DateOfEntry)
|
|
if replenishment == 0 {
|
|
continue
|
|
}
|
|
fmt.Printf("用户 %v 的入职日期为 %v,需要补充年假 %v 天\n", i.UserId, i.DateOfEntry, replenishment)
|
|
_, err = GrpcOAImpl.ModifyTheLeaveBalance(context.Background(), &oa.ModifyTheLeaveBalanceReq{
|
|
StaffUid: i.UserId,
|
|
LeaveType: "annualLeave",
|
|
Movement: 1,
|
|
Year: int32(time.Now().Year()),
|
|
Days: float32(replenishment),
|
|
})
|
|
if err != nil {
|
|
fmt.Printf("更新用户 %v 的假期余额失败: %v\n", i.UserId, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// CreateLeaveBalance 创建假期余额
|
|
func CreateLeaveBalance() {
|
|
WorkingConditionId, err := GrpcEmployeeProvider.SearchDictionaryList(context.Background(), &employee.SearchDictionaryRequest{
|
|
Name: "在职",
|
|
Tag: "workingCondition",
|
|
})
|
|
if err != nil || WorkingConditionId.WorkingCondition == nil {
|
|
fmt.Println("查询工作状态失败!")
|
|
return
|
|
}
|
|
employeeFileList, err := GrpcEmployeeProvider.FindEmployeeFileList(context.Background(), &employee.FindEmployeeFileListRequest{
|
|
WorkingConditionId: WorkingConditionId.WorkingCondition[0].Id,
|
|
})
|
|
if err != nil || len(employeeFileList.EmployeeFileList) == 0 {
|
|
fmt.Println("定时创建假期余额失败!")
|
|
return
|
|
}
|
|
for _, i := range employeeFileList.EmployeeFileList {
|
|
departmentPosition := []*oa.LeaveBalancePosition{}
|
|
if i.DepartmentPostList != nil {
|
|
for _, s := range i.DepartmentPostList {
|
|
departmentPosition = append(departmentPosition, &oa.LeaveBalancePosition{
|
|
DepartmentUID: strconv.FormatUint(s.DepartmentId, 10),
|
|
DepartmentName: s.DepartmentName,
|
|
PositionUID: strconv.FormatUint(s.PostId, 10),
|
|
PositionName: s.PostName,
|
|
})
|
|
}
|
|
}
|
|
annualLeave := AnnualLeaveByYearsOfService(i.DateOfEntry)
|
|
_, err = GrpcOAImpl.SaveLeaveBalance(context.Background(), &oa.LeaveBalance{
|
|
StaffUID: i.UserId,
|
|
StaffNum: i.JobNumber,
|
|
StaffName: i.Name,
|
|
Year: int32(time.Now().Year()),
|
|
Positions: departmentPosition,
|
|
AnnualLeave: float32(annualLeave),
|
|
HasParentalLeave: 1,
|
|
HasNursingLeave: 1,
|
|
EmployeeFileId: i.Id,
|
|
})
|
|
}
|
|
return
|
|
}
|
|
|
|
// 补充年假天数
|
|
func supplementaryLeave(DateOfEntry string) int {
|
|
joinDate, err := time.Parse("2006-01-02", DateOfEntry)
|
|
if err != nil {
|
|
fmt.Println("入职日期解析错误:", err)
|
|
return 0
|
|
}
|
|
currentDate := time.Now()
|
|
yearsOfService := int(currentDate.Sub(joinDate).Hours() / 24 / 365)
|
|
|
|
//if !isEligibleForSupplementaryLeave(joinDate, currentDate) {
|
|
// return 0
|
|
//}
|
|
|
|
supplementaryLeaveDays := 0
|
|
switch yearsOfService {
|
|
case 1:
|
|
supplementaryLeaveDays = 5
|
|
case 5:
|
|
supplementaryLeaveDays = 2
|
|
case 10:
|
|
supplementaryLeaveDays = 3
|
|
case 20:
|
|
supplementaryLeaveDays = 5
|
|
default:
|
|
return 0
|
|
}
|
|
|
|
// 计算补充年假
|
|
endOfYear := time.Date(currentDate.Year(), 12, 31, 0, 0, 0, 0, currentDate.Location())
|
|
daysUntilEndOfYear := endOfYear.Sub(currentDate).Hours() / 24
|
|
supplementaryLeave := (daysUntilEndOfYear / 365) * float64(supplementaryLeaveDays)
|
|
return int(supplementaryLeave)
|
|
}
|
|
|
|
// 工龄年假天数
|
|
func AnnualLeaveByYearsOfService(DateOfEntry string) int {
|
|
joinDate, err := time.Parse("2006-01-02", DateOfEntry)
|
|
if err != nil {
|
|
fmt.Println("入职日期解析错误:", err)
|
|
return 0
|
|
}
|
|
currentDate := time.Now()
|
|
yearsOfService := int(currentDate.Sub(joinDate).Hours() / 24 / 365)
|
|
switch {
|
|
case yearsOfService < 1:
|
|
return 0
|
|
case yearsOfService < 5:
|
|
return 5
|
|
case yearsOfService < 10:
|
|
return 7
|
|
case yearsOfService < 20:
|
|
return 10
|
|
default:
|
|
return 15
|
|
}
|
|
}
|
|
|
|
// 检查是否符合补充年假的条件
|
|
func isEligibleForSupplementaryLeave(joinDate, currentDate time.Time) bool {
|
|
yearsOfService := int(currentDate.Sub(joinDate).Hours() / 24 / 365)
|
|
anniversaryDate := joinDate.AddDate(yearsOfService, 0, 0)
|
|
return currentDate.Equal(anniversaryDate)
|
|
}
|
|
|
|
func UpdateAttendanceRegularly() {
|
|
_, err := GrpcEmployeeProvider.UpdateAttendanceRegularly(context.Background(), &employee.EmptyStructure{})
|
|
if err != nil {
|
|
fmt.Println("定时更新考勤组失败!")
|
|
return
|
|
}
|
|
return
|
|
}
|
|
func UpdateWorkingStatus() {
|
|
_, err := GrpcEmployeeProvider.UpdateWorkingStatus(context.Background(), &employee.EmptyStructure{})
|
|
if err != nil {
|
|
fmt.Println("定时更新员工工作状态失败!")
|
|
return
|
|
}
|
|
return
|
|
}
|
|
func CreateAReminderMessage() {
|
|
_, err := GrpcEmployeeProvider.CreateAReminderMessage(context.Background(), &employee.IdUnifiedReturn{})
|
|
if err != nil {
|
|
fmt.Println("创建到期消息提醒失败!")
|
|
return
|
|
}
|
|
fmt.Println("----------------创建到期消息提醒成功-------------------")
|
|
return
|
|
}
|
|
func RebootClockDevice() {
|
|
var batch account.ClockBatchBindRequest
|
|
devRes, err := AccountProvider.ClockDeviceBatchList(context.Background(), &batch) //获取设备列表
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, i := range devRes.Data {
|
|
uuidObj := uuid.New()
|
|
fmt.Println(uuidObj.String())
|
|
synReq := turnstile.TurnStile{
|
|
Cmd: "to_device",
|
|
From: "Message1",
|
|
To: i.DeviceNum,
|
|
Extra: uuidObj.String(),
|
|
Data: turnstile.TurnData{
|
|
Cmd: e.Reboot,
|
|
},
|
|
}
|
|
err, _ := utils.IssueTheCardPunchData(synReq, i.DeviceNum, uuidObj)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func SendAReportToBoss() {
|
|
now := time.Now()
|
|
weekday := now.Weekday()
|
|
lastMonday := now.AddDate(0, 0, -int(weekday)+1-6)
|
|
lastSunday := now.AddDate(0, 0, -int(weekday)+7-6)
|
|
host := ""
|
|
if config1.Env == "prod" {
|
|
host = "https://sale.fontree.cn"
|
|
} else {
|
|
host = "https://sellertest.szjixun.cn"
|
|
}
|
|
lastStart := lastMonday.Format("2006-01-02")
|
|
lastEnd := lastSunday.Format("2006-01-02")
|
|
telList, err := OrderProvider.GetSmsConfig(context.Background(), &order.SmsConfigRequest{
|
|
Position: "boss",
|
|
})
|
|
if err != nil || len(telList.SmsConfig) == 0 {
|
|
fmt.Println("获取手机号失败!")
|
|
return
|
|
}
|
|
for _, i := range telList.SmsConfig {
|
|
infoUrl := fmt.Sprintf("%v/#/pages/examine/examine?startDate=%v&endDate=%v&uid=%v&", host, lastStart, lastEnd, i.Id)
|
|
url := lastStart + "||" + lastEnd + "||" + infoUrl
|
|
_, err1 := AccountProvider.SendExCustomMsg(context.Background(), &account.SendCustomMsgRequest{
|
|
TelNum: i.TelNum,
|
|
Url: url,
|
|
MId: 145217, //模板Id
|
|
SigNo: 159789, //签名id
|
|
})
|
|
if err1 != nil {
|
|
fmt.Println("短信发送失败!")
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CheckCopyright 检验版权文件
|
|
func CheckCopyright() {
|
|
logger.Error("MoveCopyrightFile start", time.Now().Format("2006-01-02 15:04:05"))
|
|
files, err := os.ReadDir(model.CopyrightDir)
|
|
if err != nil {
|
|
logger.Error("MoveCopyrightFile err", err)
|
|
return
|
|
}
|
|
//utils.CheckDirPath(model.CopyrightDir+"/old", true)
|
|
var lock sync.RWMutex
|
|
lock.Lock()
|
|
defer lock.Unlock()
|
|
for _, v := range files {
|
|
if !v.IsDir() {
|
|
if path.Ext(v.Name()) == ".psb" {
|
|
var req artwork.UpdateCrHashByTfnumRequest
|
|
var temp artwork.UpdateCrHashByTfnumRequest_Info
|
|
filePath := model.CopyrightDir + "/" + v.Name()
|
|
temp.Tfnum = strings.TrimSuffix(v.Name(), path.Ext(v.Name()))
|
|
temp.CopyrightHash, _ = utils.GenerateSHA256Hash(filePath)
|
|
if temp.Tfnum != "" && temp.CopyrightHash != "" {
|
|
req.Data = append(req.Data, &temp)
|
|
}
|
|
_, err = GrpcArtworkImpl.UpdateCrHashByTfnum(context.Background(), &req)
|
|
if err != nil {
|
|
logger.Errorf("GrpcArtworkImpl UpdateCopyrightHash err", err)
|
|
_ = os.Rename(filePath, filePath+"_err")
|
|
return
|
|
}
|
|
_ = os.Rename(filePath, filePath+"_use")
|
|
logger.Error("MoveCopyrightFile end", &temp)
|
|
}
|
|
}
|
|
}
|
|
//if len(req.Data) > 0 {
|
|
// _, err = GrpcArtworkImpl.UpdateCrHashByTfnum(context.Background(), &req)
|
|
// if err != nil {
|
|
// logger.Errorf("GrpcArtworkImpl UpdateCopyrightHash err", err)
|
|
// return
|
|
// }
|
|
//}
|
|
}
|
|
|
|
// CheckSeries 检测系列
|
|
func CheckSeries() {
|
|
var req backendSeries.CheckSeriesReq
|
|
resp, err := GrpcBackendSeriesImpl.CheckSeries(context.Background(), &req)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return
|
|
}
|
|
if len(resp.Data) > 0 {
|
|
// 请求brand
|
|
var brandReq shopbrand.BrandListreq
|
|
|
|
for _, v := range resp.Data {
|
|
brandReq.BrandUid = append(brandReq.BrandUid, v.BrandId)
|
|
}
|
|
brandList, err := GrpcShopBrandImpl.BrandList(context.Background(), &brandReq)
|
|
logger.Info("brandList CheckSeries", brandList, "ntfReq", brandList.Data)
|
|
if err != nil {
|
|
logger.Error("brandList err", err)
|
|
return
|
|
}
|
|
var brandDataMap map[string]shopbrand.BrandListres_Info = map[string]shopbrand.BrandListres_Info{}
|
|
if len(brandList.Data) > 0 {
|
|
for _, v := range brandList.Data {
|
|
brandDataMap[v.BrandUid] = shopbrand.BrandListres_Info{
|
|
BrandUid: v.BrandUid,
|
|
Address: v.Address,
|
|
}
|
|
}
|
|
}
|
|
//得到hash 请求藏品服,上链
|
|
var ntfReq collections.StoreNFTList
|
|
for _, v := range resp.Data {
|
|
var ntfInfo collections.StoreNFTInfo
|
|
ntfInfo.SeriesUID = v.SeriesUuid
|
|
ntfInfo.BrandHash = brandDataMap[v.BrandId].Address
|
|
ntfReq.NFT = append(ntfReq.NFT, &ntfInfo)
|
|
}
|
|
ntfResp, err := GrpcCollectionImpl.StoreNFT(context.Background(), &ntfReq)
|
|
logger.Info("ntfResp CheckSeries", ntfResp, "ntfReq", ntfReq.NFT)
|
|
if err != nil {
|
|
logger.Errorf("HandShelf StoreNFT err", err)
|
|
err = errors.New(e.GetMsg(e.ErrorStoreNTF))
|
|
return
|
|
}
|
|
if len(ntfResp.SeriesUID) == len(ntfReq.NFT) {
|
|
return
|
|
}
|
|
failSeriesUuid := make(map[string]struct{}, len(ntfResp.SeriesUID))
|
|
if len(ntfResp.SeriesUID) > 0 {
|
|
for _, seriesUuid := range ntfResp.SeriesUID {
|
|
failSeriesUuid[seriesUuid] = struct{}{}
|
|
}
|
|
}
|
|
for _, v := range ntfReq.NFT {
|
|
_, ok := failSeriesUuid[v.SeriesUID]
|
|
if !ok {
|
|
var seriesReq backendSeries.UpdateSeriesChainReq
|
|
seriesReq.SeriesUuid = v.SeriesUID
|
|
seriesReq.ChainStatus = 1
|
|
_, _ = GrpcBackendSeriesImpl.UpdateSeriesChain(context.Background(), &seriesReq)
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|