feat(shop-role): 实现店铺角色继承功能和权限检查优化
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m39s

- 新增店铺角色管理 API 和数据模型
- 实现角色继承和权限检查逻辑
- 添加流程测试框架和集成测试
- 更新权限服务和账号管理逻辑
- 添加数据库迁移脚本
- 归档 OpenSpec 变更文档

Ultraworked with Sisyphus
This commit is contained in:
2026-02-03 10:06:13 +08:00
parent bc7e5d6f6d
commit 5a90caa619
61 changed files with 21284 additions and 131 deletions

View File

@@ -19,6 +19,7 @@ func initHandlers(svc *services, deps *Dependencies) *Handlers {
Permission: admin.NewPermissionHandler(svc.Permission),
PersonalCustomer: app.NewPersonalCustomerHandler(svc.PersonalCustomer, deps.Logger),
Shop: admin.NewShopHandler(svc.Shop),
ShopRole: admin.NewShopRoleHandler(svc.Shop),
AdminAuth: admin.NewAuthHandler(svc.Auth, validate),
H5Auth: h5.NewAuthHandler(svc.Auth, validate),
ShopCommission: admin.NewShopCommissionHandler(svc.ShopCommission),

View File

@@ -74,14 +74,15 @@ type services struct {
func initServices(s *stores, deps *Dependencies) *services {
purchaseValidation := purchaseValidationSvc.New(deps.DB, s.IotCard, s.Device, s.Package, s.ShopSeriesAllocation)
accountAudit := accountAuditSvc.NewService(s.AccountOperationLog)
account := accountSvc.New(s.Account, s.Role, s.AccountRole, s.ShopRole, s.Shop, s.Enterprise, accountAudit)
return &services{
Account: accountSvc.New(s.Account, s.Role, s.AccountRole, s.Shop, s.Enterprise, accountAudit),
Account: account,
AccountAudit: accountAudit,
Role: roleSvc.New(s.Role, s.Permission, s.RolePermission),
Permission: permissionSvc.New(s.Permission, s.AccountRole, s.RolePermission, deps.Redis),
Permission: permissionSvc.New(s.Permission, s.AccountRole, s.RolePermission, account, deps.Redis),
PersonalCustomer: personalCustomerSvc.NewService(s.PersonalCustomer, s.PersonalCustomerPhone, deps.VerificationService, deps.JWTManager, deps.WechatOfficialAccount, deps.Logger),
Shop: shopSvc.New(s.Shop, s.Account),
Shop: shopSvc.New(s.Shop, s.Account, s.ShopRole, s.Role),
Auth: authSvc.New(s.Account, s.AccountRole, s.RolePermission, s.Permission, deps.TokenManager, deps.Logger),
ShopCommission: shopCommissionSvc.New(s.Shop, s.Account, s.Wallet, s.CommissionWithdrawalRequest, s.CommissionRecord),
CommissionWithdrawal: commissionWithdrawalSvc.New(deps.DB, s.Shop, s.Account, s.Wallet, s.WalletTransaction, s.CommissionWithdrawalRequest),

View File

@@ -11,6 +11,7 @@ type stores struct {
Role *postgres.RoleStore
Permission *postgres.PermissionStore
AccountRole *postgres.AccountRoleStore
ShopRole *postgres.ShopRoleStore
RolePermission *postgres.RolePermissionStore
PersonalCustomer *postgres.PersonalCustomerStore
PersonalCustomerPhone *postgres.PersonalCustomerPhoneStore
@@ -50,6 +51,7 @@ func initStores(deps *Dependencies) *stores {
Role: postgres.NewRoleStore(deps.DB),
Permission: postgres.NewPermissionStore(deps.DB),
AccountRole: postgres.NewAccountRoleStore(deps.DB, deps.Redis),
ShopRole: postgres.NewShopRoleStore(deps.DB, deps.Redis),
RolePermission: postgres.NewRolePermissionStore(deps.DB, deps.Redis),
PersonalCustomer: postgres.NewPersonalCustomerStore(deps.DB, deps.Redis),
PersonalCustomerPhone: postgres.NewPersonalCustomerPhoneStore(deps.DB),

View File

@@ -17,6 +17,7 @@ type Handlers struct {
Permission *admin.PermissionHandler
PersonalCustomer *app.PersonalCustomerHandler
Shop *admin.ShopHandler
ShopRole *admin.ShopRoleHandler
AdminAuth *admin.AuthHandler
H5Auth *h5.AuthHandler
ShopCommission *admin.ShopCommissionHandler

View File

@@ -0,0 +1,75 @@
package admin
import (
"strconv"
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
shopService "github.com/break/junhong_cmp_fiber/internal/service/shop"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/response"
)
type ShopRoleHandler struct {
service *shopService.Service
}
func NewShopRoleHandler(service *shopService.Service) *ShopRoleHandler {
return &ShopRoleHandler{service: service}
}
func (h *ShopRoleHandler) AssignShopRoles(c *fiber.Ctx) error {
shopIDStr := c.Params("shop_id")
shopID, err := strconv.ParseUint(shopIDStr, 10, 32)
if err != nil {
return errors.New(errors.CodeInvalidParam, "店铺ID格式错误")
}
var req dto.AssignShopRolesRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
result, err := h.service.AssignRolesToShop(c.UserContext(), uint(shopID), req.RoleIDs)
if err != nil {
return err
}
return response.Success(c, result)
}
func (h *ShopRoleHandler) GetShopRoles(c *fiber.Ctx) error {
shopIDStr := c.Params("shop_id")
shopID, err := strconv.ParseUint(shopIDStr, 10, 32)
if err != nil {
return errors.New(errors.CodeInvalidParam, "店铺ID格式错误")
}
result, err := h.service.GetShopRoles(c.UserContext(), uint(shopID))
if err != nil {
return err
}
return response.Success(c, result)
}
func (h *ShopRoleHandler) DeleteShopRole(c *fiber.Ctx) error {
shopIDStr := c.Params("shop_id")
shopID, err := strconv.ParseUint(shopIDStr, 10, 32)
if err != nil {
return errors.New(errors.CodeInvalidParam, "店铺ID格式错误")
}
roleIDStr := c.Params("role_id")
roleID, err := strconv.ParseUint(roleIDStr, 10, 32)
if err != nil {
return errors.New(errors.CodeInvalidParam, "角色ID格式错误")
}
if err := h.service.DeleteShopRole(c.UserContext(), uint(shopID), uint(roleID)); err != nil {
return err
}
return response.Success(c, nil)
}

View File

@@ -0,0 +1,33 @@
package dto
// AssignShopRolesRequest 分配店铺角色请求
type AssignShopRolesRequest struct {
ShopID uint `json:"-" params:"shop_id" path:"shop_id" validate:"required" description:"店铺ID"`
RoleIDs []uint `json:"role_ids" validate:"required" description:"角色ID列表"`
}
// GetShopRolesRequest 查询店铺角色请求
type GetShopRolesRequest struct {
ShopID uint `json:"-" params:"shop_id" path:"shop_id" validate:"required" description:"店铺ID"`
}
// DeleteShopRoleRequest 删除店铺角色请求
type DeleteShopRoleRequest struct {
ShopID uint `json:"-" params:"shop_id" path:"shop_id" validate:"required" description:"店铺ID"`
RoleID uint `json:"-" params:"role_id" path:"role_id" validate:"required" description:"角色ID"`
}
// ShopRoleResponse 店铺-角色关联响应
type ShopRoleResponse struct {
ShopID uint `json:"shop_id" description:"店铺ID"`
RoleID uint `json:"role_id" description:"角色ID"`
RoleName string `json:"role_name" description:"角色名称"`
RoleDesc string `json:"role_desc" description:"角色描述"`
Status int `json:"status" description:"状态 (0:禁用, 1:启用)"`
}
// ShopRolesResponse 店铺的角色列表响应
type ShopRolesResponse struct {
ShopID uint `json:"shop_id" description:"店铺ID"`
Roles []*ShopRoleResponse `json:"roles" description:"角色列表"`
}

View File

@@ -0,0 +1,24 @@
package model
import (
"time"
"gorm.io/gorm"
)
// ShopRole 店铺-角色关联模型
type ShopRole struct {
ID uint `gorm:"column:id;primarykey;comment:主键ID" json:"id"`
ShopID uint `gorm:"column:shop_id;not null;index;uniqueIndex:uq_shop_role_shop_id_role_id,where:deleted_at IS NULL;comment:店铺ID" json:"shop_id"`
RoleID uint `gorm:"column:role_id;not null;index;uniqueIndex:uq_shop_role_shop_id_role_id,where:deleted_at IS NULL;comment:角色ID" json:"role_id"`
Status int `gorm:"column:status;not null;default:1;comment:状态 0=禁用 1=启用" json:"status"`
Creator uint `gorm:"column:creator;not null;comment:创建人ID" json:"creator"`
Updater uint `gorm:"column:updater;not null;comment:更新人ID" json:"updater"`
CreatedAt time.Time `gorm:"column:created_at;not null;comment:创建时间" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null;comment:更新时间" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index;comment:删除时间" json:"deleted_at,omitempty"`
}
func (ShopRole) TableName() string {
return "tb_shop_role"
}

View File

@@ -24,6 +24,9 @@ func RegisterAdminRoutes(router fiber.Router, handlers *bootstrap.Handlers, midd
if handlers.Shop != nil {
registerShopRoutes(authGroup, handlers.Shop, doc, basePath)
}
if handlers.ShopRole != nil {
registerShopRoleRoutes(authGroup, handlers.ShopRole, doc, basePath)
}
if handlers.ShopCommission != nil {
registerShopCommissionRoutes(authGroup, handlers.ShopCommission, doc, basePath)

View File

@@ -45,6 +45,35 @@ func registerShopRoutes(router fiber.Router, handler *admin.ShopHandler, doc *op
})
}
func registerShopRoleRoutes(router fiber.Router, handler *admin.ShopRoleHandler, doc *openapi.Generator, basePath string) {
shops := router.Group("/shops")
groupPath := basePath + "/shops"
Register(shops, doc, groupPath, "POST", "/:shop_id/roles", handler.AssignShopRoles, RouteSpec{
Summary: "分配店铺默认角色",
Tags: []string{"店铺管理"},
Input: new(dto.AssignShopRolesRequest),
Output: new(dto.ShopRolesResponse),
Auth: true,
})
Register(shops, doc, groupPath, "GET", "/:shop_id/roles", handler.GetShopRoles, RouteSpec{
Summary: "查询店铺默认角色",
Tags: []string{"店铺管理"},
Input: new(dto.GetShopRolesRequest),
Output: new(dto.ShopRolesResponse),
Auth: true,
})
Register(shops, doc, groupPath, "DELETE", "/:shop_id/roles/:role_id", handler.DeleteShopRole, RouteSpec{
Summary: "删除店铺默认角色",
Tags: []string{"店铺管理"},
Input: new(dto.DeleteShopRoleRequest),
Output: nil,
Auth: true,
})
}
func registerShopCommissionRoutes(router fiber.Router, handler *admin.ShopCommissionHandler, doc *openapi.Generator, basePath string) {
shops := router.Group("/shops")
groupPath := basePath + "/shops"

View File

@@ -0,0 +1,37 @@
package account
import (
"context"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
)
func (s *Service) GetRoleIDsForAccount(ctx context.Context, accountID uint) ([]uint, error) {
account, err := s.accountStore.GetByID(ctx, accountID)
if err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "查询账号失败")
}
if account.UserType == constants.UserTypeSuperAdmin {
return []uint{}, nil
}
accountRoles, err := s.accountRoleStore.GetRoleIDsByAccountID(ctx, accountID)
if err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "查询账号角色失败")
}
if len(accountRoles) > 0 {
return accountRoles, nil
}
if account.UserType == constants.UserTypeAgent && account.ShopID != nil {
shopRoles, err := s.shopRoleStore.GetRoleIDsByShopID(ctx, *account.ShopID)
if err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "查询店铺角色失败")
}
return shopRoles, nil
}
return []uint{}, nil
}

View File

@@ -0,0 +1,211 @@
package account
import (
"context"
"testing"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/tests/testutils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetRoleIDsForAccount(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
accountStore := postgres.NewAccountStore(tx, rdb)
roleStore := postgres.NewRoleStore(tx)
accountRoleStore := postgres.NewAccountRoleStore(tx, rdb)
shopRoleStore := postgres.NewShopRoleStore(tx, rdb)
service := New(
accountStore,
roleStore,
accountRoleStore,
shopRoleStore,
nil,
nil,
nil,
)
ctx := context.Background()
t.Run("超级管理员返回空数组", func(t *testing.T) {
account := &model.Account{
Username: "admin_roletest",
Phone: "13800010001",
Password: "hashed",
UserType: constants.UserTypeSuperAdmin,
Status: constants.StatusEnabled,
}
require.NoError(t, accountStore.Create(ctx, account))
roleIDs, err := service.GetRoleIDsForAccount(ctx, account.ID)
require.NoError(t, err)
assert.Empty(t, roleIDs)
})
t.Run("平台用户返回账号级角色", func(t *testing.T) {
account := &model.Account{
Username: "platform_roletest",
Phone: "13800010002",
Password: "hashed",
UserType: constants.UserTypePlatform,
Status: constants.StatusEnabled,
}
require.NoError(t, accountStore.Create(ctx, account))
role := &model.Role{
RoleName: "平台管理员",
RoleType: constants.RoleTypePlatform,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(ctx, role))
accountRole := &model.AccountRole{
AccountID: account.ID,
RoleID: role.ID,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}
require.NoError(t, accountRoleStore.Create(ctx, accountRole))
roleIDs, err := service.GetRoleIDsForAccount(ctx, account.ID)
require.NoError(t, err)
assert.Equal(t, []uint{role.ID}, roleIDs)
})
t.Run("代理账号有账号级角色,不继承店铺角色", func(t *testing.T) {
shopID := uint(1)
account := &model.Account{
Username: "agent_with_roletest",
Phone: "13800010003",
Password: "hashed",
UserType: constants.UserTypeAgent,
ShopID: &shopID,
Status: constants.StatusEnabled,
}
require.NoError(t, accountStore.Create(ctx, account))
accountRole := &model.Role{
RoleName: "账号角色",
RoleType: constants.RoleTypeCustomer,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(ctx, accountRole))
shopRole := &model.Role{
RoleName: "店铺角色",
RoleType: constants.RoleTypeCustomer,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(ctx, shopRole))
require.NoError(t, accountRoleStore.Create(ctx, &model.AccountRole{
AccountID: account.ID,
RoleID: accountRole.ID,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}))
require.NoError(t, shopRoleStore.Create(ctx, &model.ShopRole{
ShopID: shopID,
RoleID: shopRole.ID,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}))
roleIDs, err := service.GetRoleIDsForAccount(ctx, account.ID)
require.NoError(t, err)
assert.Equal(t, []uint{accountRole.ID}, roleIDs)
})
t.Run("代理账号无账号级角色,继承店铺角色", func(t *testing.T) {
shopID := uint(2)
account := &model.Account{
Username: "agent_inheritest",
Phone: "13800010004",
Password: "hashed",
UserType: constants.UserTypeAgent,
ShopID: &shopID,
Status: constants.StatusEnabled,
}
require.NoError(t, accountStore.Create(ctx, account))
shopRole := &model.Role{
RoleName: "店铺默认角色",
RoleType: constants.RoleTypeCustomer,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(ctx, shopRole))
require.NoError(t, shopRoleStore.Create(ctx, &model.ShopRole{
ShopID: shopID,
RoleID: shopRole.ID,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}))
roleIDs, err := service.GetRoleIDsForAccount(ctx, account.ID)
require.NoError(t, err)
assert.Equal(t, []uint{shopRole.ID}, roleIDs)
})
t.Run("代理账号无角色且店铺无角色,返回空数组", func(t *testing.T) {
shopID := uint(3)
account := &model.Account{
Username: "agent_notest",
Phone: "13800010005",
Password: "hashed",
UserType: constants.UserTypeAgent,
ShopID: &shopID,
Status: constants.StatusEnabled,
}
require.NoError(t, accountStore.Create(ctx, account))
roleIDs, err := service.GetRoleIDsForAccount(ctx, account.ID)
require.NoError(t, err)
assert.Empty(t, roleIDs)
})
t.Run("企业账号返回账号级角色", func(t *testing.T) {
enterpriseID := uint(1)
account := &model.Account{
Username: "enterprise_roletest",
Phone: "13800010006",
Password: "hashed",
UserType: constants.UserTypeEnterprise,
EnterpriseID: &enterpriseID,
Status: constants.StatusEnabled,
}
require.NoError(t, accountStore.Create(ctx, account))
role := &model.Role{
RoleName: "企业管理员",
RoleType: constants.RoleTypeCustomer,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(ctx, role))
accountRole := &model.AccountRole{
AccountID: account.ID,
RoleID: role.ID,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}
require.NoError(t, accountRoleStore.Create(ctx, accountRole))
roleIDs, err := service.GetRoleIDsForAccount(ctx, account.ID)
require.NoError(t, err)
assert.Equal(t, []uint{role.ID}, roleIDs)
})
}

View File

@@ -22,6 +22,7 @@ type Service struct {
accountStore *postgres.AccountStore
roleStore *postgres.RoleStore
accountRoleStore *postgres.AccountRoleStore
shopRoleStore *postgres.ShopRoleStore
shopStore middleware.ShopStoreInterface
enterpriseStore middleware.EnterpriseStoreInterface
auditService AuditServiceInterface
@@ -36,6 +37,7 @@ func New(
accountStore *postgres.AccountStore,
roleStore *postgres.RoleStore,
accountRoleStore *postgres.AccountRoleStore,
shopRoleStore *postgres.ShopRoleStore,
shopStore middleware.ShopStoreInterface,
enterpriseStore middleware.EnterpriseStoreInterface,
auditService AuditServiceInterface,
@@ -44,6 +46,7 @@ func New(
accountStore: accountStore,
roleStore: roleStore,
accountRoleStore: accountRoleStore,
shopRoleStore: shopRoleStore,
shopStore: shopStore,
enterpriseStore: enterpriseStore,
auditService: auditService,

View File

@@ -69,7 +69,7 @@ func TestAccountService_Create_SuperAdminSuccess(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -111,7 +111,7 @@ func TestAccountService_Create_PlatformUserCreatePlatformAccount(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -150,7 +150,7 @@ func TestAccountService_Create_PlatformUserCreateAgentAccount(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -192,7 +192,7 @@ func TestAccountService_Create_AgentCreateSubordinateShopAccount(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
agentShopID := uint(10)
subordinateShopID := uint(11)
@@ -238,7 +238,7 @@ func TestAccountService_Create_AgentCreateOtherShopAccountForbidden(t *testing.T
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
agentShopID := uint(10)
otherShopID := uint(99)
@@ -281,7 +281,7 @@ func TestAccountService_Create_AgentCreatePlatformAccountForbidden(t *testing.T)
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -318,7 +318,7 @@ func TestAccountService_Create_EnterpriseUserForbidden(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -355,7 +355,7 @@ func TestAccountService_Create_UsernameDuplicate(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -404,7 +404,7 @@ func TestAccountService_Create_PhoneDuplicate(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -453,7 +453,7 @@ func TestAccountService_Create_Unauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -488,7 +488,7 @@ func TestAccountService_Update_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -534,7 +534,7 @@ func TestAccountService_Update_NotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -565,7 +565,7 @@ func TestAccountService_Update_AgentUnauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -619,7 +619,7 @@ func TestAccountService_Update_UsernameDuplicate(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -676,7 +676,7 @@ func TestAccountService_Update_PhoneDuplicate(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -735,7 +735,7 @@ func TestAccountService_Delete_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -778,7 +778,7 @@ func TestAccountService_Delete_NotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -804,7 +804,7 @@ func TestAccountService_Delete_AgentUnauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -855,7 +855,7 @@ func TestAccountService_AssignRoles_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -906,7 +906,7 @@ func TestAccountService_AssignRoles_SuperAdminForbidden(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -947,7 +947,7 @@ func TestAccountService_AssignRoles_RoleTypeMismatch(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -997,7 +997,7 @@ func TestAccountService_AssignRoles_EmptyArrayClearsRoles(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1049,7 +1049,7 @@ func TestAccountService_RemoveRole_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1104,7 +1104,7 @@ func TestAccountService_RemoveRole_AccountNotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1132,7 +1132,7 @@ func TestAccountService_GetRoles_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1183,7 +1183,7 @@ func TestAccountService_GetRoles_EmptyArray(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1224,7 +1224,7 @@ func TestAccountService_List_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1269,7 +1269,7 @@ func TestAccountService_List_FilterByUsername(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1318,7 +1318,7 @@ func TestAccountService_ValidatePassword_Correct(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1357,7 +1357,7 @@ func TestAccountService_ValidatePassword_Incorrect(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1398,7 +1398,7 @@ func TestAccountService_UpdatePassword_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1449,7 +1449,7 @@ func TestAccountService_UpdateStatus_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1494,7 +1494,7 @@ func TestAccountService_Get_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1534,7 +1534,7 @@ func TestAccountService_Get_NotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1560,7 +1560,7 @@ func TestAccountService_UpdatePassword_AccountNotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1586,7 +1586,7 @@ func TestAccountService_UpdateStatus_AccountNotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1612,7 +1612,7 @@ func TestAccountService_UpdatePassword_Unauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -1635,7 +1635,7 @@ func TestAccountService_UpdateStatus_Unauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -1658,7 +1658,7 @@ func TestAccountService_Delete_Unauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -1681,7 +1681,7 @@ func TestAccountService_AssignRoles_Unauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -1704,7 +1704,7 @@ func TestAccountService_RemoveRole_Unauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -1727,7 +1727,7 @@ func TestAccountService_Update_Unauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -1755,7 +1755,7 @@ func TestAccountService_AssignRoles_NotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1781,7 +1781,7 @@ func TestAccountService_GetRoles_NotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1807,7 +1807,7 @@ func TestAccountService_List_FilterByUserType(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1854,7 +1854,7 @@ func TestAccountService_List_FilterByStatus(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1901,7 +1901,7 @@ func TestAccountService_List_FilterByPhone(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1947,7 +1947,7 @@ func TestAccountService_Update_UpdatePassword(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -1993,7 +1993,7 @@ func TestAccountService_Update_UpdateStatus(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2037,7 +2037,7 @@ func TestAccountService_Update_UpdatePhone(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2081,7 +2081,7 @@ func TestAccountService_AssignRoles_AgentUnauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2130,7 +2130,7 @@ func TestAccountService_Create_EnterpriseAccountSuccess(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2173,7 +2173,7 @@ func TestAccountService_Create_AgentMissingShopID(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2209,7 +2209,7 @@ func TestAccountService_Create_EnterpriseMissingEnterpriseID(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2245,7 +2245,7 @@ func TestAccountService_RemoveRole_AgentUnauthorized(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2294,7 +2294,7 @@ func TestAccountService_AssignRoles_MultipleRoles(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2353,7 +2353,7 @@ func TestAccountService_Update_AllFields(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2409,7 +2409,7 @@ func TestAccountService_ListPlatformAccounts_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2454,7 +2454,7 @@ func TestAccountService_CreateSystemAccount_Success(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -2486,7 +2486,7 @@ func TestAccountService_CreateSystemAccount_MissingUsername(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -2517,7 +2517,7 @@ func TestAccountService_CreateSystemAccount_MissingPhone(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -2548,7 +2548,7 @@ func TestAccountService_CreateSystemAccount_MissingPassword(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -2579,7 +2579,7 @@ func TestAccountService_CreateSystemAccount_UsernameDuplicate(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -2625,7 +2625,7 @@ func TestAccountService_CreateSystemAccount_PhoneDuplicate(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := context.Background()
@@ -2671,7 +2671,7 @@ func TestAccountService_ListPlatformAccounts_FilterByUsername(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2717,7 +2717,7 @@ func TestAccountService_ListPlatformAccounts_FilterByPhone(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2763,7 +2763,7 @@ func TestAccountService_ListPlatformAccounts_FilterByStatus(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2810,7 +2810,7 @@ func TestAccountService_Create_PlatformUserCreateEnterpriseAccount(t *testing.T)
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2852,7 +2852,7 @@ func TestAccountService_List_DefaultPagination(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2882,7 +2882,7 @@ func TestAccountService_ListPlatformAccounts_DefaultPagination(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2912,7 +2912,7 @@ func TestAccountService_AssignRoles_RoleNotFound(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2953,7 +2953,7 @@ func TestAccountService_Update_SameUsername(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -2996,7 +2996,7 @@ func TestAccountService_Update_SamePhone(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3039,7 +3039,7 @@ func TestAccountService_AssignRoles_DuplicateRoles(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3086,7 +3086,7 @@ func TestAccountService_Create_PlatformUserCreateAgentWithShop(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3129,7 +3129,7 @@ func TestAccountService_AssignRoles_CustomerAccountType(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3179,7 +3179,7 @@ func TestAccountService_Delete_AgentAccountWithShop(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3231,7 +3231,7 @@ func TestAccountService_Update_AgentAccountWithShop(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3286,7 +3286,7 @@ func TestAccountService_AssignRoles_AgentAccountWithShop(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3344,7 +3344,7 @@ func TestAccountService_RemoveRole_AgentAccountWithShop(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3408,7 +3408,7 @@ func TestAccountService_Create_EnterpriseAccountWithShop(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3454,7 +3454,7 @@ func TestAccountService_Delete_PlatformAccountByAgent(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3501,7 +3501,7 @@ func TestAccountService_Update_PlatformAccountByAgent(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3553,7 +3553,7 @@ func TestAccountService_AssignRoles_PlatformAccountByAgent(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
@@ -3600,7 +3600,7 @@ func TestAccountService_RemoveRole_PlatformAccountByAgent(t *testing.T) {
mockShop := new(MockShopStore)
mockEnterprise := new(MockEnterpriseStore)
svc := New(accountStore, roleStore, accountRoleStore, mockShop, mockEnterprise, mockAudit)
svc := New(accountStore, roleStore, accountRoleStore, nil, mockShop, mockEnterprise, mockAudit)
superAdminCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,

View File

@@ -22,11 +22,16 @@ import (
// permCodeRegex 权限编码格式验证正则module:action
var permCodeRegex = regexp.MustCompile(`^[a-z][a-z0-9_]*:[a-z][a-z0-9_]*$`)
type AccountServiceInterface interface {
GetRoleIDsForAccount(ctx context.Context, accountID uint) ([]uint, error)
}
// Service 权限业务服务
type Service struct {
permissionStore *postgres.PermissionStore
accountRoleStore *postgres.AccountRoleStore
rolePermStore *postgres.RolePermissionStore
accountService AccountServiceInterface
redisClient *redis.Client
}
@@ -35,12 +40,14 @@ func New(
permissionStore *postgres.PermissionStore,
accountRoleStore *postgres.AccountRoleStore,
rolePermStore *postgres.RolePermissionStore,
accountService AccountServiceInterface,
redisClient *redis.Client,
) *Service {
return &Service{
permissionStore: permissionStore,
accountRoleStore: accountRoleStore,
rolePermStore: rolePermStore,
accountService: accountService,
redisClient: redisClient,
}
}
@@ -298,7 +305,7 @@ func (s *Service) CheckPermission(ctx context.Context, userID uint, permCode str
}
}
roleIDs, err := s.accountRoleStore.GetRoleIDsByAccountID(ctx, userID)
roleIDs, err := s.accountService.GetRoleIDsForAccount(ctx, userID)
if err != nil {
return false, errors.Wrap(errors.CodeInternalError, err, "查询用户角色失败")
}

View File

@@ -15,14 +15,23 @@ import (
)
type Service struct {
shopStore *postgres.ShopStore
accountStore *postgres.AccountStore
shopStore *postgres.ShopStore
accountStore *postgres.AccountStore
shopRoleStore *postgres.ShopRoleStore
roleStore *postgres.RoleStore
}
func New(shopStore *postgres.ShopStore, accountStore *postgres.AccountStore) *Service {
func New(
shopStore *postgres.ShopStore,
accountStore *postgres.AccountStore,
shopRoleStore *postgres.ShopRoleStore,
roleStore *postgres.RoleStore,
) *Service {
return &Service{
shopStore: shopStore,
accountStore: accountStore,
shopStore: shopStore,
accountStore: accountStore,
shopRoleStore: shopRoleStore,
roleStore: roleStore,
}
}

View File

@@ -0,0 +1,145 @@
package shop
import (
"context"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
)
func (s *Service) AssignRolesToShop(ctx context.Context, shopID uint, roleIDs []uint) ([]*model.ShopRole, error) {
if err := middleware.CanManageShop(ctx, shopID, s.shopStore); err != nil {
return nil, err
}
shop, err := s.shopStore.GetByID(ctx, shopID)
if err != nil {
return nil, errors.New(errors.CodeNotFound, "店铺不存在")
}
currentUserID := middleware.GetUserIDFromContext(ctx)
if len(roleIDs) == 0 {
if err := s.shopRoleStore.DeleteByShopID(ctx, shopID); err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "清空店铺角色失败")
}
return []*model.ShopRole{}, nil
}
roles, err := s.roleStore.GetByIDs(ctx, roleIDs)
if err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "查询角色失败")
}
if len(roles) != len(roleIDs) {
return nil, errors.New(errors.CodeNotFound, "部分角色不存在")
}
for _, role := range roles {
if role.RoleType != constants.RoleTypeCustomer {
return nil, errors.New(errors.CodeInvalidParam, "店铺只能分配客户角色")
}
if role.Status != constants.StatusEnabled {
return nil, errors.New(errors.CodeInvalidParam, "角色已禁用")
}
}
if err := s.shopRoleStore.DeleteByShopID(ctx, shopID); err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "删除现有店铺角色失败")
}
shopRoles := make([]*model.ShopRole, 0, len(roleIDs))
for _, roleID := range roleIDs {
shopRole := &model.ShopRole{
ShopID: shop.ID,
RoleID: roleID,
Status: constants.StatusEnabled,
Creator: currentUserID,
Updater: currentUserID,
}
shopRoles = append(shopRoles, shopRole)
}
if err := s.shopRoleStore.BatchCreate(ctx, shopRoles); err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "批量创建店铺角色失败")
}
return shopRoles, nil
}
func (s *Service) GetShopRoles(ctx context.Context, shopID uint) (*dto.ShopRolesResponse, error) {
if err := middleware.CanManageShop(ctx, shopID, s.shopStore); err != nil {
return nil, err
}
_, err := s.shopStore.GetByID(ctx, shopID)
if err != nil {
return nil, errors.New(errors.CodeNotFound, "店铺不存在")
}
shopRoles, err := s.shopRoleStore.GetByShopID(ctx, shopID)
if err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "查询店铺角色失败")
}
if len(shopRoles) == 0 {
return &dto.ShopRolesResponse{
ShopID: shopID,
Roles: []*dto.ShopRoleResponse{},
}, nil
}
roleIDs := make([]uint, 0, len(shopRoles))
for _, sr := range shopRoles {
roleIDs = append(roleIDs, sr.RoleID)
}
roles, err := s.roleStore.GetByIDs(ctx, roleIDs)
if err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "查询角色详情失败")
}
roleMap := make(map[uint]*model.Role)
for _, role := range roles {
roleMap[role.ID] = role
}
responses := make([]*dto.ShopRoleResponse, 0, len(shopRoles))
for _, sr := range shopRoles {
role, exists := roleMap[sr.RoleID]
if !exists {
continue
}
responses = append(responses, &dto.ShopRoleResponse{
ShopID: sr.ShopID,
RoleID: sr.RoleID,
RoleName: role.RoleName,
RoleDesc: role.RoleDesc,
Status: sr.Status,
})
}
return &dto.ShopRolesResponse{
ShopID: shopID,
Roles: responses,
}, nil
}
func (s *Service) DeleteShopRole(ctx context.Context, shopID, roleID uint) error {
if err := middleware.CanManageShop(ctx, shopID, s.shopStore); err != nil {
return err
}
_, err := s.shopStore.GetByID(ctx, shopID)
if err != nil {
return errors.New(errors.CodeNotFound, "店铺不存在")
}
if err := s.shopRoleStore.Delete(ctx, shopID, roleID); err != nil {
return errors.Wrap(errors.CodeInternalError, err, "删除店铺角色失败")
}
return nil
}

View File

@@ -0,0 +1,243 @@
package shop
import (
"context"
"testing"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
"github.com/break/junhong_cmp_fiber/tests/testutils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAssignRolesToShop(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
shopStore := postgres.NewShopStore(tx, rdb)
accountStore := postgres.NewAccountStore(tx, rdb)
shopRoleStore := postgres.NewShopRoleStore(tx, rdb)
roleStore := postgres.NewRoleStore(tx)
service := New(shopStore, accountStore, shopRoleStore, roleStore)
shop := &model.Shop{
ShopName: "测试店铺",
ShopCode: "TEST_SHOP_001",
Level: 1,
Status: constants.StatusEnabled,
}
require.NoError(t, tx.Create(shop).Error)
role := &model.Role{
RoleName: "代理店长",
RoleType: constants.RoleTypeCustomer,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(context.Background(), role))
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
UserType: constants.UserTypeSuperAdmin,
})
t.Run("成功分配单个角色", func(t *testing.T) {
result, err := service.AssignRolesToShop(ctx, shop.ID, []uint{role.ID})
require.NoError(t, err)
assert.Len(t, result, 1)
assert.Equal(t, shop.ID, result[0].ShopID)
assert.Equal(t, role.ID, result[0].RoleID)
})
t.Run("清空所有角色", func(t *testing.T) {
result, err := service.AssignRolesToShop(ctx, shop.ID, []uint{})
require.NoError(t, err)
assert.Empty(t, result)
roles, err := service.GetShopRoles(ctx, shop.ID)
require.NoError(t, err)
assert.Empty(t, roles.Roles)
})
t.Run("替换现有角色", func(t *testing.T) {
require.NoError(t, shopRoleStore.Create(ctx, &model.ShopRole{
ShopID: shop.ID,
RoleID: role.ID,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}))
newRole := &model.Role{
RoleName: "代理经理",
RoleType: constants.RoleTypeCustomer,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(ctx, newRole))
result, err := service.AssignRolesToShop(ctx, shop.ID, []uint{newRole.ID})
require.NoError(t, err)
assert.Len(t, result, 1)
assert.Equal(t, newRole.ID, result[0].RoleID)
})
t.Run("角色类型校验失败", func(t *testing.T) {
platformRole := &model.Role{
RoleName: "平台角色",
RoleType: constants.RoleTypePlatform,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(ctx, platformRole))
_, err := service.AssignRolesToShop(ctx, shop.ID, []uint{platformRole.ID})
require.Error(t, err)
assert.Contains(t, err.Error(), "店铺只能分配客户角色")
})
t.Run("角色不存在", func(t *testing.T) {
_, err := service.AssignRolesToShop(ctx, shop.ID, []uint{99999})
require.Error(t, err)
assert.Contains(t, err.Error(), "部分角色不存在")
})
t.Run("店铺不存在", func(t *testing.T) {
_, err := service.AssignRolesToShop(ctx, 99999, []uint{role.ID})
require.Error(t, err)
assert.Contains(t, err.Error(), "店铺不存在")
})
}
func TestGetShopRoles(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
shopStore := postgres.NewShopStore(tx, rdb)
accountStore := postgres.NewAccountStore(tx, rdb)
shopRoleStore := postgres.NewShopRoleStore(tx, rdb)
roleStore := postgres.NewRoleStore(tx)
service := New(shopStore, accountStore, shopRoleStore, roleStore)
shop := &model.Shop{
ShopName: "测试店铺2",
ShopCode: "TEST_SHOP_002",
Level: 1,
Status: constants.StatusEnabled,
}
require.NoError(t, tx.Create(shop).Error)
role := &model.Role{
RoleName: "代理店长",
RoleType: constants.RoleTypeCustomer,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(context.Background(), role))
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
UserType: constants.UserTypeSuperAdmin,
})
t.Run("查询已分配角色", func(t *testing.T) {
require.NoError(t, shopRoleStore.Create(ctx, &model.ShopRole{
ShopID: shop.ID,
RoleID: role.ID,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}))
result, err := service.GetShopRoles(ctx, shop.ID)
require.NoError(t, err)
assert.Len(t, result.Roles, 1)
assert.Equal(t, shop.ID, result.ShopID)
assert.Equal(t, role.ID, result.Roles[0].RoleID)
assert.Equal(t, "代理店长", result.Roles[0].RoleName)
})
t.Run("查询未分配角色的店铺", func(t *testing.T) {
emptyShop := &model.Shop{
ShopName: "空店铺",
ShopCode: "EMPTY_SHOP",
Level: 1,
Status: constants.StatusEnabled,
}
require.NoError(t, tx.Create(emptyShop).Error)
result, err := service.GetShopRoles(ctx, emptyShop.ID)
require.NoError(t, err)
assert.Empty(t, result.Roles)
})
t.Run("店铺不存在", func(t *testing.T) {
_, err := service.GetShopRoles(ctx, 99999)
require.Error(t, err)
assert.Contains(t, err.Error(), "店铺不存在")
})
}
func TestDeleteShopRole(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
shopStore := postgres.NewShopStore(tx, rdb)
accountStore := postgres.NewAccountStore(tx, rdb)
shopRoleStore := postgres.NewShopRoleStore(tx, rdb)
roleStore := postgres.NewRoleStore(tx)
service := New(shopStore, accountStore, shopRoleStore, roleStore)
shop := &model.Shop{
ShopName: "测试店铺3",
ShopCode: "TEST_SHOP_003",
Level: 1,
Status: constants.StatusEnabled,
}
require.NoError(t, tx.Create(shop).Error)
role := &model.Role{
RoleName: "代理店长",
RoleType: constants.RoleTypeCustomer,
Status: constants.StatusEnabled,
}
require.NoError(t, roleStore.Create(context.Background(), role))
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
UserID: 1,
UserType: constants.UserTypeSuperAdmin,
})
t.Run("成功删除角色", func(t *testing.T) {
require.NoError(t, shopRoleStore.Create(ctx, &model.ShopRole{
ShopID: shop.ID,
RoleID: role.ID,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}))
err := service.DeleteShopRole(ctx, shop.ID, role.ID)
require.NoError(t, err)
result, err := service.GetShopRoles(ctx, shop.ID)
require.NoError(t, err)
assert.Empty(t, result.Roles)
})
t.Run("删除不存在的角色关联(幂等)", func(t *testing.T) {
err := service.DeleteShopRole(ctx, shop.ID, role.ID)
require.NoError(t, err)
})
t.Run("店铺不存在", func(t *testing.T) {
err := service.DeleteShopRole(ctx, 99999, role.ID)
require.Error(t, err)
assert.Contains(t, err.Error(), "店铺不存在")
})
}

View File

@@ -0,0 +1,101 @@
package postgres
import (
"context"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
type ShopRoleStore struct {
db *gorm.DB
redisClient *redis.Client
}
func NewShopRoleStore(db *gorm.DB, redisClient *redis.Client) *ShopRoleStore {
return &ShopRoleStore{
db: db,
redisClient: redisClient,
}
}
func (s *ShopRoleStore) Create(ctx context.Context, sr *model.ShopRole) error {
if err := s.db.WithContext(ctx).Create(sr).Error; err != nil {
return err
}
s.clearShopRoleCache(ctx, sr.ShopID)
return nil
}
func (s *ShopRoleStore) BatchCreate(ctx context.Context, srs []*model.ShopRole) error {
if len(srs) == 0 {
return nil
}
if err := s.db.WithContext(ctx).Create(&srs).Error; err != nil {
return err
}
s.clearShopRoleCache(ctx, srs[0].ShopID)
return nil
}
func (s *ShopRoleStore) Delete(ctx context.Context, shopID, roleID uint) error {
if err := s.db.WithContext(ctx).
Where("shop_id = ? AND role_id = ?", shopID, roleID).
Delete(&model.ShopRole{}).Error; err != nil {
return err
}
s.clearShopRoleCache(ctx, shopID)
return nil
}
func (s *ShopRoleStore) DeleteByShopID(ctx context.Context, shopID uint) error {
if err := s.db.WithContext(ctx).
Where("shop_id = ?", shopID).
Delete(&model.ShopRole{}).Error; err != nil {
return err
}
s.clearShopRoleCache(ctx, shopID)
return nil
}
func (s *ShopRoleStore) GetByShopID(ctx context.Context, shopID uint) ([]*model.ShopRole, error) {
var srs []*model.ShopRole
if err := s.db.WithContext(ctx).
Where("shop_id = ?", shopID).
Find(&srs).Error; err != nil {
return nil, err
}
return srs, nil
}
func (s *ShopRoleStore) GetRoleIDsByShopID(ctx context.Context, shopID uint) ([]uint, error) {
var roleIDs []uint
if err := s.db.WithContext(ctx).
Model(&model.ShopRole{}).
Where("shop_id = ?", shopID).
Pluck("role_id", &roleIDs).Error; err != nil {
return nil, err
}
return roleIDs, nil
}
func (s *ShopRoleStore) clearShopRoleCache(ctx context.Context, shopID uint) {
if s.redisClient == nil {
return
}
var accountIDs []uint
if err := s.db.WithContext(ctx).
Model(&model.Account{}).
Where("shop_id = ?", shopID).
Pluck("id", &accountIDs).Error; err != nil {
return
}
for _, accountID := range accountIDs {
key := constants.RedisUserPermissionsKey(accountID)
s.redisClient.Del(ctx, key)
}
}

View File

@@ -0,0 +1,171 @@
package postgres
import (
"context"
"testing"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/tests/testutils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestShopRoleStore_Create(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
store := NewShopRoleStore(tx, rdb)
ctx := context.Background()
sr := &model.ShopRole{
ShopID: 1,
RoleID: 5,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}
err := store.Create(ctx, sr)
require.NoError(t, err)
assert.NotZero(t, sr.ID)
}
func TestShopRoleStore_BatchCreate(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
store := NewShopRoleStore(tx, rdb)
ctx := context.Background()
srs := []*model.ShopRole{
{
ShopID: 1,
RoleID: 5,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
},
}
err := store.BatchCreate(ctx, srs)
require.NoError(t, err)
assert.NotZero(t, srs[0].ID)
}
func TestShopRoleStore_Delete(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
store := NewShopRoleStore(tx, rdb)
ctx := context.Background()
sr := &model.ShopRole{
ShopID: 1,
RoleID: 5,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}
require.NoError(t, store.Create(ctx, sr))
err := store.Delete(ctx, 1, 5)
require.NoError(t, err)
results, err := store.GetByShopID(ctx, 1)
require.NoError(t, err)
assert.Empty(t, results)
}
func TestShopRoleStore_DeleteByShopID(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
store := NewShopRoleStore(tx, rdb)
ctx := context.Background()
srs := []*model.ShopRole{
{
ShopID: 1,
RoleID: 5,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
},
{
ShopID: 1,
RoleID: 6,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
},
}
require.NoError(t, store.BatchCreate(ctx, srs))
err := store.DeleteByShopID(ctx, 1)
require.NoError(t, err)
results, err := store.GetByShopID(ctx, 1)
require.NoError(t, err)
assert.Empty(t, results)
}
func TestShopRoleStore_GetByShopID(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
store := NewShopRoleStore(tx, rdb)
ctx := context.Background()
t.Run("查询已分配角色", func(t *testing.T) {
sr := &model.ShopRole{
ShopID: 1,
RoleID: 5,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}
require.NoError(t, store.Create(ctx, sr))
results, err := store.GetByShopID(ctx, 1)
require.NoError(t, err)
assert.Len(t, results, 1)
assert.Equal(t, uint(1), results[0].ShopID)
assert.Equal(t, uint(5), results[0].RoleID)
})
t.Run("查询未分配角色的店铺", func(t *testing.T) {
results, err := store.GetByShopID(ctx, 999)
require.NoError(t, err)
assert.Empty(t, results)
})
}
func TestShopRoleStore_GetRoleIDsByShopID(t *testing.T) {
tx := testutils.NewTestTransaction(t)
rdb := testutils.GetTestRedis(t)
testutils.CleanTestRedisKeys(t, rdb)
store := NewShopRoleStore(tx, rdb)
ctx := context.Background()
t.Run("查询已分配角色的店铺", func(t *testing.T) {
sr := &model.ShopRole{
ShopID: 1,
RoleID: 5,
Status: constants.StatusEnabled,
Creator: 1,
Updater: 1,
}
require.NoError(t, store.Create(ctx, sr))
roleIDs, err := store.GetRoleIDsByShopID(ctx, 1)
require.NoError(t, err)
assert.Equal(t, []uint{5}, roleIDs)
})
t.Run("查询未分配角色的店铺", func(t *testing.T) {
roleIDs, err := store.GetRoleIDsByShopID(ctx, 999)
require.NoError(t, err)
assert.Empty(t, roleIDs)
})
}