实现多商户履约平台基础
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"affiliate_dash/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// TenantService 负责商户成员关系与请求租户解析。
|
||||
type TenantService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewTenantService(db *gorm.DB) *TenantService {
|
||||
return &TenantService{db: db}
|
||||
}
|
||||
|
||||
func (s *TenantService) ResolveMember(userID uint, merchantRef string) (*model.MerchantMember, error) {
|
||||
if userID == 0 {
|
||||
return nil, errors.New("无效的用户身份")
|
||||
}
|
||||
tx := s.db.Preload("Merchant").
|
||||
Where("merchant_members.user_id = ? AND merchant_members.status = ?", userID, 1).
|
||||
Joins("JOIN merchants ON merchants.id = merchant_members.merchant_id AND merchants.status = ?", model.MerchantStatusActive)
|
||||
if merchantRef != "" {
|
||||
if id, err := strconv.ParseUint(merchantRef, 10, 64); err == nil {
|
||||
tx = tx.Where("merchant_members.merchant_id = ?", uint(id))
|
||||
} else {
|
||||
tx = tx.Where("merchants.code = ?", merchantRef)
|
||||
}
|
||||
}
|
||||
var member model.MerchantMember
|
||||
err := tx.Order("merchant_members.is_default DESC, merchant_members.id ASC").First(&member).Error
|
||||
if err == nil {
|
||||
return &member, nil
|
||||
}
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.New("当前账号无权访问该商户")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *TenantService) EnsureSelfMember(userID uint, role string, status int) error {
|
||||
var merchant model.Merchant
|
||||
if err := s.db.Where("code = ?", "self-operated").First(&merchant).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return s.EnsureMember(merchant.ID, userID, role, status, role == model.MemberRoleOwner)
|
||||
}
|
||||
|
||||
func (s *TenantService) EnsureMember(merchantID, userID uint, role string, status int, isDefault bool) error {
|
||||
if merchantID == 0 || userID == 0 {
|
||||
return errors.New("商户和用户不能为空")
|
||||
}
|
||||
if !isValidMemberRole(role) {
|
||||
return errors.New("无效的商户成员角色")
|
||||
}
|
||||
member := model.MerchantMember{
|
||||
MerchantID: merchantID,
|
||||
UserID: userID,
|
||||
Role: role,
|
||||
Status: status,
|
||||
IsDefault: isDefault,
|
||||
}
|
||||
return s.db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "merchant_id"}, {Name: "user_id"}},
|
||||
DoUpdates: clause.Assignments(map[string]interface{}{
|
||||
"role": role,
|
||||
"status": status,
|
||||
"is_default": isDefault,
|
||||
}),
|
||||
}).Create(&member).Error
|
||||
}
|
||||
|
||||
func isValidMemberRole(role string) bool {
|
||||
switch role {
|
||||
case model.MemberRoleOwner, model.MemberRoleOperator, model.MemberRoleFinance, model.MemberRoleViewer:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func MemberCanManage(memberRole string) bool {
|
||||
return memberRole == model.MemberRoleOwner || memberRole == model.MemberRoleOperator
|
||||
}
|
||||
|
||||
func MemberCanManageFinance(memberRole string) bool {
|
||||
return memberRole == model.MemberRoleOwner || memberRole == model.MemberRoleFinance
|
||||
}
|
||||
|
||||
func ParseScopes(scopes string) map[string]struct{} {
|
||||
out := make(map[string]struct{})
|
||||
for _, scope := range strings.FieldsFunc(scopes, func(r rune) bool {
|
||||
return r == ',' || r == ' ' || r == '\n' || r == '\t'
|
||||
}) {
|
||||
if scope != "" {
|
||||
out[scope] = struct{}{}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func HasAnyScope(scopes string, wanted ...string) bool {
|
||||
set := ParseScopes(scopes)
|
||||
if _, ok := set["*"]; ok {
|
||||
return true
|
||||
}
|
||||
for _, scope := range wanted {
|
||||
if _, ok := set[scope]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user