问题:settlementService.GetBillingSummary 方法存在但未在接口中暴露 解决: 1. 在 SettlementService 接口添加 GetBillingSummary 方法 2. 添加 TestSettlementService_GetBillingSummary 测试 Coverage: - GetBillingSummary: 0% -> 100% - Total domain coverage: 72.0% -> 72.3% Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
624 lines
19 KiB
Go
624 lines
19 KiB
Go
package domain
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/stretchr/testify/assert"
|
||
|
||
"lijiaoqiao/supply-api/internal/audit"
|
||
)
|
||
|
||
// mockSettlementStore Mock结算存储
|
||
type mockSettlementStore struct {
|
||
settlements map[int64]*Settlement
|
||
balances map[int64]float64
|
||
nextID int64
|
||
// 控制 HasPendingOrProcessingWithdraw 的返回值
|
||
hasPendingWithdraw bool
|
||
hasPendingWithdrawError error
|
||
}
|
||
|
||
func newMockSettlementStore() *mockSettlementStore {
|
||
return &mockSettlementStore{
|
||
settlements: make(map[int64]*Settlement),
|
||
balances: make(map[int64]float64),
|
||
nextID: 1,
|
||
}
|
||
}
|
||
|
||
func (m *mockSettlementStore) Create(ctx context.Context, s *Settlement) error {
|
||
s.ID = m.nextID
|
||
m.nextID++
|
||
m.settlements[s.ID] = s
|
||
return nil
|
||
}
|
||
|
||
// CreateWithdrawTx 原子化提现创建(mock实现)
|
||
func (m *mockSettlementStore) CreateWithdrawTx(ctx context.Context, s *Settlement) error {
|
||
// 检查是否有pending的提现
|
||
if m.hasPendingWithdraw {
|
||
return errors.New("already has pending or processing withdrawal")
|
||
}
|
||
return m.Create(ctx, s)
|
||
}
|
||
|
||
func (m *mockSettlementStore) CreateInTx(ctx context.Context, s *Settlement) error {
|
||
return m.Create(ctx, s)
|
||
}
|
||
|
||
func (m *mockSettlementStore) GetByID(ctx context.Context, supplierID, id int64) (*Settlement, error) {
|
||
if s, ok := m.settlements[id]; ok && s.SupplierID == supplierID {
|
||
return s, nil
|
||
}
|
||
return nil, errors.New("settlement not found")
|
||
}
|
||
|
||
func (m *mockSettlementStore) Update(ctx context.Context, s *Settlement, expectedVersion int) error {
|
||
if s.Version != expectedVersion {
|
||
return errors.New("concurrency conflict")
|
||
}
|
||
m.settlements[s.ID] = s
|
||
return nil
|
||
}
|
||
|
||
func (m *mockSettlementStore) List(ctx context.Context, supplierID int64) ([]*Settlement, error) {
|
||
var result []*Settlement
|
||
for _, s := range m.settlements {
|
||
if s.SupplierID == supplierID {
|
||
result = append(result, s)
|
||
}
|
||
}
|
||
return result, nil
|
||
}
|
||
|
||
func (m *mockSettlementStore) GetWithdrawableBalance(ctx context.Context, supplierID int64) (float64, error) {
|
||
if balance, ok := m.balances[supplierID]; ok {
|
||
return balance, nil
|
||
}
|
||
return 0, nil
|
||
}
|
||
|
||
func (m *mockSettlementStore) HasPendingOrProcessingWithdraw(ctx context.Context, supplierID int64) (bool, error) {
|
||
if m.hasPendingWithdrawError != nil {
|
||
return false, m.hasPendingWithdrawError
|
||
}
|
||
return m.hasPendingWithdraw, nil
|
||
}
|
||
|
||
// mockEarningStore Mock收益存储
|
||
type mockEarningStore struct {
|
||
records []*EarningRecord
|
||
}
|
||
|
||
func newMockEarningStore() *mockEarningStore {
|
||
return &mockEarningStore{
|
||
records: make([]*EarningRecord, 0),
|
||
}
|
||
}
|
||
|
||
func (m *mockEarningStore) ListRecords(ctx context.Context, supplierID int64, startDate, endDate string, page, pageSize int) ([]*EarningRecord, int, error) {
|
||
var result []*EarningRecord
|
||
for _, r := range m.records {
|
||
if r.SupplierID == supplierID {
|
||
result = append(result, r)
|
||
}
|
||
}
|
||
return result, len(result), nil
|
||
}
|
||
|
||
func (m *mockEarningStore) GetBillingSummary(ctx context.Context, supplierID int64, startDate, endDate string) (*BillingSummary, error) {
|
||
return &BillingSummary{
|
||
Period: BillingPeriod{
|
||
Start: startDate,
|
||
End: endDate,
|
||
},
|
||
Summary: BillingTotal{
|
||
TotalRevenue: 1000.00,
|
||
TotalOrders: 100,
|
||
TotalUsage: 5000,
|
||
TotalRequests: 10000,
|
||
AvgSuccessRate: 99.5,
|
||
PlatformFee: 10.00,
|
||
NetEarnings: 990.00,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// mockAuditStoreForSettlement Mock审计存储
|
||
type mockAuditStoreForSettlement struct{}
|
||
|
||
func (m *mockAuditStoreForSettlement) Emit(ctx context.Context, event audit.Event) error {
|
||
return nil
|
||
}
|
||
|
||
func (m *mockAuditStoreForSettlement) Query(ctx context.Context, filter audit.EventFilter) ([]audit.Event, error) {
|
||
return nil, nil
|
||
}
|
||
|
||
func (m *mockAuditStoreForSettlement) QueryWithTotal(ctx context.Context, filter audit.EventFilter) ([]audit.Event, int64, error) {
|
||
return nil, 0, nil
|
||
}
|
||
|
||
func (m *mockAuditStoreForSettlement) GetByID(ctx context.Context, eventID string) (audit.Event, error) {
|
||
return audit.Event{}, errors.New("not found")
|
||
}
|
||
|
||
// mockSMSVerifierForSettlement Mock短信验证码验证器
|
||
type mockSMSVerifierForSettlement struct {
|
||
verifyResult bool
|
||
verifyError error
|
||
}
|
||
|
||
func (m *mockSMSVerifierForSettlement) Verify(ctx context.Context, phone string, code string) (bool, error) {
|
||
if m.verifyError != nil {
|
||
return false, m.verifyError
|
||
}
|
||
// Mock 验证器忽略 phone 和 code 参数,只根据 verifyResult 返回
|
||
// 真实测试中应根据具体场景设置 verifyResult
|
||
return m.verifyResult, nil
|
||
}
|
||
|
||
// TestSettlementConstants 测试结算状态常量
|
||
func TestSettlementConstants(t *testing.T) {
|
||
assert.Equal(t, SettlementStatus("pending"), SettlementStatusPending)
|
||
assert.Equal(t, SettlementStatus("processing"), SettlementStatusProcessing)
|
||
assert.Equal(t, SettlementStatus("completed"), SettlementStatusCompleted)
|
||
assert.Equal(t, SettlementStatus("failed"), SettlementStatusFailed)
|
||
}
|
||
|
||
// TestPaymentMethodConstants 测试支付方式常量
|
||
func TestPaymentMethodConstants(t *testing.T) {
|
||
assert.Equal(t, PaymentMethod("bank"), PaymentMethodBank)
|
||
assert.Equal(t, PaymentMethod("alipay"), PaymentMethodAlipay)
|
||
assert.Equal(t, PaymentMethod("wechat"), PaymentMethodWechat)
|
||
}
|
||
|
||
// TestSettlementStruct 测试结算单结构体
|
||
func TestSettlementStruct(t *testing.T) {
|
||
now := time.Now()
|
||
s := &Settlement{
|
||
ID: 1,
|
||
SupplierID: 1001,
|
||
SettlementNo: "SET-2024-001",
|
||
Status: SettlementStatusPending,
|
||
TotalAmount: 1000.00,
|
||
FeeAmount: 10.00,
|
||
NetAmount: 990.00,
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
PeriodStart: now,
|
||
PeriodEnd: now.Add(24 * time.Hour),
|
||
TotalOrders: 100,
|
||
CurrencyCode: "CNY",
|
||
AmountUnit: "yuan",
|
||
Version: 1,
|
||
CreatedAt: now,
|
||
UpdatedAt: now,
|
||
}
|
||
|
||
assert.Equal(t, int64(1), s.ID)
|
||
assert.Equal(t, int64(1001), s.SupplierID)
|
||
assert.Equal(t, "SET-2024-001", s.SettlementNo)
|
||
assert.Equal(t, SettlementStatusPending, s.Status)
|
||
assert.Equal(t, 1000.00, s.TotalAmount)
|
||
assert.Equal(t, 10.00, s.FeeAmount)
|
||
assert.Equal(t, 990.00, s.NetAmount)
|
||
assert.Equal(t, PaymentMethodBank, s.PaymentMethod)
|
||
assert.Equal(t, "1234567890", s.PaymentAccount)
|
||
assert.Equal(t, 100, s.TotalOrders)
|
||
assert.Equal(t, "CNY", s.CurrencyCode)
|
||
assert.Equal(t, "yuan", s.AmountUnit)
|
||
assert.Equal(t, 1, s.Version)
|
||
}
|
||
|
||
// TestEarningRecordStruct 测试收益记录结构体
|
||
func TestEarningRecordStruct(t *testing.T) {
|
||
now := time.Now()
|
||
e := &EarningRecord{
|
||
ID: 1,
|
||
SupplierID: 1001,
|
||
SettlementID: 10,
|
||
EarningsType: "usage",
|
||
Amount: 500.00,
|
||
Status: "available",
|
||
Description: "usage earnings",
|
||
EarnedAt: now,
|
||
}
|
||
|
||
assert.Equal(t, int64(1), e.ID)
|
||
assert.Equal(t, int64(1001), e.SupplierID)
|
||
assert.Equal(t, int64(10), e.SettlementID)
|
||
assert.Equal(t, "usage", e.EarningsType)
|
||
assert.Equal(t, 500.00, e.Amount)
|
||
assert.Equal(t, "available", e.Status)
|
||
}
|
||
|
||
// TestSettlementStatusTransitions 测试结算状态转换
|
||
func TestSettlementStatusTransitions(t *testing.T) {
|
||
// 测试有效状态
|
||
s := &Settlement{Status: SettlementStatusPending}
|
||
assert.Equal(t, SettlementStatusPending, s.Status)
|
||
|
||
s.Status = SettlementStatusProcessing
|
||
assert.Equal(t, SettlementStatusProcessing, s.Status)
|
||
|
||
s.Status = SettlementStatusCompleted
|
||
assert.Equal(t, SettlementStatusCompleted, s.Status)
|
||
|
||
s.Status = SettlementStatusFailed
|
||
assert.Equal(t, SettlementStatusFailed, s.Status)
|
||
}
|
||
|
||
// TestInvariantErrors 测试结算相关不变量错误
|
||
func TestSettlementInvariantErrors(t *testing.T) {
|
||
// ERRORS from invariants.go related to settlements
|
||
assert.Contains(t, ErrSettlementCannotCancel.Error(), "cannot cancel")
|
||
assert.Contains(t, ErrWithdrawExceedsBalance.Error(), "exceeds available balance")
|
||
assert.Contains(t, ErrSettlementBalanceMismatch.Error(), "does not match balance")
|
||
}
|
||
|
||
// TestNewSettlementService 测试创建结算服务
|
||
func TestNewSettlementService(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
|
||
svc := NewSettlementService(store, earningStore, auditStore)
|
||
assert.NotNil(t, svc)
|
||
}
|
||
|
||
// TestSettlementService_Withdraw 测试提现
|
||
func TestSettlementService_Withdraw(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
|
||
// 设置余额
|
||
store.balances[1001] = 5000.0
|
||
|
||
// 测试无效验证码
|
||
t.Run("invalid sms code", func(t *testing.T) {
|
||
smsVerifier := &mockSMSVerifierForSettlement{verifyResult: false}
|
||
svc := NewSettlementServiceWithSMS(store, earningStore, auditStore, smsVerifier)
|
||
|
||
req := &WithdrawRequest{
|
||
Amount: 1000,
|
||
SMSCode: "000000",
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
}
|
||
result, err := svc.Withdraw(context.Background(), 1001, req)
|
||
assert.Error(t, err)
|
||
assert.Nil(t, result)
|
||
assert.Contains(t, err.Error(), "invalid sms code")
|
||
})
|
||
|
||
// 测试验证码错误
|
||
t.Run("sms verify error", func(t *testing.T) {
|
||
smsVerifier := &mockSMSVerifierForSettlement{verifyError: errors.New("SMS service unavailable")}
|
||
svc := NewSettlementServiceWithSMS(store, earningStore, auditStore, smsVerifier)
|
||
|
||
req := &WithdrawRequest{
|
||
Amount: 1000,
|
||
SMSCode: "123456",
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
}
|
||
result, err := svc.Withdraw(context.Background(), 1001, req)
|
||
assert.Error(t, err)
|
||
assert.Nil(t, result)
|
||
assert.Contains(t, err.Error(), "failed to verify SMS code")
|
||
})
|
||
|
||
// 测试负数金额
|
||
t.Run("negative amount", func(t *testing.T) {
|
||
smsVerifier := &mockSMSVerifierForSettlement{verifyResult: true}
|
||
svc := NewSettlementServiceWithSMS(store, earningStore, auditStore, smsVerifier)
|
||
|
||
req := &WithdrawRequest{
|
||
Amount: -100,
|
||
SMSCode: "123456",
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
}
|
||
result, err := svc.Withdraw(context.Background(), 1001, req)
|
||
assert.Error(t, err)
|
||
assert.Nil(t, result)
|
||
assert.Contains(t, err.Error(), "must be positive")
|
||
})
|
||
|
||
// 测试零金额
|
||
t.Run("zero amount", func(t *testing.T) {
|
||
smsVerifier := &mockSMSVerifierForSettlement{verifyResult: true}
|
||
svc := NewSettlementServiceWithSMS(store, earningStore, auditStore, smsVerifier)
|
||
|
||
req := &WithdrawRequest{
|
||
Amount: 0,
|
||
SMSCode: "123456",
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
}
|
||
result, err := svc.Withdraw(context.Background(), 1001, req)
|
||
assert.Error(t, err)
|
||
assert.Nil(t, result)
|
||
assert.Contains(t, err.Error(), "must be positive")
|
||
})
|
||
|
||
// 测试超过余额
|
||
t.Run("exceeds balance", func(t *testing.T) {
|
||
smsVerifier := &mockSMSVerifierForSettlement{verifyResult: true}
|
||
svc := NewSettlementServiceWithSMS(store, earningStore, auditStore, smsVerifier)
|
||
|
||
req := &WithdrawRequest{
|
||
Amount: 10000,
|
||
SMSCode: "123456",
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
}
|
||
result, err := svc.Withdraw(context.Background(), 1001, req)
|
||
assert.Error(t, err)
|
||
assert.Nil(t, result)
|
||
assert.Contains(t, err.Error(), "exceeds available balance")
|
||
})
|
||
|
||
// 测试成功提现
|
||
t.Run("success", func(t *testing.T) {
|
||
smsVerifier := &mockSMSVerifierForSettlement{verifyResult: true}
|
||
svc := NewSettlementServiceWithSMS(store, earningStore, auditStore, smsVerifier)
|
||
|
||
req := &WithdrawRequest{
|
||
Amount: 1000,
|
||
SMSCode: "123456",
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
}
|
||
result, err := svc.Withdraw(context.Background(), 1001, req)
|
||
assert.NoError(t, err)
|
||
assert.NotNil(t, result)
|
||
assert.Equal(t, int64(1001), result.SupplierID)
|
||
assert.Equal(t, SettlementStatusPending, result.Status)
|
||
assert.Equal(t, 1000.0, result.TotalAmount)
|
||
assert.Equal(t, 10.0, result.FeeAmount) // 1% fee
|
||
assert.Equal(t, 990.0, result.NetAmount) // 99%
|
||
})
|
||
}
|
||
|
||
// TestSettlementService_Withdraw_AlreadyHasPending 测试已有待处理提现时拒绝新提现
|
||
func TestSettlementService_Withdraw_AlreadyHasPending(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
smsVerifier := &mockSMSVerifierForSettlement{verifyResult: true} // Mock SMS验证通过
|
||
|
||
// 设置已有待处理提现
|
||
store.hasPendingWithdraw = true
|
||
|
||
svc := NewSettlementServiceWithSMS(store, earningStore, auditStore, smsVerifier)
|
||
|
||
// 设置余额
|
||
store.balances[1001] = 5000.0
|
||
|
||
req := &WithdrawRequest{
|
||
Amount: 1000,
|
||
SMSCode: "123456",
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
}
|
||
|
||
result, err := svc.Withdraw(context.Background(), 1001, req)
|
||
assert.Error(t, err)
|
||
assert.Nil(t, result)
|
||
assert.Contains(t, err.Error(), "already processing")
|
||
}
|
||
|
||
// TestSettlementService_Withdraw_HasPendingCheckError 测试 HasPendingOrProcessingWithdraw 出错
|
||
func TestSettlementService_Withdraw_HasPendingCheckError(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
smsVerifier := &mockSMSVerifierForSettlement{verifyResult: true} // Mock SMS验证通过
|
||
|
||
// 设置 HasPendingOrProcessingWithdraw 返回错误
|
||
store.hasPendingWithdrawError = errors.New("database error")
|
||
|
||
svc := NewSettlementServiceWithSMS(store, earningStore, auditStore, smsVerifier)
|
||
|
||
// 设置余额
|
||
store.balances[1001] = 5000.0
|
||
|
||
req := &WithdrawRequest{
|
||
Amount: 1000,
|
||
SMSCode: "123456",
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
}
|
||
|
||
result, err := svc.Withdraw(context.Background(), 1001, req)
|
||
assert.Error(t, err)
|
||
assert.Nil(t, result)
|
||
assert.Contains(t, err.Error(), "database error")
|
||
}
|
||
|
||
// TestSettlementService_Cancel 测试取消结算
|
||
func TestSettlementService_Cancel(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
|
||
svc := NewSettlementService(store, earningStore, auditStore)
|
||
|
||
// 创建待处理结算
|
||
settlement := &Settlement{
|
||
ID: 1,
|
||
SupplierID: 1001,
|
||
SettlementNo: "SET-001",
|
||
Status: SettlementStatusPending,
|
||
TotalAmount: 1000,
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
Version: 1,
|
||
}
|
||
store.Create(context.Background(), settlement)
|
||
|
||
// 取消待处理结算应该成功
|
||
canceled, err := svc.Cancel(context.Background(), 1001, 1)
|
||
assert.NoError(t, err)
|
||
assert.NotNil(t, canceled)
|
||
assert.Equal(t, SettlementStatusFailed, canceled.Status)
|
||
}
|
||
|
||
// TestSettlementService_Cancel_ProcessingFails 测试取消处理中结算失败
|
||
func TestSettlementService_Cancel_ProcessingFails(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
|
||
svc := NewSettlementService(store, earningStore, auditStore)
|
||
|
||
// 创建处理中结算
|
||
settlement := &Settlement{
|
||
ID: 1,
|
||
SupplierID: 1001,
|
||
SettlementNo: "SET-001",
|
||
Status: SettlementStatusProcessing,
|
||
TotalAmount: 1000,
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
Version: 1,
|
||
}
|
||
store.Create(context.Background(), settlement)
|
||
|
||
// 取消处理中结算应该失败
|
||
_, err := svc.Cancel(context.Background(), 1001, 1)
|
||
assert.Error(t, err)
|
||
assert.Contains(t, err.Error(), "cannot cancel")
|
||
}
|
||
|
||
// TestSettlementService_GetByID 测试获取结算单
|
||
func TestSettlementService_GetByID(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
|
||
svc := NewSettlementService(store, earningStore, auditStore)
|
||
|
||
// 创建结算单
|
||
settlement := &Settlement{
|
||
SupplierID: 1001,
|
||
SettlementNo: "SET-001",
|
||
Status: SettlementStatusPending,
|
||
TotalAmount: 1000,
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
Version: 1,
|
||
}
|
||
store.Create(context.Background(), settlement)
|
||
|
||
// 获取
|
||
found, err := svc.GetByID(context.Background(), 1001, settlement.ID)
|
||
assert.NoError(t, err)
|
||
assert.NotNil(t, found)
|
||
assert.Equal(t, settlement.ID, found.ID)
|
||
}
|
||
|
||
// TestSettlementService_GetByID_NotFound 测试获取不存在的结算单
|
||
func TestSettlementService_GetByID_NotFound(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
|
||
svc := NewSettlementService(store, earningStore, auditStore)
|
||
|
||
_, err := svc.GetByID(context.Background(), 1001, 9999)
|
||
assert.Error(t, err)
|
||
}
|
||
|
||
// TestSettlementService_List 测试列出结算单
|
||
func TestSettlementService_List(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
|
||
svc := NewSettlementService(store, earningStore, auditStore)
|
||
|
||
// 创建结算单
|
||
for i := 0; i < 3; i++ {
|
||
settlement := &Settlement{
|
||
SupplierID: 1001,
|
||
SettlementNo: "SET-00" + string(rune('1'+i)),
|
||
Status: SettlementStatusPending,
|
||
TotalAmount: 1000 + float64(i)*100,
|
||
PaymentMethod: PaymentMethodBank,
|
||
PaymentAccount: "1234567890",
|
||
Version: 1,
|
||
}
|
||
store.Create(context.Background(), settlement)
|
||
}
|
||
|
||
list, err := svc.List(context.Background(), 1001)
|
||
assert.NoError(t, err)
|
||
assert.Len(t, list, 3)
|
||
}
|
||
|
||
// TestNewEarningService 测试创建收益服务
|
||
func TestNewEarningService(t *testing.T) {
|
||
earningStore := newMockEarningStore()
|
||
|
||
svc := NewEarningService(earningStore)
|
||
assert.NotNil(t, svc)
|
||
}
|
||
|
||
// TestEarningService_ListRecords 测试列出收益记录
|
||
func TestEarningService_ListRecords(t *testing.T) {
|
||
earningStore := newMockEarningStore()
|
||
|
||
svc := NewEarningService(earningStore)
|
||
|
||
records, total, err := svc.ListRecords(context.Background(), 1001, "2024-01-01", "2024-01-31", 1, 10)
|
||
assert.NoError(t, err)
|
||
assert.Equal(t, 0, total)
|
||
assert.Len(t, records, 0)
|
||
}
|
||
|
||
// TestEarningService_GetBillingSummary 测试获取账单摘要
|
||
func TestEarningService_GetBillingSummary(t *testing.T) {
|
||
earningStore := newMockEarningStore()
|
||
|
||
svc := NewEarningService(earningStore)
|
||
|
||
summary, err := svc.GetBillingSummary(context.Background(), 1001, "2024-01-01", "2024-01-31")
|
||
assert.NoError(t, err)
|
||
assert.NotNil(t, summary)
|
||
assert.Equal(t, "2024-01-01", summary.Period.Start)
|
||
assert.Equal(t, "2024-01-31", summary.Period.End)
|
||
assert.Equal(t, float64(1000), summary.Summary.TotalRevenue)
|
||
}
|
||
|
||
// TestGenerateSettlementNo 测试生成结算单号
|
||
func TestGenerateSettlementNo(t *testing.T) {
|
||
no := generateSettlementNo()
|
||
|
||
assert.NotEmpty(t, no)
|
||
// 格式为时间戳 20060102150405
|
||
assert.Equal(t, 14, len(no))
|
||
}
|
||
|
||
// TestSettlementService_GetBillingSummary 测试通过结算服务获取账单摘要
|
||
func TestSettlementService_GetBillingSummary(t *testing.T) {
|
||
store := newMockSettlementStore()
|
||
earningStore := newMockEarningStore()
|
||
auditStore := &mockAuditStoreForSettlement{}
|
||
|
||
svc := NewSettlementService(store, earningStore, auditStore)
|
||
|
||
summary, err := svc.GetBillingSummary(context.Background(), 1001, "2024-01-01", "2024-01-31")
|
||
assert.NoError(t, err)
|
||
assert.NotNil(t, summary)
|
||
assert.Equal(t, "2024-01-01", summary.Period.Start)
|
||
assert.Equal(t, "2024-01-31", summary.Period.End)
|
||
assert.Equal(t, float64(1000), summary.Summary.TotalRevenue)
|
||
}
|