feat: tenant-scoped routing and portal navigation

This commit is contained in:
2026-01-08 21:30:46 +08:00
parent f3aa92078a
commit 3e095c57f3
52 changed files with 1111 additions and 670 deletions

View File

@@ -21,14 +21,19 @@ import (
// @provider
type order struct{}
func (s *order) ListUserOrders(ctx context.Context, userID int64, status string) ([]user_dto.Order, error) {
func (s *order) ListUserOrders(ctx context.Context, tenantID, userID int64, status string) ([]user_dto.Order, error) {
if userID == 0 {
return nil, errorx.ErrUnauthorized
}
uid := userID
tbl, q := models.OrderQuery.QueryContext(ctx)
q = q.Where(tbl.UserID.Eq(uid))
if tenantID > 0 {
q = q.Where(tbl.UserID.Eq(uid), tbl.TenantID.Eq(tenantID)).
Or(tbl.UserID.Eq(uid), tbl.Type.Eq(consts.OrderTypeRecharge))
} else {
q = q.Where(tbl.UserID.Eq(uid))
}
if status != "" && status != "all" {
q = q.Where(tbl.Status.Eq(consts.OrderStatus(status)))
@@ -46,14 +51,21 @@ func (s *order) ListUserOrders(ctx context.Context, userID int64, status string)
return data, nil
}
func (s *order) GetUserOrder(ctx context.Context, userID, id int64) (*user_dto.Order, error) {
func (s *order) GetUserOrder(ctx context.Context, tenantID, userID, id int64) (*user_dto.Order, error) {
if userID == 0 {
return nil, errorx.ErrUnauthorized
}
uid := userID
tbl, q := models.OrderQuery.QueryContext(ctx)
item, err := q.Where(tbl.ID.Eq(id), tbl.UserID.Eq(uid)).First()
itemQuery := q
if tenantID > 0 {
itemQuery = itemQuery.Where(tbl.ID.Eq(id), tbl.UserID.Eq(uid), tbl.TenantID.Eq(tenantID)).
Or(tbl.ID.Eq(id), tbl.UserID.Eq(uid), tbl.Type.Eq(consts.OrderTypeRecharge))
} else {
itemQuery = itemQuery.Where(tbl.ID.Eq(id), tbl.UserID.Eq(uid))
}
item, err := itemQuery.First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errorx.ErrRecordNotFound
@@ -70,6 +82,7 @@ func (s *order) GetUserOrder(ctx context.Context, userID, id int64) (*user_dto.O
func (s *order) Create(
ctx context.Context,
tenantID int64,
userID int64,
form *transaction_dto.OrderCreateForm,
) (*transaction_dto.OrderCreateResponse, error) {
@@ -86,7 +99,11 @@ func (s *order) Create(
}
if idempotencyKey != "" {
tbl, q := models.OrderQuery.QueryContext(ctx)
existing, err := q.Where(tbl.UserID.Eq(uid), tbl.IdempotencyKey.Eq(idempotencyKey)).First()
q = q.Where(tbl.UserID.Eq(uid), tbl.IdempotencyKey.Eq(idempotencyKey))
if tenantID > 0 {
q = q.Where(tbl.TenantID.Eq(tenantID))
}
existing, err := q.First()
if err == nil {
return &transaction_dto.OrderCreateResponse{OrderID: existing.ID}, nil
}
@@ -96,7 +113,11 @@ func (s *order) Create(
}
// 1. Fetch Content & Price
content, err := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(cid)).First()
contentQuery := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(cid))
if tenantID > 0 {
contentQuery = contentQuery.Where(models.ContentQuery.TenantID.Eq(tenantID))
}
content, err := contentQuery.First()
if err != nil {
return nil, errorx.ErrRecordNotFound.WithMsg("内容不存在")
}
@@ -188,6 +209,7 @@ func (s *order) Create(
func (s *order) Pay(
ctx context.Context,
tenantID int64,
userID int64,
id int64,
form *transaction_dto.OrderPayForm,
@@ -204,6 +226,9 @@ func (s *order) Pay(
if err != nil {
return nil, errorx.ErrRecordNotFound
}
if tenantID > 0 && o.TenantID > 0 && o.TenantID != tenantID {
return nil, errorx.ErrForbidden.WithMsg("租户不匹配")
}
if o.Status != consts.OrderStatusCreated {
return nil, errorx.ErrStatusConflict.WithMsg("订单状态不可支付")
}
@@ -219,11 +244,14 @@ func (s *order) Pay(
}
// ProcessExternalPayment handles callback from payment gateway
func (s *order) ProcessExternalPayment(ctx context.Context, orderID int64, externalID string) error {
func (s *order) ProcessExternalPayment(ctx context.Context, tenantID, orderID int64, externalID string) error {
o, err := models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.ID.Eq(orderID)).First()
if err != nil {
return errorx.ErrRecordNotFound
}
if tenantID > 0 && o.TenantID > 0 && o.TenantID != tenantID {
return errorx.ErrForbidden.WithMsg("租户不匹配")
}
if o.Status != consts.OrderStatusCreated {
return nil // Already processed idempotency
}
@@ -365,7 +393,7 @@ func (s *order) settleOrder(ctx context.Context, o *models.Order, method, extern
return nil
}
func (s *order) Status(ctx context.Context, id int64) (*transaction_dto.OrderStatusResponse, error) {
func (s *order) Status(ctx context.Context, tenantID, id int64) (*transaction_dto.OrderStatusResponse, error) {
o, err := models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.ID.Eq(id)).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
@@ -373,6 +401,9 @@ func (s *order) Status(ctx context.Context, id int64) (*transaction_dto.OrderSta
}
return nil, errorx.ErrDatabaseError.WithCause(err)
}
if tenantID > 0 && o.TenantID > 0 && o.TenantID != tenantID {
return nil, errorx.ErrForbidden.WithMsg("租户不匹配")
}
return &transaction_dto.OrderStatusResponse{
Status: string(o.Status),