package service import ( "bkb-seller/global" "bkb-seller/model" "bkb-seller/model/request" "bkb-seller/model/response" "bkb-seller/utils" "encoding/json" "errors" "fmt" "gorm.io/gorm" "math" "strings" "time" ) func GetMissionDetail(uuid string, id uint) (error, model.MissionDetail) { var ( err error result model.MissionDetail ) err = global.MG_DB.Model(&model.Mission{}). //Select("id,title,goods_id,goods_status,num,hire_type,hire_money,hire_ratio,claim_num,start_time,end_time,`status`"). Where("create_by = ? AND id = ?", uuid, id). Preload("Goods", func(db *gorm.DB) *gorm.DB { return db.Select("id,spu_no,title,title_eng,images,retail_price,price_min,price_max,stock,sales,online,created_at,updated_at") }).First(&result).Error if err != nil { return err, result } switch result.HireType { case 1: result.HireMoneyExpect = fmt.Sprintf("固定金额\n$%.2f/单", result.HireMoney) case 2: result.HireMoneyExpect = fmt.Sprintf("按%.f%%分佣", result.HireRatio) } //视频素材 if result.HasVideo == 1 { result.ReleaseCountry = GetSysDictDataLabel(model.ReleaseCountryCode, result.VideoCountryId) var channelNames []string for _, cid := range strings.Split(result.VideoChannelIds, ",") { vLabel := GetSysDictDataLabel(model.ReleaseChannelCode, cid) channelNames = append(channelNames, vLabel) } result.ReleaseChannels = strings.Join(channelNames, "/") } return nil, result } func GetMissionList(uuid string, info request.SearchMission) (err error, list interface{}, total int64) { limit := info.PageSize offset := info.PageSize * (info.Page - 1) db := global.MG_DB.Model(&model.Mission{}).Where("create_by = ?", uuid) if info.Title != "" { db = db.Where("title LIKE ?", "%"+info.Title+"%") } if info.Status != 0 { db = db.Where("status = ?", info.Status) } if info.MissionTime != "" { var tmpT time.Time tmpT, err = time.ParseInLocation(utils.DateFormat, info.MissionTime, time.UTC) if err != nil { err = errors.New("search mission time format error") return err, nil, 0 } db = db.Where("DATE_FORMAT(start_time,'%Y-%m-%d') <= ? AND end_time >= ?", tmpT, tmpT) } err = db.Count(&total).Error var res []model.MissionDetail err = db.Select("id,title,goods_id,goods_status,num,hire_type,hire_money,hire_ratio,claim_num,start_time,end_time,`status`,has_video,video_channel_ids,video_country_id,claim_days,video_url,description,has_sample,sample_num"). Preload("Goods", func(db *gorm.DB) *gorm.DB { return db.Select("id,spu_no,title,title_eng,images,retail_price,price_min,price_max,stock,sales,online,created_at,updated_at") }).Order("id DESC").Limit(limit).Offset(offset).Find(&res).Error if err != nil { return err, nil, 0 } for i := 0; i < len(res); i++ { //查询订单数 res[i].OrderNum = GetMissionOrderCount("", res[i].ID) switch res[i].HireType { case 1: res[i].HireMoneyExpect = fmt.Sprintf("固定金额\n$%.2f/单", res[i].HireMoney) case 2: res[i].HireMoneyExpect = fmt.Sprintf("按%.f%%分佣", res[i].HireRatio) } //发布国家 if res[i].HasVideo == 1 { res[i].ReleaseCountry = GetSysDictDataLabel(model.ReleaseCountryCode, res[i].VideoCountryId) var channelNames []string for _, cid := range strings.Split(res[i].VideoChannelIds, ",") { vLabel := GetSysDictDataLabel(model.ReleaseChannelCode, cid) channelNames = append(channelNames, vLabel) } res[i].ReleaseChannels = strings.Join(channelNames, "/") } } return err, res, total } func CreateMission(uuid string, storeNo string, info request.CreateMission) (err error, id uint) { var ( goods model.TbGoods mission model.Mission ) //判断商品可用性 err = global.MG_DB.Model(&model.TbGoods{}).Where("store_no = ? AND id = ?", storeNo, info.GoodsId).First(&goods).Error if err != nil { return errors.New("未找到商品"), 0 } mission.Title = info.Title mission.StoreNo = storeNo mission.GoodsId = info.GoodsId if goods.Online == "off" || goods.Stock <= 0 { return errors.New("商品已下架或库存为0"), 0 } if goods.Online == "on" { mission.GoodsStatus = 1 } else { mission.GoodsStatus = 2 } mission.Num = info.Num mission.HireType = info.HireType mission.ClaimDays = info.ClaimDays mission.Description = info.Description mission.ClaimDemands = info.ClaimDemands if mission.HireType == 1 { //固定佣金 mission.HireMoney = info.HireMoney mission.ClaimStock = info.ClaimStock mission.FundLock = math.Ceil((float64(info.ClaimStock)*info.HireMoney)*100) / 100 } else { //比例佣金 mission.HireRatio = info.HireRatio } //样品信息 mission.HasSample = info.HasSample if mission.HasSample == 1 { mission.SampleNum = info.SampleNum } //视频素材 mission.HasVideo = info.HasVideo if mission.HasVideo == 1 { mission.VideoUrl = info.VideoUrl } mission.VideoCountryId = info.VideoCountryId mission.VideoChannelIds = info.VideoChannelIds mission.CreateBy = uuid var tmpS, tmpE time.Time tmpS, err = time.Parse(time.RFC3339, info.StartTimeUnix) tx := global.MG_DB.Begin() if err != nil { tx.Rollback() //err = errors.New("start time format error") err = errors.New("任务起始时间格式错误") return err, 0 } now := time.Now() if tmpS.Before(now) { //若开始时间< 当前时间 则 任务状态未进行中 mission.Status = 2 } else { mission.Status = 1 } mission.StartTime = &tmpS tmpE, err = time.Parse(time.RFC3339, info.EndTimeUnix) if err != nil { tx.Rollback() //err = errors.New("end time format error") err = errors.New("任务结束时间格式错误") return err, 0 } //判断时间可取 if tmpE.Unix() < now.Unix() { tx.Rollback() //err = errors.New("end time need to be later than current time") err = errors.New("任务结束时间须大于当前时间") return err, 0 } mission.EndTime = &tmpE err = tx.Create(&mission).Error if err != nil { tx.Rollback() return err, 0 } if mission.HireType == 1 { // 固定佣金 err = walletFundLock(tx, &request.FundLock{Appid: mission.Appid, UserID: mission.StoreNo, Amount: mission.FundLock}) if err != nil { tx.Rollback() return err, 0 } } tx.Commit() go func() { var now = time.Now() //if mission.StartTime.Unix() >= now.Unix() { if !mission.StartTime.Before(now) { difference := mission.StartTime.Sub(now).Seconds() _, err = global.MG_REDIS.Set(fmt.Sprintf("mission_start_%v", mission.ID), mission.ID, time.Duration(int64(difference))*time.Second).Result() } else { difference := mission.EndTime.Sub(now).Seconds() _, err = global.MG_REDIS.Set(fmt.Sprintf("mission_end_%v", mission.ID), mission.ID, time.Duration(int64(difference))*time.Second).Result() } //if mission.StartTime.Unix() < now.Unix() && mission.EndTime.Unix() >= now.Unix() { // difference := mission.EndTime.Sub(now).Seconds() // _, err = global.MG_REDIS.Set(fmt.Sprintf("mission_end_%v", mission.ID), mission.ID, time.Duration(int64(difference))*time.Second).Result() // return //} }() return nil, mission.ID } func UpdateMission(storeNo string, info request.UpdateMission) (err error, id uint) { //待开始的任务可以编辑 var ( goods model.TbGoods mission model.Mission missionBak model.Mission ) //判断任务信息 err = global.MG_DB.Model(&model.Mission{}).Where("store_no = ? AND id = ?", storeNo, info.ID).First(&missionBak).Error if err != nil { return errors.New("未找到任务"), 0 } if missionBak.Status != 1 { return errors.New("该状态不可修改"), 0 } //判断商品可用性 err = global.MG_DB.Model(&model.TbGoods{}).Where("store_no = ? AND id = ?", storeNo, info.GoodsId).First(&goods).Error if err != nil { return errors.New("未找到商品"), 0 } mission.Title = info.Title mission.GoodsId = info.GoodsId if goods.Online == "off" || goods.Stock <= 0 { return errors.New("商品已下架或库存为0"), 0 } if goods.Online == "on" { mission.GoodsStatus = 1 } else { mission.GoodsStatus = 2 } mission.Num = info.Num mission.HireType = info.HireType mission.ClaimDays = info.ClaimDays mission.Description = info.Description mission.ClaimDemands = info.ClaimDemands // TODO 任务佣金类型应该不可以修改?编辑前领取状态、数量等判断 if mission.HireType == 1 { //固定佣金 mission.HireMoney = info.HireMoney mission.ClaimStock = info.ClaimStock } else { //比例佣金 mission.HireRatio = info.HireRatio } //样品信息 mission.HasSample = info.HasSample if mission.HasSample == 1 { mission.SampleNum = info.SampleNum } //视频素材 mission.HasVideo = info.HasVideo if mission.HasVideo == 1 { mission.VideoUrl = info.VideoUrl } mission.VideoCountryId = info.VideoCountryId mission.VideoChannelIds = info.VideoChannelIds if info.StartTimeUnix != "" { var tmpS, tmpE time.Time tmpS, err = time.Parse(time.RFC3339, info.StartTimeUnix) if err != nil { //err = errors.New("start time format error") err = errors.New("任务起始时间格式错误") return err, 0 } now := time.Now() if tmpS.Before(now) { //若开始时间< 当前时间 则 任务状态未进行中 mission.Status = 2 } else { mission.Status = 1 } mission.StartTime = &tmpS tmpE, err = time.Parse(time.RFC3339, info.EndTimeUnix) if err != nil { //err = errors.New("end time format error") err = errors.New("任务结束时间格式错误") return err, 0 } //判断时间可取 if tmpE.Unix() < now.Unix() { //err = errors.New("end time need to be later than current time") err = errors.New("任务结束时间须大于当前时间") return err, 0 } mission.EndTime = &tmpE } tx := global.MG_DB.Begin() err = tx.Model(&model.Mission{}).Where("store_no = ? AND id = ?", storeNo, info.ID).Updates(&mission).Error if err != nil { tx.Rollback() return err, 0 } if mission.HireType == 1 { err = updateWalletFundLock(tx, &request.FundLock{Appid: mission.Appid, UserID: mission.StoreNo, Amount: mission.FundLock}) if err != nil { tx.Rollback() return err, 0 } } tx.Commit() go func() { if mission.StartTime.IsZero() { return } var now = time.Now() //if mission.StartTime.Unix() >= now.Unix() { if !mission.StartTime.Before(now) { difference := mission.StartTime.Sub(now).Seconds() _, err = global.MG_REDIS.Set(fmt.Sprintf("mission_start_%v", mission.ID), mission.ID, time.Duration(int64(difference))*time.Second).Result() } else { difference := mission.EndTime.Sub(now).Seconds() _, err = global.MG_REDIS.Set(fmt.Sprintf("mission_end_%v", mission.ID), mission.ID, time.Duration(int64(difference))*time.Second).Result() } //if mission.StartTime.Unix() < now.Unix() && mission.EndTime.Unix() >= now.Unix() { // difference := mission.EndTime.Sub(now).Seconds() // _, err = global.MG_REDIS.Set(fmt.Sprintf("mission_end_%v", mission.ID), mission.ID, time.Duration(int64(difference))*time.Second).Result() // return //} }() return nil, info.ID } func StopMission(uuid string, info request.StopMission) (err error) { var ( mission model.Mission checkStop, missionStop model.MissionStop ) err = global.MG_DB.Model(&model.Mission{}).Where("id = ? AND create_by = ?", info.ID, uuid).First(&mission).Error if errors.Is(err, gorm.ErrRecordNotFound) { return gorm.ErrRecordNotFound } missionStop = model.MissionStop{ Remark: info.Remark, Status: 1, MissionId: info.ID, CreateBy: uuid, } tx := global.MG_DB.Begin() switch mission.Status { case 1: err = global.MG_DB.Model(&model.Mission{}).Where("id = ? AND create_by = ?", info.ID, uuid).Update("status", 3).Update("end_time", time.Now()).Error if err != nil { tx.Rollback() return err } //清除任务定时 _, _ = global.MG_REDIS.Del(fmt.Sprintf("mission_start_%v", info.ID), fmt.Sprintf("mission_stop_%v", info.ID)).Result() missionStop.Status = 2 case 2: missionStop.Status = 1 default: tx.Rollback() return errors.New("任务已结束") } err = global.MG_DB.Model(&model.MissionStop{}).Where("mission_id = ? and status = 1", info.ID).First(&checkStop).Error if !errors.Is(err, gorm.ErrRecordNotFound) { tx.Rollback() return errors.New("不能重复提交") } err = global.MG_DB.Model(&model.MissionStop{}).Create(&missionStop).Error if err != nil { tx.Rollback() return errors.New("创建结束任务失败") } tx.Commit() return err } func BatchDeleteMission(uuid string, info request.IdsReq) (err error) { return nil } func GetMissionClaimList(info request.SearchMissionClaim) (err error, list []model.MissionClaimDetail, total int64) { limit := info.PageSize offset := info.PageSize * (info.Page - 1) db := global.MG_DB.Model(&model.MissionClaim{}). Joins("INNER JOIN mission ON mission.id = mission_claim.mission_id"). Where("mission.create_by = ?", info.CreateBy) if info.MissionId != 0 { db = db.Where("mission.id = ?", info.MissionId) } if info.Status != 0 { db = db.Where("mission_claim.`status` = ?", info.Status) } if info.Uuid != "" { db = db.Where("mission_claim.create_by = ?", info.Uuid) } err = db.Count(&total).Error var res []model.MissionClaimDetail err = db.Select("mission_claim.id,mission_claim.mission_id,mission_claim.claim_no,mission_claim.achieve_num,mission_claim.`status`,mission_claim.create_by,mission_claim.created_at,mission_claim.updated_at"). Preload("Influencer", func(db *gorm.DB) *gorm.DB { return db.Select("uuid,nick_name,phone") }).Preload("Works").Limit(limit).Offset(offset).Find(&res).Error if err != nil { return err, nil, 0 } return err, res, total } func StartMissionTiming(id uint) error { err := global.MG_DB.Model(&model.Mission{}).Where("id = ?", id).UpdateColumn("status", 2).Error if err != nil { return err } var mission model.Mission err = global.MG_DB.Model(&model.Mission{}).Where("id = ?", id).First(&mission).Error if err != nil { return err } now := time.Now().UTC() if mission.EndTime.Unix() >= now.Unix() { difference := mission.EndTime.Sub(now).Seconds() _, err = global.MG_REDIS.Set(fmt.Sprintf("mission_end_%v", mission.ID), mission.ID, time.Duration(int64(difference))*time.Second).Result() } return nil } func EndMissionTiming(id uint) error { return global.MG_DB.Model(&model.Mission{}).Where("id = ?", id).UpdateColumn("status", 3).Error } func GetMissionClaimOrder(uuid string, orderId string) (error, model.MissionClaimOrderDetail) { var ( err error result model.MissionClaimOrderDetail ) err = global.MG_DB.Model(&model.MissionClaimOrder{}). Joins("INNER JOIN mission_claim ON mission_claim.id = mission_claim_order.mission_claim_id"). Joins("INNER JOIN mission ON mission.id = mission_claim.mission_id"). Where("mission.create_by = ? AND mission_claim_order.order_id = ?", uuid, orderId). Select("mission_claim_order.*").Preload("Goods").Preload("Address"). Preload("MissionClaim", func(db *gorm.DB) *gorm.DB { return db.Select("id,mission_id,claim_no,achieve_num,`status`,create_by,created_at,updated_at") }).Preload("MissionClaim.Influencer", func(db *gorm.DB) *gorm.DB { return db.Select("uuid,nick_name,phone") }).First(&result).Error if err != nil { return err, result } return nil, result } func GetMissionClaimOrderList(uuid string, info request.SearchMissionClaimOrder) (err error, list interface{}, total int64) { limit := info.PageSize offset := info.PageSize * (info.Page - 1) db := global.MG_DB.Model(&model.MissionClaimOrder{}).Joins("INNER JOIN mission_claim ON mission_claim.id = mission_claim_order.mission_claim_id"). Joins("INNER JOIN mission ON mission.id = mission_claim.mission_id").Where("mission.create_by = ?", uuid) if info.OrderID != "" { db = db.Where("mission_claim_order.order_id = ?", info.OrderID) } if info.Status != 0 { db = db.Where("mission_claim_order.`status` = ?", info.Status) } if info.SpuNo != "" { db = db.Where("mission_claim_order.spu_no = ?", info.SpuNo) } if info.AddressName != "" || info.AddressPhone != "" { db = db.Joins("INNER JOIN mission_claim_address ON mission_claim_address.mission_claim_id = mission_claim.id") if info.AddressName != "" { name := "%" + info.AddressName + "%" db = db.Where("CONCAT(mission_claim_address.first_name,mission_claim_address.last_name) LIKE ? OR CONCAT(mission_claim_address.first_name,' ',mission_claim_address.last_name) LIKE ?", name, name) } if info.AddressPhone != "" { db = db.Where("mission_claim_address.phone LIKE ?", "%"+info.AddressPhone+"%") } } if info.OrderTimeStart != "" { var tmpT time.Time tmpT, err = time.ParseInLocation(utils.DateTimeFormat, info.OrderTimeStart, time.UTC) if err != nil { err = errors.New("search mission time format error") return err, nil, 0 } db = db.Where("mission_claim_order.created_at >= ?", tmpT) } if info.OrderTimeEnd != "" { var tmpT time.Time tmpT, err = time.ParseInLocation(utils.DateTimeFormat, info.OrderTimeEnd, time.UTC) if err != nil { err = errors.New("search mission time format error") return err, nil, 0 } //tmpT = tmpT.AddDate(0, 0, 1) db = db.Where("mission_claim_order.created_at <= ?", tmpT) } err = db.Count(&total).Error var res []model.MissionClaimOrderDetail err = db.Select("mission_claim_order.*").Preload("Goods").Preload("Address"). Preload("MissionClaim", func(db *gorm.DB) *gorm.DB { return db.Select("id,mission_id,claim_no,achieve_num,`status`,create_by,created_at,updated_at") }).Preload("MissionClaim.Influencer", func(db *gorm.DB) *gorm.DB { return db.Select("uuid,nick_name,phone") }).Order("mission_claim_order.id DESC").Limit(limit).Offset(offset).Find(&res).Error if err != nil { return err, nil, 0 } return err, res, total } func SendMissionClaimOrder(uuid string, info request.MissionClaimOrderSend) (err error) { var ( order model.MissionClaimOrder courier model.Courier ) // 校验物流信息 err = global.MG_DB.Model(&model.Courier{}).Where("`name` = ?", info.Courier).First(&courier).Error if err != nil { return errors.New("courier company name is failed or not currently supported") } err = global.MG_DB.Model(&model.MissionClaimOrder{}).Joins("INNER JOIN mission_claim ON mission_claim.id = mission_claim_order.mission_claim_id"). Joins("INNER JOIN mission ON mission.id = mission_claim.mission_id").Where("mission.create_by = ? AND mission_claim_order.order_id = ?", uuid, info.OrderID). Select("mission_claim_order.*").First(&order).Error if err != nil { err = errors.New("不可进行此操作") return } var trackId uint trackId, err = CreateTrack(info.CourierNumber, courier.Code) if err != nil { fmt.Println("提交物流单号:", err.Error()) return errors.New("物流单号有误,发货失败") } tx := global.MG_DB.Begin() err = tx.Model(&model.MissionClaimOrder{}).Where("order_id = ?", info.OrderID). UpdateColumns(map[string]interface{}{"status": "3", "courier": info.Courier, "courier_url": info.CourierUrl, "courier_number": info.CourierNumber, "send_time": utils.GetNow(), "track_id": trackId}).Error if err != nil { tx.Rollback() return } err = tx.Model(&model.MissionClaim{}).Where("id = ? AND status = 1", order.MissionClaimId).UpdateColumn("status", "2").Error if err != nil { tx.Rollback() return } tx.Commit() { var trackId uint trackId, err = CreateTrack(info.CourierNumber, courier.Code) if err != nil { fmt.Println("提交物流单号:", err.Error()) return nil } err = global.MG_DB.Model(&model.MissionClaimOrder{}).Where("order_id = ?", order.OrderID).Update("track_id", trackId).Error if err != nil { return nil } } return } // 任务视频审核列表 func GetMissionClaimVideoList(info request.SearchMissionClaimVideo, uuid string) (err error, list []response.MissionClaimVideo, total int64) { limit := info.PageSize offset := info.PageSize * (info.Page - 1) db := global.MG_DB.Model(&model.MissionClaimVideo{}). Joins("INNER JOIN mission_claim ON mission_claim.id = mission_claim_video.mission_claim_id"). Joins("INNER JOIN mission ON mission.id = mission_claim.mission_id"). Where("mission_claim_video.source_type = 1"). //固定费用上传任务 Where("mission.create_by = ?", uuid) if info.MissionId != 0 { db = db.Where("mission.id = ?", info.MissionId) } if info.MissionTitle != "" { db = db.Where("mission.title like ?", "%"+info.MissionTitle+"%") } if info.Status != 0 { db = db.Where("mission_claim_video.`status` = ?", info.Status) } if info.Uuid != "" { db = db.Where("mission_claim.create_by = ?", info.Uuid) } if info.RewardStatus != 0 { db = db.Where("mission_claim_video.`reward_status` = ?", info.RewardStatus) } err = db.Count(&total).Error var res []model.MissionClaimVideoDetail err = db.Select("mission_claim_video.id,mission_claim_video.mission_claim_id,mission_claim_video.`status`,mission_claim_video.video_url,mission_claim_video.remark,mission_claim_video.created_at,mission_claim_video.updated_at,mission_claim_video.reward_status"). Preload("MissionClaim", func(db *gorm.DB) *gorm.DB { return db.Select("id,mission_id,claim_no,achieve_num,`status`,created_at,updated_at,expire_at,create_by"). Preload("Mission", func(db *gorm.DB) *gorm.DB { return db.Select("id,title,goods_id,goods_status,num,hire_type,hire_money,hire_ratio,start_time,end_time,`status`,create_by,claim_days"). Preload("Goods", func(db *gorm.DB) *gorm.DB { return db.Select("id,spu_no,title,title_eng,images,tags,retail_price,price_min,price_max").Unscoped() }) }). Preload("Influencer", func(db *gorm.DB) *gorm.DB { return db.Select("uuid,nick_name,phone") }) }).Limit(limit).Offset(offset).Find(&res).Error if err != nil { return err, nil, 0 } for i := range res { fmt.Println(res[i].MissionClaim.Influencer) vInfo := response.MissionClaimVideo{ MissionClaimVideo: res[i].MissionClaimVideo, MissionTitle: res[i].MissionClaim.Mission.Title, GoodsTitle: res[i].MissionClaim.Mission.Goods.Title, InfluencerUser: res[i].MissionClaim.Influencer, ClaimAt: res[i].MissionClaim.CreatedAt, ClaimDays: res[i].MissionClaim.Mission.ClaimDays, HireMoneyExpect: utils.FormatFloatToString(res[i].MissionClaim.Mission.HireMoney), MissionId: res[i].MissionClaim.MissionId, } list = append(list, vInfo) } return err, list, total } func DealMissionClaimVideoStatus(params request.StatusParamInt) (err error) { var ( claimVideo model.MissionClaimVideo ) err = global.MG_DB.Model(&model.MissionClaimVideo{}).Where("id = ?", params.ID).First(&claimVideo).Error if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("信息不存在") } if claimVideo.Status != 1 { return errors.New("当前状态不允许审核") } if params.Status != 2 && params.Status != 3 { return errors.New("修改状态不正确") } if params.Status == 3 && params.Remark == "" { return errors.New("请填写审核理由") } tx := global.MG_DB.Begin() claimVideo.Status = params.Status claimVideo.Remark = params.Remark claimVideo.RewardStatus = 1 // 奖励标记为未发放 err = tx.Model(&claimVideo).Where("id = ?", claimVideo.ID).Updates(claimVideo).Error if err != nil { tx.Rollback() return } if params.Status == 2 { // 审核通过 var mission model.Mission err = global.MG_DB.Model(&model.Mission{}).Where("id = ?", claimVideo.MissionId).First(&mission).Error if err != nil { tx.Rollback() err = errors.New("settle influencer wallet failed") return } if mission.HireType != 1 { tx.Rollback() err = errors.New("mission type is error") return } // 结算至网红钱包-在途佣金 var wallet model.Wallet err = tx.Model(&model.Wallet{}).Where("platform = 'influencer' AND user_id = ?", claimVideo.CreateBy). Updates(map[string]interface{}{"transit_balance": gorm.Expr("transit_balance + ?", mission.HireMoney)}).First(&wallet).Error if err != nil { tx.Rollback() err = errors.New("settle influencer wallet failed") return } } tx.Commit() return err } // 任务视频审核详情 func GetMissionClaimVideoDetail(id uint, uuid string) (err error, data response.MissionClaimVideoDetail) { var ( claimVideo model.MissionClaimVideo missionClaimDetail model.MissionClaimDetail influencerUser *model.InfluencerUserDesc ) err = global.MG_DB.Model(&model.MissionClaimVideo{}).Where("id = ?", id).First(&claimVideo).Error if errors.Is(err, gorm.ErrRecordNotFound) { return gorm.ErrRecordNotFound, data } db := global.MG_DB.Model(&model.MissionClaim{}). Joins("INNER JOIN mission ON mission.id = mission_claim.mission_id"). Where("mission.create_by = ?", uuid). Where("mission_claim.id = ?", claimVideo.MissionClaimId) err = db.Select("mission_claim.id,mission_id,mission_claim.claim_no,mission_claim.achieve_num,mission_claim.`status`,mission_claim.created_at,mission_claim.updated_at,mission_claim.expire_at,mission_claim.create_by"). Preload("Order", func(db *gorm.DB) *gorm.DB { return db.Select("order_id,mission_claim_id,`status`,courier,courier_url,courier_number,send_time"). Preload("OrderGoods", func(db *gorm.DB) *gorm.DB { return db.Select("order_id,price,sku_no,title,image,specs,id") }) }). Preload("Mission", func(db *gorm.DB) *gorm.DB { return db. Select("id,title,goods_id,goods_status,num,hire_type,hire_money,hire_ratio,start_time,end_time,`status`,create_by,claim_days,claim_num,claim_stock,has_video,video_url,video_channel_ids,video_country_id"). Preload("Goods", func(db *gorm.DB) *gorm.DB { return db.Select("id,spu_no,title,title_eng,images,tags,retail_price,price_min,price_max,tags,status").Unscoped() }) }).First(&missionClaimDetail).Error if err != nil { return err, data } err, influencerUser = GetInfluencerUserDetail(missionClaimDetail.CreateBy) data.InfluencerUser = *influencerUser data.ClaimVideo = claimVideo data.MissionClaim = response.MissionClaimInfo{ MissionId: missionClaimDetail.MissionId, Title: missionClaimDetail.Mission.Title, ClaimAt: missionClaimDetail.CreatedAt, HireType: missionClaimDetail.Mission.HireType, HireMoney: missionClaimDetail.Mission.HireMoney, HireRatio: missionClaimDetail.Mission.HireRatio, HireMoneyExpect: utils.FormatFloatToString(missionClaimDetail.Order.OrderGoods.Price), StartTime: missionClaimDetail.Mission.StartTime, EndTime: missionClaimDetail.Mission.EndTime, Status: missionClaimDetail.Status, ClaimNum: missionClaimDetail.Mission.ClaimNum, ClaimStock: missionClaimDetail.Mission.ClaimStock, OrderNum: missionClaimDetail.Mission.OrderNum, ClaimDays: missionClaimDetail.Mission.ClaimDays, ClaimDemands: missionClaimDetail.Mission.ClaimDemands, Description: missionClaimDetail.Mission.Description, Sample: missionClaimDetail.Mission.Sample, VideoMaterial: missionClaimDetail.Mission.VideoMaterial, ReleaseCountry: "", ReleaseChannels: "", } //发布国家 if data.MissionClaim.HasVideo == 1 { data.MissionClaim.ReleaseCountry = GetSysDictDataLabel(model.ReleaseCountryCode, data.MissionClaim.VideoCountryId) var channelNames []string for _, cid := range strings.Split(data.MissionClaim.VideoChannelIds, ",") { vLabel := GetSysDictDataLabel(model.ReleaseChannelCode, cid) channelNames = append(channelNames, vLabel) } data.MissionClaim.ReleaseChannels = strings.Join(channelNames, "/") } data.ClaimGoods = response.MissionClaimGoods{ GoodsId: missionClaimDetail.Mission.GoodsId, OrderId: missionClaimDetail.Order.OrderID, SpuNo: missionClaimDetail.Mission.Goods.SpuNo, Title: missionClaimDetail.Mission.Goods.Title, TitleEng: missionClaimDetail.Mission.Goods.TitleEng, Sales: 0.0, Sales30: 0.0, Status: missionClaimDetail.Mission.Goods.Status, Specs: missionClaimDetail.Order.OrderGoods.Specs, SkuNo: missionClaimDetail.Order.OrderGoods.SkuNo, Stock: missionClaimDetail.Mission.Goods.Stock, Price: missionClaimDetail.Order.OrderGoods.Price, Image: missionClaimDetail.Order.OrderGoods.Image, Tags: missionClaimDetail.Mission.Goods.Tags, } //查询销量 totalSales := GetMissionClaimSales(missionClaimDetail.ClaimNo, nil, nil) endTime, _ := time.Parse(utils.DateFormat, time.Now().Format(utils.DateFormat)) startTime := endTime.AddDate(0, 0, -29) sales30 := GetMissionClaimSales(missionClaimDetail.ClaimNo, &startTime, &endTime) data.ClaimGoods.Sales = totalSales.Sales data.ClaimGoods.Sales30 = sales30.Sales return err, data } // 获取任务所有网红信息 func GetAllMissionClaimInfluencers(params request.MissionInfluencers) (err error, res []model.MissionClaimInfluencer, total int64) { db := global.MG_DB.Model(&model.MissionClaim{}). Where("mission_claim.mission_id = ?", params.MissionId) if params.SalesType == 1 { db = db.Where("achieve_num > 0") } db = db.Select("mission_claim.id,mission_claim.mission_id,mission_claim.claim_no,mission_claim.achieve_num,mission_claim.`status`,mission_claim.created_at,mission_claim.updated_at,mission_claim.expire_at,mission_claim.create_by"). Preload("Video", func(db *gorm.DB) *gorm.DB { return db.Order("id desc").Limit(1) }).Preload("Influencer", func(db *gorm.DB) *gorm.DB { return db.Select("id,uuid,nick_name,phone,platform,tags") }) err = db.Count(&total).Error err = db.Order("mission_claim.id DESC").Find(&res).Error if err != nil { return } for i := 0; i < len(res); i++ { var ( platform interface{} ) if res[i].Influencer.Platform != "" { err = json.Unmarshal([]byte(res[i].Influencer.Platform), &platform) if err != nil { fmt.Println(err) } } res[i].Influencer.PlatformStr = platform } return } func SendVideoMissionReward(storeNo string, info request.IdReq) (err error) { var ( checkMission model.MissionClaim checkVideo model.MissionClaimVideo mission model.Mission ) err = global.MG_DB.Model(&model.MissionClaimVideo{}).Where("id = ?", info.ID).First(&checkVideo).Error if errors.Is(err, gorm.ErrRecordNotFound) { return err } if checkVideo.Status != 2 { err = errors.New("unexpected reward status") return err } if checkVideo.RewardStatus != 1 { err = errors.New("repeated reward distribution") return } err = global.MG_DB.Model(&model.MissionClaim{}).Where("id = ?", checkVideo.MissionClaimId).First(&checkMission).Error if errors.Is(err, gorm.ErrRecordNotFound) { return err } err = global.MG_DB.Model(&model.Mission{}).Where("id = ?", checkVideo.MissionId).First(&mission).Error if errors.Is(err, gorm.ErrRecordNotFound) { return err } if mission.HireType != 1 { err = errors.New("mission type is error") return } tx := global.MG_DB.Begin() // 扣除商家锁定营销账户 err = tx.Model(&model.Wallet{}).Where("platform = 'seller' AND user_id = ?", storeNo).UpdateColumn("fund_lock", gorm.Expr("fund_lock - ?", mission.HireMoney)).Error if err != nil { tx.Rollback() err = errors.New("settle seller wallet failed") return } err = tx.Model(&model.BillFund{}).Where("platform = 'seller' AND user_id = ? AND related_id = ?", storeNo, checkMission.ClaimNo).Update("status", 2).Error if err != nil { tx.Rollback() err = errors.New("settle seller bill_fund failed") return } err = tx.Model(&model.MissionClaimVideo{}).Where("id = ?", checkVideo.ID).UpdateColumn("reward_status", 2).Error if err != nil { tx.Rollback() err = errors.New("update video reward status failed") return } // 结算至网红钱包-余额 var wallet model.Wallet err = tx.Model(&model.Wallet{}).Where("platform = 'influencer' AND user_id = ?", checkVideo.CreateBy). Updates(map[string]interface{}{"balance": gorm.Expr("balance + ?", mission.HireMoney), "transit_balance": gorm.Expr("transit_balance - ?", mission.HireMoney)}).First(&wallet).Error if err != nil { tx.Rollback() err = errors.New("settle influencer wallet failed") return } // 创建任务结算账单 var bill model.Bill bill.UserID = checkVideo.CreateBy bill.Type = "1" bill.Title = "固定费用发放-完成任务" + mission.Title bill.Price = mission.HireMoney bill.Balance = wallet.Balance bill.Amount = 1 bill.Status = 2 bill.Receipt = 1 bill.Platform = "influencer" err = tx.Model(&model.Bill{}).Create(&bill).Error if err != nil { tx.Rollback() err = errors.New("create influencer mission settle bill failed") return } tx.Commit() calculateFinishMissionClaimStatistics(request.OrderStatistic{ ClaimNo: checkMission.ClaimNo, Reward: mission.HireMoney, }) return err } // 任务状态检查task func MissionStatusCheckTask() (err error) { var ( lastId uint pageSize int missionList []model.Mission ) pageSize = 10 lastId = 0 for { err = global.MG_DB.Model(&model.Mission{}).Where("id > ? and status in (?)", lastId, []int{1, 2}).Order("id asc").Limit(pageSize).Find(&missionList).Error if err != nil { return err } if len(missionList) == 0 { break } var now = time.Now() for _, m := range missionList { var tmpS, tmpE time.Time tmpS = *m.StartTime tmpE = *m.EndTime if tmpS.Before(now) && now.Before(tmpE) { //任务进行中 if m.Status == 1 { //fmt.Printf("start mission,id:%d,s:%s,e:%s\n",m.ID,m.StartTime,m.EndTime) _ = StartMissionTiming(m.ID) //清除任务定时 _, _ = global.MG_REDIS.Del(fmt.Sprintf("mission_start_%v", m.ID)).Result() } } else if tmpE.Before(now) { //fmt.Printf("end mission,id:%d,s:%s,e:%s\n",m.ID,m.StartTime,m.EndTime) //任务结束 _ = EndMissionTiming(m.ID) //清除任务定时 _, _ = global.MG_REDIS.Del(fmt.Sprintf("mission_stop_%v", m.ID)).Result() } lastId = m.ID } } return err }