You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

955 lines
33 KiB

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
}