Files
jx-callback/business/jxstore/cms/job.go
2020-10-19 10:38:39 +08:00

447 lines
15 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 (
"fmt"
"time"
"git.rosy.net.cn/jx-callback/globals"
"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/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
const (
AcceptMaxCount = 2
CancelMaxCount = 5
)
var (
DayTimeBegin time.Time
DayTimeEnd time.Time
WeekTimeBegin time.Time
WeekTimeEnd time.Time
)
func init() {
DayTimeBegin = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + " 00:00:00")
DayTimeEnd = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + " 23:59:59")
WeekTimeBegin, WeekTimeEnd = getWeekTime()
}
func getWeekTime() (weekTimeBegin, weekTimeEnd time.Time) {
offset := int(time.Now().Weekday() - 1)
if offset == -1 {
offset = -6
}
weekTimeBegin = time.Now().AddDate(0, 0, offset)
weekTimeEnd = weekTimeBegin.AddDate(0, 0, 7)
return weekTimeBegin, weekTimeEnd
}
func PublishJob(ctx *jxcontext.Context, job *model.Job) (err error) {
var (
db = dao.GetDB()
timeNow = utils.Time2Date(time.Now())
fromTime = utils.Time2Str(timeNow) + "00:00:00"
toTime = utils.Time2Str(timeNow) + "23:59:59"
)
//需根据任务类型做一些参数判断,比如门店商品链接,地址
// switch job.JobCategoryID {
// case 1:
// }
if ctx.GetUserID() != job.UserID {
return fmt.Errorf("用户信息已过期,请重新登录!")
}
//发布任务要扣除任务总额的保证金,不够扣就要进行充值
userBill, err := dao.GetUserBill(db, job.UserID, "")
if userBill == nil {
return fmt.Errorf("未查询到该用户的账单!")
}
job.TotalPrice = job.Count * job.AvgPrice
if userBill.AccountBalance < job.TotalPrice {
job.Status = model.JobStatusFailed
} else {
job.Status = model.JobStatusDoing
}
if job.Count <= 0 {
return fmt.Errorf("任务数量不能为0")
}
if job.UserID == "" {
return fmt.Errorf("任务发起人不能为空!")
}
jobs, err := dao.GetJobsNoPage(db, []string{job.UserID}, nil, nil, utils.Str2Time(fromTime), utils.Str2Time(toTime), false)
if len(jobs) > 0 {
members, err := dao.GetUserMember(db, job.UserID, 0, 0, true)
if err != nil {
return err
}
if len(members) <= 0 {
return fmt.Errorf("非会员一天只能发布一起任务,请确认!")
}
}
if job.Address != "" && (job.Lng == 0 || job.Lat == 0) {
lng, lat, err := api.AutonaviAPI.GetCoordinateFromAddressByPage(job.Address)
if err != nil {
return err
}
job.Lng = jxutils.StandardCoordinate2Int(lng)
job.Lat = jxutils.StandardCoordinate2Int(lat)
}
dao.WrapAddIDCULEntity(job, ctx.GetUserName())
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
err = dao.CreateEntity(db, job)
for _, v := range job.JobSteps {
dao.WrapAddIDCULEntity(v, ctx.GetUserName())
v.JobID = job.ID
err = dao.CreateEntity(db, v)
}
if err != nil {
dao.Rollback(db)
}
//发布任务要扣除任务总额的保证金,不够扣就要进行充值
if err == nil && job.Status != model.JobStatusFailed {
//1、账户支出增加一条记录
if err = financial.AddBillExpend(db, userBill.BillID, model.BillTypeDeposit, job.TotalPrice); err != nil {
dao.Rollback(db)
}
//2、账户表余额减少相应值
userBill.AccountBalance -= job.TotalPrice
if _, err = dao.UpdateEntity(db, userBill, "AccountBalance"); err != nil {
dao.Rollback(db)
}
}
dao.Commit(db)
return 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("未查询到该用户的账单!")
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
//1、根据任务剩余数量退钱到账户余额中
userBill.AccountBalance += job.SurplusCount * job.AvgPrice
if _, err = dao.UpdateEntity(db, userBill, "AccountBalance"); err != nil {
dao.Rollback(db)
}
//2、账户收入增加一条记录
if err = financial.AddBillIncome(db, userBill.BillID, model.BillTypeJobCancelOverdue, job.SurplusCount*job.AvgPrice); err != nil {
dao.Rollback(db)
}
//3、任务状态被取消
job.Status = model.JobStatusFailed
if _, err = dao.UpdateEntity(db, job, "Status"); err != nil {
dao.Rollback(db)
}
dao.Commit(db)
return err
}
func GetJobs(ctx *jxcontext.Context, userIDs []string, categoryIDs, statuss, vendorIDs []int, includeStep bool, fromTime, toTime string, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
return dao.GetJobs(dao.GetDB(), userIDs, categoryIDs, statuss, vendorIDs, includeStep, utils.Str2Time(fromTime), utils.Str2Time(toTime), pageSize, offset)
}
func AcceptJob(ctx *jxcontext.Context, jobID int) (err error) {
var (
db = dao.GetDB()
userID = ctx.GetUserID()
num int
)
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("未找到该任务或该任务状态不正常,无法接单!")
}
num, err = checkJobOrders(db, 0, "<= "+utils.Int2Str(model.JobOrderStatusAccept), userID, utils.ZeroTimeValue, utils.ZeroTimeValue)
if num >= AcceptMaxCount {
return fmt.Errorf("每人最多接取" + utils.Int2Str(AcceptMaxCount) + "个任务,请核实!")
}
num, err = checkJobOrders(db, jobID, "<= "+utils.Int2Str(model.JobOrderStatusWaitAudit), userID, utils.ZeroTimeValue, utils.ZeroTimeValue)
if num > 0 {
return fmt.Errorf("您还有此任务未完成,请完成后再接取!")
}
// num, err = checkJobOrders(db, "= "+utils.Int2Str(model.JobOrderStatusAuditUnPass), userID, utils.ZeroTimeValue, utils.ZeroTimeValue)
// if num > 0 {
// return 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 fmt.Errorf("此任务只支持每人做一次!")
}
case model.JobLimitCountTypePDO:
num, err = checkJobOrders(db, jobID, "<> "+utils.Int2Str(model.JobOrderStatusCancel), userID, DayTimeBegin, DayTimeEnd)
if num > 0 {
return fmt.Errorf("此任务只支持每人每天做一次!")
}
case model.JobLimitCountTypePWO:
num, err = checkJobOrders(db, jobID, "<> "+utils.Int2Str(model.JobOrderStatusCancel), userID, WeekTimeBegin, WeekTimeEnd)
if num > 0 {
return fmt.Errorf("此任务只支持每人每周做一次!")
}
case model.JobLimitCountTypeNoLimit:
default:
return fmt.Errorf("不支持的任务限次类型!%v", job.LimitCountType)
}
jobOrder := &model.JobOrder{
JobID: jobID,
JobOrderID: jxutils.GenJobOrderNo(),
UserID: job.UserID,
Status: model.JobOrderStatusAccept,
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if err = dao.CreateEntity(db, jobOrder); err != nil {
dao.Rollback(db)
}
//用户接受任务,任务剩余次数-1
job.SurplusCount -= 1
if _, err = dao.UpdateEntity(db, job, "SurplusCount"); err != nil {
dao.Rollback(db)
}
dao.Commit(db)
//任务限时完成
checkLimitJobOrders(db, job, jobOrder)
return 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")
job := &model.Job{}
job.ID = jobID
err = dao.GetEntity(db, &job)
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
//如果当前任务状态正常剩余数量就加1
if job.Status > 0 {
job.SurplusCount += 1
if _, err = dao.UpdateEntity(db, job, "SurplusCount"); err != nil {
dao.Rollback(db)
}
} else {
userBill, err := dao.GetUserBill(db, job.UserID, "")
if userBill == nil {
return fmt.Errorf("未查询到该用户的账单!")
}
//如果状态不正常(取消或者过期)就要把这一笔退回去
//1、根据任务剩余数量退钱到任务保证金余额中
userBill.AccountBalance += job.AvgPrice
if _, err = dao.UpdateEntity(db, userBill, "AccountBalance"); err != nil {
dao.Rollback(db)
}
//2、账户收入增加一条记录
if err = financial.AddBillIncome(db, userBill.BillID, model.BillTypeJobCancelOverdue, job.AvgPrice); err != nil {
dao.Rollback(db)
}
//3、任务订单状态被取消
jobOrder.Status = model.JobOrderStatusCancel
if _, err = dao.UpdateEntity(db, jobOrder, "Status"); err != nil {
dao.Rollback(db)
}
}
dao.Commit(db)
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) {
utils.AfterFuncWithRecover(time.Hour*time.Duration(job.JobLimitAt), func() {
utils.CallFuncAsync(func() {
globals.SugarLogger.Debugf("checkLimitJobOrders jobID: %v, jobOrderID: %v", job.ID, jobOrder.JobOrderID)
jobOrders, _ := dao.GetJobOrdersNoPage(db, job.ID, jobOrder.JobOrderID, job.UserID, "", utils.ZeroTimeValue, utils.ZeroTimeValue, nil)
if len(jobOrders) == 0 {
return
}
jobOrder := jobOrders[0]
if jobOrder.Status == model.JobOrderStatusCancel {
return
}
jobOrder.Status = model.JobOrderStatusCancel
dao.UpdateEntity(db, jobOrder, "Status")
})
})
}
func checkLimitAuditJobOrders(db *dao.DaoDB, job *model.Job, jobOrder *model.JobOrder) {
utils.AfterFuncWithRecover(time.Hour*time.Duration(job.AuditLimitAt), func() {
utils.CallFuncAsync(func() {
globals.SugarLogger.Debugf("checkLimitAuditJobOrders jobID: %v, jobOrderID: %v", job.ID, jobOrder.JobOrderID)
if jobOrder.Status == model.JobOrderStatusWaitAudit {
err := AuditJob(jxcontext.AdminCtx, int(jobOrder.JobOrderID), model.JobOrderStatusAuditPass, "超时系统通过")
if err != nil {
globals.SugarLogger.Debugf("checkLimitAuditJobOrders err: %v jobID: %v, jobOrderID: %v", err, job.ID, jobOrder.JobOrderID)
}
}
})
})
}
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 jobOrder2.JobID == 0 {
return fmt.Errorf("未查询到相应的任务!")
}
if jobOrder2.Status >= model.JobOrderStatusWaitAudit {
return fmt.Errorf("任务订单状态有误!")
}
if ctx.GetUserID() != jobOrder2.UserID {
return fmt.Errorf("任务订单接收人有误!")
}
jobOrder2.Img = jobOrder.Img
jobOrder2.Content = jobOrder.Content
jobOrder2.SubmitAuditAt = time.Now()
jobOrder2.Status = model.JobOrderStatusWaitAudit
if _, err = dao.UpdateEntity(db, jobOrder2, "Img", "Content", "SubmitAuditAt", "Status"); err == nil {
//审核定时
checkLimitAuditJobOrders(db, job, jobOrder2)
}
return err
}
func AuditJob(ctx *jxcontext.Context, jobOrderID, status int, comment 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 {
return fmt.Errorf("任务发起人才能审核!")
}
//审核时,若此任务已过期或者已取消,不通过则应将此任务保证金退还给发起人,通过则应将单次任务保证金给接受人
//若此任务未过期,不通过则此任务剩余数量将+1通过则应将单次任务保证金给接受人
jobOrder.Status = status
jobOrder.Comment = comment
jobOrder.AuditAt = time.Now()
jobOrder.LastOperator = ctx.GetUserName()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if _, err = dao.UpdateEntity(db, jobOrder, "Status", "Comment", "AuditAt", "LastOperator"); err != nil {
dao.Rollback(db)
}
if status == model.JobOrderStatusAuditPass {
//接收人账户增加任务单次
userBillJobOrder, err := dao.GetUserBill(db, jobOrder.UserID, "")
userBillJobOrder.AccountBalance += job.AvgPrice
if _, err = dao.UpdateEntity(db, userBillJobOrder, "AccountBalance"); err != nil {
dao.Rollback(db)
}
//接收人账户收入增加一条
if err = financial.AddBillIncome(db, userBillJobOrder.BillID, model.BillTypeJob, job.AvgPrice); err != nil {
dao.Rollback(db)
}
} else {
if job.Status < 0 {
userBill, err := dao.GetUserBill(db, job.UserID, "")
//1、根据任务剩余数量退钱到任务保证金余额中
userBill.AccountBalance += job.AvgPrice
if _, err = dao.UpdateEntity(db, userBill, "AccountBalance"); err != nil {
dao.Rollback(db)
}
//2、账户收入增加一条记录
if err = financial.AddBillIncome(db, userBill.BillID, model.BillTypeJobAuditUnPassWithCancelOverdue, job.AvgPrice); err != nil {
dao.Rollback(db)
}
} else {
job.SurplusCount += 1
if _, err = dao.UpdateEntity(db, job, "SurplusCount"); err != nil {
dao.Rollback(db)
}
}
}
dao.Commit(db)
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}, utils.ZeroTimeValue, utils.ZeroTimeValue, false)
if err != nil {
globals.SugarLogger.Debugf("RefreshJobStatus err :%v", err)
return
}
for _, job := range jobs {
if time.Now().Sub(job.FinishedAt) >= 0 {
job.Status = model.JobStatusOverdue
dao.UpdateEntity(db, job, "Status")
}
}
globals.SugarLogger.Debugf("RefreshJobStatus end...")
return err
}