feat: 移除“租户管理员为用户充值 / 每租户一套余额”能力:余额统一为全局用户余额
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -46,15 +47,24 @@ func Test_Ledger(t *testing.T) {
|
||||
}
|
||||
|
||||
func (s *LedgerTestSuite) seedTenantUser(ctx context.Context, tenantID, userID, balance, frozen int64) {
|
||||
database.Truncate(ctx, s.DB, models.TableNameTenantLedger, models.TableNameTenantUser)
|
||||
database.Truncate(ctx, s.DB, models.TableNameTenantLedger, models.TableNameTenantUser, models.TableNameUser)
|
||||
|
||||
now := time.Now().UTC()
|
||||
_, err := s.DB.ExecContext(ctx, `
|
||||
INSERT INTO users (id, username, password, roles, status, metas, created_at, updated_at, balance, balance_frozen)
|
||||
VALUES ($1, $2, 'x', ARRAY['user'], $3, '{}'::jsonb, $4, $4, $5, $6)
|
||||
ON CONFLICT (id) DO UPDATE
|
||||
SET balance = EXCLUDED.balance, balance_frozen = EXCLUDED.balance_frozen, updated_at = EXCLUDED.updated_at
|
||||
`, userID, fmt.Sprintf("u%d", userID), consts.UserStatusVerified, now, balance, frozen)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
tu := &models.TenantUser{
|
||||
TenantID: tenantID,
|
||||
UserID: userID,
|
||||
Role: types.NewArray([]consts.TenantUserRole{consts.TenantUserRoleMember}),
|
||||
Balance: balance,
|
||||
BalanceFrozen: frozen,
|
||||
Status: consts.UserStatusVerified,
|
||||
TenantID: tenantID,
|
||||
UserID: userID,
|
||||
Role: types.NewArray([]consts.TenantUserRole{consts.TenantUserRoleMember}),
|
||||
Status: consts.UserStatusVerified,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
So(tu.Create(ctx), ShouldBeNil)
|
||||
}
|
||||
@@ -82,7 +92,7 @@ func (s *LedgerTestSuite) Test_Freeze() {
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldNotBeNil)
|
||||
So(res.Ledger, ShouldNotBeNil)
|
||||
So(res.TenantUser, ShouldNotBeNil)
|
||||
So(res.User, ShouldNotBeNil)
|
||||
So(res.Ledger.Type, ShouldEqual, consts.TenantLedgerTypeFreeze)
|
||||
So(res.Ledger.Amount, ShouldEqual, 300)
|
||||
So(res.Ledger.BalanceBefore, ShouldEqual, 1000)
|
||||
@@ -92,8 +102,8 @@ func (s *LedgerTestSuite) Test_Freeze() {
|
||||
So(res.Ledger.OperatorUserID, ShouldEqual, userID)
|
||||
So(res.Ledger.BizRefType, ShouldEqual, "")
|
||||
So(res.Ledger.BizRefID, ShouldEqual, int64(0))
|
||||
So(res.TenantUser.Balance, ShouldEqual, 700)
|
||||
So(res.TenantUser.BalanceFrozen, ShouldEqual, 300)
|
||||
So(res.User.Balance, ShouldEqual, 700)
|
||||
So(res.User.BalanceFrozen, ShouldEqual, 300)
|
||||
})
|
||||
|
||||
Convey("幂等键重复调用不应重复扣减", func() {
|
||||
@@ -106,10 +116,10 @@ func (s *LedgerTestSuite) Test_Freeze() {
|
||||
So(res2.Ledger, ShouldNotBeNil)
|
||||
So(res2.Ledger.IdempotencyKey, ShouldEqual, "k_freeze_idem")
|
||||
|
||||
var tu2 models.TenantUser
|
||||
So(_db.WithContext(ctx).Where("tenant_id = ? AND user_id = ?", tenantID, userID).First(&tu2).Error, ShouldBeNil)
|
||||
So(tu2.Balance, ShouldEqual, 700)
|
||||
So(tu2.BalanceFrozen, ShouldEqual, 300)
|
||||
var u2 models.User
|
||||
So(_db.WithContext(ctx).Where("id = ?", userID).First(&u2).Error, ShouldBeNil)
|
||||
So(u2.Balance, ShouldEqual, 700)
|
||||
So(u2.BalanceFrozen, ShouldEqual, 300)
|
||||
})
|
||||
|
||||
Convey("余额不足应返回前置条件失败", func() {
|
||||
@@ -157,8 +167,8 @@ func (s *LedgerTestSuite) Test_Unfreeze() {
|
||||
So(res.Ledger.OperatorUserID, ShouldEqual, userID)
|
||||
So(res.Ledger.BizRefType, ShouldEqual, "")
|
||||
So(res.Ledger.BizRefID, ShouldEqual, int64(0))
|
||||
So(res.TenantUser.Balance, ShouldEqual, 1000)
|
||||
So(res.TenantUser.BalanceFrozen, ShouldEqual, 0)
|
||||
So(res.User.Balance, ShouldEqual, 1000)
|
||||
So(res.User.BalanceFrozen, ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("幂等键重复调用不应重复入账", func() {
|
||||
@@ -172,10 +182,10 @@ func (s *LedgerTestSuite) Test_Unfreeze() {
|
||||
So(err, ShouldBeNil)
|
||||
So(res2, ShouldNotBeNil)
|
||||
|
||||
var tu2 models.TenantUser
|
||||
So(_db.WithContext(ctx).Where("tenant_id = ? AND user_id = ?", tenantID, userID).First(&tu2).Error, ShouldBeNil)
|
||||
So(tu2.Balance, ShouldEqual, 1000)
|
||||
So(tu2.BalanceFrozen, ShouldEqual, 0)
|
||||
var u2 models.User
|
||||
So(_db.WithContext(ctx).Where("id = ?", userID).First(&u2).Error, ShouldBeNil)
|
||||
So(u2.Balance, ShouldEqual, 1000)
|
||||
So(u2.BalanceFrozen, ShouldEqual, 0)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -210,8 +220,8 @@ func (s *LedgerTestSuite) Test_DebitPurchaseTx() {
|
||||
So(res.Ledger.OperatorUserID, ShouldEqual, userID)
|
||||
So(res.Ledger.BizRefType, ShouldEqual, "order")
|
||||
So(res.Ledger.BizRefID, ShouldEqual, int64(123))
|
||||
So(res.TenantUser.Balance, ShouldEqual, 700)
|
||||
So(res.TenantUser.BalanceFrozen, ShouldEqual, 0)
|
||||
So(res.User.Balance, ShouldEqual, 700)
|
||||
So(res.User.BalanceFrozen, ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("幂等键重复调用不应重复扣减冻结余额", func() {
|
||||
@@ -224,10 +234,10 @@ func (s *LedgerTestSuite) Test_DebitPurchaseTx() {
|
||||
_, err = Ledger.DebitPurchaseTx(ctx, _db, tenantID, userID, userID, 123, 300, "k_debit_idem", "debit", now.Add(time.Second))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
var tu2 models.TenantUser
|
||||
So(_db.WithContext(ctx).Where("tenant_id = ? AND user_id = ?", tenantID, userID).First(&tu2).Error, ShouldBeNil)
|
||||
So(tu2.Balance, ShouldEqual, 700)
|
||||
So(tu2.BalanceFrozen, ShouldEqual, 0)
|
||||
var u2 models.User
|
||||
So(_db.WithContext(ctx).Where("id = ?", userID).First(&u2).Error, ShouldBeNil)
|
||||
So(u2.Balance, ShouldEqual, 700)
|
||||
So(u2.BalanceFrozen, ShouldEqual, 0)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -259,8 +269,8 @@ func (s *LedgerTestSuite) Test_CreditRefundTx() {
|
||||
So(res.Ledger.OperatorUserID, ShouldEqual, userID)
|
||||
So(res.Ledger.BizRefType, ShouldEqual, "order")
|
||||
So(res.Ledger.BizRefID, ShouldEqual, int64(123))
|
||||
So(res.TenantUser.Balance, ShouldEqual, 1000)
|
||||
So(res.TenantUser.BalanceFrozen, ShouldEqual, 0)
|
||||
So(res.User.Balance, ShouldEqual, 1000)
|
||||
So(res.User.BalanceFrozen, ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("幂等键重复调用不应重复退款入账", func() {
|
||||
@@ -274,48 +284,9 @@ func (s *LedgerTestSuite) Test_CreditRefundTx() {
|
||||
_, err = Ledger.CreditRefundTx(ctx, _db, tenantID, userID, userID, 123, 300, "k_refund_idem", "refund", now.Add(time.Second))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
var tu2 models.TenantUser
|
||||
So(_db.WithContext(ctx).Where("tenant_id = ? AND user_id = ?", tenantID, userID).First(&tu2).Error, ShouldBeNil)
|
||||
So(tu2.Balance, ShouldEqual, 1000)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *LedgerTestSuite) Test_CreditTopupTx() {
|
||||
Convey("Ledger.CreditTopupTx", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
tenantID := int64(1)
|
||||
userID := int64(2)
|
||||
now := time.Now().UTC()
|
||||
|
||||
s.seedTenantUser(ctx, tenantID, userID, 1000, 0)
|
||||
|
||||
Convey("金额非法应返回参数错误", func() {
|
||||
_, err := Ledger.CreditTopupTx(ctx, _db, tenantID, 999, userID, 456, 0, "k_topup_invalid_amount", "topup", now)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("成功充值应增加可用余额并写入账本", func() {
|
||||
res, err := Ledger.CreditTopupTx(ctx, _db, tenantID, 999, userID, 456, 200, "k_topup_1", "topup", now)
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldNotBeNil)
|
||||
So(res.Ledger.Type, ShouldEqual, consts.TenantLedgerTypeCreditTopup)
|
||||
So(res.Ledger.OperatorUserID, ShouldEqual, int64(999))
|
||||
So(res.Ledger.BizRefType, ShouldEqual, "order")
|
||||
So(res.Ledger.BizRefID, ShouldEqual, int64(456))
|
||||
So(res.TenantUser.Balance, ShouldEqual, 1200)
|
||||
So(res.TenantUser.BalanceFrozen, ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("幂等键重复调用不应重复充值入账", func() {
|
||||
_, err := Ledger.CreditTopupTx(ctx, _db, tenantID, 999, userID, 456, 200, "k_topup_idem", "topup", now)
|
||||
So(err, ShouldBeNil)
|
||||
_, err = Ledger.CreditTopupTx(ctx, _db, tenantID, 999, userID, 456, 200, "k_topup_idem", "topup", now.Add(time.Second))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
var tu2 models.TenantUser
|
||||
So(_db.WithContext(ctx).Where("tenant_id = ? AND user_id = ?", tenantID, userID).First(&tu2).Error, ShouldBeNil)
|
||||
So(tu2.Balance, ShouldEqual, 1200)
|
||||
var u2 models.User
|
||||
So(_db.WithContext(ctx).Where("id = ?", userID).First(&u2).Error, ShouldBeNil)
|
||||
So(u2.Balance, ShouldEqual, 1000)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -328,7 +299,7 @@ func (s *LedgerTestSuite) Test_MyBalance() {
|
||||
|
||||
s.seedTenantUser(ctx, tenantID, userID, 1000, 200)
|
||||
|
||||
Convey("成功返回租户内余额", func() {
|
||||
Convey("成功返回全局余额", func() {
|
||||
m, err := Ledger.MyBalance(ctx, tenantID, userID)
|
||||
So(err, ShouldBeNil)
|
||||
So(m, ShouldNotBeNil)
|
||||
@@ -352,9 +323,9 @@ func (s *LedgerTestSuite) Test_MyLedgerPage() {
|
||||
|
||||
s.seedTenantUser(ctx, tenantID, userID, 1000, 0)
|
||||
|
||||
_, err := Ledger.CreditTopupTx(ctx, _db, tenantID, userID, userID, 1, 200, "k_topup_for_page", "topup", now)
|
||||
_, err := Ledger.Freeze(ctx, tenantID, userID, 1, 200, "k_freeze_for_page_1", "freeze", now)
|
||||
So(err, ShouldBeNil)
|
||||
_, err = Ledger.Freeze(ctx, tenantID, userID, 2, 100, "k_freeze_for_page", "freeze", now.Add(time.Second))
|
||||
_, err = Ledger.Unfreeze(ctx, tenantID, userID, 1, 100, "k_unfreeze_for_page_1", "unfreeze", now.Add(time.Second))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("分页返回流水列表", func() {
|
||||
@@ -365,7 +336,7 @@ func (s *LedgerTestSuite) Test_MyLedgerPage() {
|
||||
})
|
||||
|
||||
Convey("按 type 过滤", func() {
|
||||
typ := consts.TenantLedgerTypeCreditTopup
|
||||
typ := consts.TenantLedgerTypeFreeze
|
||||
pager, err := Ledger.MyLedgerPage(ctx, tenantID, userID, &dto.MyLedgerListFilter{Type: &typ})
|
||||
So(err, ShouldBeNil)
|
||||
So(pager.Total, ShouldEqual, 1)
|
||||
@@ -382,8 +353,8 @@ func (s *LedgerTestSuite) Test_AdminLedgerPage() {
|
||||
|
||||
s.seedTenantUser(ctx, tenantID, userID, 1000, 0)
|
||||
|
||||
// 模拟后台管理员为用户充值:operator_user_id 与 user_id 不同。
|
||||
_, err := Ledger.CreditTopupTx(ctx, _db, tenantID, 999, userID, 777, 200, "k_admin_topup_for_page", "topup", now)
|
||||
// 模拟后台管理员为用户冻结资金:operator_user_id 与 user_id 不同。
|
||||
_, err := Ledger.FreezeTx(ctx, _db, tenantID, 999, userID, 777, 200, "k_admin_freeze_for_page", "freeze", now)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("按 operator_user_id 过滤", func() {
|
||||
|
||||
Reference in New Issue
Block a user