修复(#11): 修复家庭组订单退款订阅归属 (#13)

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-06-07 08:23:19 -07:00
committed by GitHub
parent bcb8cd222c
commit b98d718f3c
2 changed files with 258 additions and 15 deletions
@@ -8,9 +8,9 @@ import (
"time"
"github.com/DATA-DOG/go-sqlmock"
"github.com/perfect-panel/server/internal/svc"
modelorder "github.com/perfect-panel/server/internal/model/order"
modeluser "github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/constant"
"github.com/perfect-panel/server/pkg/logger"
@@ -195,6 +195,141 @@ func TestRefundOrder_RejectsWhenStatusNotRefundable(t *testing.T) {
}
}
func TestLockRefundTargetSubscription_FamilyMemberPurchaseLocksOwnerSubscription(t *testing.T) {
const (
orderID = int64(2001)
memberUID = int64(101)
ownerUID = int64(201)
subscribeID = int64(301)
userSubID = int64(401)
)
db, mock, cleanup := newRefundOrderTestDB(t)
defer cleanup()
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(orderID, 1).
WillReturnError(gorm.ErrRecordNotFound)
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(ownerUID, subscribeID, orderID, 1).
WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "order_id", "subscribe_id", "status", "expire_time"}).
AddRow(userSubID, ownerUID, orderID, subscribeID, uint8(1), time.Now().Add(24*time.Hour)))
logic := &RefundOrderLogic{}
got, err := logic.lockRefundTargetSubscription(db, &modelorder.Order{
Id: orderID,
UserId: memberUID,
SubscriptionUserId: ownerUID,
Type: 1,
SubscribeId: subscribeID,
})
if err != nil {
t.Fatalf("lockRefundTargetSubscription error: %v", err)
}
if got.Id != userSubID || got.UserId != ownerUID {
t.Fatalf("locked subscription = %+v, want id=%d user_id=%d", got, userSubID, ownerUID)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet sql expectations: %v", err)
}
}
func TestLockRefundTargetSubscription_RenewalFallsBackToParentOwnerEntitlement(t *testing.T) {
const (
orderID = int64(2101)
parentOrderID = int64(2100)
memberUID = int64(111)
ownerUID = int64(211)
subscribeID = int64(311)
userSubID = int64(411)
)
db, mock, cleanup := newRefundOrderTestDB(t)
defer cleanup()
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(orderID, 1).
WillReturnError(gorm.ErrRecordNotFound)
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(ownerUID, subscribeID, orderID, "renew-token", 1).
WillReturnError(gorm.ErrRecordNotFound)
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(ownerUID, subscribeID, int64(0), int64(1), int64(2), int64(3), int64(5), 1).
WillReturnError(gorm.ErrRecordNotFound)
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(parentOrderID, 1).
WillReturnError(gorm.ErrRecordNotFound)
mock.ExpectQuery("FROM `order`").
WithArgs(parentOrderID, 1).
WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "subscription_user_id", "subscribe_id", "subscribe_token"}).
AddRow(parentOrderID, memberUID, ownerUID, subscribeID, "owner-token"))
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(ownerUID, subscribeID, parentOrderID, "owner-token", 1).
WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "order_id", "subscribe_id", "status", "expire_time", "token"}).
AddRow(userSubID, ownerUID, parentOrderID, subscribeID, uint8(1), time.Now().Add(24*time.Hour), "owner-token"))
logic := &RefundOrderLogic{}
got, err := logic.lockRefundTargetSubscription(db, &modelorder.Order{
Id: orderID,
ParentId: parentOrderID,
UserId: memberUID,
SubscriptionUserId: ownerUID,
Type: 2,
SubscribeId: subscribeID,
SubscribeToken: "renew-token",
})
if err != nil {
t.Fatalf("lockRefundTargetSubscription error: %v", err)
}
if got.Id != userSubID || got.UserId != ownerUID || got.OrderId != parentOrderID {
t.Fatalf("locked subscription = %+v, want id=%d user_id=%d order_id=%d", got, userSubID, ownerUID, parentOrderID)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet sql expectations: %v", err)
}
}
func TestRefundOrder_NoTargetSubscriptionDoesNotRefundOrder(t *testing.T) {
const (
orderID = int64(2201)
orderNo = "ORD-NO-SUB"
operatorUID = int64(519)
userID = int64(7001)
subscribeID = int64(8001)
)
db, mock, cleanup := newRefundOrderTestDB(t)
defer cleanup()
mock.ExpectBegin()
mock.ExpectQuery("FROM `order`").
WithArgs(orderID, 1).
WillReturnRows(sqlmock.NewRows([]string{"id", "order_no", "status", "type", "commission", "user_id", "subscribe_id"}).
AddRow(orderID, orderNo, uint8(5), uint8(1), int64(0), userID, subscribeID))
mock.ExpectQuery("FROM `system_logs`").
WithArgs(uint8(33), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)).
WillReturnRows(sqlmock.NewRows([]string{"id", "content"}))
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(orderID, 1).
WillReturnError(gorm.ErrRecordNotFound)
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(userID, subscribeID, orderID, 1).
WillReturnError(gorm.ErrRecordNotFound)
mock.ExpectQuery("FROM `user_subscribe`").
WithArgs(userID, subscribeID, int64(0), int64(1), int64(2), int64(3), int64(5), 1).
WillReturnError(gorm.ErrRecordNotFound)
mock.ExpectRollback()
logic := newTestRefundOrderLogic(t, db, operatorUID)
err := logic.RefundOrder(&types.RefundOrderRequest{Id: orderID, Reason: "missing subscription"})
if !isErrCode(err, xerr.OrderRefundNoSubscription) {
t.Fatalf("RefundOrder error code = %v, want OrderRefundNoSubscription; raw=%v", errCodeOf(err), err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet sql expectations: %v", err)
}
}
func newRefundOrderTestDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock, func()) {
t.Helper()