企业授权增强与资产列表扩展
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m9s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m9s
- 企业卡授权唯一约束:新增 DB 迁移(000154),卡级部分唯一索引防止同一张卡被多个企业同时持有,Service 层新增跨企业冲突检测 - 单卡列表新增 network_status 过滤参数 - 单卡/设备列表新增 asset_status、asset_status_name、generation 响应字段 - 单卡/设备列表新增企业维度过滤(authorized_enterprise_id、is_authorized_to_enterprise)及响应中企业授权信息(批量加载,无 N+1) - 主钱包流水/退款列表新增 asset_identifier 精确过滤参数 - 企业卡授权/收回接口升级为三模式(list/range/filter),企业设备授权/收回升级为双模式(list/filter) - 升级 sonic v1.14.2 → v1.15.2 以兼容 Go 1.26 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -112,6 +112,92 @@ func (s *Service) AllocateCardsPreview(ctx context.Context, enterpriseID uint, r
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// resolveICCIDsForAllocate 根据选取模式解析待授权的 ICCID 列表
|
||||
func (s *Service) resolveICCIDsForAllocate(ctx context.Context, req *dto.AllocateCardsReq) ([]string, error) {
|
||||
switch req.SelectionType {
|
||||
case "list":
|
||||
return req.ICCIDs, nil
|
||||
case "range":
|
||||
cards, err := s.iotCardStore.GetStandaloneByICCIDRangeForAuth(ctx, req.ICCIDStart, req.ICCIDEnd)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "按号段查询卡失败")
|
||||
}
|
||||
iccids := make([]string, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
iccids = append(iccids, c.ICCID)
|
||||
}
|
||||
return iccids, nil
|
||||
case "filter":
|
||||
filters := map[string]any{}
|
||||
if req.ICCID != "" {
|
||||
filters["iccid"] = req.ICCID
|
||||
}
|
||||
if req.BatchNo != "" {
|
||||
filters["batch_no"] = req.BatchNo
|
||||
}
|
||||
if req.CarrierID != nil {
|
||||
filters["carrier_id"] = *req.CarrierID
|
||||
}
|
||||
if req.ShopID != nil {
|
||||
filters["shop_id"] = *req.ShopID
|
||||
}
|
||||
if len(req.ShopIDs) > 0 {
|
||||
filters["shop_ids"] = req.ShopIDs
|
||||
}
|
||||
cards, err := s.iotCardStore.GetStandaloneByAuthFilters(ctx, filters)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "按条件查询卡失败")
|
||||
}
|
||||
iccids := make([]string, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
iccids = append(iccids, c.ICCID)
|
||||
}
|
||||
return iccids, nil
|
||||
default:
|
||||
return nil, errors.New(errors.CodeInvalidParam, "无效的选取模式")
|
||||
}
|
||||
}
|
||||
|
||||
// resolveICCIDsForRecall 根据选取模式解析待回收的 ICCID 列表
|
||||
func (s *Service) resolveICCIDsForRecall(ctx context.Context, enterpriseID uint, req *dto.RecallCardsReq) ([]string, error) {
|
||||
switch req.SelectionType {
|
||||
case "list":
|
||||
return req.ICCIDs, nil
|
||||
case "range":
|
||||
cards, err := s.iotCardStore.GetAuthorizedStandaloneByICCIDRange(ctx, enterpriseID, req.ICCIDStart, req.ICCIDEnd)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "按号段查询已授权卡失败")
|
||||
}
|
||||
iccids := make([]string, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
iccids = append(iccids, c.ICCID)
|
||||
}
|
||||
return iccids, nil
|
||||
case "filter":
|
||||
filters := map[string]any{}
|
||||
if req.ICCID != "" {
|
||||
filters["iccid"] = req.ICCID
|
||||
}
|
||||
if req.BatchNo != "" {
|
||||
filters["batch_no"] = req.BatchNo
|
||||
}
|
||||
if req.CarrierID != nil {
|
||||
filters["carrier_id"] = *req.CarrierID
|
||||
}
|
||||
cards, err := s.iotCardStore.GetAuthorizedStandaloneByFilters(ctx, enterpriseID, filters)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "按条件查询已授权卡失败")
|
||||
}
|
||||
iccids := make([]string, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
iccids = append(iccids, c.ICCID)
|
||||
}
|
||||
return iccids, nil
|
||||
default:
|
||||
return nil, errors.New(errors.CodeInvalidParam, "无效的选取模式")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) AllocateCards(ctx context.Context, enterpriseID uint, req *dto.AllocateCardsReq) (*dto.AllocateCardsResp, error) {
|
||||
currentUserID := middleware.GetUserIDFromContext(ctx)
|
||||
if currentUserID == 0 {
|
||||
@@ -123,7 +209,12 @@ func (s *Service) AllocateCards(ctx context.Context, enterpriseID uint, req *dto
|
||||
return nil, errors.New(errors.CodeEnterpriseNotFound, "企业不存在")
|
||||
}
|
||||
|
||||
preview, err := s.AllocateCardsPreview(ctx, enterpriseID, &dto.AllocateCardsPreviewReq{ICCIDs: req.ICCIDs})
|
||||
iccids, err := s.resolveICCIDsForAllocate(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
preview, err := s.AllocateCardsPreview(ctx, enterpriseID, &dto.AllocateCardsPreviewReq{ICCIDs: iccids})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -133,9 +224,31 @@ func (s *Service) AllocateCards(ctx context.Context, enterpriseID uint, req *dto
|
||||
FailCount: len(preview.FailedItems),
|
||||
}
|
||||
|
||||
cardIDsToAllocate := make([]uint, 0)
|
||||
// 构建 cardID -> ICCID 映射,用于组装失败原因
|
||||
cardIDToICCID := make(map[uint]string, len(preview.StandaloneCards))
|
||||
allCandidateIDs := make([]uint, 0, len(preview.StandaloneCards))
|
||||
for _, card := range preview.StandaloneCards {
|
||||
cardIDsToAllocate = append(cardIDsToAllocate, card.IotCardID)
|
||||
cardIDToICCID[card.IotCardID] = card.ICCID
|
||||
allCandidateIDs = append(allCandidateIDs, card.IotCardID)
|
||||
}
|
||||
|
||||
// 检测已被其他企业授权的卡,阻止重复授权
|
||||
conflictAuths, err := s.enterpriseCardAuthStore.GetConflictingAuthsByCardIDs(ctx, enterpriseID, allCandidateIDs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询冲突授权失败")
|
||||
}
|
||||
|
||||
cardIDsToAllocate := make([]uint, 0, len(allCandidateIDs))
|
||||
for _, cardID := range allCandidateIDs {
|
||||
if _, conflict := conflictAuths[cardID]; conflict {
|
||||
resp.FailedItems = append(resp.FailedItems, dto.FailedItem{
|
||||
ICCID: cardIDToICCID[cardID],
|
||||
Reason: "卡已授权给其他企业,请先收回",
|
||||
})
|
||||
resp.FailCount++
|
||||
continue
|
||||
}
|
||||
cardIDsToAllocate = append(cardIDsToAllocate, cardID)
|
||||
}
|
||||
|
||||
existingAuths, err := s.enterpriseCardAuthStore.GetActiveAuthsByCardIDs(ctx, enterpriseID, cardIDsToAllocate)
|
||||
@@ -181,7 +294,12 @@ func (s *Service) RecallCards(ctx context.Context, enterpriseID uint, req *dto.R
|
||||
return nil, errors.New(errors.CodeEnterpriseNotFound, "企业不存在")
|
||||
}
|
||||
|
||||
iotCardPtrs, err := s.iotCardStore.GetByICCIDs(ctx, req.ICCIDs)
|
||||
iccids, err := s.resolveICCIDsForRecall(ctx, enterpriseID, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iotCardPtrs, err := s.iotCardStore.GetByICCIDs(ctx, iccids)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询卡信息失败")
|
||||
}
|
||||
@@ -206,7 +324,7 @@ func (s *Service) RecallCards(ctx context.Context, enterpriseID uint, req *dto.R
|
||||
}
|
||||
|
||||
cardIDsToRecall := make([]uint, 0)
|
||||
for _, iccid := range req.ICCIDs {
|
||||
for _, iccid := range iccids {
|
||||
card, exists := cardMap[iccid]
|
||||
if !exists {
|
||||
resp.FailedItems = append(resp.FailedItems, dto.FailedItem{
|
||||
|
||||
Reference in New Issue
Block a user