Refactor order and tenant ledger models to use consts for Currency and Type fields; add new UserStatus values; implement comprehensive test cases for content, creator, order, super, and wallet services.

This commit is contained in:
2025-12-29 14:21:20 +08:00
parent d648a1e45b
commit 8fa3d18a9c
30 changed files with 2251 additions and 85 deletions

View File

@@ -0,0 +1,125 @@
package services
import (
"context"
"database/sql"
"testing"
"quyun/v2/app/commands/testx"
order_dto "quyun/v2/app/http/v1/dto"
"quyun/v2/database"
"quyun/v2/database/models"
"quyun/v2/pkg/consts"
. "github.com/smartystreets/goconvey/convey"
"github.com/spf13/cast"
"github.com/stretchr/testify/suite"
"go.ipao.vip/atom/contracts"
"go.uber.org/dig"
)
type OrderTestSuiteInjectParams struct {
dig.In
DB *sql.DB
Initials []contracts.Initial `group:"initials"`
}
type OrderTestSuite struct {
suite.Suite
OrderTestSuiteInjectParams
}
func Test_Order(t *testing.T) {
providers := testx.Default().With(Provide)
testx.Serve(providers, t, func(p OrderTestSuiteInjectParams) {
suite.Run(t, &OrderTestSuite{OrderTestSuiteInjectParams: p})
})
}
func (s *OrderTestSuite) Test_PurchaseFlow() {
Convey("Purchase Flow", s.T(), func() {
ctx := s.T().Context()
database.Truncate(ctx, s.DB,
models.TableNameOrder, models.TableNameOrderItem, models.TableNameUser,
models.TableNameContent, models.TableNameContentPrice, models.TableNameTenant,
models.TableNameContentAccess, models.TableNameTenantLedger,
)
// 1. Setup Data
// Creator
creator := &models.User{Username: "creator", Phone: "13800000001"}
models.UserQuery.WithContext(ctx).Create(creator)
// Tenant
tenant := &models.Tenant{UserID: creator.ID, Name: "Music Shop", Code: "shop1", Status: consts.TenantStatusVerified}
models.TenantQuery.WithContext(ctx).Create(tenant)
// Content
content := &models.Content{TenantID: tenant.ID, UserID: creator.ID, Title: "Song A", Status: consts.ContentStatusPublished}
models.ContentQuery.WithContext(ctx).Create(content)
// Price (10.00 CNY = 1000 cents)
price := &models.ContentPrice{TenantID: tenant.ID, ContentID: content.ID, PriceAmount: 1000, Currency: consts.CurrencyCNY}
models.ContentPriceQuery.WithContext(ctx).Create(price)
// Buyer
buyer := &models.User{Username: "buyer", Phone: "13900000001", Balance: 2000} // Has 20.00
models.UserQuery.WithContext(ctx).Create(buyer)
buyerCtx := context.WithValue(ctx, consts.CtxKeyUser, buyer.ID)
Convey("should create and pay order successfully", func() {
// Step 1: Create Order
form := &order_dto.OrderCreateForm{ContentID: cast.ToString(content.ID)}
createRes, err := Order.Create(buyerCtx, form)
So(err, ShouldBeNil)
So(createRes.OrderID, ShouldNotBeEmpty)
// Verify created status
oid := cast.ToInt64(createRes.OrderID)
o, _ := models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.ID.Eq(oid)).First()
So(o.Status, ShouldEqual, consts.OrderStatusCreated)
So(o.AmountPaid, ShouldEqual, 1000)
// Step 2: Pay Order
payForm := &order_dto.OrderPayForm{Method: "balance"}
_, err = Order.Pay(buyerCtx, createRes.OrderID, payForm)
So(err, ShouldBeNil)
// Verify Order Paid
o, _ = models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.ID.Eq(oid)).First()
So(o.Status, ShouldEqual, consts.OrderStatusPaid)
So(o.PaidAt, ShouldNotBeZeroValue)
// Verify Balance Deducted
b, _ := models.UserQuery.WithContext(ctx).Where(models.UserQuery.ID.Eq(buyer.ID)).First()
So(b.Balance, ShouldEqual, 1000) // 2000 - 1000
// Verify Access Granted
access, _ := models.ContentAccessQuery.WithContext(ctx).Where(models.ContentAccessQuery.UserID.Eq(buyer.ID), models.ContentAccessQuery.ContentID.Eq(content.ID)).First()
So(access, ShouldNotBeNil)
So(access.Status, ShouldEqual, consts.ContentAccessStatusActive)
// Verify Ledger Created (Creator received money logic?)
// Note: My implementation credits the TENANT OWNER (creator.ID).
l, _ := models.TenantLedgerQuery.WithContext(ctx).Where(models.TenantLedgerQuery.OrderID.Eq(o.ID)).First()
So(l, ShouldNotBeNil)
So(l.UserID, ShouldEqual, creator.ID)
So(l.Amount, ShouldEqual, 1000)
So(l.Type, ShouldEqual, consts.TenantLedgerTypeDebitPurchase)
})
Convey("should fail pay if insufficient balance", func() {
// Set balance to 5.00
models.UserQuery.WithContext(ctx).Where(models.UserQuery.ID.Eq(buyer.ID)).Update(models.UserQuery.Balance, 500)
form := &order_dto.OrderCreateForm{ContentID: cast.ToString(content.ID)}
createRes, err := Order.Create(buyerCtx, form)
So(err, ShouldBeNil)
payForm := &order_dto.OrderPayForm{Method: "balance"}
_, err = Order.Pay(buyerCtx, createRes.OrderID, payForm)
So(err, ShouldNotBeNil)
// Error should be QuotaExceeded or similar
})
})
}