feat: add superadmin creator review and coupon governance
This commit is contained in:
@@ -953,6 +953,76 @@ func (s *super) TenantHealth(ctx context.Context, filter *super_dto.TenantListFi
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) ListCreatorApplications(ctx context.Context, filter *super_dto.TenantListFilter) (*requests.Pager, error) {
|
||||
if filter == nil {
|
||||
filter = &super_dto.TenantListFilter{}
|
||||
}
|
||||
if filter.Status == nil || *filter.Status == "" {
|
||||
status := consts.TenantStatusPendingVerify
|
||||
filter.Status = &status
|
||||
}
|
||||
return s.ListTenants(ctx, filter)
|
||||
}
|
||||
|
||||
func (s *super) ReviewCreatorApplication(ctx context.Context, operatorID, tenantID int64, form *super_dto.SuperCreatorApplicationReviewForm) error {
|
||||
if operatorID == 0 {
|
||||
return errorx.ErrUnauthorized.WithMsg("缺少操作者信息")
|
||||
}
|
||||
if tenantID == 0 || form == nil {
|
||||
return errorx.ErrBadRequest.WithMsg("审核参数无效")
|
||||
}
|
||||
|
||||
action := strings.ToLower(strings.TrimSpace(form.Action))
|
||||
if action != "approve" && action != "reject" {
|
||||
return errorx.ErrBadRequest.WithMsg("审核动作无效")
|
||||
}
|
||||
|
||||
tbl, q := models.TenantQuery.QueryContext(ctx)
|
||||
tenant, err := q.Where(tbl.ID.Eq(tenantID)).First()
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errorx.ErrRecordNotFound.WithMsg("创作者申请不存在")
|
||||
}
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if tenant.Status != consts.TenantStatusPendingVerify {
|
||||
return errorx.ErrBadRequest.WithMsg("创作者申请已处理")
|
||||
}
|
||||
|
||||
nextStatus := consts.TenantStatusVerified
|
||||
if action == "reject" {
|
||||
nextStatus = consts.TenantStatusBanned
|
||||
}
|
||||
_, err = q.Where(tbl.ID.Eq(tenant.ID), tbl.Status.Eq(consts.TenantStatusPendingVerify)).Update(tbl.Status, nextStatus)
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
if Notification != nil {
|
||||
title := "创作者申请审核结果"
|
||||
detail := "您的创作者申请已通过"
|
||||
if nextStatus == consts.TenantStatusBanned {
|
||||
detail = "您的创作者申请已驳回"
|
||||
if strings.TrimSpace(form.Reason) != "" {
|
||||
detail += ",原因:" + strings.TrimSpace(form.Reason)
|
||||
}
|
||||
}
|
||||
_ = Notification.Send(ctx, tenant.ID, tenant.UserID, string(consts.NotificationTypeAudit), title, detail)
|
||||
}
|
||||
if Audit != nil {
|
||||
detail := "approve"
|
||||
if nextStatus == consts.TenantStatusBanned {
|
||||
detail = "reject"
|
||||
}
|
||||
if strings.TrimSpace(form.Reason) != "" {
|
||||
detail += ",原因:" + strings.TrimSpace(form.Reason)
|
||||
}
|
||||
Audit.Log(ctx, operatorID, "review_creator_application", cast.ToString(tenant.ID), detail)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *super) CreateTenant(ctx context.Context, form *super_dto.TenantCreateForm) error {
|
||||
uid := form.AdminUserID
|
||||
if _, err := models.UserQuery.WithContext(ctx).Where(models.UserQuery.ID.Eq(uid)).First(); err != nil {
|
||||
@@ -1065,6 +1135,191 @@ func (s *super) ListTenantUsers(ctx context.Context, tenantID int64, filter *sup
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) ListPayoutAccounts(ctx context.Context, filter *super_dto.SuperPayoutAccountListFilter) (*requests.Pager, error) {
|
||||
if filter == nil {
|
||||
filter = &super_dto.SuperPayoutAccountListFilter{}
|
||||
}
|
||||
|
||||
tbl, q := models.PayoutAccountQuery.QueryContext(ctx)
|
||||
if filter.TenantID != nil && *filter.TenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(*filter.TenantID))
|
||||
}
|
||||
if filter.UserID != nil && *filter.UserID > 0 {
|
||||
q = q.Where(tbl.UserID.Eq(*filter.UserID))
|
||||
}
|
||||
if filter.Type != nil && strings.TrimSpace(*filter.Type) != "" {
|
||||
q = q.Where(tbl.Type.Eq(strings.TrimSpace(*filter.Type)))
|
||||
}
|
||||
|
||||
tenantIDs, tenantFilter, err := s.lookupTenantIDs(ctx, filter.TenantCode, filter.TenantName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tenantFilter {
|
||||
if len(tenantIDs) == 0 {
|
||||
q = q.Where(tbl.ID.Eq(-1))
|
||||
} else {
|
||||
q = q.Where(tbl.TenantID.In(tenantIDs...))
|
||||
}
|
||||
}
|
||||
|
||||
userIDs, userFilter, err := s.lookupUserIDs(ctx, filter.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userFilter {
|
||||
if len(userIDs) == 0 {
|
||||
q = q.Where(tbl.ID.Eq(-1))
|
||||
} else {
|
||||
q = q.Where(tbl.UserID.In(userIDs...))
|
||||
}
|
||||
}
|
||||
|
||||
if filter.CreatedAtFrom != nil {
|
||||
from, err := s.parseFilterTime(filter.CreatedAtFrom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if from != nil {
|
||||
q = q.Where(tbl.CreatedAt.Gte(*from))
|
||||
}
|
||||
}
|
||||
if filter.CreatedAtTo != nil {
|
||||
to, err := s.parseFilterTime(filter.CreatedAtTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if to != nil {
|
||||
q = q.Where(tbl.CreatedAt.Lte(*to))
|
||||
}
|
||||
}
|
||||
|
||||
filter.Pagination.Format()
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
list, err := q.Order(tbl.CreatedAt.Desc()).
|
||||
Offset(int(filter.Pagination.Offset())).
|
||||
Limit(int(filter.Pagination.Limit)).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
tenantMap := make(map[int64]*models.Tenant)
|
||||
userMap := make(map[int64]*models.User)
|
||||
if len(list) > 0 {
|
||||
tenantIDSet := make(map[int64]struct{})
|
||||
userIDSet := make(map[int64]struct{})
|
||||
for _, pa := range list {
|
||||
if pa.TenantID > 0 {
|
||||
tenantIDSet[pa.TenantID] = struct{}{}
|
||||
}
|
||||
if pa.UserID > 0 {
|
||||
userIDSet[pa.UserID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
tenantIDs = tenantIDs[:0]
|
||||
for id := range tenantIDSet {
|
||||
tenantIDs = append(tenantIDs, id)
|
||||
}
|
||||
if len(tenantIDs) > 0 {
|
||||
tenantTbl, tenantQuery := models.TenantQuery.QueryContext(ctx)
|
||||
tenants, err := tenantQuery.Where(tenantTbl.ID.In(tenantIDs...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, tenant := range tenants {
|
||||
tenantMap[tenant.ID] = tenant
|
||||
}
|
||||
}
|
||||
|
||||
userIDs = userIDs[:0]
|
||||
for id := range userIDSet {
|
||||
userIDs = append(userIDs, id)
|
||||
}
|
||||
if len(userIDs) > 0 {
|
||||
userTbl, userQuery := models.UserQuery.QueryContext(ctx)
|
||||
users, err := userQuery.Where(userTbl.ID.In(userIDs...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, user := range users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]super_dto.SuperPayoutAccountItem, 0, len(list))
|
||||
for _, pa := range list {
|
||||
tenant := tenantMap[pa.TenantID]
|
||||
user := userMap[pa.UserID]
|
||||
tenantCode := ""
|
||||
tenantName := ""
|
||||
if tenant != nil {
|
||||
tenantCode = tenant.Code
|
||||
tenantName = tenant.Name
|
||||
}
|
||||
username := ""
|
||||
if user != nil {
|
||||
username = user.Username
|
||||
}
|
||||
if username == "" && pa.UserID > 0 {
|
||||
username = "ID:" + strconv.FormatInt(pa.UserID, 10)
|
||||
}
|
||||
|
||||
items = append(items, super_dto.SuperPayoutAccountItem{
|
||||
ID: pa.ID,
|
||||
TenantID: pa.TenantID,
|
||||
TenantCode: tenantCode,
|
||||
TenantName: tenantName,
|
||||
UserID: pa.UserID,
|
||||
Username: username,
|
||||
Type: pa.Type,
|
||||
Name: pa.Name,
|
||||
Account: pa.Account,
|
||||
Realname: pa.Realname,
|
||||
CreatedAt: s.formatTime(pa.CreatedAt),
|
||||
UpdatedAt: s.formatTime(pa.UpdatedAt),
|
||||
})
|
||||
}
|
||||
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) RemovePayoutAccount(ctx context.Context, operatorID, id int64) error {
|
||||
if operatorID == 0 {
|
||||
return errorx.ErrUnauthorized.WithMsg("缺少操作者信息")
|
||||
}
|
||||
if id == 0 {
|
||||
return errorx.ErrBadRequest.WithMsg("结算账户ID不能为空")
|
||||
}
|
||||
|
||||
tbl, q := models.PayoutAccountQuery.QueryContext(ctx)
|
||||
account, err := q.Where(tbl.ID.Eq(id)).First()
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errorx.ErrRecordNotFound.WithMsg("结算账户不存在")
|
||||
}
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
if _, err := q.Where(tbl.ID.Eq(account.ID)).Delete(); err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
if Audit != nil {
|
||||
Audit.Log(ctx, operatorID, "remove_payout_account", cast.ToString(account.ID), "Removed payout account")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *super) ListTenantJoinRequests(ctx context.Context, filter *super_dto.SuperTenantJoinRequestListFilter) (*requests.Pager, error) {
|
||||
if filter == nil {
|
||||
filter = &super_dto.SuperTenantJoinRequestListFilter{}
|
||||
@@ -3214,6 +3469,241 @@ func (s *super) ListCoupons(ctx context.Context, filter *super_dto.SuperCouponLi
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) ListCouponGrants(ctx context.Context, filter *super_dto.SuperCouponGrantListFilter) (*requests.Pager, error) {
|
||||
if filter == nil {
|
||||
filter = &super_dto.SuperCouponGrantListFilter{}
|
||||
}
|
||||
|
||||
tbl, q := models.UserCouponQuery.QueryContext(ctx)
|
||||
if filter.UserID != nil && *filter.UserID > 0 {
|
||||
q = q.Where(tbl.UserID.Eq(*filter.UserID))
|
||||
}
|
||||
if filter.Status != nil && *filter.Status != "" {
|
||||
q = q.Where(tbl.Status.Eq(*filter.Status))
|
||||
}
|
||||
|
||||
userIDs, userFilter, err := s.lookupUserIDs(ctx, filter.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userFilter {
|
||||
if len(userIDs) == 0 {
|
||||
q = q.Where(tbl.ID.Eq(-1))
|
||||
} else {
|
||||
q = q.Where(tbl.UserID.In(userIDs...))
|
||||
}
|
||||
}
|
||||
|
||||
couponIDs, couponFilter, err := s.filterCouponGrantCouponIDs(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if couponFilter {
|
||||
if len(couponIDs) == 0 {
|
||||
filter.Pagination.Format()
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: 0,
|
||||
Items: []super_dto.SuperCouponGrantItem{},
|
||||
}, nil
|
||||
}
|
||||
q = q.Where(tbl.CouponID.In(couponIDs...))
|
||||
}
|
||||
|
||||
if filter.CreatedAtFrom != nil {
|
||||
from, err := s.parseFilterTime(filter.CreatedAtFrom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if from != nil {
|
||||
q = q.Where(tbl.CreatedAt.Gte(*from))
|
||||
}
|
||||
}
|
||||
if filter.CreatedAtTo != nil {
|
||||
to, err := s.parseFilterTime(filter.CreatedAtTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if to != nil {
|
||||
q = q.Where(tbl.CreatedAt.Lte(*to))
|
||||
}
|
||||
}
|
||||
if filter.UsedAtFrom != nil {
|
||||
from, err := s.parseFilterTime(filter.UsedAtFrom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if from != nil {
|
||||
q = q.Where(tbl.UsedAt.Gte(*from))
|
||||
}
|
||||
}
|
||||
if filter.UsedAtTo != nil {
|
||||
to, err := s.parseFilterTime(filter.UsedAtTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if to != nil {
|
||||
q = q.Where(tbl.UsedAt.Lte(*to))
|
||||
}
|
||||
}
|
||||
|
||||
filter.Pagination.Format()
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
list, err := q.Order(tbl.CreatedAt.Desc()).
|
||||
Offset(int(filter.Pagination.Offset())).
|
||||
Limit(int(filter.Pagination.Limit)).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if len(list) == 0 {
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: []super_dto.SuperCouponGrantItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
couponIDSet := make(map[int64]struct{})
|
||||
userIDSet := make(map[int64]struct{})
|
||||
for _, uc := range list {
|
||||
if uc.CouponID > 0 {
|
||||
couponIDSet[uc.CouponID] = struct{}{}
|
||||
}
|
||||
if uc.UserID > 0 {
|
||||
userIDSet[uc.UserID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
couponIDs = couponIDs[:0]
|
||||
for id := range couponIDSet {
|
||||
couponIDs = append(couponIDs, id)
|
||||
}
|
||||
userIDs = userIDs[:0]
|
||||
for id := range userIDSet {
|
||||
userIDs = append(userIDs, id)
|
||||
}
|
||||
|
||||
couponMap := make(map[int64]*models.Coupon, len(couponIDs))
|
||||
tenantMap := make(map[int64]*models.Tenant)
|
||||
if len(couponIDs) > 0 {
|
||||
couponTbl, couponQuery := models.CouponQuery.QueryContext(ctx)
|
||||
coupons, err := couponQuery.Where(couponTbl.ID.In(couponIDs...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
tenantSet := make(map[int64]struct{})
|
||||
for _, coupon := range coupons {
|
||||
couponMap[coupon.ID] = coupon
|
||||
if coupon.TenantID > 0 {
|
||||
tenantSet[coupon.TenantID] = struct{}{}
|
||||
}
|
||||
}
|
||||
tenantIDs := make([]int64, 0, len(tenantSet))
|
||||
for id := range tenantSet {
|
||||
tenantIDs = append(tenantIDs, id)
|
||||
}
|
||||
if len(tenantIDs) > 0 {
|
||||
tenantTbl, tenantQuery := models.TenantQuery.QueryContext(ctx)
|
||||
tenants, err := tenantQuery.Where(tenantTbl.ID.In(tenantIDs...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, tenant := range tenants {
|
||||
tenantMap[tenant.ID] = tenant
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*models.User, len(userIDs))
|
||||
if len(userIDs) > 0 {
|
||||
userTbl, userQuery := models.UserQuery.QueryContext(ctx)
|
||||
users, err := userQuery.Where(userTbl.ID.In(userIDs...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, user := range users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]super_dto.SuperCouponGrantItem, 0, len(list))
|
||||
for _, uc := range list {
|
||||
item := super_dto.SuperCouponGrantItem{
|
||||
ID: uc.ID,
|
||||
CouponID: uc.CouponID,
|
||||
UserID: uc.UserID,
|
||||
Status: uc.Status,
|
||||
StatusDescription: uc.Status.Description(),
|
||||
OrderID: uc.OrderID,
|
||||
UsedAt: s.formatTime(uc.UsedAt),
|
||||
CreatedAt: s.formatTime(uc.CreatedAt),
|
||||
}
|
||||
if user := userMap[uc.UserID]; user != nil {
|
||||
item.Username = user.Username
|
||||
} else if uc.UserID > 0 {
|
||||
item.Username = "ID:" + strconv.FormatInt(uc.UserID, 10)
|
||||
}
|
||||
if coupon := couponMap[uc.CouponID]; coupon != nil {
|
||||
item.CouponTitle = coupon.Title
|
||||
item.TenantID = coupon.TenantID
|
||||
if tenant := tenantMap[coupon.TenantID]; tenant != nil {
|
||||
item.TenantCode = tenant.Code
|
||||
item.TenantName = tenant.Name
|
||||
}
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) UpdateCouponStatus(ctx context.Context, operatorID, couponID int64, form *super_dto.SuperCouponStatusUpdateForm) error {
|
||||
if operatorID == 0 {
|
||||
return errorx.ErrUnauthorized.WithMsg("缺少操作者信息")
|
||||
}
|
||||
if couponID == 0 || form == nil {
|
||||
return errorx.ErrBadRequest.WithMsg("参数无效")
|
||||
}
|
||||
status := strings.ToLower(strings.TrimSpace(form.Status))
|
||||
if status != "frozen" {
|
||||
return errorx.ErrBadRequest.WithMsg("仅支持冻结操作")
|
||||
}
|
||||
|
||||
tbl, q := models.CouponQuery.QueryContext(ctx)
|
||||
coupon, err := q.Where(tbl.ID.Eq(couponID)).First()
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errorx.ErrRecordNotFound.WithMsg("优惠券不存在")
|
||||
}
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
if !coupon.EndAt.IsZero() && now.After(coupon.EndAt) {
|
||||
return nil
|
||||
}
|
||||
_, err = q.Where(tbl.ID.Eq(coupon.ID)).UpdateSimple(
|
||||
tbl.EndAt.Value(now),
|
||||
tbl.UpdatedAt.Value(now),
|
||||
)
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
if Audit != nil {
|
||||
Audit.Log(ctx, operatorID, "freeze_coupon", cast.ToString(coupon.ID), "Freeze coupon")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *super) ReportOverview(ctx context.Context, filter *super_dto.SuperReportOverviewFilter) (*v1_dto.ReportOverviewResponse, error) {
|
||||
// 统一统计时间范围与粒度。
|
||||
rg, err := s.normalizeReportRange(filter)
|
||||
@@ -3766,6 +4256,50 @@ func (s *super) filterCouponIDs(ctx context.Context, filter *super_dto.SuperUser
|
||||
return ids, true, nil
|
||||
}
|
||||
|
||||
func (s *super) filterCouponGrantCouponIDs(ctx context.Context, filter *super_dto.SuperCouponGrantListFilter) ([]int64, bool, error) {
|
||||
if filter == nil {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
if filter.CouponID != nil && *filter.CouponID > 0 {
|
||||
return []int64{*filter.CouponID}, true, nil
|
||||
}
|
||||
|
||||
tenantIDs := make([]int64, 0)
|
||||
applied := false
|
||||
if filter.TenantID != nil && *filter.TenantID > 0 {
|
||||
applied = true
|
||||
tenantIDs = append(tenantIDs, *filter.TenantID)
|
||||
}
|
||||
|
||||
lookupIDs, tenantFilter, err := s.lookupTenantIDs(ctx, filter.TenantCode, filter.TenantName)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
if tenantFilter {
|
||||
applied = true
|
||||
tenantIDs = append(tenantIDs, lookupIDs...)
|
||||
}
|
||||
|
||||
if !applied {
|
||||
return nil, false, nil
|
||||
}
|
||||
if len(tenantIDs) == 0 {
|
||||
return []int64{}, true, nil
|
||||
}
|
||||
|
||||
couponTbl, couponQuery := models.CouponQuery.QueryContext(ctx)
|
||||
coupons, err := couponQuery.Where(couponTbl.TenantID.In(tenantIDs...)).Select(couponTbl.ID).Find()
|
||||
if err != nil {
|
||||
return nil, true, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
ids := make([]int64, 0, len(coupons))
|
||||
for _, coupon := range coupons {
|
||||
ids = append(ids, coupon.ID)
|
||||
}
|
||||
return ids, true, nil
|
||||
}
|
||||
|
||||
func (s *super) RejectWithdrawal(ctx context.Context, operatorID, id int64, reason string) error {
|
||||
if operatorID == 0 {
|
||||
return errorx.ErrUnauthorized.WithMsg("缺少操作者信息")
|
||||
|
||||
Reference in New Issue
Block a user