154 lines
8.5 KiB
Go
154 lines
8.5 KiB
Go
package sys
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"hotgo/internal/consts"
|
|
"hotgo/internal/dao"
|
|
"hotgo/internal/library/contexts"
|
|
"hotgo/internal/library/hgorm/handler"
|
|
"hotgo/internal/library/hgorm/hook"
|
|
"hotgo/internal/model/entity"
|
|
"hotgo/internal/model/input/sysin"
|
|
"hotgo/internal/service"
|
|
"hotgo/utility/encrypt"
|
|
|
|
"github.com/gogf/gf/v2/database/gdb"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
"github.com/gogf/gf/v2/util/grand"
|
|
)
|
|
|
|
type sSysTaskSubmission struct{}
|
|
|
|
func NewSysTaskSubmission() *sSysTaskSubmission { return &sSysTaskSubmission{} }
|
|
func init() { service.RegisterSysTaskSubmission(NewSysTaskSubmission()) }
|
|
func (s *sSysTaskSubmission) Model(ctx context.Context) *gdb.Model {
|
|
return handler.Model(dao.TaskSubmission.Ctx(ctx), &handler.Option{FilterTenant: true})
|
|
}
|
|
func (s *sSysTaskSubmission) listModel(ctx context.Context) *gdb.Model {
|
|
sc, tc, mc, lc := dao.TaskSubmission.Columns(), dao.Task.Columns(), dao.AppMember.Columns(), dao.AppMemberLevel.Columns()
|
|
return s.Model(ctx).As("s").LeftJoin(dao.Task.Table()+" t", col("t", tc.Id)+"="+col("s", sc.TaskId)).LeftJoin(dao.AppMember.Table()+" m", col("m", mc.Id)+"="+col("s", sc.MemberId)).LeftJoin(dao.AppMemberLevel.Table()+" l", col("l", lc.Id)+"="+col("s", sc.MemberLevelId)).Fields(col("s", sc.Id), col("s", sc.SubmissionNo), col("s", sc.TradeOrderId), col("s", sc.TaskId), fmt.Sprintf("COALESCE(%s,'') task_title", col("t", tc.Title)), col("s", sc.MemberId), col("m", mc.Username), col("m", mc.MobileMask), fmt.Sprintf("COALESCE(%s,'') level_name", col("l", lc.Name)), col("s", sc.EvidenceText), col("s", sc.EvidenceAttachmentIds), col("s", sc.SubmissionStatus), col("s", sc.CommissionAmount), col("s", sc.SuccessRate), col("s", sc.ReviewReasonCode), col("s", sc.ReviewReason), col("s", sc.AllowResubmit), col("s", sc.LedgerId), col("s", sc.ReviewedAt), col("s", sc.SettledAt), col("s", sc.CreatedAt))
|
|
}
|
|
func (s *sSysTaskSubmission) filter(ctx context.Context, mod *gdb.Model, in *sysin.TaskSubmissionListInp) (*gdb.Model, error) {
|
|
sc, mc := dao.TaskSubmission.Columns(), dao.AppMember.Columns()
|
|
if in.Username != "" {
|
|
mod = mod.WhereLike(col("m", mc.Username), "%"+in.Username+"%")
|
|
}
|
|
if in.Mobile != "" {
|
|
hash, err := encrypt.HashField(ctx, in.Mobile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
mod = mod.Where(col("m", mc.MobileHash), hash)
|
|
}
|
|
if in.SubmissionStatus > 0 {
|
|
mod = mod.Where(col("s", sc.SubmissionStatus), in.SubmissionStatus)
|
|
}
|
|
if len(in.CreatedAt) == 2 {
|
|
mod = mod.WhereBetween(col("s", sc.CreatedAt), in.CreatedAt[0], in.CreatedAt[1])
|
|
}
|
|
return mod, nil
|
|
}
|
|
func (s *sSysTaskSubmission) List(ctx context.Context, in *sysin.TaskSubmissionListInp) (list []*sysin.TaskSubmissionListModel, total int, err error) {
|
|
mod, err := s.filter(ctx, s.listModel(ctx), in)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
if err = mod.Page(in.Page, in.PerPage).OrderDesc(col("s", dao.TaskSubmission.Columns().Id)).ScanAndCount(&list, &total, false); err != nil {
|
|
return nil, 0, gerror.Wrap(err, "获取会员任务审核列表失败")
|
|
}
|
|
return
|
|
}
|
|
func (s *sSysTaskSubmission) View(ctx context.Context, in *sysin.TaskSubmissionViewInp) (res *sysin.TaskSubmissionListModel, err error) {
|
|
if err = s.listModel(ctx).Where(col("s", dao.TaskSubmission.Columns().Id), in.Id).Scan(&res); err != nil {
|
|
return nil, gerror.Wrap(err, "获取任务提交详情失败")
|
|
}
|
|
if res == nil {
|
|
return nil, gerror.New("任务提交不存在")
|
|
}
|
|
return
|
|
}
|
|
func (s *sSysTaskSubmission) Review(ctx context.Context, in *sysin.TaskSubmissionReviewInp) error {
|
|
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
|
sc := dao.TaskSubmission.Columns()
|
|
var submission *entity.TaskSubmission
|
|
if err := s.Model(ctx).WherePri(in.Id).LockUpdate().Scan(&submission); err != nil {
|
|
return err
|
|
}
|
|
if submission == nil {
|
|
return gerror.New("任务提交不存在")
|
|
}
|
|
if submission.SubmissionStatus != consts.TaskSubmissionPending {
|
|
return gerror.New("该记录已审核,请勿重复操作")
|
|
}
|
|
var task *entity.Task
|
|
if err := handler.Model(dao.Task.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(submission.TaskId).Scan(&task); err != nil {
|
|
return err
|
|
}
|
|
if task == nil {
|
|
return gerror.New("关联任务不存在")
|
|
}
|
|
var member *entity.AppMember
|
|
if err := handler.Model(dao.AppMember.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(submission.MemberId).Scan(&member); err != nil {
|
|
return err
|
|
}
|
|
if member == nil || member.MemberStatus != consts.AppMemberStatusNormal {
|
|
return gerror.New("会员不存在或状态异常")
|
|
}
|
|
now := gtime.Now()
|
|
uid := contexts.GetUserId(ctx)
|
|
if in.Decision == consts.FinanceDecisionReject {
|
|
_, err := s.Model(ctx).WherePri(in.Id).Data(g.Map{sc.SubmissionStatus: consts.TaskSubmissionRejected, sc.ReviewedBy: uid, sc.ReviewedAt: now, sc.ReviewReasonCode: in.ReasonCode, sc.ReviewReason: in.ReasonText, sc.AllowResubmit: in.AllowResubmit, sc.UpdatedBy: uid}).Update()
|
|
if err != nil {
|
|
return gerror.Wrap(err, "驳回任务提交失败")
|
|
}
|
|
return service.SysBizAudit().Record(ctx, &sysin.BizAuditRecordInp{Module: "task_submission", Action: "task_submission.reject", TargetType: "task_submission", TargetId: submission.Id, Before: submission, After: g.Map{"status": consts.TaskSubmissionRejected, "allowResubmit": in.AllowResubmit}, Reason: in.ReasonText})
|
|
}
|
|
wc := dao.WalletAccount.Columns()
|
|
var account *entity.WalletAccount
|
|
if err := handler.Model(dao.WalletAccount.Ctx(ctx), &handler.Option{FilterTenant: true}).Where(wc.MemberId, submission.MemberId).Where(wc.Currency, "CNY").LockUpdate().Scan(&account); err != nil {
|
|
return err
|
|
}
|
|
if account == nil || account.AccountStatus != 1 {
|
|
return gerror.New("会员钱包不存在或不可结算")
|
|
}
|
|
lc := dao.WalletLedger.Columns()
|
|
count, err := handler.Model(dao.WalletLedger.Ctx(ctx), &handler.Option{FilterTenant: true}).Where(lc.IdempotencyKey, in.IdempotencyKey).Count()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if count > 0 {
|
|
return gerror.New("该幂等键已使用,任务佣金未重复发放")
|
|
}
|
|
after := account.AvailableAmount + submission.CommissionAmount
|
|
result, err := dao.WalletLedger.Ctx(ctx).Fields(lc.LedgerNo, lc.AccountId, lc.MemberId, lc.BizType, lc.BizNo, lc.EntryType, lc.Direction, lc.Amount, lc.BeforeAmount, lc.AfterAmount, lc.Currency, lc.IdempotencyKey, lc.Remark, lc.OperatorId, lc.OccurredAt).Hook(hook.SaveTenant).Data(g.Map{lc.LedgerNo: "WL" + gtime.Now().Format("YmdHis") + grand.S(7), lc.AccountId: account.Id, lc.MemberId: submission.MemberId, lc.BizType: "commission", lc.BizNo: submission.SubmissionNo, lc.EntryType: "available", lc.Direction: consts.WalletDirectionIncome, lc.Amount: submission.CommissionAmount, lc.BeforeAmount: account.AvailableAmount, lc.AfterAmount: after, lc.Currency: account.Currency, lc.IdempotencyKey: in.IdempotencyKey, lc.Remark: in.ReasonText, lc.OperatorId: uid, lc.OccurredAt: now}).Insert()
|
|
if err != nil {
|
|
return gerror.Wrap(err, "写入任务佣金台账失败")
|
|
}
|
|
ledgerId64, _ := result.LastInsertId()
|
|
update, err := handler.Model(dao.WalletAccount.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(account.Id).Where(wc.Version, account.Version).Data(g.Map{wc.AvailableAmount: after, wc.TotalIncome: gdb.Raw(wc.TotalIncome + "+" + fmt.Sprint(submission.CommissionAmount)), wc.Version: gdb.Raw(wc.Version + "+1")}).Update()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rows, _ := update.RowsAffected()
|
|
if rows != 1 {
|
|
return gerror.New("钱包余额已变化,请重试")
|
|
}
|
|
_, err = s.Model(ctx).WherePri(in.Id).Data(g.Map{sc.SubmissionStatus: consts.TaskSubmissionSettled, sc.ReviewedBy: uid, sc.ReviewedAt: now, sc.ReviewReasonCode: in.ReasonCode, sc.ReviewReason: in.ReasonText, sc.AllowResubmit: consts.StatusDisable, sc.LedgerId: uint64(ledgerId64), sc.SettledAt: now, sc.UpdatedBy: uid}).Update()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if submission.TradeOrderId > 0 {
|
|
tc := dao.TradeOrder.Columns()
|
|
_, err = handler.Model(dao.TradeOrder.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(submission.TradeOrderId).Data(g.Map{tc.OrderStatus: consts.TradeOrderCompleted, tc.CompletedAt: now, tc.UpdatedBy: uid}).Update()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return service.SysBizAudit().Record(ctx, &sysin.BizAuditRecordInp{Module: "task_submission", Action: "task_submission.settle", TargetType: "task_submission", TargetId: submission.Id, Before: submission, After: g.Map{"status": consts.TaskSubmissionSettled, "ledgerId": uint64(ledgerId64), "commissionAmount": submission.CommissionAmount}, Reason: in.ReasonText})
|
|
})
|
|
}
|