Files
jx-callback/business/jxstore/cms/job.go
suyl e3be541ccd aa
2021-05-13 09:07:59 +08:00

2087 lines
76 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cms
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/tbunionapi"
"math"
"strings"
"sync"
"time"
"git.rosy.net.cn/jx-callback/business/jxstore/event"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"git.rosy.net.cn/baseapi/platformapi/txcloudapi"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/platformapi/jdeclpapi"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/jxstore/financial"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
const (
AcceptMaxCount = 2
CancelMaxCount = 5
waybillKgPrice = 200
mtwmMemberPrice = 1100
)
type JobTimer struct {
JobTimerMap map[int64]*time.Timer
JobAuditTimerMap map[int64]*time.Timer
s *sync.RWMutex
}
var (
JobTimers = &JobTimer{}
)
func init() {
JobTimerMap := make(map[int64]*time.Timer)
JobAuditTimerMap := make(map[int64]*time.Timer)
JobTimers.JobTimerMap = JobTimerMap
JobTimers.JobAuditTimerMap = JobAuditTimerMap
JobTimers.s = new(sync.RWMutex)
}
func PublishJob(ctx *jxcontext.Context, jobExt *model.JobExt) (errCode string, err error) {
var (
db = dao.GetDB()
job = &model.Job{}
finishedAt time.Time
DayTimeBegin, DayTimeEnd = jxutils.GetDayTime()
)
if data, err := json.Marshal(jobExt); err == nil {
json.Unmarshal(data, &job)
}
finishedAt = utils.Str2Time(jobExt.FinishedAtStr)
job.FinishedAt = &finishedAt
// 需根据任务类型做一些参数判断,比如门店商品链接,地址
if job.JobCategoryID != model.JobCategoryIDUnion {
if job.AvgPrice == 0 {
return errCode, fmt.Errorf("请输入单个任务奖励(保证)金额!")
}
}
switch job.JobCategoryID {
case model.JobCategoryIDwmtg:
if job.Address == "" {
return errCode, fmt.Errorf("外卖推广任务请输入门店地址!")
}
case model.JobCategoryIDOther:
case model.JobCategoryIDDropShipping:
if job.DropShippingAt == 0 {
return errCode, fmt.Errorf("一件代发任务请输入承诺x天内发货")
}
if job.DropShippingSkuPrice == 0 {
return errCode, fmt.Errorf("一件代发任务请输入商品价格!")
}
job.CashbackType = model.JobCashbackPrice
job.LimitCountType = model.JobLimitCountTypeNoLimit
job.JobLimitAt = 0
job.AuditLimitAt = 0
case model.JobCategoryIDUnion:
if job.UnionImg == "" || job.UnionQrcodePosition == "" {
return errCode, fmt.Errorf("联盟任务发布请输入分享的背景图和二维码图方位!")
}
default:
return errCode, fmt.Errorf("暂不支持的任务类型! %v", job.JobCategoryID)
}
// 需根据返现类型做一些参数判断
switch job.CashbackType {
case model.JobCashbackPercentage:
if job.Percentage <= 0 || job.Percentage > 100 {
return errCode, fmt.Errorf("返现比例请输入1-100之间的比例")
}
case model.JobCashbackPrice:
default:
return errCode, fmt.Errorf("暂不支持的返现类型! %v", job.CashbackType)
}
if job.Count <= 0 {
return errCode, fmt.Errorf("任务数量不能为0")
}
job.SurplusCount = job.Count
if job.UserID == "" {
return errCode, fmt.Errorf("任务发起人不能为空!")
}
var (
userBill *model.UserBill
)
if ctx.GetToken() != jxcontext.RsmDefultToken {
if ctx.GetUserID() != job.UserID {
return errCode, fmt.Errorf("用户信息已过期,请重新登录!")
}
//验证微信绑定
if err = auth2.CheckWeixinminiAuthBind(ctx.GetUserID()); err != nil {
return "", err
}
//发布任务要扣除任务总额的保证金,不够扣就要进行充值
userBill, _ = dao.GetUserBill(db, job.UserID, "")
if userBill == nil {
return errCode, fmt.Errorf("未查询到该用户的账单!")
}
job.TotalPrice = job.Count * job.AvgPrice
if userBill.AccountBalance < job.TotalPrice {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足!")
}
jobs, _ := dao.GetJobsNoPage(db, []string{job.UserID}, nil, nil, nil, DayTimeBegin, DayTimeEnd, 0, false)
if len(jobs) > 0 {
members, err := dao.GetUserMember(db, job.UserID, model.MemberTypeNormal)
if err != nil {
return errCode, err
}
if len(members) <= 0 {
return errCode, fmt.Errorf("非会员一天只能发布一起任务,请确认!")
}
}
if job.Address != "" && (job.Lng == 0 || job.Lat == 0) {
lng, lat, _ := api.AutonaviAPI.GetCoordinateFromAddressByPage(job.Address, job.JobCityCode)
if lng == 0 || lat == 0 {
return errCode, fmt.Errorf("请填写完整且正确的门店地址!")
}
job.Lng = jxutils.StandardCoordinate2Int(lng)
job.Lat = jxutils.StandardCoordinate2Int(lat)
}
}
if job.FinishedAt.Sub(time.Now()) <= 0 {
return errCode, fmt.Errorf("任务截止日期必须大于今天!")
}
if job2, _ := dao.GetJobWithTitle(db, job.Title); job2 != nil {
return errCode, fmt.Errorf("任务标题重复,请重新输入!")
}
if job.JobCityCode != model.JobCountrywideCode {
_, _, job.JobCityCode, err = getAddressInfoFromCoord(db, job.JobLng, job.JobLat)
}
dao.WrapAddIDCULDEntity(job, ctx.GetUserName())
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if err = dao.CreateEntityTx(txDB, job); err != nil {
dao.Rollback(db, txDB)
return
}
for _, v := range jobExt.JobSteps {
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
v.JobID = job.ID
err = dao.CreateEntityTx(txDB, v)
}
for _, v := range jobExt.JobImgs {
dao.WrapAddIDCULEntity(v, ctx.GetUserName())
v.JobID = job.ID
err = dao.CreateEntityTx(txDB, v)
}
if err != nil {
dao.Rollback(db, txDB)
return
}
//发布任务要扣除任务总额的保证金,不够扣就要进行充值
if err == nil && job.Status != model.JobStatusFailed && ctx.GetToken() != jxcontext.RsmDefultToken {
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeDeposit, job.TotalPrice, job.ID); err != nil {
dao.Rollback(db, txDB)
return
}
}
dao.Commit(db, txDB)
if ctx.GetToken() != jxcontext.RsmDefultToken {
content := new(strings.Builder)
content.WriteString("您的任务:")
content.WriteString(job.Title)
content.WriteString("。已发布成功,已扣除您的余额:")
content.WriteString(utils.Float64ToStr(jxutils.IntPrice2Standard(int64(job.TotalPrice))))
content.WriteString("元")
event.SendSysMessageSimple(content.String(), job.UserID)
}
return errCode, err
}
func CancelPublishJob(ctx *jxcontext.Context, jobID int) (err error) {
var (
db = dao.GetDB()
)
job := &model.Job{}
job.ID = jobID
err = dao.GetEntity(db, job)
if job.UserID == "" || job.Status == model.JobStatusFailed || job.Status == model.JobStatusOverdue || job.FinishedAt.Sub(time.Now()) <= 0 || job.SurplusCount <= 0 || job.LimitCountType <= 0 {
return fmt.Errorf("未找到该任务或该任务状态不正常,无法取消!")
}
//取消已发布的任务
userBill, err := dao.GetUserBill(db, job.UserID, "")
if userBill == nil {
return fmt.Errorf("未查询到该用户的账单!")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//如果是固定返现,退给任务发起人剩余数量*单价
//如果是比例返现,推给任务发起人任务总价-接取这个任务的用户实际返现的价格之和
var price int
if job.CashbackType == model.JobCashbackPrice {
price = job.SurplusCount * job.AvgPrice
} else {
if billIncomes, err := dao.GetBillIncome(db, jobID, 0); err == nil {
for _, v := range billIncomes {
price += v.IncomePrice
}
}
price = job.TotalPrice - price
}
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeJobCancelOverdue, price, jobID); err != nil {
dao.Rollback(db, txDB)
return
}
//3、任务状态被取消
job.Status = model.JobStatusFailed
// job.DeletedAt = time.Now()
if _, err = dao.UpdateEntityTx(txDB, job, "Status"); err != nil {
dao.Rollback(db, txDB)
return
}
dao.Commit(db, txDB)
content := new(strings.Builder)
content.WriteString("您的任务:")
content.WriteString(job.Title)
content.WriteString("。已过期或被取消,")
content.WriteString(utils.Float64ToStr(jxutils.IntPrice2Standard(int64(price))))
content.WriteString("元已返回您的余额中!")
event.SendSysMessageSimple(content.String(), job.UserID)
return err
}
func GetJobs(ctx *jxcontext.Context, userIDs []string, categoryIDs, statuss, vendorIDs, cityCodes []int, includeStep bool, fromTime, toTime string, lng, lat float64, span int, keyword string, sortType, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
var (
db = dao.GetDB()
userID = ctx.GetUserID()
_, _, cityCode, _ = getAddressInfoFromCoord(db, lng, lat)
)
if toTime != "" {
toTime = toTime + " 23:59:59"
}
pagedInfo, err = dao.GetJobs(db, userIDs, categoryIDs, statuss, vendorIDs, []int{model.JobTypeNormal}, cityCodes, includeStep, utils.Str2Time(fromTime), utils.Str2Time(toTime), lng, lat, cityCode, span, keyword, sortType, pageSize, offset)
//插入用户搜索关键词
if keyword != "" && ctx.GetToken() != jxcontext.RsmDefultToken {
if userSearchs, _ := dao.GetUserSearch(db, userID, keyword); len(userSearchs) > 0 {
userSearchs[0].Count++
userSearchs[0].UpdatedAt = time.Now()
dao.UpdateEntity(db, userSearchs[0], "Count", "UpdatedAt")
} else {
userSearch := &model.UserSearch{
UserID: userID,
Keyword: keyword,
}
dao.WrapAddIDCULEntity(userSearch, ctx.GetUserName())
dao.CreateEntity(db, userSearch)
}
}
return pagedInfo, err
}
func GetJobDetail(ctx *jxcontext.Context, jobID int, lng, lat float64) (job *dao.GetJobsResult, err error) {
var (
db = dao.GetDB()
)
job, err = dao.GetJobDetail(db, jobID)
if job.Lng != 0 && job.Lat != 0 {
job.Distance = jxutils.EarthDistance(lng, lat, jxutils.IntCoordinate2Standard(job.Lng), jxutils.IntCoordinate2Standard(job.Lat))
}
utils.CallFuncAsync(func() {
job2 := &model.Job{}
job2.ID = job.ID
dao.GetEntity(db, job2)
job2.BrowseCount++
dao.UpdateEntity(db, job2, "BrowseCount")
})
return job, err
}
func AcceptJob(ctx *jxcontext.Context, jobID, dropShippingDeliveryID, dropShippingCount int) (jobOrderID int64, errCode string, err error) {
var (
db = dao.GetDB()
userID = ctx.GetUserID()
num int
DayTimeBegin, DayTimeEnd = jxutils.GetDayTime()
WeekTimeBegin, WeekTimeEnd = jxutils.GetWeekTime()
)
job := &model.Job{}
job.ID = jobID
err = dao.GetEntity(db, job)
if job.UserID == "" || job.Status == model.JobStatusFailed || job.Status == model.JobStatusOverdue || job.FinishedAt.Sub(time.Now()) <= 0 || job.SurplusCount <= 0 || job.LimitCountType <= 0 {
if job.JobCategoryID == model.JobCategoryIDUnion {
return 0, errCode, fmt.Errorf("活动已结束,请等待下批次活动!")
} else {
return 0, errCode, fmt.Errorf("未找到该任务或该任务状态不正常,无法接单!")
}
}
// num, err = checkJobOrders(db, 0, "<= "+utils.Int2Str(model.JobOrderStatusAccept), userID, utils.ZeroTimeValue, utils.ZeroTimeValue)
// if num >= AcceptMaxCount {
// return 0, errCode, fmt.Errorf("每人最多接取" + utils.Int2Str(AcceptMaxCount) + "个任务,请核实!")
// }
//非快递任务
if jobID != 2 && job.JobCategoryID != model.JobCategoryIDUnion {
num, err = checkJobOrders(db, jobID, "<= "+utils.Int2Str(model.JobOrderStatusWaitAudit), userID, utils.ZeroTimeValue, utils.ZeroTimeValue)
if num > 0 {
return 0, errCode, fmt.Errorf("您还有此任务未完成,请完成后再接取!")
}
num, err = checkJobOrders(db, jobID, "= "+utils.Int2Str(model.JobOrderStatusAuditUnPass), userID, utils.ZeroTimeValue, utils.ZeroTimeValue)
if num > 0 {
return 0, errCode, fmt.Errorf("您还有此任务未审核通过记录,可直接在未审核中重新提交!")
}
}
switch job.LimitCountType {
case model.JobLimitCountTypePO:
num, err = checkJobOrders(db, jobID, "<> "+utils.Int2Str(model.JobOrderStatusCancel), userID, utils.ZeroTimeValue, utils.ZeroTimeValue)
if num > 0 {
return 0, errCode, fmt.Errorf("此任务只支持每人做一次!")
}
case model.JobLimitCountTypePDO:
num, err = checkJobOrders(db, jobID, "<> "+utils.Int2Str(model.JobOrderStatusCancel), userID, DayTimeBegin, DayTimeEnd)
if num > 0 {
return 0, errCode, fmt.Errorf("此任务只支持每人每天做一次!")
}
case model.JobLimitCountTypePWO:
num, err = checkJobOrders(db, jobID, "<> "+utils.Int2Str(model.JobOrderStatusCancel), userID, WeekTimeBegin, WeekTimeEnd)
if num > 0 {
return 0, errCode, fmt.Errorf("此任务只支持每人每周做一次!")
}
case model.JobLimitCountTypeNoLimit:
default:
return 0, errCode, fmt.Errorf("不支持的任务限次类型!%v", job.LimitCountType)
}
jobOrder := &model.JobOrder{
JobID: jobID,
JobOrderID: jxutils.GenJobOrderNo(),
UserID: ctx.GetUserID(),
}
jobOrder.Status = model.JobOrderStatusAccept
//如果是一件代发任务,用户需要支付订单金额
var userBill *model.UserBill
if job.JobCategoryID == model.JobCategoryIDDropShipping {
if dropShippingCount == 0 || dropShippingDeliveryID == 0 {
return 0, errCode, fmt.Errorf("一件代发订单请输入商品数量和收件人地址!")
}
//验证微信绑定
if err = auth2.CheckWeixinminiAuthBind(ctx.GetUserID()); err != nil {
return 0, "", err
}
//发布任务要扣除任务总额的保证金,不够扣就要进行充值
userBill, err = dao.GetUserBill(db, ctx.GetUserID(), "")
if userBill == nil {
return 0, errCode, fmt.Errorf("未查询到该用户的账单!")
}
jobOrder.UserActualPrice = job.DropShippingSkuPrice * dropShippingCount
if userBill.AccountBalance < jobOrder.UserActualPrice {
return 0, model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足!")
}
if deliveryList, _, err2 := dao.QueryUserDeliveryAddress(db, int64(dropShippingDeliveryID), nil, 0, 0, 0); err2 == nil {
delivery := deliveryList[0]
jobOrder.DropShippingCount = dropShippingCount
jobOrder.DropShippingDeliveryID = dropShippingDeliveryID
jobOrder.DropShippingName = delivery.ConsigneeName
jobOrder.DropShippingMobile = delivery.ConsigneeMobile
jobOrder.DropShippingAddress = delivery.Address
jobOrder.DropShippingDetailAddress = delivery.DetailAddress
jobOrder.DropShippingLng = delivery.Lng
jobOrder.DropShippingLat = delivery.Lat
jobOrder.DropShippingAutoAddress = delivery.AutoAddress
jobOrder.DropShippingCityCode = delivery.CityCode
jobOrder.DropShippingDistrictCode = delivery.DistrictCode
}
// jobOrder.Status = model.JobOrderStatusWaitAudit
} else if job.JobCategoryID == model.JobCategoryIDUnion {
jobOrder.Status = model.JobOrderStatusSpec
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
dao.WrapAddIDCULEntity(jobOrder, ctx.GetUserName())
if err = dao.CreateEntityTx(txDB, jobOrder); err != nil {
dao.Rollback(db, txDB)
return
}
//用户接受任务,任务剩余次数-1
job.SurplusCount -= 1
if _, err = dao.UpdateEntityTx(txDB, job, "SurplusCount"); err != nil {
dao.Rollback(db, txDB)
return
}
dao.Commit(db, txDB)
if job.JobCategoryID == model.JobCategoryIDDropShipping {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeDropShipping, jobOrder.UserActualPrice, job.ID); err != nil {
dao.Rollback(db, txDB)
return
}
//一件代发
if err = SubmitJob(ctx, jobOrder); err != nil {
dao.Rollback(db, txDB)
return
}
dao.Commit(db, txDB)
} else if job.JobCategoryID != model.JobCategoryIDUnion {
//任务限时完成
timer := checkLimitJobOrders(db, job, jobOrder, model.JobTimerTypeAccept)
JobTimers.s.Lock()
JobTimers.JobTimerMap[jobOrder.JobOrderID] = timer
JobTimers.s.Unlock()
}
return jobOrder.JobOrderID, errCode, err
}
func CancelAcceptJob(ctx *jxcontext.Context, jobID int, jobOrderID int64) (err error) {
var (
db = dao.GetDB()
)
jobOrder := &model.JobOrder{}
jobOrder.JobOrderID = jobOrderID
err = dao.GetEntity(db, jobOrder, "JobOrderID")
if jobOrder.ID != 0 && jobOrder.Status == model.JobOrderStatusCancel {
return fmt.Errorf("此任务已被取消了!")
}
job := &model.Job{}
job.ID = jobID
err = dao.GetEntity(db, job)
//系统消息
content := new(strings.Builder)
content.WriteString("您接取的任务:")
content.WriteString(job.Title)
if ctx.GetUserName() == "jxadmin" {
content.WriteString(",因超时未完成已被系统自动取消。")
} else {
content.WriteString(",已被取消。")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//如果当前任务状态正常剩余数量就加1
if job.Status >= 0 {
job.SurplusCount += 1
if _, err = dao.UpdateEntityTx(txDB, job, "SurplusCount"); err != nil {
dao.Rollback(db, txDB)
return
}
} else {
userBill, err := dao.GetUserBill(db, job.UserID, "")
if userBill == nil {
return fmt.Errorf("未查询到该用户的账单!")
}
//如果状态不正常(取消或者过期)就要把这一笔退回去
//2、账户收入
//是固定返现才会退一笔任务单价
if job.CashbackType == model.JobCashbackPrice {
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeJobCancelOverdue, job.AvgPrice, jobID); err != nil {
dao.Rollback(db, txDB)
return err
}
}
}
//一件代发任务要退钱给用户
if job.JobCategoryID == model.JobCategoryIDDropShipping {
userBill, err := dao.GetUserBill(db, jobOrder.UserID, "")
if userBill == nil {
return fmt.Errorf("未查询到该用户的账单!")
}
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeJobCancelOverdue, jobOrder.UserActualPrice, jobID); err != nil {
dao.Rollback(db, txDB)
return err
}
}
//3、任务订单状态被取消
jobOrder.Status = model.JobOrderStatusCancel
if _, err = dao.UpdateEntityTx(txDB, jobOrder, "Status"); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.Commit(db, txDB)
event.SendSysMessageSimple(content.String(), jobOrder.UserID)
return err
}
func checkJobOrders(db *dao.DaoDB, jobID int, statusCompareStr, userID string, fromTime, toTime time.Time) (num int, err error) {
jobOrders, err := dao.GetJobOrdersNoPage(db, jobID, 0, userID, statusCompareStr, fromTime, toTime, nil)
return len(jobOrders), err
}
func checkLimitJobOrders(db *dao.DaoDB, job *model.Job, jobOrder *model.JobOrder, jobTimerType int) (timer *time.Timer) {
//插到定时任务表里,主要是重启项目后的重启定时器用
//main 里有重启的函数
jobTimer := &model.JobTimer{
JobID: job.ID,
JobOrderID: jobOrder.JobOrderID,
Type: jobTimerType,
Status: model.JobTimerStatusWait,
StartAt: jobOrder.CreatedAt,
// LimitAt: job.JobLimitAt,
}
switch jobTimerType {
case model.JobTimerTypeAccept:
timer = time.NewTimer(time.Hour * time.Duration(job.JobLimitAt))
jobTimer.LimitAt = job.JobLimitAt
case model.JobTimerTypeSubmit:
timer = time.NewTimer(time.Hour * time.Duration(job.AuditLimitAt))
jobTimer.LimitAt = job.AuditLimitAt
case model.JobTimerTypeDropShipping:
timer = time.NewTimer(time.Hour * time.Duration(job.DropShippingAt))
jobTimer.LimitAt = job.DropShippingAt
}
dao.WrapAddIDCULEntity(jobTimer, jxcontext.AdminCtx.GetUserName())
dao.CreateEntity(db, jobTimer)
utils.CallFuncAsync(func() {
select {
case <-timer.C:
switch jobTimerType {
case model.JobTimerTypeAccept:
UpdateLimitJobOrders(db, timer, job.ID, jobOrder.JobOrderID, jobTimer)
case model.JobTimerTypeSubmit:
UpdateLimitAuditJobOrders(db, timer, job.ID, jobOrder.JobOrderID, jobTimer)
case model.JobTimerTypeDropShipping:
UpdateDropShippingJobOrders(db, timer, job.ID, jobOrder.JobOrderID, jobTimer)
}
}
})
return timer
}
func UpdateLimitJobOrders(db *dao.DaoDB, timer *time.Timer, jobID int, jobOrderID int64, jobTimer *model.JobTimer) {
globals.SugarLogger.Debugf("updateLimitJobOrders jobID: %v, jobOrderID: %v", jobID, jobOrderID)
defer timer.Stop()
jobOrder := &model.JobOrder{JobOrderID: jobOrderID}
if err := dao.GetEntity(db, jobOrder, "JobOrderID"); err == nil {
if jobOrder.Status > model.JobOrderStatusAccept {
return
}
if err := CancelAcceptJob(jxcontext.AdminCtx, jobID, jobOrderID); err == nil {
jobTimer.Status = model.JobTimerStatusFinish
dao.UpdateEntity(db, jobTimer, "Status")
}
}
}
func UpdateLimitAuditJobOrders(db *dao.DaoDB, timer *time.Timer, jobID int, jobOrderID int64, jobTimer *model.JobTimer) {
globals.SugarLogger.Debugf("checkLimitAuditJobOrders jobID: %v, jobOrderID: %v", jobID, jobOrderID)
defer timer.Stop()
jobOrder := &model.JobOrder{JobOrderID: jobOrderID}
if err := dao.GetEntity(db, jobOrder, "JobOrderID"); err == nil {
if jobOrder.Status == model.JobOrderStatusWaitAudit {
err := AuditJob(jxcontext.AdminCtx, int(jobOrderID), model.JobOrderStatusAuditPass, "超时系统通过", "")
if err != nil {
globals.SugarLogger.Debugf("checkLimitAuditJobOrders err: %v jobID: %v, jobOrderID: %v", err, jobID, jobOrderID)
} else {
jobTimer.Status = model.JobTimerStatusFinish
dao.UpdateEntity(db, jobTimer, "Status")
}
}
}
}
func UpdateDropShippingJobOrders(db *dao.DaoDB, timer *time.Timer, jobID int, jobOrderID int64, jobTimer *model.JobTimer) {
globals.SugarLogger.Debugf("UpdateDropShippingJobOrders jobID: %v, jobOrderID: %v", jobID, jobOrderID)
defer timer.Stop()
jobOrder := &model.JobOrder{JobOrderID: jobOrderID}
job := &model.Job{}
job.ID = jobID
if err := dao.GetEntity(db, jobOrder, "JobOrderID"); err == nil {
if err := dao.GetEntity(db, job); err == nil {
//如果限时内还没发货
if jobOrder.Status < model.JobOrderStatusFinish {
userBill, err := dao.GetUserBill(db, jobOrder.UserID, "")
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeDropShippingDeposit, job.AvgPrice, job.ID); err != nil {
dao.Rollback(db, txDB)
return
}
dao.Commit(db, txDB)
}
}
}
jobTimer.Status = model.JobTimerStatusFinish
dao.UpdateEntity(db, jobTimer, "Status")
}
func SubmitJob(ctx *jxcontext.Context, jobOrder *model.JobOrder) (err error) {
var (
db = dao.GetDB()
)
if jobOrder.JobID == 0 || jobOrder.JobOrderID == 0 {
return fmt.Errorf("传入数据有误!")
}
job := &model.Job{}
job.ID = jobOrder.JobID
err = dao.GetEntity(db, job)
jobOrder2 := &model.JobOrder{}
jobOrder2.JobOrderID = jobOrder.JobOrderID
err = dao.GetEntity(db, jobOrder2, "JobOrderID")
//如果是比例返现
if job.CashbackType == model.JobCashbackPercentage {
if jobOrder.UserActualPrice == 0 {
return fmt.Errorf("比例返现任务请输入订单实际实付金额,用于任务发起人审核!")
}
}
if jobOrder2.JobID == 0 {
return fmt.Errorf("未查询到相应的任务!")
}
if jobOrder2.Status >= model.JobOrderStatusWaitAudit {
return fmt.Errorf("任务订单状态有误!")
}
if ctx.GetUserID() != jobOrder2.UserID {
return fmt.Errorf("任务订单接收人有误!")
}
jobOrder2.Imgs = jobOrder.Imgs
jobOrder2.Content = jobOrder.Content
jobOrder2.SubmitAuditAt = time.Now()
jobOrder2.UserActualPrice = jobOrder.UserActualPrice
jobOrder2.Status = model.JobOrderStatusWaitAudit
if _, err = dao.UpdateEntity(db, jobOrder2, "Imgs", "Content", "SubmitAuditAt", "Status", "UserActualPrice"); err == nil {
//任务定时器停止
JobTimers.s.RLock()
if JobTimers.JobTimerMap[jobOrder2.JobOrderID] != nil {
JobTimers.JobTimerMap[jobOrder2.JobOrderID].Stop()
//任务定时表状态完成
jobTimer := &model.JobTimer{
JobID: job.ID,
JobOrderID: jobOrder2.JobOrderID,
Type: model.JobTimerTypeAccept,
}
if err = dao.GetEntity(db, jobTimer, "JobID", "JobOrderID", "Type"); err == nil {
jobTimer.Status = model.JobTimerStatusFinish
dao.UpdateEntity(db, jobTimer, "Status")
}
}
JobTimers.s.RUnlock()
//一件代发
var timerType int
if job.JobCategoryID == model.JobCategoryIDDropShipping {
timerType = model.JobTimerTypeDropShipping
} else {
timerType = model.JobTimerTypeSubmit
}
//审核定时开启
timer := checkLimitJobOrders(db, job, jobOrder2, timerType)
JobTimers.s.Lock()
JobTimers.JobAuditTimerMap[jobOrder2.JobOrderID] = timer
JobTimers.s.Unlock()
}
content := new(strings.Builder)
content.WriteString("您的任务:")
content.WriteString(job.Title)
content.WriteString("。已有人提交了审核,请及时审核!")
event.SendSysMessageSimple(content.String(), job.UserID)
return err
}
func AuditJob(ctx *jxcontext.Context, jobOrderID, status int, comment, vendorWaybillID string) (err error) {
var (
db = dao.GetDB()
)
jobOrder := &model.JobOrder{}
jobOrder.JobOrderID = int64(jobOrderID)
err = dao.GetEntity(db, jobOrder, "JobOrderID")
job := &model.Job{}
job.ID = jobOrder.JobID
err = dao.GetEntity(db, job)
if ctx.GetUserID() != job.UserID && ctx.GetUserName() != "jxadmin" {
return fmt.Errorf("任务发起人才能审核!")
}
if job.JobCategoryID == model.JobCategoryIDDropShipping && vendorWaybillID == "" {
return fmt.Errorf("一件代发任务发货请输入运单号!")
}
if job.JobCategoryID == model.JobCategoryIDDropShipping && status != model.JobOrderStatusAuditPass {
return fmt.Errorf("一件代发任务发货参数有误!")
}
if jobOrder.Status != model.JobOrderStatusWaitAudit {
return fmt.Errorf("审核状态不正确!")
}
//固定返现
//1、审核时若此任务已过期或者已取消不通过则应将此任务保证金退还给发起人通过则应将单次任务保证金给接受人
//2、若此任务未过期不通过则此任务剩余数量将+1通过则应将单次任务保证金给接受人
jobOrder.Status = status
jobOrder.Comment = comment
jobOrder.AuditAt = time.Now()
jobOrder.LastOperator = ctx.GetUserName()
userBillJobOrder, err := dao.GetUserBill(db, jobOrder.UserID, "")
//系统消息
content := new(strings.Builder)
content.WriteString("恭喜您完成了任务:")
content.WriteString(job.Title)
if ctx.GetUserName() == "jxadmin" {
content.WriteString(",因超时未审核已被系统自动审核")
} else {
content.WriteString(",商家已经审核")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntityTx(txDB, jobOrder, "Status", "Comment", "AuditAt", "LastOperator"); err != nil {
dao.Rollback(db, txDB)
return
}
if status == model.JobOrderStatusAuditPass {
content.WriteString("通过,")
if job.JobCategoryID != model.JobCategoryIDDropShipping {
var price int
if job.CashbackType == model.JobCashbackPrice {
price = job.AvgPrice
} else {
price = jobOrder.UserActualPrice * job.Percentage / 100
if price > job.AvgPrice {
price = job.AvgPrice
}
}
//若完成任务的人在某个群组中,则要向群主分成
if messageGroupMembers, err := dao.GetMessageGroupMembers(db, 0, model.GroupTypeMulit, jobOrder.UserID); err == nil {
if len(messageGroupMembers) > 1 {
return fmt.Errorf("审核异常,该任务提交人加入了多个群组!")
} else if len(messageGroupMembers) == 1 {
if messageGroupsResult, err := dao.GetMessageGroups(db, "", messageGroupMembers[0].GroupID, model.GroupTypeMulit, false, ""); err == nil {
if len(messageGroupsResult) == 1 {
if messageGroupsResult[0].DividePercentage != 0 {
if userBillGroupMaster, err := dao.GetUserBill(db, messageGroupsResult[0].UserID, ""); err == nil {
if err = financial.AddIncomeUpdateAccount(txDB, userBillGroupMaster, model.BillTypeDivide, price*messageGroupsResult[0].DividePercentage/100, job.ID); err != nil {
dao.Rollback(db, txDB)
return err
}
}
//接收人账户收入
if err = financial.AddIncomeUpdateAccount(txDB, userBillJobOrder, model.BillTypeJobDivide, price*(100-messageGroupsResult[0].DividePercentage)/100, job.ID); err != nil {
dao.Rollback(db, txDB)
return err
}
} else {
//接收人账户收入
if err = financial.AddIncomeUpdateAccount(txDB, userBillJobOrder, model.BillTypeJob, price, job.ID); err != nil {
dao.Rollback(db, txDB)
return err
}
}
}
}
} else if len(messageGroupMembers) == 0 { //若没有在某个群组,则得到全部
//接收人账户收入
if err = financial.AddIncomeUpdateAccount(txDB, userBillJobOrder, model.BillTypeJob, price, job.ID); err != nil {
dao.Rollback(db, txDB)
return err
}
}
}
jobOrder.Status = model.JobOrderStatusFinish
if _, err = dao.UpdateEntityTx(txDB, jobOrder, "Status"); err != nil {
dao.Rollback(db, txDB)
return err
}
content.WriteString(utils.Float64ToStr(jxutils.IntPrice2Standard(int64(price))))
content.WriteString("元已存入您的余额中!")
} else {
//一件代发处理,审核相当于发货
jobOrder.VendorWaybillID = vendorWaybillID
jobOrder.Status = model.JobOrderStatusFinish
if _, err = dao.UpdateEntityTx(txDB, jobOrder, "Status", "VendorWaybillID"); err != nil {
dao.Rollback(db, txDB)
return err
}
userBill, err := dao.GetUserBill(db, job.UserID, "")
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeDropShippingDeposit, job.AvgPrice, job.ID); err != nil {
dao.Rollback(db, txDB)
return err
}
}
event.SendSysMessageSimple(content.String(), jobOrder.UserID)
} else {
content2 := new(strings.Builder)
content2.WriteString("非常抱歉,您提交的任务: ")
content2.WriteString(job.Title)
content2.WriteString("未通过审核,请您修改后重新提交!")
if job.Status < 0 {
if job.CashbackType == model.JobCashbackPrice {
userBill, err := dao.GetUserBill(db, job.UserID, "")
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeJobAuditUnPassWithCancelOverdue, job.AvgPrice, job.ID); err != nil {
dao.Rollback(db, txDB)
return err
}
}
} else {
//审核不通过的话,要重新变成待上传,再重新开个定时器
jobOrder.Status = model.JobOrderStatusAccept
if _, err = dao.UpdateEntityTx(txDB, jobOrder, "Status"); err != nil {
dao.Rollback(db, txDB)
return
}
//之前的定时表删了?
jobTimer := &model.JobTimer{
JobID: job.ID,
JobOrderID: jobOrder.JobOrderID,
}
if _, err = dao.DeleteEntityTx(txDB, jobTimer, "JobID", "JobOrderID"); err != nil {
dao.Rollback(db, txDB)
return
}
//任务限时完成
timer := checkLimitJobOrders(db, job, jobOrder, model.JobTimerTypeAccept)
JobTimers.s.Lock()
JobTimers.JobTimerMap[jobOrder.JobOrderID] = timer
JobTimers.s.Unlock()
}
event.SendSysMessageSimple(content2.String(), jobOrder.UserID)
}
dao.Commit(db, txDB)
//任务定时器停止
JobTimers.s.RLock()
if JobTimers.JobAuditTimerMap[int64(jobOrderID)] != nil {
JobTimers.JobAuditTimerMap[int64(jobOrderID)].Stop()
}
JobTimers.s.RUnlock()
//任务定时表状态完成
jobTimer := &model.JobTimer{
JobID: job.ID,
JobOrderID: jobOrder.JobOrderID,
// Type: model.JobTimerTypeSubmit,
}
if job.JobCategoryID != model.JobCategoryIDDropShipping {
jobTimer.Type = model.JobTimerTypeSubmit
} else {
jobTimer.Type = model.JobTimerTypeDropShipping
}
if err = dao.GetEntity(db, jobTimer, "JobID", "JobOrderID", "Type"); err == nil {
jobTimer.Status = model.JobTimerStatusFinish
dao.UpdateEntity(db, jobTimer, "Status")
}
return err
}
func RefreshJobStatus(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
)
globals.SugarLogger.Debugf("RefreshJobStatus begin...")
jobs, err := dao.GetJobsNoPage(db, nil, nil, []int{model.JobStatusDoing}, nil, utils.ZeroTimeValue, utils.ZeroTimeValue, 0, false)
if err != nil {
globals.SugarLogger.Debugf("RefreshJobStatus err :%v", err)
return
}
for _, job := range jobs {
if time.Now().Sub(*job.FinishedAt) >= 0 {
//取消已发布的任务
userBill, err := dao.GetUserBill(db, job.UserID, "")
if userBill == nil {
return fmt.Errorf("未查询到该用户的账单!")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//如果是固定返现,退给任务发起人剩余数量*单价
//如果是比例返现,推给任务发起人任务总价-接取这个任务的用户实际返现的价格之和
var price int
if job.CashbackType == model.JobCashbackPrice {
price = job.SurplusCount * job.AvgPrice
} else {
if billIncomes, err := dao.GetBillIncome(db, job.ID, 0); err == nil {
for _, v := range billIncomes {
price += v.IncomePrice
}
}
price = job.TotalPrice - price
}
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeJobCancelOverdue, price, job.ID); err != nil {
dao.Rollback(db, txDB)
return err
}
//3、任务状态被取消
job2 := &model.Job{}
job2.ID = job.ID
dao.GetEntity(db, job2)
if job2 != nil {
job2.Status = model.JobStatusOverdue
// job.DeletedAt = time.Now()
if _, err = dao.UpdateEntityTx(txDB, job2, "Status"); err != nil {
dao.Rollback(db, txDB)
return err
}
}
dao.Commit(db, txDB)
}
}
globals.SugarLogger.Debugf("RefreshJobStatus end...")
return err
}
func ImprotMtMembers(ctx *jxcontext.Context, mtMembers []*model.MtMember) (err error) {
var (
db = dao.GetDB()
)
for _, v := range mtMembers {
v.ShortLink = v.URL[strings.LastIndex(v.URL, "/")+1 : len(v.URL)]
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
}
if err = dao.CreateMultiEntities(db, mtMembers); err == nil {
job, err := dao.GetJob(db, nil, nil, nil, []int{model.JobTypeMtMember}, utils.ZeroTimeValue, utils.ZeroTimeValue, false)
if job != nil && err == nil {
job.Count += len(mtMembers)
job.SurplusCount += len(mtMembers)
dao.UpdateEntity(db, job, "Count", "SurplusCount")
}
}
return err
}
func RechargeMtMembers(ctx *jxcontext.Context, phone int) (errCode string, err error) {
var (
db = dao.GetDB()
db2 = dao.GetDB()
userID = ctx.GetUserID()
)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
nums, err := dao.GetMtMembers(db)
if nums < 10 {
utils.CallFuncAsync(func() {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "F4836F9238F611EB9101525400C36BDA", "美团会员券", "美团会员券仅剩"+utils.Int2Str(nums)+"张了!")
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "EFA9876238FC11EB9101525400C36BDA", "美团会员券", "美团会员券仅剩"+utils.Int2Str(nums)+"张了!")
})
}
if err != nil {
dao.Rollback(db, txDB)
return errCode, err
}
//验证微信绑定
if err = auth2.CheckWeixinminiAuthBind(userID); err != nil {
dao.Rollback(db, txDB)
return "", err
}
//特殊任务,如美团会员,是直接要支付
userBill, err := dao.GetUserBill(db, userID, "")
if err != nil {
return errCode, err
}
if userBill.AccountBalance < mtwmMemberPrice {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足,请充值!")
}
//账户支出
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeSpJob, mtwmMemberPrice, 1); err != nil {
dao.Rollback(db, txDB)
return errCode, err
}
dao.Commit(db, txDB)
for {
txDB, _ := dao.Begin(db2)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db2, txDB)
panic(r)
}
}()
mtMember, err := dao.GetMtMember(db2)
if mtMember == nil {
return errCode, fmt.Errorf("补券中,请稍后再试!")
}
err = api.MtMemberAPI.RechargeExchange(phone, mtMember.ShortLink)
mtMember.DeletedAt = time.Now()
dao.UpdateEntity(db2, mtMember, "DeletedAt")
dao.Commit(db2, txDB)
if err == nil {
job, err := dao.GetJob(db2, nil, nil, nil, []int{model.JobTypeMtMember}, utils.ZeroTimeValue, utils.ZeroTimeValue, false)
_, errCode, err = AcceptJob(ctx, job.ID, 0, 0)
if errCode != "" {
return errCode, err
}
if err != nil {
return errCode, err
}
break
}
}
return errCode, err
}
func SendJdDelivery(ctx *jxcontext.Context, dOrder *model.DeliveryOrder) (errCode string, err error) {
var (
db = dao.GetDB()
)
if dOrder.Weight == 0 {
return errCode, fmt.Errorf("重量必须填写!")
}
if dOrder.PayPrice == 0 {
if dOrder.Weight <= 3 {
dOrder.PayPrice = 1000
} else {
dOrder.PayPrice = 1000 + int(float64(waybillKgPrice)*math.Ceil(dOrder.Weight-3))
}
}
var (
sendDelivery *dao.UserDeliveryAddressEx
receiveDelivery *dao.UserDeliveryAddressEx
)
sendDeliveryList, _, err := dao.QueryUserDeliveryAddress(db, int64(dOrder.DeliverySendID), nil, 0, 0, 0)
receiveDeliveryList, _, err := dao.QueryUserDeliveryAddress(db, int64(dOrder.DeliveryReceiveID), nil, 0, 0, 0)
userBill, err := dao.GetUserBill(db, ctx.GetUserID(), "")
if err != nil {
return errCode, err
}
//验证微信绑定
if err = auth2.CheckWeixinminiAuthBind(ctx.GetUserID()); err != nil {
return "", err
}
if userBill.AccountBalance < dOrder.PayPrice {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足,请充值!")
}
if len(sendDeliveryList) == 0 {
return errCode, fmt.Errorf("未找到寄件人地址!")
} else {
sendDelivery = sendDeliveryList[0]
}
if len(receiveDeliveryList) == 0 {
return errCode, fmt.Errorf("未找到取件人地址!")
} else {
receiveDelivery = receiveDeliveryList[0]
}
//内蒙古海南统一35
//新疆西藏统一45
if receiveDelivery.ParentCode == 150000 || receiveDelivery.ParentCode == 460000 ||
receiveDelivery.ParentCode == 650000 || receiveDelivery.ParentCode == 540000 ||
sendDelivery.ParentCode == 150000 || sendDelivery.ParentCode == 460000 ||
sendDelivery.ParentCode == 650000 || sendDelivery.ParentCode == 540000 {
return errCode, fmt.Errorf("暂不支持该地区的快递业务!")
}
sendProvinceName := ""
receiveProvinceName := ""
if place1, err := dao.GetPlaceByCode(db, sendDelivery.CityCode); err == nil {
if place2, err2 := dao.GetPlaceByCode(db, place1.ParentCode); err2 == nil {
sendProvinceName = place2.Name
}
}
if place1, err := dao.GetPlaceByCode(db, receiveDelivery.CityCode); err == nil {
if place2, err2 := dao.GetPlaceByCode(db, place1.ParentCode); err2 == nil {
receiveProvinceName = place2.Name
}
}
dao.WrapAddIDCULEntity(dOrder, ctx.GetUserName())
if vendorWaybillID, err := api.JdEclpAPI.WaybillReceive(&jdeclpapi.WaybillReceiveParam{
SalePlat: jdeclpapi.SalePlatSourceDelivery,
CustomerCode: jdeclpapi.CustomerCode,
OrderID: utils.Int64ToStr(jxutils.GenOrderNo()),
SenderName: sendDelivery.ConsigneeName,
SenderAddress: sendProvinceName + sendDelivery.CityName + sendDelivery.DistrictName + sendDelivery.Address + sendDelivery.DetailAddress,
SenderTel: sendDelivery.ConsigneeMobile,
ReceiveName: receiveDelivery.ConsigneeName,
ReceiveAddress: receiveProvinceName + receiveDelivery.CityName + receiveDelivery.DistrictName + receiveDelivery.Address + receiveDelivery.DetailAddress,
ReceiveTel: receiveDelivery.ConsigneeMobile,
Weight: dOrder.Weight,
Vloumn: dOrder.Vloumn,
PackageCount: dOrder.PackageCount,
Description: dOrder.Description,
Aging: 5,
PromiseTimeType: 1, //特惠送
}); err == nil {
dOrder.VendorWaybillID = vendorWaybillID
} else {
return errCode, err
}
dOrder.Status = model.OrderStatusNew
dOrder.UserID = ctx.GetUserID()
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//账户支出明细
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeSpJob, dOrder.PayPrice, 2); err != nil {
dao.Rollback(db, txDB)
return
}
dOrder.SendName = sendDelivery.ConsigneeName
dOrder.SendMobile = sendDelivery.ConsigneeMobile
dOrder.SendAddress = sendDelivery.Address
dOrder.SendAutoAddress = sendDelivery.AutoAddress
dOrder.SendCityCode = sendDelivery.CityCode
dOrder.SendDetailAddress = sendDelivery.DetailAddress
dOrder.SendLng = sendDelivery.Lng
dOrder.SendLat = sendDelivery.Lat
dOrder.ReceiveName = receiveDelivery.ConsigneeName
dOrder.ReceiveMobile = receiveDelivery.ConsigneeMobile
dOrder.ReceiveAddress = receiveDelivery.Address
dOrder.ReceiveAutoAddress = receiveDelivery.AutoAddress
dOrder.ReceiveCityCode = receiveDelivery.CityCode
dOrder.ReceiveDetailAddress = receiveDelivery.DetailAddress
dOrder.ReceiveLng = receiveDelivery.Lng
dOrder.ReceiveLat = receiveDelivery.Lat
if err = dao.CreateEntity(db, dOrder); err != nil {
dao.Rollback(db, txDB)
return
}
dao.Commit(db, txDB)
utils.CallFuncAsync(func() {
job, _ := dao.GetJob(db, nil, nil, nil, []int{model.JobTypeJdDelivery}, utils.ZeroTimeValue, utils.ZeroTimeValue, false)
if jobOrderID, _, err := AcceptJob(ctx, job.ID, 0, 0); err == nil {
dOrder.JobOrderID = utils.Int64ToStr(jobOrderID)
dao.UpdateEntity(db, dOrder, "JobOrderID")
}
})
return errCode, err
}
func CancelJdDelivery(ctx *jxcontext.Context, vendorWaybillID, reason string) (err error) {
var (
db = dao.GetDB()
dOrder = &model.DeliveryOrder{
VendorWaybillID: vendorWaybillID,
}
// DayTimeBegin, DayTimeEnd = jxutils.GetDayTime()
)
err = dao.GetEntity(db, dOrder, "VendorWaybillID")
userBill, err := dao.GetUserBill(db, ctx.GetUserID(), "")
// dOrders, err := dao.GetDeliveryOrdersNoPage(db, []string{ctx.GetUserID()}, []int{model.OrderStatusCanceled}, DayTimeBegin, DayTimeEnd, nil)
// if err != nil {
// return err
// }
// if len(dOrders) > 0 {
// return fmt.Errorf("抱歉,您已经在今天取消过京东物流订单!")
// }
if dOrder.ID == 0 {
return fmt.Errorf("未找到该运单!")
}
if err = api.JdEclpAPI.CancelWayBill(&jdeclpapi.CancelWayBillParam{
WaybillCode: vendorWaybillID,
CustomerCode: jdeclpapi.CustomerCode,
Source: "JOS",
CancelReason: reason,
OperatorName: ctx.GetUserName(),
}); err != nil {
return err
}
dOrder.Status = model.OrderStatusCanceled
dOrder.OrderFinishedAt = time.Now()
dOrder.Comment = reason
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntity(db, dOrder, "Status", "OrderFinishedAt", "Comment"); err != nil {
dao.Rollback(db, txDB)
return
}
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeSpJob, dOrder.PayPrice, 2); err != nil {
dao.Rollback(db, txDB)
return
}
if err = CancelAcceptJob(ctx, 2, utils.Str2Int64(dOrder.JobOrderID)); err != nil {
dao.Rollback(db, txDB)
}
dao.Commit(db, txDB)
return err
}
func GetJdDelivery(ctx *jxcontext.Context, status int, fromTime, toTime string, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
var (
db = dao.GetDB()
statuss []int
)
if status != 0 {
statuss = append(statuss, status)
}
RefreshJdDelivery(ctx)
return dao.GetDeliveryOrders(db, []string{ctx.GetUserID()}, statuss, utils.Str2Time(fromTime), utils.Str2Time(toTime), pageSize, offset)
}
func RefreshJdDelivery(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
userID string
userIDs []string
)
if ctx.GetUserName() == "jxadmin" {
userID = ""
userIDs = nil
} else {
userID = ctx.GetUserID()
userIDs = append(userIDs, userID)
}
pages, _ := dao.GetDeliveryOrders(db, userIDs, []int{model.OrderStatusNew, model.OrderStatusDelivering}, utils.ZeroTimeValue, utils.ZeroTimeValue, 9999, 0)
list := pages.Data.([]*dao.GetDeliveryOrdersResult)
task := tasksch.NewParallelTask("RefreshJdDelivery", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
v := batchItemList[0].(*dao.GetDeliveryOrdersResult)
if v != nil && v.VendorWaybillID != "" {
var (
isDeliverying, isFinished, isCancel bool
)
if results, err := api.JdEclpAPI.QueryDynamicTraceInfo(v.VendorWaybillID); err == nil {
for _, result := range results {
if result.State == jdeclpapi.TraceInfoStateM640 {
isDeliverying = true
}
if result.State == jdeclpapi.TraceInfoStateM650 || result.State == jdeclpapi.TraceInfoStateM790 {
isCancel = true
break
}
if result.State == jdeclpapi.TraceInfoState150 {
isFinished = true
break
}
}
}
dOrder := &model.DeliveryOrder{}
dOrder.VendorWaybillID = v.VendorWaybillID
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if err = dao.GetEntity(db, dOrder, "VendorWaybillID"); err == nil {
if isCancel {
//退钱给发快递的
dOrder.Status = model.OrderStatusCanceled
userBill, _ := dao.GetUserBill(db, v.UserID, "")
err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeSpJob, v.PayPrice+v.DiffPrice, 2)
} else if isFinished {
//快递任务要完成
dOrder.Status = model.OrderStatusFinished
err = AuditJob(ctx, utils.Str2Int(dOrder.JobOrderID), model.JobOrderStatusAuditPass, "快递完成,自动审核通过", "")
} else if isDeliverying {
dOrder.Status = model.OrderStatusDelivering
} else {
return retVal, err
}
if err == nil {
dao.UpdateEntityTx(txDB, dOrder, "Status")
} else {
if strings.Contains(err.Error(), "审核状态不正确") {
dao.UpdateEntityTx(txDB, dOrder, "Status")
}
}
}
dao.Commit(db, txDB)
}
return retVal, err
}, list)
tasksch.HandleTask(task, nil, true).Run()
task.GetID()
return err
}
func GetDeliveryDetail(ctx *jxcontext.Context, vendorWaybillID string) (queryDynamicTraceInfo []*jdeclpapi.QueryDynamicTraceInfoResult, err error) {
return api.JdEclpAPI.QueryDynamicTraceInfo(vendorWaybillID)
}
func GetAllDeliveryDetail(ctx *jxcontext.Context, vendorWaybillID, comType string) (result *txcloudapi.GetWaybillDetailInfoResult, err error) {
var (
db = dao.GetDB()
getWaybillDetailInfoResult = &txcloudapi.GetWaybillDetailInfoResult{}
)
jobOrder := &model.JobOrder{
VendorWaybillID: vendorWaybillID,
}
err = dao.GetEntity(db, jobOrder, "VendorWaybillID")
if jobOrder == nil {
return result, fmt.Errorf("运单号有误,无法查询!")
}
if jobOrder.WaybillStatus >= model.OrderStatusFinished {
json.Unmarshal([]byte(jobOrder.WaybillInfo), &getWaybillDetailInfoResult)
return getWaybillDetailInfoResult, err
}
//距上次查询时间要大于12小时的才去真正查
if jobOrder.WaybillQueryTime != utils.ZeroTimeValue {
if time.Now().Sub(jobOrder.WaybillQueryTime) <= time.Hour*12 {
json.Unmarshal([]byte(jobOrder.WaybillInfo), &getWaybillDetailInfoResult)
return getWaybillDetailInfoResult, err
}
}
if getWaybillDetailInfoResult, err = api.TxAPI.GetWaybillDetailInfo(vendorWaybillID, comType); err != nil {
return nil, err
}
jobOrder.WaybillQueryTime = time.Now()
if waybillInfo, err := json.Marshal(getWaybillDetailInfoResult); err == nil {
jobOrder.WaybillInfo = string(waybillInfo)
}
if getWaybillDetailInfoResult.State == utils.Int2Str(txcloudapi.StatusFinished) && jobOrder.WaybillStatus < model.OrderStatusFinished {
jobOrder.WaybillStatus = model.OrderStatusFinished
}
dao.UpdateEntity(db, jobOrder, "WaybillQueryTime", "WaybillInfo", "WaybillStatus")
return getWaybillDetailInfoResult, err
}
func CheckJdDeliveryWeight(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
)
userBill, err := dao.GetUserBill(db, ctx.GetUserID(), "")
if userBill.AccountBalance < 0 {
return fmt.Errorf("您有京东物流订单实际超重,请支付欠款!")
}
deliveryOrders, err := dao.GetDeliveryOrdersNoPage(db, []string{ctx.GetUserID()}, nil, utils.ZeroTimeValue, utils.ZeroTimeValue, []int{0})
if err != nil {
return err
}
task := tasksch.NewParallelTask("CheckJdDeliveryWeight", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
deliveryOrder := batchItemList[0].(*model.DeliveryOrder)
waybill, err := api.JdEclpAPI.WaybillQuery(deliveryOrder.VendorWaybillID)
if err == nil {
return retVal, err
}
if waybill.DeliveryID == "" {
return retVal, err
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if waybill.DeliveryID == deliveryOrder.VendorWaybillID {
deliveryOrder.IsWeight = 1 //合格
if waybill.Weight > 3 && math.Floor(deliveryOrder.Weight) < math.Floor(waybill.Weight) {
diffPrice := (math.Floor(waybill.Weight) - math.Floor(deliveryOrder.Weight)) * waybillKgPrice
if err != nil {
return retVal, err
}
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeJdWaybillOverWeight, utils.Float64TwoInt(diffPrice), 2); err != nil {
txDB.Rollback()
return retVal, err
}
deliveryOrder.IsWeight = 2 //超重
deliveryOrder.DiffPrice = utils.Float64TwoInt(diffPrice)
}
}
deliveryOrder.ActualWeight = waybill.Weight
dao.UpdateEntityTx(txDB, deliveryOrder, "IsWeight", "ActualWeight", "DiffPrice")
dao.Commit(db, txDB)
return retVal, err
}, deliveryOrders)
tasksch.HandleTask(task, nil, true).Run()
task.GetID()
return err
}
func ResetJobTimers() {
var (
db = dao.GetDB()
)
jobTimers, err := dao.GetJobTimers(db, model.JobTimerStatusWait)
if err != nil {
return
}
task := tasksch.NewParallelTask("ResetJobTimers", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
jobTimer := batchItemList[0].(*model.JobTimer)
timer := time.NewTimer(jobTimer.StartAt.Add(time.Duration(jobTimer.LimitAt) * time.Hour).Sub(time.Now()))
jobOrders, err := dao.GetJobOrdersNoPage(db, jobTimer.JobID, jobTimer.JobOrderID, "", "", utils.ZeroTimeValue, utils.ZeroTimeValue, nil)
if err != nil {
return retVal, err
}
utils.CallFuncAsync(func() {
select {
case <-timer.C:
switch jobTimer.Type {
case model.JobTimerTypeAccept:
UpdateLimitJobOrders(db, timer, jobTimer.JobID, jobOrders[0].JobOrderID, jobTimer)
case model.JobTimerTypeSubmit:
UpdateLimitAuditJobOrders(db, timer, jobTimer.JobID, jobOrders[0].JobOrderID, jobTimer)
case model.JobTimerTypeDropShipping:
UpdateDropShippingJobOrders(db, timer, jobTimer.JobID, jobOrders[0].JobOrderID, jobTimer)
}
}
})
return retVal, err
}, jobTimers)
tasksch.HandleTask(task, nil, true).Run()
task.GetID()
}
func CreateJobSpan(ctx *jxcontext.Context, jobIDs []int, endAt string, span int) (err error) {
var (
db = dao.GetDB()
maxSeq = 0
)
if span == model.JobSpanTop {
maxSeq, err = dao.GetMaxJobTopSeq(db)
} else {
maxSeq, err = dao.GetMaxJobRecmdSeq(db)
}
for k, jobID := range jobIDs {
endAt2 := utils.Str2Time(endAt)
jonSpan := &model.JobSpan{
JobID: jobID,
EndAt: &endAt2,
SpanType: span,
}
if err = dao.CreateEntity(db, jonSpan); err == nil {
job := &model.Job{}
job.ID = jobID
if err = dao.GetEntity(db, job); err == nil {
if span == model.JobSpanTop {
job.TopSeq = k + 1 + maxSeq
job.JobSpanTop = 1
dao.UpdateEntity(db, job, "TopSeq", "JobSpanTop")
} else {
job.RecmdSeq = k + 1 + maxSeq
job.JobSpanRecmd = 1
dao.UpdateEntity(db, job, "RecmdSeq", "JobSpanRecmd")
}
}
}
}
return err
}
func RefreshJobSpan(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
)
jobSpans, err := dao.GetJobSpans(db)
task := tasksch.NewParallelTask("RefreshJobSpan", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
jobSpan := batchItemList[0].(*model.JobSpan)
if time.Now().Sub(*jobSpan.EndAt) >= 0 {
job := &model.Job{}
job.ID = jobSpan.JobID
if err = dao.GetEntity(db, job); err == nil {
if jobSpan.SpanType == model.JobSpanTop {
job.TopSeq = 0
job.JobSpanTop = 0
dao.UpdateEntity(db, job, "TopSeq", "JobSpanTop")
} else {
job.RecmdSeq = 0
job.JobSpanRecmd = 0
dao.UpdateEntity(db, job, "RecmdSeq", "JobSpanRecmd")
}
}
jobSpan.DeletedAt = time.Now()
dao.UpdateEntity(db, jobSpan, "DeletedAt")
}
return retVal, err
}, jobSpans)
tasksch.HandleTask(task, nil, true).Run()
task.GetID()
return err
}
func ReloadJobSpan(ctx *jxcontext.Context, jobIDs []int, span int) (err error) {
var (
db = dao.GetDB()
)
for k, v := range jobIDs {
job := &model.Job{}
job.ID = v
if err = dao.GetEntity(db, job); err == nil {
if span == model.JobSpanTop {
if job.JobSpanTop == model.JobSpanTop {
job.TopSeq = k + 1
dao.UpdateEntity(db, job, "TopSeq")
} else {
continue
}
} else {
if job.JobSpanRecmd == 1 {
job.RecmdSeq = k + 1
dao.UpdateEntity(db, job, "RecmdSeq")
} else {
continue
}
}
}
}
return err
}
func ConfirmDropShippingJob(ctx *jxcontext.Context, jobOrderID int) (err error) {
var (
db = dao.GetDB()
)
jobOrder := &model.JobOrder{
JobOrderID: int64(jobOrderID),
}
if err = dao.GetEntity(db, jobOrder, "JobOrderID"); err != nil {
return err
}
job := &model.Job{}
job.ID = jobOrder.JobID
if err = dao.GetEntity(db, job); err != nil {
return err
}
if ctx.GetUserID() != jobOrder.UserID && ctx.GetUserName() != "jxadmin" {
return fmt.Errorf("只有任务接取人才能确认收货!")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//确认收货更新时间和收货人
jobOrder.DropShippingConfirmTime = time.Now()
jobOrder.DropShippingConfirmUser = ctx.GetUserName()
jobOrder.Status = model.OrderStatusConfirm
if _, err = dao.UpdateEntity(db, jobOrder, "DropShippingConfirmTime", "DropShippingConfirmUser", "Status"); err != nil {
dao.Rollback(db, txDB)
return
}
userBill, err := dao.GetUserBill(db, job.UserID, "")
if err = financial.AddIncomeUpdateAccount(txDB, userBill, model.BillTypeDropShipping, jobOrder.UserActualPrice, job.ID); err != nil {
dao.Rollback(db, txDB)
return
}
dao.Commit(db, txDB)
return err
}
func RefreshDropShippingJob(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
jobOrders []*model.JobOrder
)
if time.Now().Weekday() != 5 && time.Now().Weekday() != 1 {
return
}
//找出没有完成的,顺便刷成完成
sql := `
SELECT a.*
FROM job_order a
JOIN job b ON a.job_id = b.id AND b.job_category_id = ?
WHERE a.waybill_status <= ?
AND a.drop_shipping_confirm_user = ''
AND a.status = ?
AND a.vendor_waybill_id <> ''
`
sqlParams := []interface{}{
model.JobCategoryIDDropShipping,
model.OrderStatusFinished,
model.OrderStatusFinished,
}
err = dao.GetRows(db, &jobOrders, sql, sqlParams)
task := tasksch.NewParallelTask("RefreshDropShippingJob", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
jobOrder := batchItemList[0].(*model.JobOrder)
result, err := GetAllDeliveryDetail(ctx, jobOrder.VendorWaybillID, "")
//完成了的现在判断是如果收货时间已经过了3天了就自动确认收货
if result.State == utils.Int2Str(txcloudapi.StatusFinished) && time.Now().Sub(utils.Str2Time(result.UpdateTime)) > time.Hour*72 {
err = ConfirmDropShippingJob(ctx, int(jobOrder.JobOrderID))
}
return retVal, err
}, jobOrders)
tasksch.HandleTask(task, nil, true).Run()
task.GetID()
return err
}
func AddressDistinguish(ctx *jxcontext.Context, address string) (result *txcloudapi.AddressDistinguishResult, err error) {
var (
db = dao.GetDB()
addressDistinguish = &model.AddressDistinguish{Address: address}
)
if len(address) <= 11 {
return result, fmt.Errorf("地址长度过短,请确认后再进行识别!")
}
//建了个表,有查过的记录就存一下吧
if err = dao.GetEntity(db, addressDistinguish, "Address"); err == nil && addressDistinguish.ID != 0 {
if err = json.Unmarshal([]byte(addressDistinguish.Info), &result); err == nil {
return result, err
}
}
result, err = api.TxAPI.AddressDistinguish(address)
result.Lng, result.Lat, err = api.AutonaviAPI.GetCoordinateFromAddressByPage(result.AddressDetail, result.CityCode)
if data, err := json.Marshal(result); err == nil {
addressDistinguish.Info = string(data)
dao.CreateEntity(db, addressDistinguish)
}
return result, err
}
func UpdateJob(ctx *jxcontext.Context, payload map[string]interface{}) (err error) {
var (
db = dao.GetDB()
jobExt = &model.JobExt{}
job2 = &model.Job{}
)
utils.Map2StructByJson(payload, &jobExt, false)
job2.ID = int(utils.MustInterface2Int64(payload["id"]))
dao.GetEntity(db, job2)
valid := dao.StrictMakeMapByStructObject(payload, job2, ctx.GetUserName())
if len(valid) > 0 {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntityByKV(db, job2, valid, nil); err != nil {
dao.Rollback(db, txDB)
return err
}
if len(jobExt.JobSteps) > 0 {
steps, _ := dao.GetJobSteps(db, job2.ID)
for _, v := range steps {
v.DeletedAt = time.Now()
dao.UpdateEntity(db, v, "DeletedAt")
}
for _, v := range jobExt.JobSteps {
v.DeletedAt = utils.DefaultTimeValue
v.LastOperator = ctx.GetUserName()
v.JobID = job2.ID
dao.CreateEntity(db, v)
}
}
if len(jobExt.JobImgs) > 0 {
imgs, _ := dao.GetJobImgs(db, job2.ID)
for _, v := range imgs {
dao.DeleteEntity(db, v)
}
for _, v := range jobExt.JobImgs {
v.LastOperator = ctx.GetUserName()
v.JobID = job2.ID
dao.CreateEntity(db, v)
}
}
dao.Commit(db, txDB)
}
return err
}
type Store struct {
model.ModelIDCULD
OriginalName string `orm:"-" json:"originalName"`
Name string `orm:"size(255)" json:"name"`
CityCode int `orm:"default(0);null" json:"cityCode"` // todo ?
DistrictCode int `orm:"default(0);null" json:"districtCode"` // todo ?
Address string `orm:"size(255)" json:"address"`
Tel1 string `orm:"size(32);index" json:"tel1"`
Tel2 string `orm:"size(32);index" json:"tel2"`
OpenTime1 int16 `json:"openTime1" validate:"max=2359,min=1,ltfield=CloseTime1"` // 930就表示9点半用两个的原因是为了支持中午休息1与2的时间段不能交叉为0表示没有
CloseTime1 int16 `json:"closeTime1" validate:"max=2359,min=1` // 格式同上
OpenTime2 int16 `json:"openTime2" validate:"max=2359,min=1,ltfield=CloseTime2"` // 格式同上
CloseTime2 int16 `json:"closeTime2" validate:"max=2359,min=1` // 格式同上
Lng int `json:"-"` // 乘了10的6次方
Lat int `json:"-"` // 乘了10的6次方
DeliveryRangeType int8 `json:"deliveryRangeType"` // 参见相关常量定义
DeliveryRange string `orm:"type(text)" json:"deliveryRange"` // 如果DeliveryRangeType为DeliveryRangeTypePolygon则为逗号分隔坐标分号分隔的坐标点坐标与Lng和Lat一样都是整数比如 121361504,31189308;121420555,31150238。否则为半径单位为米
Status int `json:"status"`
AutoEnableAt *time.Time `orm:"type(datetime);null" json:"autoEnableAt"` // 自动营业时间(临时休息用)
ChangePriceType int8 `json:"changePriceType"` // 修改价格类型,即是否需要审核
SMSNotify int8 `orm:"column(sms_notify);" json:"smsNotify"` // 是否通过短信接收订单消息(每天只推一条)
SMSNotifyMark int8 `orm:"column(sms_notify_mark);" json:"smsNotifyMark"` //今天是否已经推送过订单消息
AutoReplyType int8 `json:"autoReplyType"` // 订单评价自动回复类型
LinkStoreID int `orm:"column(link_store_id);default(0);index" json:"linkStoreID"` // 关联门店ID
StoreLevel string `orm:"default(C);size(32)" json:"storeLevel"` // 门店等级(筛选用,京西的)
Comment string `orm:"size(255)" json:"comment"` //门店备注
PrinterDisabled int8 `orm:"default(0)" json:"printerDisabled"` // 是否禁用网络打印机
PrinterFontSize int8 `orm:"default(0)" json:"printerFontSize"` // 打印字体-10正常1
PrinterVendorID int `orm:"column(printer_vendor_id);" json:"printerVendorID"`
PrinterSN string `orm:"size(32);column(printer_sn);index" json:"printerSN"`
PrinterKey string `orm:"size(64)" json:"printerKey"`
PrinterBindInfo string `orm:"size(1024)" json:"-"`
IDCardFront string `orm:"size(255);column(id_card_front)" json:"idCardFront"`
IDCardBack string `orm:"size(255);column(id_card_back)" json:"idCardBack"`
IDCardHand string `orm:"size(255);column(id_card_hand)" json:"idCardHand"`
Licence string `orm:"size(255)" json:"licence"` // 营业执照图片
LicenceCode string `orm:"size(32)" json:"licenceCode"`
LicenceType int8 `json:"licenceType"` // 营业执照类型0个人1公司
LicenceCorpName string `orm:"size(64)" json:"licenceCorpName"` // 营业执照公司名称
LicenceOwnerName string `orm:"size(8)" json:"licenceOwnerName"` // 法人姓名
LicenceAddress string `orm:"size(255)" json:"licenceAddress"` // 地址
LicenceValid string `orm:"size(32)" json:"licenceValid"` // 有效期开始
LicenceExpire string `orm:"size(32)" json:"licenceExpire"` // 有效期结束
IDName string `orm:"size(8);column(id_name)" json:"idName"` // 身份证姓名
IDCode string `orm:"size(32);column(id_code)" json:"idCode"` // 身份证号
IDValid string `orm:"column(id_valid);size(32)" json:"idValid"` // 有效期开始
IDExpire string `orm:"column(id_expire);size(32)" json:"idExpire"` // 有效期结束
Licence2Image string `orm:"size(255)" json:"licence2Image"` // 食品经营许可证
Licence2Code string `orm:"size(32)" json:"licence2Code"` // 食品经营许可证编号
Licence2Valid string `orm:"size(32)" json:"licence2Valid"` // 有效期开始
Licence2Expire string `orm:"size(32)" json:"licence2Expire"` // 有效期结束
// MarketManName string `orm:"size(8)" json:"marketManName"` // 市场负责人姓名
MarketManPhone string `orm:"size(16)" json:"marketManPhone"` // 市场负责人电话
MarketManRole string `orm:"size(32)" json:"marketManRole"` // 市场负责人组(角色,单人)
JxBrandFeeFactor int `json:"jxBrandFeeFactor"` // 京西品牌费因子
MarketAddFeeFactor int `json:"marketAddFeeFactor"` // 市场附加费因子
PayeeName string `orm:"size(8)" json:"payeeName"` // 收款人姓名
PayeeAccountNo string `orm:"size(255)" json:"payeeAccountNo"` // 收款账号
PayeeBankBranchName string `orm:"size(255)" json:"payeeBankBranchName"` // 开户支行
PayeeBankCode string `orm:"size(8)" json:"payeeBankCode"` // 开户行代码
PayPercentage int `json:"payPercentage"`
OldPayPercentage int `json:"oldPayPercentage"`
StoreFrontPic string `orm:"size(255)" json:"storeFrontPic"` //门面照
StoreInPic string `orm:"size(255)" json:"storeInPic"` //门店内照片
// OperatorName string `orm:"size(8)" json:"operatorName"` // 运营人姓名
OperatorPhone string `orm:"size(16)" json:"operatorPhone"` // 京东运营人电话
OperatorRole string `orm:"size(32)" json:"operatorRole"` // 京东运营人组(角色)
OperatorPhone2 string `orm:"size(16)" json:"operatorPhone2"` // 美团运营人电话
OperatorRole2 string `orm:"size(32)" json:"operatorRole2"` // 美团运营人组(角色)
OperatorPhone3 string `orm:"size(16)" json:"operatorPhone3"` // 饿百运营人电话
OperatorRole3 string `orm:"size(32)" json:"operatorRole3"` // 饿百运营人组(角色)
PromoteInfo string `orm:"size(255)" json:"promoteInfo"` //门店公告(所有平台统一的公告)
IsBoughtMatter int `json:"isBoughtMatter"` //这周是否申请过物料
SoundPercentage int `json:"soundPercentage"` //打印机声音大小比例
Banner string `orm:"size(9999)" json:"banner"` //门店商城bannar图
BrandID int `orm:"column(brand_id)" json:"brandID"` //品牌ID
VendorStoreID string `orm:"column(vendor_store_id)" json:"vendorStoreID"`
}
func TempJob() (err error) {
//var (
// db = dao.GetDB()
// ctx = jxcontext.AdminCtx
// storesJD []*Store
// storesMT []*Store
//)
//db.Db.Using("c4")
//sql := `
// SELECT a.*, b.vendor_store_id
// FROM store a
// JOIN store_map b ON a.id = b.store_id AND b.vendor_id = 0 AND b.deleted_at = ? AND b.vendor_store_id <> ''
// WHERE a.deleted_at = ?
// AND a.id <> 667281
// AND a.id <> 667278
// AND a.status IN (1,0)
//`
//sqlParams := []interface{}{utils.DefaultTimeValue, utils.DefaultTimeValue}
//if err = dao.GetRows(db, &storesJD, sql, sqlParams); err != nil {
// return err
//}
//sql2 := `
// SELECT a.*, b.vendor_store_id
// FROM store a
// JOIN store_map b ON a.id = b.store_id AND b.vendor_id = 1 AND b.deleted_at = ? AND b.vendor_store_id <> ''
// WHERE a.deleted_at = ?
// AND a.id <> 667281
// AND a.id <> 667278
// AND a.status IN (1,0)
//`
//sqlParams2 := []interface{}{utils.DefaultTimeValue, utils.DefaultTimeValue}
//if err = dao.GetRows(db, &storesMT, sql2, sqlParams2); err != nil {
// return err
//}
//db.Db.Using("default")
//task := tasksch.NewParallelTask("TempJob", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
// func(task2 *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// step := batchItemList[0].(int)
// switch step {
// case 0:
// task := tasksch.NewParallelTask("TempJob1", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// store := batchItemList[0].(*Store)
// job := &model.Job{
// UserID: "906380C7390E11EB8831525400C36BDA",
// JobCategoryID: 3,
// Title: "京东(" + store.Name + ")",
// Content: "领取任务后,需要尽快去完成,并提交截图。如超时未完成,任务会被取消",
// Count: 1000,
// AvgPrice: 300,
// TotalPrice: 300000,
// Status: 0,
// Address: store.Address,
// StoreURL: store.VendorStoreID,
// SurplusCount: 1000,
// JobLimitAt: 72,
// AuditLimitAt: 168,
// LimitCountType: 3,
// VendorID: 0,
// CashbackType: 1,
// JobLat: jxutils.IntCoordinate2Standard(store.Lat),
// JobLng: jxutils.IntCoordinate2Standard(store.Lng),
// Lng: store.Lng,
// Lat: store.Lat,
// JobCityCode: store.CityCode,
// }
// finishAt := utils.Str2Time("2021-12-31 00:00:00")
// job.FinishedAt = &finishAt
// dao.WrapAddIDCULDEntity(job, ctx.GetUserName())
// if err = dao.CreateEntity(db, job); err == nil {
// jobsteps, _ := dao.GetJobSteps(db, 171)
// for _, v := range jobsteps {
// jobStep := &model.JobStep{
// JobID: job.ID,
// StepCount: v.StepCount,
// Content: v.Content,
// Img: v.Img,
// Type: v.Type,
// }
// dao.WrapAddIDCULDEntity(jobStep, ctx.GetUserName())
// err = dao.CreateEntity(db, jobStep)
// }
// jobImgs, _ := dao.GetJobImgs(db, 171)
// for _, v := range jobImgs {
// jobImg := &model.JobImg{
// JobID: job.ID,
// Img: v.Img,
// }
// dao.WrapAddIDCULEntity(jobImg, ctx.GetUserName())
// err = dao.CreateEntity(db, jobImg)
// }
// }
// return retVal, err
// }, storesJD)
// tasksch.HandleTask(task, task2, true).Run()
// task.GetResult(0)
// case 1:
// task := tasksch.NewParallelTask("TempJob2", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// store := batchItemList[0].(*Store)
// job := &model.Job{
// UserID: "906380C7390E11EB8831525400C36BDA",
// JobCategoryID: 3,
// Title: "美团(" + store.Name + ")",
// Content: "领取任务后,需要尽快去完成,并提交截图。如超时未完成,任务会被取消",
// Count: 1000,
// AvgPrice: 300,
// TotalPrice: 300000,
// Status: 0,
// Address: store.Address,
// StoreURL: store.VendorStoreID,
// SurplusCount: 1000,
// JobLimitAt: 72,
// AuditLimitAt: 168,
// LimitCountType: 3,
// VendorID: 1,
// CashbackType: 1,
// JobLat: jxutils.IntCoordinate2Standard(store.Lat),
// JobLng: jxutils.IntCoordinate2Standard(store.Lng),
// Lng: store.Lng,
// Lat: store.Lat,
// JobCityCode: store.CityCode,
// }
// finishAt := utils.Str2Time("2021-12-31 00:00:00")
// job.FinishedAt = &finishAt
// dao.WrapAddIDCULDEntity(job, ctx.GetUserName())
// if err = dao.CreateEntity(db, job); err == nil {
// jobsteps, _ := dao.GetJobSteps(db, 173)
// for _, v := range jobsteps {
// jobStep := &model.JobStep{
// JobID: job.ID,
// StepCount: v.StepCount,
// Content: v.Content,
// Img: v.Img,
// Type: v.Type,
// }
// dao.WrapAddIDCULDEntity(jobStep, ctx.GetUserName())
// err = dao.CreateEntity(db, jobStep)
// }
// jobImgs, _ := dao.GetJobImgs(db, 173)
// for _, v := range jobImgs {
// jobImg := &model.JobImg{
// JobID: job.ID,
// Img: v.Img,
// }
// dao.WrapAddIDCULEntity(jobImg, ctx.GetUserName())
// err = dao.CreateEntity(db, jobImg)
// }
// }
// return retVal, err
// }, storesMT)
// tasksch.HandleTask(task, task2, true).Run()
// task.GetResult(0)
// }
// return retVal, err
// }, []int{0, 1})
//tasksch.HandleTask(task, nil, true).Run()
//task.GetID()
return err
}
func GetUnionActList(ctx *jxcontext.Context, vendorID, actType int) (actList []*partner.ActivityList, err error) {
if handler := partner.GetHandler(vendorID); handler != nil {
actList, err = handler.GetUnionActList(ctx, actType)
}
return actList, err
}
func ShareUnionLink(ctx *jxcontext.Context, jobID, shareType, linkType, resourceType int, goodsID string) (link string, err error) {
var (
job = &model.Job{}
db = dao.GetDB()
sid string //推广位ID美团为userID淘宝饿了么本地化暂时是固定的京西推广位IDpdd为表中推广位ID
//userID = ctx.GetUserID()
mobile, userID = ctx.GetMobileAndUserID()
userBinds []*model.UserUnionBind
)
if jobID == 0 {
return "", fmt.Errorf("该活动已结束,请选择其他活动!")
}
job.ID = jobID
if err = dao.GetEntity(db, job); err != nil {
return "", err
}
vendorID := job.VendorID
unionID := mobile + utils.Int2Str(jobID)
handler := partner.GetHandler(vendorID)
//1、建推广位本地和平台
if userBinds, err = dao.GetUserUnionBind(db, userID, vendorID, ""); err != nil {
return "", err
}
//本地已有推广位
if len(userBinds) > 0 {
sid = userBinds[0].UnionID
} else {
userBind := &model.UserUnionBind{
UserID: userID,
VendorID: vendorID,
}
dao.WrapAddIDCULDEntity(userBind, ctx.GetUserName())
if handler != nil {
if sid, err = handler.CreateUnionPosition(ctx, unionID); err == nil {
if sid == "" {
sid = unionID
if vendorID == model.VendorIDTB {
sid = utils.Int2Str(tbunionapi.JxAdzoneID)
}
}
}
}
userBind.UnionID = sid
dao.CreateEntity(db, userBind)
}
//2、分享链接
if handler != nil {
if link, err = handler.ShareUnionLink(ctx, linkType, utils.Str2Int(job.UnionActID), sid, userID, resourceType, goodsID); err == nil {
if vendorID == model.VendorIDMTWM || vendorID == model.VendorIDTB {
if linkType == partner.LinkTypeWeiXinMini {
if resBinary, _, err := jxutils.DownloadFileByURL(link); err == nil {
if downloadURL, err := jxutils.UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix())+link[strings.LastIndex(link, "/")+1:len(link)]); err == nil {
if err == nil {
link = jxutils.MixWatermarkImg(downloadURL+"?imageView2/1/w/120/h/120/q/75", job.UnionImg, job.UnionQrcodePosition)
link += "?imageslim"
}
}
}
}
}
}
}
return link, err
}
type GetUnionJobOrderInfoResult struct {
AcceptCouponCount int `json:"acceptCouponCount"` //领取优惠券数量
FinishedOrderCount int `json:"finishedOrderCount"` //完成订单量
IncomePrice int `json:"incomePrice"` //收入
}
func GetUnionJobOrderInfo(ctx *jxcontext.Context, jobOrderID int) (getUnionJobOrderInfoResult *GetUnionJobOrderInfoResult, err error) {
var (
jobOrder = &model.JobOrder{}
job = &model.Job{}
db = dao.GetDB()
)
jobOrder.ID = int64(jobOrderID)
if err = dao.GetEntity(db, jobOrder); err != nil {
return nil, err
}
job.ID = jobOrder.JobID
if err = dao.GetEntity(db, job); err != nil {
return nil, err
}
if job.JobCategoryID != model.JobCategoryIDUnion {
return nil, fmt.Errorf("只允许联盟任务才能查看!")
}
userBill, err := dao.GetUserBill(db, jobOrder.UserID, "")
if err != nil {
return nil, err
}
incomes, err := dao.GetBillIncome(db, job.ID, userBill.BillID)
if err != nil {
return nil, err
}
incomeTotal := 0
for _, v := range incomes {
incomeTotal += v.IncomePrice
}
getUnionJobOrderInfoResult.IncomePrice = incomeTotal
return getUnionJobOrderInfoResult, err
}
func GetVendorMatters(ctx *jxcontext.Context, vendorID int, vendorCatID, keyword string, offset, pageSize, sortType int, listID string) (result *partner.MatterList, err error) {
handler := partner.GetHandler(vendorID)
return handler.GetUnionMatterList(ctx, vendorCatID, keyword, offset, pageSize, sortType, listID)
}
func GetVendorMatterDetail(ctx *jxcontext.Context, vendorID int, goodsID string) (goodsDetail *partner.GoodsDetail, err error) {
handler := partner.GetHandler(vendorID)
return handler.GetUnionMatterDetail(ctx, goodsID)
}
func GetVendorMatterRcmmd(ctx *jxcontext.Context, vendorID int, goodsID string, rcmmdType, offset, pageSize int) (result *partner.MatterList, err error) {
handler := partner.GetHandler(vendorID)
return handler.GetUnionMatterListRcmmd(ctx, goodsID, rcmmdType, offset, pageSize)
}