恢复余额功能 & 管理员修改余额功能
This commit is contained in:
@@ -122,7 +122,7 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error {
|
||||
// 更新管理员基本信息
|
||||
if len(simples) > 0 {
|
||||
_, err := tx.Admin.
|
||||
Where(tx.Admin.ID.Eq(update.Id)).
|
||||
Where(tx.Admin.ID.Eq(update.Id), tx.Admin.Username.Neq("admin")).
|
||||
UpdateSimple(simples...)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -154,6 +154,6 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error {
|
||||
}
|
||||
|
||||
func (s *adminService) RemoveAdmin(id int32) error {
|
||||
_, err := q.Admin.Where(q.Admin.ID.Eq(id)).UpdateColumn(q.Admin.DeletedAt, time.Now())
|
||||
_, err := q.Admin.Where(q.Admin.ID.Eq(id), q.Admin.Username.Neq("admin")).UpdateColumn(q.Admin.DeletedAt, time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ var Coupon = &couponService{}
|
||||
type couponService struct{}
|
||||
|
||||
func (s *couponService) All() (result []*m.Coupon, err error) {
|
||||
return q.Coupon.Find()
|
||||
return q.Coupon.Order(q.Coupon.CreatedAt.Desc()).Find()
|
||||
}
|
||||
|
||||
func (s *couponService) Page(req *core.PageReq) (result []*m.Coupon, count int64, err error) {
|
||||
return q.Coupon.FindByPage(req.GetOffset(), req.GetLimit())
|
||||
return q.Coupon.Order(q.Coupon.CreatedAt.Desc()).FindByPage(req.GetOffset(), req.GetLimit())
|
||||
}
|
||||
|
||||
func (s *couponService) Create(data CreateCouponData) error {
|
||||
|
||||
@@ -15,5 +15,5 @@ func (r *permissionService) ListPermissions() (result []*m.Permission, err error
|
||||
}
|
||||
|
||||
func (p *permissionService) PagePermissions(req core.PageReq) (result []*m.Permission, count int64, err error) {
|
||||
return q.Permission.FindByPage(req.GetOffset(), req.GetLimit())
|
||||
return q.Permission.Order(q.Permission.Sort).FindByPage(req.GetOffset(), req.GetLimit())
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ func (s *productService) GetPrice(code string) {
|
||||
|
||||
// 获取所有产品
|
||||
func (s *productService) AllProducts() ([]*m.Product, error) {
|
||||
return q.Product.Find()
|
||||
return q.Product.
|
||||
Order(q.Product.Sort.Asc(), q.Product.CreatedAt.Desc()).
|
||||
Find()
|
||||
}
|
||||
|
||||
// 新增产品
|
||||
|
||||
@@ -14,11 +14,11 @@ var ProductDiscount = &productDiscountService{}
|
||||
type productDiscountService struct{}
|
||||
|
||||
func (s *productDiscountService) All() (result []*m.ProductDiscount, err error) {
|
||||
return q.ProductDiscount.Find()
|
||||
return q.ProductDiscount.Order(q.ProductDiscount.CreatedAt.Desc()).Find()
|
||||
}
|
||||
|
||||
func (s *productDiscountService) Page(req *core.PageReq) (result []*m.ProductDiscount, count int64, err error) {
|
||||
return q.ProductDiscount.FindByPage(req.GetOffset(), req.GetLimit())
|
||||
return q.ProductDiscount.Order(q.ProductDiscount.CreatedAt.Desc()).FindByPage(req.GetOffset(), req.GetLimit())
|
||||
}
|
||||
|
||||
func (s *productDiscountService) Create(data CreateProductDiscountData) (err error) {
|
||||
|
||||
@@ -20,6 +20,7 @@ func (s *productSkuService) All(product_code string) (result []*m.ProductSku, er
|
||||
Joins(q.ProductSku.Product).
|
||||
Where(q.Product.As("Product").Code.Eq(product_code)).
|
||||
Select(q.ProductSku.ALL).
|
||||
Order(q.ProductSku.CreatedAt.Desc()).
|
||||
Find()
|
||||
}
|
||||
|
||||
@@ -31,6 +32,7 @@ func (s *productSkuService) Page(req *core.PageReq, productId *int32) (result []
|
||||
return q.ProductSku.
|
||||
Joins(q.ProductSku.Discount).
|
||||
Where(do...).
|
||||
Order(q.ProductSku.CreatedAt.Desc()).
|
||||
FindByPage(req.GetOffset(), req.GetLimit())
|
||||
}
|
||||
|
||||
|
||||
@@ -26,21 +26,10 @@ func (s *resourceService) CreateResourceByBalance(user *m.User, data *CreateReso
|
||||
return core.NewServErr("获取产品支付信息失败", err)
|
||||
}
|
||||
|
||||
newBalance := user.Balance.Sub(detail.Actual)
|
||||
if newBalance.IsNegative() {
|
||||
return ErrBalanceNotEnough
|
||||
}
|
||||
|
||||
return q.Q.Transaction(func(q *q.Query) error {
|
||||
|
||||
// 更新用户余额
|
||||
_, err = q.User.
|
||||
Where(
|
||||
q.User.ID.Eq(user.ID),
|
||||
q.User.Balance.Eq(user.Balance),
|
||||
).
|
||||
UpdateSimple(q.User.Balance.Value(newBalance))
|
||||
if err != nil {
|
||||
if err := User.UpdateBalance(q, user, detail.Actual.Neg(), "余额购买产品", nil); err != nil {
|
||||
return core.NewServErr("更新用户余额失败", err)
|
||||
}
|
||||
|
||||
@@ -273,13 +262,21 @@ func (data *CreateResourceData) TradeDetail(user *m.User) (*TradeDetail, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var discountId *int32 = nil
|
||||
if discount != nil {
|
||||
discountId = &discount.ID
|
||||
}
|
||||
var couponId *int32 = nil
|
||||
if coupon != nil {
|
||||
couponId = &coupon.ID
|
||||
}
|
||||
return &TradeDetail{
|
||||
data,
|
||||
m.TradeTypePurchase,
|
||||
sku.Name,
|
||||
amount, actual,
|
||||
&discount.ID, discount,
|
||||
&coupon.ID, coupon,
|
||||
discountId, discount,
|
||||
couponId, coupon,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -26,13 +27,18 @@ import (
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(&CreateResourceData{})
|
||||
gob.Register(&UpdateBalanceData{})
|
||||
}
|
||||
|
||||
var Trade = &tradeService{}
|
||||
|
||||
type tradeService struct {
|
||||
}
|
||||
|
||||
// 创建交易
|
||||
func (s *tradeService) Create(user *m.User, tradeData *CreateTradeData, productData *CreateResourceData) (*CreateTradeResult, error) {
|
||||
func (s *tradeService) Create(user *m.User, tradeData *CreateTradeData, productData ProductData) (*CreateTradeResult, error) {
|
||||
if user == nil {
|
||||
return nil, core.NewBizErr("用户未登录")
|
||||
}
|
||||
@@ -196,15 +202,12 @@ func (s *tradeService) Create(user *m.User, tradeData *CreateTradeData, productD
|
||||
}
|
||||
|
||||
// 缓存产品数据
|
||||
serialized, err := json.Marshal(detail)
|
||||
if err != nil {
|
||||
return nil, core.NewServErr("序列化产品信息失败", err)
|
||||
}
|
||||
|
||||
w := bytes.Buffer{}
|
||||
gob.NewEncoder(&w).Encode(detail)
|
||||
err = g.Redis.Set(
|
||||
context.Background(),
|
||||
tradeProductKey(tradeNo),
|
||||
serialized,
|
||||
w.Bytes(),
|
||||
expireIn,
|
||||
).Err()
|
||||
if err != nil {
|
||||
@@ -267,14 +270,15 @@ func (s *tradeService) OnCompleteTrade(user *m.User, interNo string, outerNo str
|
||||
case m.TradeStatusPending:
|
||||
}
|
||||
|
||||
// 恢复购买信息
|
||||
detailStr, err := g.Redis.Get(context.Background(), tradeProductKey(interNo)).Result()
|
||||
// 恢复购买信息;如果反序列化失败,检查开头 init 函数中是否注册了对应的 struct 类型
|
||||
detailBytes, err := g.Redis.Get(context.Background(), tradeProductKey(interNo)).Bytes()
|
||||
if err != nil {
|
||||
return core.NewServErr("恢复购买信息失败", err)
|
||||
}
|
||||
|
||||
var detail TradeDetail
|
||||
if err := json.Unmarshal([]byte(detailStr), &detail); err != nil {
|
||||
r := bytes.NewReader(detailBytes)
|
||||
if err := gob.NewDecoder(r).Decode(&detail); err != nil {
|
||||
return core.NewServErr("解析购买信息失败", err)
|
||||
}
|
||||
|
||||
@@ -299,7 +303,7 @@ func (s *tradeService) OnCompleteTrade(user *m.User, interNo string, outerNo str
|
||||
switch trade.Type {
|
||||
case m.TradeTypeRecharge:
|
||||
// 更新用户余额
|
||||
if err := User.UpdateBalance(q, user, detail.Actual); err != nil {
|
||||
if err := User.UpdateBalance(q, user, detail.Actual, "充值余额", nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -605,12 +609,12 @@ type OnTradeCompletedData struct {
|
||||
*TradeSuccessResult
|
||||
}
|
||||
|
||||
type ProductInfo interface {
|
||||
type ProductData interface {
|
||||
TradeDetail(user *m.User) (*TradeDetail, error)
|
||||
}
|
||||
|
||||
type TradeDetail struct {
|
||||
Product ProductInfo `json:"product"`
|
||||
Product ProductData `json:"product"`
|
||||
Type m.TradeType `json:"type"`
|
||||
Subject string `json:"subject"`
|
||||
Amount decimal.Decimal `json:"amount"`
|
||||
@@ -621,11 +625,6 @@ type TradeDetail struct {
|
||||
Coupon *m.Coupon `json:"-"` // 不应缓存
|
||||
}
|
||||
|
||||
type CompleteEvent interface {
|
||||
Check(t m.TradeType) (ProductInfo, bool)
|
||||
OnTradeComplete(info ProductInfo, trade *m.Trade) error
|
||||
}
|
||||
|
||||
type TradeErr string
|
||||
|
||||
func (e TradeErr) Error() string {
|
||||
|
||||
@@ -28,12 +28,28 @@ func (s *userService) Get(q *q.Query, uid int32) (*m.User, error) {
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Decimal) error {
|
||||
func (s *userService) UpdateBalanceByAdmin(user *m.User, newBalance decimal.Decimal, adminId *int32) error {
|
||||
if user == nil {
|
||||
return core.NewServErr("用户不存在")
|
||||
}
|
||||
|
||||
amount := newBalance.Sub(user.Balance)
|
||||
if amount.IsZero() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return q.Q.Transaction(func(q *q.Query) error {
|
||||
return s.UpdateBalance(q, user, amount, "管理员修改余额", adminId)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Decimal, remark string, adminId *int32) error {
|
||||
balance := user.Balance.Add(amount)
|
||||
if balance.IsNegative() {
|
||||
return core.NewServErr("用户余额不足")
|
||||
}
|
||||
|
||||
// 更新余额
|
||||
_, err := q.User.
|
||||
Where(
|
||||
q.User.ID.Eq(user.ID),
|
||||
@@ -46,6 +62,19 @@ func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Dec
|
||||
return core.NewServErr("更新用户余额失败", err)
|
||||
}
|
||||
|
||||
// 新增动账记录
|
||||
err = q.BalanceActivity.Create(&m.BalanceActivity{
|
||||
UserID: user.ID,
|
||||
AdminID: adminId,
|
||||
Amount: amount.StringFixed(2),
|
||||
BalancePrev: user.Balance.StringFixed(2),
|
||||
BalanceCurr: balance.StringFixed(2),
|
||||
Remark: &remark,
|
||||
})
|
||||
if err != nil {
|
||||
return core.NewServErr("新增动账记录失败", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user