新功能(#26): 拆分退款日志查询接口
拆分用户中心退款日志查询: - 新增 GET /v1/public/user/commission_return_log(333/337/338) - 旧 GET /v1/public/user/withdrawal_log?biz_type=commission_refund 复用新逻辑做兼容 - 默认 withdrawal_log 行为不变(仍查 withdrawals 表) - 单测覆盖 333/337/338 happy path、坏 JSON 跳过、object_id 隔离、handler 级 HTTP 响应 父 issue: HIF-25 子 issue: HIF-26
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -58,26 +59,56 @@ func TestQueryWithdrawalLog_WithWithdrawalBizType(t *testing.T) {
|
||||
if got.Id != 1001 || got.UserId != userID || got.Amount != 3000 || got.CreatedAt != createdAt.UnixMilli() || got.UpdatedAt != updatedAt.UnixMilli() {
|
||||
t.Fatalf("withdrawal item = %+v", got)
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatalf("unmet sql expectations: %v", err)
|
||||
}
|
||||
assertQueryWithdrawalLogExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestQueryWithdrawalLog_WithCommissionRefundBizType(t *testing.T) {
|
||||
func TestQueryCommissionReturnLog_HappyPathIncludes333337338(t *testing.T) {
|
||||
const userID = int64(42)
|
||||
content := `{"type":333,"amount":2500,"order_no":"ORDER-1","timestamp":1700000000123}`
|
||||
createdAt := time.Unix(1700000000, 0)
|
||||
|
||||
db, mock, cleanup := newQueryWithdrawalLogTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
mock.ExpectQuery("SELECT count(*) FROM `system_logs` WHERE `type` = ? AND object_id = ? AND `content` LIKE ?").
|
||||
WithArgs(logmodel.TypeCommission.Uint8(), userID, "%\"type\":333%").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
|
||||
mock.ExpectQuery("SELECT * FROM `system_logs` WHERE `type` = ? AND object_id = ? AND `content` LIKE ? ORDER BY id DESC LIMIT ?").
|
||||
WithArgs(logmodel.TypeCommission.Uint8(), userID, "%\"type\":333%", 10).
|
||||
expectCommissionReturnQueries(mock, userID, 3)
|
||||
mock.ExpectQuery("SELECT * FROM `system_logs` WHERE `type` = ? AND object_id = ? AND (`content` LIKE ? OR `content` LIKE ? OR `content` LIKE ?) ORDER BY id DESC LIMIT ?").
|
||||
WithArgs(logmodel.TypeCommission.Uint8(), userID, "%\"type\":333%", "%\"type\":337%", "%\"type\":338%", 10).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "type", "date", "object_id", "content", "created_at"}).
|
||||
AddRow(int64(2001), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, content, createdAt))
|
||||
AddRow(int64(2003), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, `{"type":338,"amount":1500,"order_no":"ORDER-3","timestamp":1700000003123}`, createdAt).
|
||||
AddRow(int64(2002), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, `{"type":337,"amount":2000,"order_no":"ORDER-2","timestamp":1700000002123}`, createdAt).
|
||||
AddRow(int64(2001), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, `{"type":333,"amount":2500,"order_no":"ORDER-1","timestamp":1700000001123}`, createdAt))
|
||||
|
||||
logic := NewQueryCommissionReturnLogLogic(newTestQueryCtx(userID), &svc.ServiceContext{DB: db})
|
||||
resp, err := logic.QueryCommissionReturnLog(&types.QueryCommissionReturnLogRequest{Page: 1, Size: 10})
|
||||
if err != nil {
|
||||
t.Fatalf("QueryCommissionReturnLog unexpected error: %v", err)
|
||||
}
|
||||
if resp.Total != 3 || len(resp.List) != 3 {
|
||||
t.Fatalf("QueryCommissionReturnLog response = %+v, want three logs", resp)
|
||||
}
|
||||
|
||||
eventTypes := []uint16{resp.List[0].EventType, resp.List[1].EventType, resp.List[2].EventType}
|
||||
wantTypes := []uint16{logmodel.CommissionTypeWithdrawCancel, logmodel.CommissionTypeWithdrawReject, logmodel.CommissionTypeRefund}
|
||||
if fmt.Sprint(eventTypes) != fmt.Sprint(wantTypes) {
|
||||
t.Fatalf("event types = %v, want %v", eventTypes, wantTypes)
|
||||
}
|
||||
|
||||
assertQueryWithdrawalLogExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestQueryWithdrawalLog_WithCommissionRefundBizTypeIncludes333337338(t *testing.T) {
|
||||
const userID = int64(42)
|
||||
createdAt := time.Unix(1700000000, 0)
|
||||
|
||||
db, mock, cleanup := newQueryWithdrawalLogTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
expectCommissionReturnQueries(mock, userID, 3)
|
||||
mock.ExpectQuery("SELECT * FROM `system_logs` WHERE `type` = ? AND object_id = ? AND (`content` LIKE ? OR `content` LIKE ? OR `content` LIKE ?) ORDER BY id DESC LIMIT ?").
|
||||
WithArgs(logmodel.TypeCommission.Uint8(), userID, "%\"type\":333%", "%\"type\":337%", "%\"type\":338%", 10).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "type", "date", "object_id", "content", "created_at"}).
|
||||
AddRow(int64(2003), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, `{"type":338,"amount":1500,"order_no":"ORDER-3","timestamp":1700000003123}`, createdAt).
|
||||
AddRow(int64(2002), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, `{"type":337,"amount":2000,"order_no":"ORDER-2","timestamp":1700000002123}`, createdAt).
|
||||
AddRow(int64(2001), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, `{"type":333,"amount":2500,"order_no":"ORDER-1","timestamp":1700000001123}`, createdAt))
|
||||
|
||||
logic := newTestQueryWithdrawalLogLogic(t, db, userID)
|
||||
resp, err := logic.QueryWithdrawalLog(&types.QueryWithdrawalLogListRequest{
|
||||
@@ -88,22 +119,72 @@ func TestQueryWithdrawalLog_WithCommissionRefundBizType(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("QueryWithdrawalLog unexpected error: %v", err)
|
||||
}
|
||||
if resp.Total != 1 || len(resp.List) != 1 {
|
||||
t.Fatalf("QueryWithdrawalLog response = %+v, want one commission refund", resp)
|
||||
if resp.Total != 3 || len(resp.List) != 3 {
|
||||
t.Fatalf("QueryWithdrawalLog response = %+v, want three commission returns", resp)
|
||||
}
|
||||
got := resp.List[0]
|
||||
if got.BizType != withdrawalLogBizTypeCommissionRefund {
|
||||
t.Fatalf("BizType = %q, want %q", got.BizType, withdrawalLogBizTypeCommissionRefund)
|
||||
for _, item := range resp.List {
|
||||
if item.BizType != withdrawalLogBizTypeCommissionRefund {
|
||||
t.Fatalf("BizType = %q, want %q", item.BizType, withdrawalLogBizTypeCommissionRefund)
|
||||
}
|
||||
if item.Status != 0 || item.Reason != "" || item.Method != 0 || item.Account != "" || item.QrCodeUrl != "" {
|
||||
t.Fatalf("withdrawal-only fields should keep zero values, got %+v", item)
|
||||
}
|
||||
}
|
||||
if got.Id != 2001 || got.UserId != userID || got.Amount != 2500 || got.Content != content || got.CreatedAt != 1700000000123 || got.UpdatedAt != 1700000000123 {
|
||||
t.Fatalf("commission refund item = %+v", got)
|
||||
assertQueryWithdrawalLogExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestQueryCommissionReturnLog_SkipsInvalidJSONAndLogsWarn(t *testing.T) {
|
||||
const userID = int64(42)
|
||||
createdAt := time.Unix(1700000000, 0)
|
||||
|
||||
db, mock, cleanup := newQueryWithdrawalLogTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
expectCommissionReturnQueries(mock, userID, 2)
|
||||
mock.ExpectQuery("SELECT * FROM `system_logs` WHERE `type` = ? AND object_id = ? AND (`content` LIKE ? OR `content` LIKE ? OR `content` LIKE ?) ORDER BY id DESC LIMIT ?").
|
||||
WithArgs(logmodel.TypeCommission.Uint8(), userID, "%\"type\":333%", "%\"type\":337%", "%\"type\":338%", 10).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "type", "date", "object_id", "content", "created_at"}).
|
||||
AddRow(int64(2002), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, `{"type":337,"amount":2000,"order_no":"ORDER-2","timestamp":1700000002123}`, createdAt).
|
||||
AddRow(int64(2001), logmodel.TypeCommission.Uint8(), "2023-11-14", userID, `{"type":333`, createdAt))
|
||||
|
||||
var buf bytes.Buffer
|
||||
restoreLogger := captureTestLogs(&buf)
|
||||
defer restoreLogger()
|
||||
|
||||
logic := NewQueryCommissionReturnLogLogic(newTestQueryCtx(userID), &svc.ServiceContext{DB: db})
|
||||
resp, err := logic.QueryCommissionReturnLog(&types.QueryCommissionReturnLogRequest{Page: 1, Size: 10})
|
||||
if err != nil {
|
||||
t.Fatalf("QueryCommissionReturnLog unexpected error: %v", err)
|
||||
}
|
||||
if got.Status != 0 || got.Method != 0 || got.Account != "" || got.QrCodeUrl != "" {
|
||||
t.Fatalf("commission refund withdrawal-only fields = %+v, want zero values", got)
|
||||
if resp.Total != 2 || len(resp.List) != 1 {
|
||||
t.Fatalf("QueryCommissionReturnLog response = %+v, want total=2 and one valid row", resp)
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatalf("unmet sql expectations: %v", err)
|
||||
if !strings.Contains(buf.String(), "unmarshal commission return log content failed") {
|
||||
t.Fatalf("expected warn log, got %q", buf.String())
|
||||
}
|
||||
assertQueryWithdrawalLogExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestQueryCommissionReturnLog_FiltersOtherUsersByObjectID(t *testing.T) {
|
||||
const userID = int64(42)
|
||||
|
||||
db, mock, cleanup := newQueryWithdrawalLogTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
expectCommissionReturnQueries(mock, userID, 0)
|
||||
mock.ExpectQuery("SELECT * FROM `system_logs` WHERE `type` = ? AND object_id = ? AND (`content` LIKE ? OR `content` LIKE ? OR `content` LIKE ?) ORDER BY id DESC LIMIT ?").
|
||||
WithArgs(logmodel.TypeCommission.Uint8(), userID, "%\"type\":333%", "%\"type\":337%", "%\"type\":338%", 10).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "type", "date", "object_id", "content", "created_at"}))
|
||||
|
||||
logic := NewQueryCommissionReturnLogLogic(newTestQueryCtx(userID), &svc.ServiceContext{DB: db})
|
||||
resp, err := logic.QueryCommissionReturnLog(&types.QueryCommissionReturnLogRequest{Page: 1, Size: 10})
|
||||
if err != nil {
|
||||
t.Fatalf("QueryCommissionReturnLog unexpected error: %v", err)
|
||||
}
|
||||
if resp.Total != 0 || len(resp.List) != 0 {
|
||||
t.Fatalf("QueryCommissionReturnLog response = %+v, want no rows for filtered user", resp)
|
||||
}
|
||||
assertQueryWithdrawalLogExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestQueryWithdrawalLog_RejectsInvalidBizType(t *testing.T) {
|
||||
@@ -119,9 +200,7 @@ func TestQueryWithdrawalLog_RejectsInvalidBizType(t *testing.T) {
|
||||
if !isQueryWithdrawalLogErrCode(err, xerr.InvalidParams) {
|
||||
t.Fatalf("QueryWithdrawalLog err = %v, want InvalidParams", err)
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatalf("unmet sql expectations: %v", err)
|
||||
}
|
||||
assertQueryWithdrawalLogExpectations(t, mock)
|
||||
}
|
||||
|
||||
func newQueryWithdrawalLogTestDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock, func()) {
|
||||
@@ -150,7 +229,7 @@ func newQueryWithdrawalLogTestDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock, func(
|
||||
|
||||
func newTestQueryWithdrawalLogLogic(t *testing.T, db *gorm.DB, userID int64) *QueryWithdrawalLogLogic {
|
||||
t.Helper()
|
||||
ctx := context.WithValue(context.Background(), constant.CtxKeyUser, &usermodel.User{Id: userID})
|
||||
ctx := newTestQueryCtx(userID)
|
||||
return &QueryWithdrawalLogLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
@@ -160,6 +239,37 @@ func newTestQueryWithdrawalLogLogic(t *testing.T, db *gorm.DB, userID int64) *Qu
|
||||
}
|
||||
}
|
||||
|
||||
func newTestQueryCtx(userID int64) context.Context {
|
||||
return context.WithValue(context.Background(), constant.CtxKeyUser, &usermodel.User{Id: userID})
|
||||
}
|
||||
|
||||
func expectCommissionReturnQueries(mock sqlmock.Sqlmock, userID int64, total int64) {
|
||||
mock.ExpectQuery("SELECT count(*) FROM `system_logs` WHERE `type` = ? AND object_id = ? AND (`content` LIKE ? OR `content` LIKE ? OR `content` LIKE ?)").
|
||||
WithArgs(logmodel.TypeCommission.Uint8(), userID, "%\"type\":333%", "%\"type\":337%", "%\"type\":338%").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(total))
|
||||
}
|
||||
|
||||
func assertQueryWithdrawalLogExpectations(t *testing.T, mock sqlmock.Sqlmock) {
|
||||
t.Helper()
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatalf("unmet sql expectations: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func captureTestLogs(buf *bytes.Buffer) func() {
|
||||
prevWriter := logger.Reset()
|
||||
prevLevel := logger.InfoLevel
|
||||
logger.SetLevel(logger.DebugLevel)
|
||||
logger.SetWriter(logger.NewWriter(buf))
|
||||
return func() {
|
||||
logger.Reset()
|
||||
logger.SetLevel(prevLevel)
|
||||
if prevWriter != nil {
|
||||
logger.SetWriter(prevWriter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func queryWithdrawalLogErrCodeOf(err error) uint32 {
|
||||
if err == nil {
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user