装柜只能限制一个人拣货

This commit is contained in:
2026-08-10 12:50:22 +08:00
parent ea1346ee2c
commit a1bcb519c9
12 changed files with 18 additions and 319 deletions
@@ -8585,7 +8585,7 @@ CREATE TABLE IF NOT EXISTS fl_loading_pick_operation (
UNIQUE KEY uk_loading_pick_operation_id (operation_id),
KEY idx_loading_pick_operation_task (pick_task_id, created_at),
CONSTRAINT fk_loading_pick_operation_task FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id),
CONSTRAINT chk_loading_pick_operation_action CHECK (action_type IN ('CLAIM', 'ASSIGN', 'ITEM_CLAIM', 'ITEM_ASSIGN', 'REVIEW'))
CONSTRAINT chk_loading_pick_operation_action CHECK (action_type IN ('CLAIM', 'ASSIGN', 'REVIEW'))
) ENGINE=InnoDB COMMENT='柜次PDA任务级幂等审计';
DROP TRIGGER IF EXISTS trg_loading_pick_review_before_update;
@@ -8722,47 +8722,6 @@ USE baiyue_firstleg;
ALTER TABLE fl_loading_pick_item
ADD COLUMN IF NOT EXISTS release_mode VARCHAR(10) NULL COMMENT 'AUTO按比例释放,MANUAL按人工选择释放' AFTER item_status,
ADD COLUMN IF NOT EXISTS release_location_ids JSON NULL COMMENT '人工选择释放库位ID;空数组表示明确释放0个' AFTER release_mode;
-- PDA 多人协作:领取粒度由整柜任务下沉为单条拣货明细。
CREATE TABLE IF NOT EXISTS fl_loading_pick_item_assignment (
pick_item_id BIGINT UNSIGNED NOT NULL,
assignee_id BIGINT UNSIGNED NOT NULL,
assignee_name VARCHAR(64) NOT NULL,
assigned_by BIGINT UNSIGNED NOT NULL,
assigned_by_name VARCHAR(64) NULL,
assignment_type VARCHAR(16) NOT NULL COMMENT 'CLAIMED/ASSIGNED',
version INT UNSIGNED NOT NULL DEFAULT 0,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (pick_item_id),
KEY idx_loading_pick_item_assignee (assignee_id, updated_at),
CONSTRAINT fk_loading_pick_item_assignment_item FOREIGN KEY (pick_item_id) REFERENCES fl_loading_pick_item (id),
CONSTRAINT chk_loading_pick_item_assignment_type CHECK (assignment_type IN ('CLAIMED', 'ASSIGNED'))
) ENGINE=InnoDB COMMENT='PDA拣货明细领取与作业员分配';
ALTER TABLE fl_loading_pick_operation
DROP CHECK IF EXISTS chk_loading_pick_operation_action,
ADD CONSTRAINT chk_loading_pick_operation_action
CHECK (action_type IN ('CLAIM', 'ASSIGN', 'ITEM_CLAIM', 'ITEM_ASSIGN', 'REVIEW'));
DROP PROCEDURE IF EXISTS assert_phase3_pda_item_assignment_schema;
DELIMITER $$
CREATE PROCEDURE assert_phase3_pda_item_assignment_schema()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_pick_item_assignment') <> 1
OR (SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_pick_item_assignment'
AND index_name='idx_loading_pick_item_assignee') <> 2
OR (SELECT COUNT(*) FROM information_schema.referential_constraints
WHERE constraint_schema='baiyue_firstleg'
AND constraint_name='fk_loading_pick_item_assignment_item') <> 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='PDA明细级多人分配表创建失败';
END IF;
END$$
DELIMITER ;
CALL assert_phase3_pda_item_assignment_schema();
DROP PROCEDURE IF EXISTS assert_phase3_pda_item_assignment_schema;
ALTER TABLE fl_inbound_pallet_allocation
ADD COLUMN IF NOT EXISTS reservation_id BIGINT UNSIGNED NULL COMMENT '仓库预占资源唯一ID,A0共享场景用于区分托盘' AFTER location_code;
@@ -62,28 +62,6 @@ public class PlatformLoadingPdaController {
return ApiResponse.success(service.assign(taskId, request, user.userId(), user.username()));
}
/** 同一柜按 PDA 明细领取,多个作业员可分别处理不同入库单明细。 */
@PostMapping("/tasks/{taskId}/items/{itemId}/claim")
@PreAuthorize("hasAuthority('platform:firstleg:pda:work')")
public ApiResponse<Task> claimItem(@AuthenticationPrincipal AuthenticatedUser user,
@PathVariable @Positive long taskId,
@PathVariable @Positive long itemId,
@Valid @RequestBody ClaimRequest request) {
FirstlegScopeGuard.platform(user);
return ApiResponse.success(service.claimItem(taskId, itemId, request, user.userId(), user.username()));
}
/** 管理员可将单条 PDA 明细分配给指定仓库作业员。 */
@PostMapping("/tasks/{taskId}/items/{itemId}/assign")
@PreAuthorize("hasAuthority('platform:firstleg:pda:assign')")
public ApiResponse<Task> assignItem(@AuthenticationPrincipal AuthenticatedUser user,
@PathVariable @Positive long taskId,
@PathVariable @Positive long itemId,
@Valid @RequestBody AssignRequest request) {
FirstlegScopeGuard.platform(user);
return ApiResponse.success(service.assignItem(taskId, itemId, request, user.userId(), user.username()));
}
@PostMapping("/tasks/{taskId}/items/{itemId}/pick")
@PreAuthorize("hasAuthority('platform:firstleg:pda:work')")
public ApiResponse<Task> pick(@AuthenticationPrincipal AuthenticatedUser user,
@@ -76,7 +76,7 @@ public final class LoadingPickDtos {
public record PickItem(Long id, Long loadingPlanItemId, Long inboundId, Long inboundDetailId,
Integer plannedPackageCount, Integer pickedPackageCount,
String itemStatus, Integer version, Assignment assignment) {
String itemStatus, Integer version) {
}
public record Assignment(Long assigneeId, String assigneeName, Long assignedBy,
@@ -1,25 +0,0 @@
package com.baiyue.firstleg.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
/** PDA 拣货明细的作业员领取或分配记录。 */
@Getter
@Setter
@TableName("fl_loading_pick_item_assignment")
public class LoadingPickItemAssignmentEntity {
@TableId
private Long pickItemId;
private Long assigneeId;
private String assigneeName;
private Long assignedBy;
private String assignedByName;
private String assignmentType;
private Integer version;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
@@ -1,27 +0,0 @@
package com.baiyue.firstleg.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.LoadingPickItemAssignmentEntity;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
/** 明细级作业员分配,允许同一柜的不同明细并行领取。 */
@Mapper
public interface LoadingPickItemAssignmentMapper extends BaseMapper<LoadingPickItemAssignmentEntity> {
@Insert("INSERT INTO fl_loading_pick_item_assignment "
+ "(pick_item_id,assignee_id,assignee_name,assigned_by,assigned_by_name,assignment_type,version) "
+ "VALUES (#{itemId},#{assigneeId},#{assigneeName},#{operatorId},#{operatorName},#{type},0)")
int create(@Param("itemId") long itemId, @Param("assigneeId") long assigneeId,
@Param("assigneeName") String assigneeName, @Param("operatorId") long operatorId,
@Param("operatorName") String operatorName, @Param("type") String type);
@Update("UPDATE fl_loading_pick_item_assignment SET assignee_id=#{assigneeId},assignee_name=#{assigneeName},"
+ "assigned_by=#{operatorId},assigned_by_name=#{operatorName},assignment_type=#{type},version=version+1 "
+ "WHERE pick_item_id=#{itemId} AND version=#{expectedVersion}")
int reassign(@Param("itemId") long itemId, @Param("assigneeId") long assigneeId,
@Param("assigneeName") String assigneeName, @Param("operatorId") long operatorId,
@Param("operatorName") String operatorName, @Param("type") String type,
@Param("expectedVersion") int expectedVersion);
}
@@ -9,11 +9,9 @@ import com.baiyue.firstleg.entity.LoadingPlanItemEntity;
import com.baiyue.firstleg.mapper.LoadingPickItemMapper;
import com.baiyue.firstleg.mapper.LoadingPickTaskMapper;
import com.baiyue.firstleg.mapper.LoadingPickAssignmentMapper;
import com.baiyue.firstleg.mapper.LoadingPickItemAssignmentMapper;
import com.baiyue.firstleg.mapper.LoadingPickOperationMapper;
import com.baiyue.firstleg.mapper.LoadingPickReviewMapper;
import com.baiyue.firstleg.entity.LoadingPickAssignmentEntity;
import com.baiyue.firstleg.entity.LoadingPickItemAssignmentEntity;
import com.baiyue.firstleg.entity.LoadingPickOperationEntity;
import com.baiyue.firstleg.entity.LoadingPickReviewEntity;
import com.baiyue.firstleg.loading.mapper.InboundLoadingPickTaskMapper;
@@ -35,8 +33,6 @@ public class LoadingPickRepository {
@Resource
private LoadingPickAssignmentMapper assignments;
@Resource
private LoadingPickItemAssignmentMapper itemAssignments;
@Resource
private LoadingPickReviewMapper reviews;
@Resource
private LoadingPickOperationMapper operations;
@@ -169,20 +165,6 @@ public class LoadingPickRepository {
type, expectedVersion);
}
public LoadingPickItemAssignmentEntity itemAssignment(long itemId) {
return itemAssignments.selectById(itemId);
}
public int createItemAssignment(long itemId, long assigneeId, String assigneeName,
long operatorId, String operatorName, String type) {
return itemAssignments.create(itemId, assigneeId, assigneeName, operatorId, operatorName, type);
}
public int reassignItem(long itemId, long assigneeId, String assigneeName, long operatorId,
String operatorName, String type, int expectedVersion) {
return itemAssignments.reassign(itemId, assigneeId, assigneeName, operatorId, operatorName,
type, expectedVersion);
}
public LoadingPickReviewEntity review(long taskId) {
return reviews.selectById(taskId);
@@ -14,7 +14,6 @@ import com.baiyue.firstleg.dto.LoadingPickDtos.AssignRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.ReviewRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.Operation;
import com.baiyue.firstleg.entity.LoadingPickAssignmentEntity;
import com.baiyue.firstleg.entity.LoadingPickItemAssignmentEntity;
import com.baiyue.firstleg.entity.LoadingPickHistoryEntity;
import com.baiyue.firstleg.entity.LoadingPickItemEntity;
import com.baiyue.firstleg.entity.LoadingPickOperationEntity;
@@ -119,38 +118,6 @@ public class LoadingPickService {
return view(task, null);
}
/**
* 领取单条 PDA 明细。柜次任务只是汇总容器,作业所有权必须以明细为粒度,
* 才能让多个仓库人员在同一柜中并行处理不同入库单。
*/
@Transactional
public Task claimItem(long taskId, long itemId, ClaimRequest request, long operatorId, String operatorName) {
String operationId = operation(request.operationId());
String requestHash = hash("ITEM_CLAIM|" + taskId + '|' + itemId + '|'
+ request.expectedAssignmentVersion());
Task replay = replayTaskOperation(taskId, operationId, requestHash, operatorId);
if (replay != null) return replay;
LoadingPickTaskEntity task = requiredLoadingTaskForUpdate(taskId);
LoadingPickItemEntity item = repository.item(taskId, itemId);
requireAssignableItem(item);
LoadingPickItemAssignmentEntity existing = repository.itemAssignment(itemId);
if (existing == null) {
try {
if (request.expectedAssignmentVersion() != 0 || repository.createItemAssignment(itemId, operatorId,
operatorName, operatorId, operatorName, "CLAIMED") != 1) {
throw conflict("PDA拣货明细已被其他作业员领取");
}
} catch (DuplicateKeyException exception) {
throw conflict("PDA拣货明细已被其他作业员领取");
}
} else if (!Long.valueOf(operatorId).equals(existing.getAssigneeId())
|| !request.expectedAssignmentVersion().equals(existing.getVersion())) {
throw conflict("PDA拣货明细已分配给其他作业员或分配版本已变化");
}
insertOperation(taskId, operationId, requestHash, "ITEM_CLAIM", operatorId, operatorName);
return view(task, null);
}
@Transactional
public Task assign(long taskId, AssignRequest request, long operatorId, String operatorName) {
String operationId = operation(request.operationId());
@@ -172,29 +139,6 @@ public class LoadingPickService {
return view(task, null);
}
@Transactional
public Task assignItem(long taskId, long itemId, AssignRequest request, long operatorId, String operatorName) {
String operationId = operation(request.operationId());
String assigneeName = request.assigneeName().trim();
String requestHash = hash("ITEM_ASSIGN|" + taskId + '|' + itemId + '|'
+ request.assigneeId() + '|' + assigneeName + '|' + request.expectedAssignmentVersion());
Task replay = replayTaskOperation(taskId, operationId, requestHash, operatorId);
if (replay != null) return replay;
LoadingPickTaskEntity task = requiredLoadingTaskForUpdate(taskId);
LoadingPickItemEntity item = repository.item(taskId, itemId);
requireAssignableItem(item);
LoadingPickItemAssignmentEntity existing = repository.itemAssignment(itemId);
int changed = existing == null
? request.expectedAssignmentVersion() == 0
? repository.createItemAssignment(itemId, request.assigneeId(), assigneeName, operatorId,
operatorName, "ASSIGNED") : 0
: repository.reassignItem(itemId, request.assigneeId(), assigneeName, operatorId, operatorName,
"ASSIGNED", request.expectedAssignmentVersion());
if (changed != 1) throw conflict("PDA拣货明细分配版本已变化");
insertOperation(taskId, operationId, requestHash, "ITEM_ASSIGN", operatorId, operatorName);
return view(task, null);
}
@Transactional
public Task pick(long taskId, long itemId, PickRequest request, long operatorId, String operatorName) {
ReleaseSelection release = releaseSelection(request.releaseMode(), request.locationIds());
@@ -210,12 +154,11 @@ public class LoadingPickService {
}
return view(requiredTask(taskId), request.warehouseId());
}
LoadingPickTaskEntity task = requiredLoadingTaskForUpdate(taskId);
LoadingPickTaskEntity task = requiredAssignedLoadingTaskForUpdate(taskId, operatorId);
LoadingPickItemEntity item = repository.item(taskId, itemId, request.warehouseId());
if (item == null) {
throw new BizException(ResultCode.NOT_FOUND, "PDA拣货明细不存在");
}
requireItemAssignee(taskId, itemId, operatorId);
if (repository.pick(itemId, request.pickedPackageCount(), release.mode(), release.json(),
request.version(), request.warehouseId()) != 1) {
throw conflict("拣货数量超过计划箱数或明细版本已变化");
@@ -247,9 +190,8 @@ public class LoadingPickService {
assertReplay(replay, taskId, itemId, requestHash);
return view(requiredTask(taskId), request.warehouseId());
}
LoadingPickTaskEntity task = requiredLoadingTaskForUpdate(taskId);
LoadingPickTaskEntity task = requiredAssignedLoadingTaskForUpdate(taskId, operatorId);
requireWarehouseItem(taskId, itemId, request.warehouseId());
requireItemAssignee(taskId, itemId, operatorId);
if (repository.partial(itemId, request.finalPickedPackageCount(), release.mode(), release.json(),
request.version(), request.warehouseId()) != 1) {
throw conflict("部分拣货箱数必须大于已拣箱数且小于计划箱数,或明细版本已变化");
@@ -272,9 +214,8 @@ public class LoadingPickService {
assertReplay(replay, taskId, itemId, requestHash);
return view(requiredTask(taskId), request.warehouseId());
}
LoadingPickTaskEntity task = requiredLoadingTaskForUpdate(taskId);
LoadingPickTaskEntity task = requiredAssignedLoadingTaskForUpdate(taskId, operatorId);
LoadingPickItemEntity item = requireWarehouseItem(taskId, itemId, request.warehouseId());
requireItemAssignee(taskId, itemId, operatorId);
if (repository.hasPickedOrPartialItem(taskId, item.getInboundId())) {
throw conflict("同一入库单已存在已拣或部分拣货明细,不能跳拣并恢复智能装柜候选");
}
@@ -402,27 +343,14 @@ public class LoadingPickService {
return task;
}
private void requireItemAssignee(long taskId, long itemId, long operatorId) {
LoadingPickItemAssignmentEntity assignment = repository.itemAssignment(itemId);
if (assignment != null) {
if (!Long.valueOf(operatorId).equals(assignment.getAssigneeId())) {
throw conflict("PDA拣货明细已分配给其他作业员");
}
return;
}
// 兼容已上线的整柜领取调用;新作业必须走明细领取接口。
LoadingPickAssignmentEntity legacy = repository.assignment(taskId);
if (legacy == null || !Long.valueOf(operatorId).equals(legacy.getAssigneeId())) {
throw conflict("请先领取PDA拣货明细");
}
}
private static void requireAssignableItem(LoadingPickItemEntity item) {
if (item == null) throw new BizException(ResultCode.NOT_FOUND, "PDA拣货明细不存在");
if ("PICKED".equals(item.getItemStatus()) || "PARTIAL".equals(item.getItemStatus())
|| "SKIPPED".equals(item.getItemStatus())) {
throw conflict("已完成或已跳拣的PDA明细不能再领取或改派");
private LoadingPickTaskEntity requiredAssignedLoadingTaskForUpdate(long taskId, long operatorId) {
LoadingPickTaskEntity task = requiredLoadingTaskForUpdate(taskId);
LoadingPickAssignmentEntity assignment = repository.assignment(taskId);
if (assignment == null) throw conflict("请先领取PDA拣货任务");
if (!Long.valueOf(operatorId).equals(assignment.getAssigneeId())) {
throw conflict("PDA拣货任务已分配给其他作业员");
}
return task;
}
private LoadingPickItemEntity requireWarehouseItem(long taskId, long itemId, long warehouseId) {
@@ -436,15 +364,10 @@ public class LoadingPickService {
private Task view(LoadingPickTaskEntity task, Long warehouseId) {
List<LoadingPickItemEntity> source = warehouseId == null
? repository.items(task.getId()) : repository.items(task.getId(), warehouseId);
List<PickItem> items = source.stream().map(item -> {
LoadingPickItemAssignmentEntity assignedItem = repository.itemAssignment(item.getId());
Assignment itemAssignment = assignedItem == null ? null : new Assignment(assignedItem.getAssigneeId(),
assignedItem.getAssigneeName(), assignedItem.getAssignedBy(), assignedItem.getAssignedByName(),
assignedItem.getAssignmentType(), assignedItem.getVersion());
return new PickItem(item.getId(), item.getLoadingPlanItemId(), item.getInboundId(),
List<PickItem> items = source.stream()
.map(item -> new PickItem(item.getId(), item.getLoadingPlanItemId(), item.getInboundId(),
item.getInboundDetailId(), item.getPlannedPackageCount(), item.getPickedPackageCount(),
item.getItemStatus(), item.getVersion(), itemAssignment);
}).toList();
item.getItemStatus(), item.getVersion())).toList();
LoadingPickAssignmentEntity assigned = repository.assignment(task.getId());
LoadingPickReviewEntity reviewed = repository.review(task.getId());
Assignment assignment = assigned == null ? null : new Assignment(assigned.getAssigneeId(),
@@ -452,11 +375,9 @@ public class LoadingPickService {
assigned.getAssignmentType(), assigned.getVersion());
Review review = reviewed == null ? null : new Review(reviewed.getReviewStatus(),
reviewed.getReviewedBy(), reviewed.getReviewedByName(), reviewed.getRemark(), reviewed.getVersion());
boolean hasPickedItem = source.stream().anyMatch(item -> item.getPickedPackageCount() != null
&& item.getPickedPackageCount() > 0);
String workflowStatus = "COMPLETED".equals(task.getTaskStatus()) ? "COMPLETED"
: repository.allTaskItemsResolved(task.getId()) ? "AWAITING_REVIEW"
: hasPickedItem ? "IN_PROGRESS" : "PENDING";
: assigned == null ? "UNASSIGNED"
: repository.allTaskItemsResolved(task.getId()) ? "AWAITING_REVIEW" : "IN_PROGRESS";
return new Task(task.getId(), task.getLoadingPlanId(), task.getContainerNo(), task.getTaskStatus(),
workflowStatus, task.getVersion(), assignment, review, items);
}
@@ -45,25 +45,9 @@ CREATE TABLE IF NOT EXISTS fl_loading_pick_operation (
UNIQUE KEY uk_loading_pick_operation_id (operation_id),
KEY idx_loading_pick_operation_task (pick_task_id, created_at),
CONSTRAINT fk_loading_pick_operation_task FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id),
CONSTRAINT chk_loading_pick_operation_action CHECK (action_type IN ('CLAIM', 'ASSIGN', 'ITEM_CLAIM', 'ITEM_ASSIGN', 'REVIEW'))
CONSTRAINT chk_loading_pick_operation_action CHECK (action_type IN ('CLAIM', 'ASSIGN', 'REVIEW'))
) ENGINE=InnoDB COMMENT='柜次PDA任务级幂等审计';
CREATE TABLE IF NOT EXISTS fl_loading_pick_item_assignment (
pick_item_id BIGINT UNSIGNED NOT NULL,
assignee_id BIGINT UNSIGNED NOT NULL,
assignee_name VARCHAR(64) NOT NULL,
assigned_by BIGINT UNSIGNED NOT NULL,
assigned_by_name VARCHAR(64) NULL,
assignment_type VARCHAR(16) NOT NULL COMMENT 'CLAIMED/ASSIGNED',
version INT UNSIGNED NOT NULL DEFAULT 0,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (pick_item_id),
KEY idx_loading_pick_item_assignee (assignee_id, updated_at),
CONSTRAINT fk_loading_pick_item_assignment_item FOREIGN KEY (pick_item_id) REFERENCES fl_loading_pick_item (id),
CONSTRAINT chk_loading_pick_item_assignment_type CHECK (assignment_type IN ('CLAIMED', 'ASSIGNED'))
) ENGINE=InnoDB COMMENT='PDA拣货明细领取与作业员分配';
DROP TRIGGER IF EXISTS trg_loading_pick_review_before_update;
DELIMITER $$
CREATE TRIGGER trg_loading_pick_review_before_update
@@ -29,24 +29,6 @@ paths:
content: {application/json: {schema: {$ref: '#/components/schemas/AssignRequest'}}}
responses:
'200': {description: Assigned task or A0409 on assignment version conflict}
/api/platform/v1/first-leg/pda-loading/tasks/{taskId}/items/{itemId}/claim:
post:
summary: 领取单条PDA拣货明细;同柜不同明细可由不同仓库人员并行作业
parameters: [{$ref: '#/components/parameters/TaskId'}, {$ref: '#/components/parameters/ItemId'}]
requestBody:
required: true
content: {application/json: {schema: {$ref: '#/components/schemas/ClaimRequest'}}}
responses:
'200': {description: 返回含明细作业员信息的PDA任务}
/api/platform/v1/first-leg/pda-loading/tasks/{taskId}/items/{itemId}/assign:
post:
summary: 将单条PDA拣货明细分配或改派给指定仓库人员
parameters: [{$ref: '#/components/parameters/TaskId'}, {$ref: '#/components/parameters/ItemId'}]
requestBody:
required: true
content: {application/json: {schema: {$ref: '#/components/schemas/AssignRequest'}}}
responses:
'200': {description: 返回含明细作业员信息的PDA任务}
/api/platform/v1/first-leg/pda-loading/tasks/{taskId}/items/{itemId}/pick:
post:
summary: Increment a picked item owned by the authenticated assignee
@@ -16,8 +16,6 @@ class PdaConvergenceOpenApiContractTest {
.contains("/api/platform/v1/first-leg/pda-loading/tasks:")
.contains("/tasks/{taskId}/claim:")
.contains("/tasks/{taskId}/assign:")
.contains("/tasks/{taskId}/items/{itemId}/claim:")
.contains("/tasks/{taskId}/items/{itemId}/assign:")
.contains("/tasks/{taskId}/items/{itemId}/pick:")
.contains("/tasks/{taskId}/items/{itemId}/partial:")
.contains("/tasks/{taskId}/items/{itemId}/skip:")
@@ -18,10 +18,8 @@ class PdaConvergenceSqlContractTest {
.getContentAsString(StandardCharsets.UTF_8);
assertThat(sql)
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_assignment")
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_item_assignment")
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_review")
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_operation")
.contains("'ITEM_CLAIM', 'ITEM_ASSIGN'")
.contains("UNIQUE KEY uk_loading_pick_operation_id")
.contains("trg_loading_pick_review_before_update")
.contains("trg_loading_pick_operation_before_delete")
@@ -3,13 +3,11 @@ package com.baiyue.firstleg.service;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.firstleg.dto.LoadingPickDtos.PartialPickRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.PickRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.ClaimRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.ReviewRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.SkipRequest;
import com.baiyue.firstleg.entity.LoadingPickAssignmentEntity;
import com.baiyue.firstleg.entity.LoadingPickHistoryEntity;
import com.baiyue.firstleg.entity.LoadingPickItemEntity;
import com.baiyue.firstleg.entity.LoadingPickItemAssignmentEntity;
import com.baiyue.firstleg.entity.LoadingPickOperationEntity;
import com.baiyue.firstleg.entity.LoadingPickTaskEntity;
import com.baiyue.firstleg.repository.LoadingPickRepository;
@@ -112,47 +110,6 @@ class LoadingPickServiceTest {
verify(settlementService, never()).settle(20L, 9L, "operator");
}
@Test
void permitsItemAssigneeWithoutCabinetAssignee() {
LoadingPickTaskEntity task = task();
LoadingPickItemEntity item = item();
when(repository.history("item-owner-pick")).thenReturn(null);
when(repository.task(20L)).thenReturn(task);
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.item(20L, 30L, 101L)).thenReturn(item);
when(repository.itemAssignment(30L)).thenReturn(itemAssignment(9L, "operator"));
when(repository.pick(30L, 2, "MANUAL", "[]", 0, 101L)).thenReturn(1);
when(repository.touchTask(20L, 0)).thenReturn(1);
when(repository.items(20L, 101L)).thenReturn(List.of(item));
service.pick(20L, 30L, new PickRequest(101L, 2, List.of(), 0, "item-owner-pick"),
9L, "operator");
}
@Test
void permitsTwoWorkersToClaimDifferentItemsInOneCabinet() {
LoadingPickTaskEntity task = task();
LoadingPickItemEntity first = item();
LoadingPickItemEntity second = item();
second.setId(31L);
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.task(20L)).thenReturn(task);
when(repository.item(20L, 30L)).thenReturn(first);
when(repository.item(20L, 31L)).thenReturn(second);
when(repository.itemAssignment(30L)).thenReturn(null);
when(repository.itemAssignment(31L)).thenReturn(null);
when(repository.createItemAssignment(30L, 9L, "worker-a", 9L, "worker-a", "CLAIMED")).thenReturn(1);
when(repository.createItemAssignment(31L, 10L, "worker-b", 10L, "worker-b", "CLAIMED")).thenReturn(1);
when(repository.items(20L)).thenReturn(List.of(first, second));
service.claimItem(20L, 30L, new ClaimRequest(0, "claim-a"), 9L, "worker-a");
service.claimItem(20L, 31L, new ClaimRequest(0, "claim-b"), 10L, "worker-b");
verify(repository).createItemAssignment(30L, 9L, "worker-a", 9L, "worker-a", "CLAIMED");
verify(repository).createItemAssignment(31L, 10L, "worker-b", 10L, "worker-b", "CLAIMED");
}
@Test
void reviewSettlesResolvedItemsAndCompletesPlan() {
LoadingPickTaskEntity task = task();
@@ -231,12 +188,4 @@ class LoadingPickServiceTest {
return assignment;
}
private static LoadingPickItemAssignmentEntity itemAssignment(long assigneeId, String assigneeName) {
LoadingPickItemAssignmentEntity assignment = new LoadingPickItemAssignmentEntity();
assignment.setPickItemId(30L);
assignment.setAssigneeId(assigneeId);
assignment.setAssigneeName(assigneeName);
assignment.setVersion(0);
return assignment;
}
}