修复企业授权报错的问题
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m57s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m57s
This commit is contained in:
@@ -2,6 +2,7 @@ package enterprise_device
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
stderrors "errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||||
@@ -10,6 +11,7 @@ import (
|
|||||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||||||
|
"github.com/jackc/pgx/v5/pgconn"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@@ -74,8 +76,8 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
|
|||||||
currentShopID := middleware.GetShopIDFromContext(ctx)
|
currentShopID := middleware.GetShopIDFromContext(ctx)
|
||||||
userType := middleware.GetUserTypeFromContext(ctx)
|
userType := middleware.GetUserTypeFromContext(ctx)
|
||||||
|
|
||||||
// 检查已授权的设备
|
// 检查设备是否已存在有效授权(不区分企业)
|
||||||
existingAuths, err := s.enterpriseDeviceAuthStore.GetActiveAuthsByDeviceIDs(ctx, enterpriseID, deviceIDs)
|
activeAuthEnterpriseMap, err := s.enterpriseDeviceAuthStore.GetActiveAuthEnterpriseByDeviceIDs(ctx, deviceIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询已有授权失败")
|
return nil, errors.Wrap(errors.CodeInternalError, err, "查询已有授权失败")
|
||||||
}
|
}
|
||||||
@@ -86,7 +88,17 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
|
|||||||
}
|
}
|
||||||
|
|
||||||
devicesToAllocate := make([]*model.Device, 0)
|
devicesToAllocate := make([]*model.Device, 0)
|
||||||
|
seenDeviceNos := make(map[string]struct{}, len(req.DeviceNos))
|
||||||
for _, deviceNo := range req.DeviceNos {
|
for _, deviceNo := range req.DeviceNos {
|
||||||
|
if _, exists := seenDeviceNos[deviceNo]; exists {
|
||||||
|
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
|
||||||
|
VirtualNo: deviceNo,
|
||||||
|
Reason: "请求中设备号重复",
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seenDeviceNos[deviceNo] = struct{}{}
|
||||||
|
|
||||||
device, exists := deviceMap[deviceNo]
|
device, exists := deviceMap[deviceNo]
|
||||||
if !exists {
|
if !exists {
|
||||||
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
|
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
|
||||||
@@ -116,11 +128,15 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否已授权
|
// 检查是否已授权(同企业 / 其他企业)
|
||||||
if existingAuths[device.ID] {
|
if authEnterpriseID, exists := activeAuthEnterpriseMap[device.ID]; exists {
|
||||||
|
reason := "设备已授权给其他企业"
|
||||||
|
if authEnterpriseID == enterpriseID {
|
||||||
|
reason = "设备已授权给此企业"
|
||||||
|
}
|
||||||
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
|
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
|
||||||
VirtualNo: deviceNo,
|
VirtualNo: deviceNo,
|
||||||
Reason: "设备已授权给此企业",
|
Reason: reason,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -134,38 +150,58 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
authorizerType := userType
|
authorizerType := userType
|
||||||
|
|
||||||
// 1. 创建设备授权记录
|
// 1. 创建设备授权记录(逐条处理,避免并发冲突导致整批失败)
|
||||||
deviceAuths := make([]*model.EnterpriseDeviceAuthorization, 0, len(devicesToAllocate))
|
deviceAuthIDMap := make(map[uint]uint, len(devicesToAllocate))
|
||||||
|
successDevices := make([]*model.Device, 0, len(devicesToAllocate))
|
||||||
for _, device := range devicesToAllocate {
|
for _, device := range devicesToAllocate {
|
||||||
deviceAuths = append(deviceAuths, &model.EnterpriseDeviceAuthorization{
|
deviceAuth := &model.EnterpriseDeviceAuthorization{
|
||||||
EnterpriseID: enterpriseID,
|
EnterpriseID: enterpriseID,
|
||||||
DeviceID: device.ID,
|
DeviceID: device.ID,
|
||||||
AuthorizedBy: currentUserID,
|
AuthorizedBy: currentUserID,
|
||||||
AuthorizedAt: now,
|
AuthorizedAt: now,
|
||||||
AuthorizerType: authorizerType,
|
AuthorizerType: authorizerType,
|
||||||
Remark: req.Remark,
|
Remark: req.Remark,
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err := tx.Create(deviceAuths).Error; err != nil {
|
if err := tx.Create(deviceAuth).Error; err != nil {
|
||||||
return errors.Wrap(errors.CodeInternalError, err, "创建设备授权记录失败")
|
if isUniqueConstraintViolation(err, "uq_active_device_auth") {
|
||||||
}
|
reason := "设备已授权给其他企业"
|
||||||
|
|
||||||
// 构建设备ID到授权ID的映射
|
var existingAuth model.EnterpriseDeviceAuthorization
|
||||||
deviceAuthIDMap := make(map[uint]uint)
|
queryErr := tx.Select("enterprise_id").
|
||||||
for _, auth := range deviceAuths {
|
Where("device_id = ? AND revoked_at IS NULL", device.ID).
|
||||||
deviceAuthIDMap[auth.DeviceID] = auth.ID
|
First(&existingAuth).Error
|
||||||
|
if queryErr == nil && existingAuth.EnterpriseID == enterpriseID {
|
||||||
|
reason = "设备已授权给此企业"
|
||||||
|
}
|
||||||
|
if queryErr != nil && !stderrors.Is(queryErr, gorm.ErrRecordNotFound) {
|
||||||
|
return errors.Wrap(errors.CodeInternalError, queryErr, "查询冲突授权记录失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
|
||||||
|
VirtualNo: device.VirtualNo,
|
||||||
|
Reason: reason,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.Wrap(errors.CodeInternalError, err, "创建设备授权记录失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceAuthIDMap[device.ID] = deviceAuth.ID
|
||||||
|
successDevices = append(successDevices, device)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 查询所有设备绑定的卡
|
// 2. 查询所有设备绑定的卡
|
||||||
deviceIDsToQuery := make([]uint, 0, len(devicesToAllocate))
|
deviceIDsToQuery := make([]uint, 0, len(successDevices))
|
||||||
for _, device := range devicesToAllocate {
|
for _, device := range successDevices {
|
||||||
deviceIDsToQuery = append(deviceIDsToQuery, device.ID)
|
deviceIDsToQuery = append(deviceIDsToQuery, device.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
var bindings []model.DeviceSimBinding
|
var bindings []model.DeviceSimBinding
|
||||||
if err := tx.Where("device_id IN ? AND bind_status = 1", deviceIDsToQuery).Find(&bindings).Error; err != nil {
|
if len(deviceIDsToQuery) > 0 {
|
||||||
return errors.Wrap(errors.CodeInternalError, err, "查询设备绑定卡失败")
|
if err := tx.Where("device_id IN ? AND bind_status = 1", deviceIDsToQuery).Find(&bindings).Error; err != nil {
|
||||||
|
return errors.Wrap(errors.CodeInternalError, err, "查询设备绑定卡失败")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 为每张绑定的卡创建授权记录
|
// 3. 为每张绑定的卡创建授权记录
|
||||||
@@ -196,7 +232,7 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. 构建响应
|
// 5. 构建响应
|
||||||
for _, device := range devicesToAllocate {
|
for _, device := range successDevices {
|
||||||
resp.AuthorizedDevices = append(resp.AuthorizedDevices, dto.AuthorizedDeviceItem{
|
resp.AuthorizedDevices = append(resp.AuthorizedDevices, dto.AuthorizedDeviceItem{
|
||||||
DeviceID: device.ID,
|
DeviceID: device.ID,
|
||||||
VirtualNo: device.VirtualNo,
|
VirtualNo: device.VirtualNo,
|
||||||
@@ -212,11 +248,25 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.SuccessCount = len(devicesToAllocate)
|
resp.SuccessCount = len(resp.AuthorizedDevices)
|
||||||
resp.FailCount = len(resp.FailedItems)
|
resp.FailCount = len(resp.FailedItems)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isUniqueConstraintViolation(err error, constraintName string) bool {
|
||||||
|
var pgErr *pgconn.PgError
|
||||||
|
if stderrors.As(err, &pgErr) {
|
||||||
|
if pgErr.Code != "23505" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if constraintName == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return pgErr.ConstraintName == constraintName
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// RecallDevices 撤销设备授权
|
// RecallDevices 撤销设备授权
|
||||||
func (s *Service) RecallDevices(ctx context.Context, enterpriseID uint, req *dto.RecallDevicesReq) (*dto.RecallDevicesResp, error) {
|
func (s *Service) RecallDevices(ctx context.Context, enterpriseID uint, req *dto.RecallDevicesReq) (*dto.RecallDevicesResp, error) {
|
||||||
currentUserID := middleware.GetUserIDFromContext(ctx)
|
currentUserID := middleware.GetUserIDFromContext(ctx)
|
||||||
|
|||||||
@@ -162,6 +162,29 @@ func (s *EnterpriseDeviceAuthorizationStore) GetActiveAuthsByDeviceIDs(ctx conte
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetActiveAuthEnterpriseByDeviceIDs 获取设备ID列表的有效授权企业映射(deviceID -> enterpriseID)
|
||||||
|
func (s *EnterpriseDeviceAuthorizationStore) GetActiveAuthEnterpriseByDeviceIDs(ctx context.Context, deviceIDs []uint) (map[uint]uint, error) {
|
||||||
|
if len(deviceIDs) == 0 {
|
||||||
|
return make(map[uint]uint), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var auths []model.EnterpriseDeviceAuthorization
|
||||||
|
query := s.db.WithContext(ctx).
|
||||||
|
Select("device_id, enterprise_id").
|
||||||
|
Where("device_id IN ? AND revoked_at IS NULL", deviceIDs)
|
||||||
|
// 应用企业数据权限过滤
|
||||||
|
query = middleware.ApplyEnterpriseFilter(ctx, query)
|
||||||
|
if err := query.Find(&auths).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[uint]uint, len(auths))
|
||||||
|
for _, auth := range auths {
|
||||||
|
result[auth.DeviceID] = auth.EnterpriseID
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *EnterpriseDeviceAuthorizationStore) ListDeviceIDsByEnterprise(ctx context.Context, enterpriseID uint) ([]uint, error) {
|
func (s *EnterpriseDeviceAuthorizationStore) ListDeviceIDsByEnterprise(ctx context.Context, enterpriseID uint) ([]uint, error) {
|
||||||
var deviceIDs []uint
|
var deviceIDs []uint
|
||||||
query := s.db.WithContext(ctx).
|
query := s.db.WithContext(ctx).
|
||||||
|
|||||||
Reference in New Issue
Block a user