货柜pda 添加操作人
This commit is contained in:
@@ -18,6 +18,8 @@ import com.baiyue.iam.service.TenantService;
|
||||
import com.baiyue.iam.dto.CustomerExportDtos.CustomerExportBatch;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.iam.dto.TenantDtos.FinanceCustomerSummary;
|
||||
import com.baiyue.iam.dto.DomesticPdaOperatorDtos.OperatorOption;
|
||||
import com.baiyue.iam.service.DomesticPdaOperatorService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
@@ -38,6 +40,7 @@ public class InternalTenantController {
|
||||
@Resource private MerchantOnboardingService onboardingService;
|
||||
@Resource private ProfileResourceService profileResourceService;
|
||||
@Resource private TenantService tenantService;
|
||||
@Resource private DomesticPdaOperatorService domesticPdaOperatorService;
|
||||
@Value("${baiyue.security.internal-service-token}") private String internalTokenValue;
|
||||
private byte[] internalToken;
|
||||
|
||||
@@ -128,6 +131,15 @@ public class InternalTenantController {
|
||||
return ApiResponse.success(tenantService.pageFinanceCustomers(page, size, keyword, status, customerId));
|
||||
}
|
||||
|
||||
@GetMapping("/domestic-pda-operators/{authUserId}")
|
||||
public ApiResponse<OperatorOption> domesticPdaOperator(
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
@PathVariable long authUserId,
|
||||
@RequestParam long warehouseId) {
|
||||
verify(token);
|
||||
return ApiResponse.success(domesticPdaOperatorService.required(authUserId, warehouseId));
|
||||
}
|
||||
|
||||
@GetMapping("/exports/customers")
|
||||
public ApiResponse<CustomerExportBatch> exportCustomers(
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
|
||||
@@ -6,6 +6,9 @@ import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.iam.dto.PlatformUserManagementDtos.*;
|
||||
import com.baiyue.iam.service.PlatformUserManagementService;
|
||||
import com.baiyue.iam.service.TenantGuard;
|
||||
import com.baiyue.iam.service.DomesticPdaOperatorService;
|
||||
import com.baiyue.iam.dto.DomesticPdaOperatorDtos.OperatorOption;
|
||||
import java.util.List;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
@@ -26,6 +29,19 @@ import org.springframework.web.bind.annotation.*;
|
||||
public class PlatformUserManagementController {
|
||||
@Resource
|
||||
private PlatformUserManagementService service;
|
||||
@Resource
|
||||
private DomesticPdaOperatorService domesticPdaOperators;
|
||||
|
||||
@GetMapping("/domestic-pda-operators")
|
||||
@PreAuthorize("hasAuthority('platform:firstleg:pda:assign')")
|
||||
@Operation(summary = "查询启用的国内头程 PDA 作业员候选")
|
||||
public ApiResponse<List<OperatorOption>> domesticPdaOperators(
|
||||
@RequestParam long warehouseId,
|
||||
@RequestParam(required = false) String keyword,
|
||||
@AuthenticationPrincipal AuthenticatedUser user) {
|
||||
TenantGuard.tenant(user, "PLATFORM");
|
||||
return ApiResponse.success(domesticPdaOperators.options(warehouseId, keyword));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('platform:user:list')")
|
||||
|
||||
@@ -41,12 +41,13 @@ public final class AuthorizationDtos {
|
||||
private Set<String> permissions;
|
||||
private Long permissionVersion;
|
||||
private Long overseasWarehouseId;
|
||||
private Long domesticWarehouseId;
|
||||
|
||||
public SnapshotResponse(Long userId, Long tenantId, Long membershipId, String appCode,
|
||||
String clientType, Set<String> roles, Set<String> permissions,
|
||||
Long permissionVersion) {
|
||||
this(userId, tenantId, membershipId, appCode, clientType, roles, permissions,
|
||||
permissionVersion, null);
|
||||
permissionVersion, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.baiyue.iam.dto;
|
||||
|
||||
/** 国内头程 PDA 作业员候选契约。 */
|
||||
public final class DomesticPdaOperatorDtos {
|
||||
private DomesticPdaOperatorDtos() { }
|
||||
|
||||
public record OperatorOption(Long userId, String displayName) { }
|
||||
}
|
||||
@@ -23,12 +23,13 @@ public final class PlatformUserManagementDtos {
|
||||
@NotNull Long tenantId,
|
||||
@NotNull List<Long> roleIds,
|
||||
Long overseasWarehouseId,
|
||||
Long domesticWarehouseId,
|
||||
@NotBlank @Size(min = 8, max = 64)
|
||||
@Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d).+$", message = "密码必须同时包含字母和数字") String password,
|
||||
@NotBlank @Pattern(regexp = "ACTIVE|DISABLED") String status) {
|
||||
public CreateUserRequest(String username, String displayName, String phone, String email,
|
||||
Long tenantId, List<Long> roleIds, String password, String status) {
|
||||
this(username, displayName, phone, email, tenantId, roleIds, null, password, status);
|
||||
this(username, displayName, phone, email, tenantId, roleIds, null, null, password, status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +40,15 @@ public final class PlatformUserManagementDtos {
|
||||
@Email @Size(max = 128) String email,
|
||||
@NotNull Long tenantId,
|
||||
@NotNull List<Long> roleIds,
|
||||
Long overseasWarehouseId) {
|
||||
Long overseasWarehouseId,
|
||||
Long domesticWarehouseId) {
|
||||
public UpdateUserRequest(String displayName, String phone, String email,
|
||||
Long tenantId, List<Long> roleIds, Long overseasWarehouseId) {
|
||||
this(displayName, phone, email, tenantId, roleIds, overseasWarehouseId, null);
|
||||
}
|
||||
public UpdateUserRequest(String displayName, String phone, String email,
|
||||
Long tenantId, List<Long> roleIds) {
|
||||
this(displayName, phone, email, tenantId, roleIds, null);
|
||||
this(displayName, phone, email, tenantId, roleIds, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +61,7 @@ public final class PlatformUserManagementDtos {
|
||||
String displayName, String phone, String email, Long tenantId,
|
||||
String tenantName, String memberType, String memberNo, String status,
|
||||
List<Long> roleIds, List<String> roleNames, LocalDateTime lastLoginAt,
|
||||
boolean protectedAccount, Long overseasWarehouseId) { }
|
||||
boolean protectedAccount, Long overseasWarehouseId, Long domesticWarehouseId) { }
|
||||
|
||||
public record TenantOption(Long id, String name, String status) { }
|
||||
public record RoleOption(Long id, Long tenantId, String name, String status) { }
|
||||
|
||||
@@ -9,6 +9,6 @@ import com.baiyue.common.core.model.BaseEntity; import com.baomidou.mybatisplus.
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("iam_membership") public class IamMembership extends BaseEntity {
|
||||
@TableId private Long id; private Long tenantId; private Long userId; private String memberType; private String memberNo; private Long overseasWarehouseId; private String status; private LocalDateTime joinedAt; private LocalDateTime leftAt;
|
||||
@TableId private Long id; private Long tenantId; private Long userId; private String memberType; private String memberNo; private Long overseasWarehouseId; private Long domesticWarehouseId; private String status; private LocalDateTime joinedAt; private LocalDateTime leftAt;
|
||||
|
||||
}
|
||||
|
||||
@@ -105,4 +105,8 @@ public interface AuthorizationQueryMapper {
|
||||
@Select("SELECT overseas_warehouse_id FROM iam_membership WHERE id=#{membershipId} AND tenant_id=#{tenantId} AND status='ACTIVE' AND deleted=0")
|
||||
Long findOverseasWarehouseId(@Param("tenantId") long tenantId,
|
||||
@Param("membershipId") long membershipId);
|
||||
|
||||
@Select("SELECT domestic_warehouse_id FROM iam_membership WHERE id=#{membershipId} AND tenant_id=#{tenantId} AND status='ACTIVE' AND deleted=0")
|
||||
Long findDomesticWarehouseId(@Param("tenantId") long tenantId,
|
||||
@Param("membershipId") long membershipId);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
import com.baiyue.iam.dto.DomesticPdaOperatorDtos.OperatorOption;
|
||||
|
||||
@Mapper
|
||||
public interface IamMembershipRoleMapper extends BaseMapper<IamMembershipRole> {
|
||||
@@ -26,4 +27,31 @@ public interface IamMembershipRoleMapper extends BaseMapper<IamMembershipRole> {
|
||||
""")
|
||||
List<Long> findAssignedAuthUserIds(@Param("tenantId") long tenantId,
|
||||
@Param("roleId") Long roleId);
|
||||
|
||||
@Select("""
|
||||
<script>
|
||||
SELECT DISTINCT u.auth_user_id AS userId, u.display_name AS displayName
|
||||
FROM iam_membership_role mr
|
||||
JOIN iam_role role ON role.id = mr.role_id AND role.tenant_id = mr.tenant_id
|
||||
JOIN iam_membership m ON m.id = mr.membership_id AND m.tenant_id = mr.tenant_id
|
||||
JOIN iam_user u ON u.id = m.user_id
|
||||
WHERE mr.tenant_id = #{tenantId}
|
||||
AND role.role_code = #{roleCode} AND role.app_code = 'PLATFORM'
|
||||
AND role.status = 'ACTIVE' AND role.deleted = 0
|
||||
AND m.status = 'ACTIVE' AND m.deleted = 0
|
||||
AND u.status = 'ACTIVE' AND u.deleted = 0
|
||||
<if test="warehouseId != null">AND m.domestic_warehouse_id = #{warehouseId}</if>
|
||||
<if test="authUserId != null">AND u.auth_user_id = #{authUserId}</if>
|
||||
<if test="keyword != null and keyword != ''">
|
||||
AND u.display_name LIKE CONCAT('%', #{keyword}, '%')
|
||||
</if>
|
||||
ORDER BY u.display_name, u.auth_user_id
|
||||
LIMIT 200
|
||||
</script>
|
||||
""")
|
||||
List<OperatorOption> findActiveUsersByRoleCode(@Param("tenantId") long tenantId,
|
||||
@Param("roleCode") String roleCode,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("authUserId") Long authUserId,
|
||||
@Param("warehouseId") Long warehouseId);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ public class AuthorizationSnapshotService {
|
||||
return new SnapshotResponse(request.getUserId(), request.getTenantId(), request.getMembershipId(),
|
||||
appCode, appCode, Set.copyOf(roles), Set.copyOf(permissions),
|
||||
mapper.findPermissionVersion(request.getUserId()),
|
||||
mapper.findOverseasWarehouseId(request.getTenantId(), request.getMembershipId()));
|
||||
mapper.findOverseasWarehouseId(request.getTenantId(), request.getMembershipId()),
|
||||
mapper.findDomesticWarehouseId(request.getTenantId(), request.getMembershipId()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.baiyue.iam.service;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.iam.dto.DomesticPdaOperatorDtos.OperatorOption;
|
||||
import com.baiyue.iam.mapper.IamMembershipRoleMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** 提供启用的国内头程 PDA 作业员,并作为派单时的权威角色校验。 */
|
||||
@Service
|
||||
public class DomesticPdaOperatorService {
|
||||
@Resource
|
||||
private IamMembershipRoleMapper membershipRoles;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<OperatorOption> options(long warehouseId, String keyword) {
|
||||
String normalized = keyword == null || keyword.isBlank() ? null : keyword.trim();
|
||||
return membershipRoles.findActiveUsersByRoleCode(0L, "CN_FIRSTLEG_PDA_OPERATOR", normalized, null, warehouseId);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public OperatorOption required(long authUserId, long warehouseId) {
|
||||
return membershipRoles.findActiveUsersByRoleCode(
|
||||
0L, "CN_FIRSTLEG_PDA_OPERATOR", null, authUserId, warehouseId).stream().findFirst()
|
||||
.orElseThrow(() -> new BizException(ResultCode.BAD_REQUEST,
|
||||
"所选人员不是该仓库启用的国内头程 PDA 作业员"));
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ public class PlatformUserManagementService {
|
||||
long tenantId = request.tenantId();
|
||||
requirePlatformTenant(tenantId);
|
||||
List<Long> roleIds = validateRoles(tenantId, request.roleIds());
|
||||
Long overseasWarehouseId = validateWarehouseBinding(roleIds, request.overseasWarehouseId());
|
||||
WarehouseBindings warehouses = validateWarehouseBinding(roleIds, request.overseasWarehouseId(), request.domesticWarehouseId());
|
||||
long authUserId = IdWorker.getId();
|
||||
long userId = IdWorker.getId();
|
||||
long membershipId = IdWorker.getId();
|
||||
@@ -100,7 +100,8 @@ public class PlatformUserManagementService {
|
||||
membership.setUserId(userId);
|
||||
membership.setMemberType("EMPLOYEE");
|
||||
membership.setMemberNo(memberNo(tenantId, membershipId));
|
||||
membership.setOverseasWarehouseId(overseasWarehouseId);
|
||||
membership.setOverseasWarehouseId(warehouses.overseasWarehouseId());
|
||||
membership.setDomesticWarehouseId(warehouses.domesticWarehouseId());
|
||||
membership.setStatus(request.status());
|
||||
membership.setJoinedAt(LocalDateTime.now());
|
||||
membership.setLeftAt("DISABLED".equals(request.status()) ? LocalDateTime.now() : null);
|
||||
@@ -125,7 +126,7 @@ public class PlatformUserManagementService {
|
||||
long newTenantId = request.tenantId();
|
||||
requirePlatformTenant(newTenantId);
|
||||
List<Long> roleIds = validateRoles(newTenantId, request.roleIds());
|
||||
Long overseasWarehouseId = validateWarehouseBinding(roleIds, request.overseasWarehouseId());
|
||||
WarehouseBindings warehouses = validateWarehouseBinding(roleIds, request.overseasWarehouseId(), request.domesticWarehouseId());
|
||||
List<Long> oldRoleIds = members.findRoleIds(oldTenantId, membershipId);
|
||||
if (isProtectedPlatformAdmin(membership, oldRoleIds)
|
||||
&& (newTenantId != PLATFORM_TENANT_ID || !containsPlatformAdminRole(roleIds))) {
|
||||
@@ -140,7 +141,8 @@ public class PlatformUserManagementService {
|
||||
boolean phoneChanged = !Objects.equals(user.getPhone(), request.phone().trim());
|
||||
boolean scopeChanged = oldTenantId != newTenantId;
|
||||
boolean rolesChanged = !new java.util.HashSet<>(oldRoleIds).equals(new java.util.HashSet<>(roleIds));
|
||||
boolean warehouseChanged = !Objects.equals(membership.getOverseasWarehouseId(), overseasWarehouseId);
|
||||
boolean warehouseChanged = !Objects.equals(membership.getOverseasWarehouseId(), warehouses.overseasWarehouseId())
|
||||
|| !Objects.equals(membership.getDomesticWarehouseId(), warehouses.domesticWarehouseId());
|
||||
|
||||
if (profileChanged) call(() -> authClient.profile(internalToken, user.getAuthUserId(),
|
||||
new AuthAccountClient.ProfileRequest(request.displayName().trim())));
|
||||
@@ -154,7 +156,8 @@ public class PlatformUserManagementService {
|
||||
user.setEmail(trimToNull(request.email()));
|
||||
user.setUserType(userType(newTenantId));
|
||||
membership.setTenantId(newTenantId);
|
||||
membership.setOverseasWarehouseId(overseasWarehouseId);
|
||||
membership.setOverseasWarehouseId(warehouses.overseasWarehouseId());
|
||||
membership.setDomesticWarehouseId(warehouses.domesticWarehouseId());
|
||||
if (scopeChanged && members.existsMemberNo(newTenantId, membership.getMemberNo(), membershipId)) {
|
||||
membership.setMemberNo(memberNo(newTenantId, membershipId));
|
||||
}
|
||||
@@ -239,7 +242,7 @@ public class PlatformUserManagementService {
|
||||
user.getDisplayName(), user.getPhone(), user.getEmail(), membership.getTenantId(), tenantName,
|
||||
membership.getMemberType(), membership.getMemberNo(), membership.getStatus(), roleIds,
|
||||
roleNames, account.lastLoginAt(), isProtectedPlatformAdmin(membership, roleIds),
|
||||
membership.getOverseasWarehouseId());
|
||||
membership.getOverseasWarehouseId(), membership.getDomesticWarehouseId());
|
||||
}
|
||||
|
||||
private List<IamRole> platformRoles() {
|
||||
@@ -262,7 +265,8 @@ public class PlatformUserManagementService {
|
||||
return roleIds;
|
||||
}
|
||||
|
||||
private Long validateWarehouseBinding(List<Long> roleIds, Long overseasWarehouseId) {
|
||||
private WarehouseBindings validateWarehouseBinding(List<Long> roleIds, Long overseasWarehouseId,
|
||||
Long domesticWarehouseId) {
|
||||
Set<String> roleCodes = roleIds.stream().map(roleMapper::selectById).filter(Objects::nonNull)
|
||||
.map(IamRole::getRoleCode).collect(Collectors.toSet());
|
||||
boolean overseasPda = roleCodes.contains("OVERSEAS_WAREHOUSE_PDA_OPERATOR");
|
||||
@@ -276,9 +280,17 @@ public class PlatformUserManagementService {
|
||||
if (!overseasPda && overseasWarehouseId != null) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "仅海外仓 PDA 作业员可绑定海外仓");
|
||||
}
|
||||
return overseasWarehouseId;
|
||||
if (domesticPda && (domesticWarehouseId == null || domesticWarehouseId <= 0)) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "国内头程 PDA 作业员必须绑定一个有效国内仓");
|
||||
}
|
||||
if (!domesticPda && domesticWarehouseId != null) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "仅国内头程 PDA 作业员可绑定国内仓");
|
||||
}
|
||||
return new WarehouseBindings(overseasWarehouseId, domesticWarehouseId);
|
||||
}
|
||||
|
||||
private record WarehouseBindings(Long overseasWarehouseId, Long domesticWarehouseId) { }
|
||||
|
||||
private boolean isProtectedPlatformAdmin(IamMembership membership, List<Long> roleIds) {
|
||||
return membership.getTenantId() == PLATFORM_TENANT_ID && containsPlatformAdminRole(roleIds);
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ CREATE TABLE IF NOT EXISTS iam_membership (
|
||||
member_type VARCHAR(20) NOT NULL DEFAULT 'EMPLOYEE' COMMENT '成员类型:EMPLOYEE企业员工等',
|
||||
member_no VARCHAR(64) NULL COMMENT '客户企业内部成员编号',
|
||||
overseas_warehouse_id BIGINT NULL COMMENT '海外仓PDA操作员绑定的唯一实际海外仓ID',
|
||||
domestic_warehouse_id BIGINT NULL COMMENT '国内头程PDA操作员绑定的唯一国内作业仓ID',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '成员状态:ACTIVE在职、DISABLED停用、LEFT已离开',
|
||||
joined_at DATETIME(3) NULL COMMENT '加入客户企业时间',
|
||||
left_at DATETIME(3) NULL COMMENT '离开客户企业时间',
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
USE baiyue_iam;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
DROP PROCEDURE IF EXISTS ensure_domestic_pda_operator_warehouse_column;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE ensure_domestic_pda_operator_warehouse_column()
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = 'iam_membership'
|
||||
AND column_name = 'domestic_warehouse_id'
|
||||
) THEN
|
||||
ALTER TABLE iam_membership
|
||||
ADD COLUMN domestic_warehouse_id BIGINT NULL
|
||||
COMMENT '国内头程PDA操作员绑定的唯一国内作业仓ID'
|
||||
AFTER overseas_warehouse_id,
|
||||
ADD KEY idx_membership_domestic_warehouse (tenant_id, domestic_warehouse_id, status);
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL ensure_domestic_pda_operator_warehouse_column();
|
||||
DROP PROCEDURE ensure_domestic_pda_operator_warehouse_column;
|
||||
|
||||
UPDATE iam_role
|
||||
SET role_code = 'OVERSEAS_WAREHOUSE_PDA_OPERATOR',
|
||||
role_name = '海外仓 PDA 作业员',
|
||||
@@ -72,13 +92,16 @@ CREATE TEMPORARY TABLE tmp_phase3_warehouse_role_permission (
|
||||
PRIMARY KEY (role_code, permission_code)
|
||||
) ENGINE=MEMORY;
|
||||
|
||||
-- 操作员:查看入仓业务并维护后台装柜证据,不授予完成装柜、任务分派或出仓动作。
|
||||
-- 仓管:可查看并确认预装、指定国内 PDA 作业员,不授予 PDA 执行或出仓动作。
|
||||
INSERT INTO tmp_phase3_warehouse_role_permission (role_code, permission_code) VALUES
|
||||
('WAREHOUSE_OPERATOR', 'platform:order'),
|
||||
('WAREHOUSE_OPERATOR', 'platform:firstleg:inbound:list'),
|
||||
('WAREHOUSE_OPERATOR', 'platform:firstleg:inbound:view'),
|
||||
('WAREHOUSE_OPERATOR', 'platform:firstleg:inbound:loading:view'),
|
||||
('WAREHOUSE_OPERATOR', 'platform:firstleg:inbound:loading:edit');
|
||||
('WAREHOUSE_OPERATOR', 'platform:firstleg:inbound:loading:edit'),
|
||||
('WAREHOUSE_OPERATOR', 'platform:firstleg:preload:list'),
|
||||
('WAREHOUSE_OPERATOR', 'platform:firstleg:preload:edit'),
|
||||
('WAREHOUSE_OPERATOR', 'platform:firstleg:pda:assign');
|
||||
|
||||
-- 国内头程 PDA 作业员:只允许国内任务查询、作业和现场照片,不授予后台、海外、分派或复核权限。
|
||||
INSERT INTO tmp_phase3_warehouse_role_permission (role_code, permission_code) VALUES
|
||||
@@ -112,7 +135,7 @@ BEGIN
|
||||
COALESCE(SUM(role_code = 'WAREHOUSE_TALLY'), 0)
|
||||
INTO operator_permission_count, domestic_pda_permission_count, tally_permission_count
|
||||
FROM tmp_phase3_warehouse_role_permission;
|
||||
IF operator_permission_count <> 5
|
||||
IF operator_permission_count <> 8
|
||||
OR domestic_pda_permission_count <> 2
|
||||
OR tally_permission_count <> 12 THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
@@ -208,7 +231,7 @@ BEGIN
|
||||
JOIN iam_role_permission grant_row
|
||||
ON grant_row.role_id = role.id
|
||||
AND grant_row.permission_id = permission.id
|
||||
AND grant_row.tenant_id = 0) <> 19 THEN
|
||||
AND grant_row.tenant_id = 0) <> 22 THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '仓库角色初始化失败:最小权限授权未完整写入';
|
||||
END IF;
|
||||
|
||||
@@ -435,6 +435,18 @@ paths:
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/Success'}
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
/api/platform/v1/iam/users/domestic-pda-operators:
|
||||
get:
|
||||
tags: [IAM Resources / IAM 资源]
|
||||
summary: 查询启用的国内头程 PDA 作业员候选
|
||||
description: 仅返回具有 CN_FIRSTLEG_PDA_OPERATOR 角色且账号、成员、角色均启用的平台人员。
|
||||
x-permission: platform:firstleg:pda:assign
|
||||
parameters:
|
||||
- {name: warehouseId, in: query, required: true, schema: {type: integer, format: int64, minimum: 1, description: 仅返回绑定到该国内仓的国内头程 PDA 作业员}}
|
||||
- {name: keyword, in: query, required: false, schema: {type: string}}
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/Success'}
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
/api/platform/v1/iam/users/{membershipId}:
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/MembershipId'}
|
||||
@@ -993,6 +1005,19 @@ paths:
|
||||
total: {type: integer, format: int64}
|
||||
pages: {type: integer}
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
/internal/iam/domestic-pda-operators/{authUserId}:
|
||||
get:
|
||||
tags: [IAM Resources / IAM 资源]
|
||||
summary: 校验并返回启用的国内头程 PDA 作业员
|
||||
security: []
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/InternalServiceToken'}
|
||||
- {name: authUserId, in: path, required: true, schema: {type: integer, format: int64, minimum: 1}}
|
||||
- {name: warehouseId, in: query, required: true, schema: {type: integer, format: int64, minimum: 1}}
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/Success'}
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
'404': {$ref: '#/components/responses/NotFound'}
|
||||
/internal/exports/v1/CUSTOMER_LIST/batches:
|
||||
post:
|
||||
tags: [Internal Export Provider]
|
||||
@@ -1550,6 +1575,7 @@ components:
|
||||
tenantId: {type: integer, format: int64, enum: [0], description: 保留的兼容字段,只允许平台技术作用域 0}
|
||||
roleIds: {type: array, minItems: 1, items: {type: integer, format: int64}}
|
||||
overseasWarehouseId: {type: integer, format: int64, nullable: true, description: 选择 OVERSEAS_WAREHOUSE_PDA_OPERATOR 时必填且只能绑定一个实际海外仓;CN_FIRSTLEG_PDA_OPERATOR 与其他角色必须为空;两个 PDA 角色不能同时分配}
|
||||
domesticWarehouseId: {type: integer, format: int64, nullable: true, description: 选择 CN_FIRSTLEG_PDA_OPERATOR 时必填且只能绑定一个有效国内作业仓;非国内头程 PDA 角色时必须为空;两个 PDA 角色不能同时分配}
|
||||
password: {type: string, format: password, minLength: 8, maxLength: 64, writeOnly: true}
|
||||
status: {type: string, enum: [ACTIVE, DISABLED]}
|
||||
UpdatePlatformManagedUserRequest:
|
||||
@@ -1562,6 +1588,7 @@ components:
|
||||
tenantId: {type: integer, format: int64, enum: [0], description: 保留的兼容字段,只允许平台技术作用域 0}
|
||||
roleIds: {type: array, minItems: 1, items: {type: integer, format: int64}}
|
||||
overseasWarehouseId: {type: integer, format: int64, nullable: true, description: 选择 OVERSEAS_WAREHOUSE_PDA_OPERATOR 时必填且只能绑定一个实际海外仓;CN_FIRSTLEG_PDA_OPERATOR 与其他角色必须为空;两个 PDA 角色不能同时分配}
|
||||
domesticWarehouseId: {type: integer, format: int64, nullable: true, description: 选择 CN_FIRSTLEG_PDA_OPERATOR 时必填且只能绑定一个有效国内作业仓;非国内头程 PDA 角色时必须为空;两个 PDA 角色不能同时分配}
|
||||
CreateInternalUserRequest:
|
||||
type: object
|
||||
required: [displayName]
|
||||
@@ -1635,6 +1662,7 @@ components:
|
||||
lastLoginAt: {type: string, format: date-time, nullable: true}
|
||||
protectedAccount: {type: boolean}
|
||||
overseasWarehouseId: {type: string, pattern: '^\d+$', nullable: true, description: 海外仓PDA操作员绑定的唯一实际海外仓ID}
|
||||
domesticWarehouseId: {type: string, pattern: '^\d+$', nullable: true, description: 国内头程PDA操作员绑定的唯一国内作业仓ID}
|
||||
CreateMemberRequest:
|
||||
type: object
|
||||
required: [username, password, displayName, memberType]
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.baiyue.iam.repository;
|
||||
|
||||
import com.baiyue.iam.mapper.IamMembershipRoleMapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DomesticPdaOperatorSqlContractTest {
|
||||
@Test
|
||||
void candidatesUseActivePlatformRoleAndAuthAccountIdentity() throws Exception {
|
||||
String sql = IamMembershipRoleMapper.class.getDeclaredMethod("findActiveUsersByRoleCode",
|
||||
long.class, String.class, String.class, Long.class).getAnnotation(Select.class).value()[0];
|
||||
|
||||
assertThat(sql).contains("u.auth_user_id AS userId", "role.role_code = #{roleCode}",
|
||||
"role.app_code = 'PLATFORM'", "role.status = 'ACTIVE'", "m.status = 'ACTIVE'",
|
||||
"u.status = 'ACTIVE'", "u.auth_user_id = #{authUserId}")
|
||||
.doesNotContain("baiyue_auth");
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ class WarehouseRoleSqlContractTest {
|
||||
.contains("'WAREHOUSE_TALLY', 'platform:firstleg:pda:review'")
|
||||
.contains("'WAREHOUSE_TALLY', 'platform:firstleg:inbound:loading:edit'")
|
||||
.contains("'WAREHOUSE_OPERATOR', 'platform:firstleg:inbound:loading:edit'")
|
||||
.contains("operator_permission_count <> 5")
|
||||
.contains("operator_permission_count <> 8")
|
||||
.contains("domestic_pda_permission_count <> 2")
|
||||
.contains("tally_permission_count <> 12")
|
||||
.contains("依赖的三期平台权限尚未完整部署")
|
||||
@@ -54,7 +54,7 @@ class WarehouseRoleSqlContractTest {
|
||||
.contains("expected.permission_code IS NULL")
|
||||
.contains("role.role_code = 'OVERSEAS_WAREHOUSE_PDA_OPERATOR' AND permission.permission_code = 'lastleg:pda:operate'")
|
||||
.contains("最小权限授权未完整写入")
|
||||
.contains("grant_row.tenant_id = 0) <> 19")
|
||||
.contains("grant_row.tenant_id = 0) <> 22")
|
||||
.contains("(6000004, 4000004, 0, 'TENANT', NULL)")
|
||||
.contains("(6000005, 4000005, 0, 'TENANT', NULL)")
|
||||
.contains("(6000006, 4000006, 0, 'TENANT', NULL)")
|
||||
@@ -80,7 +80,7 @@ class WarehouseRoleSqlContractTest {
|
||||
.doesNotContain("platform:firstleg:inbound:picking:view")
|
||||
.doesNotContain("platform:firstleg:outbound-dispatch:confirm");
|
||||
assertThat(sql)
|
||||
.doesNotContain("'WAREHOUSE_OPERATOR', 'platform:firstleg:pda:assign'")
|
||||
.contains("'WAREHOUSE_OPERATOR', 'platform:firstleg:pda:assign'")
|
||||
.doesNotContain("'WAREHOUSE_OPERATOR', 'platform:firstleg:inbound:loading:complete'")
|
||||
.doesNotContain("'WAREHOUSE_OPERATOR', 'platform:firstleg:outbound-dispatch:confirm'")
|
||||
.doesNotContain("'WAREHOUSE_OPERATOR', 'platform:firstleg:outbound-dispatch:reverse'")
|
||||
|
||||
Reference in New Issue
Block a user