fix(firstleg): cancel coload groups by inbound code
This commit is contained in:
+6
-7
@@ -6,7 +6,7 @@ import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.BusinessSummary;
|
||||
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.CancelRequest;
|
||||
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.CancelByInboundCodeRequest;
|
||||
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.CreateRequest;
|
||||
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.GroupSnapshot;
|
||||
import com.baiyue.firstleg.loading.coload.service.ColoadGroupService;
|
||||
@@ -15,7 +15,6 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
@@ -52,19 +51,19 @@ public class PlatformColoadGroupController {
|
||||
user.userId(), user.username()));
|
||||
}
|
||||
|
||||
@PostMapping("/{groupId}/cancel")
|
||||
@PostMapping("/by-inbound-code/{inboundCode}/cancel")
|
||||
@PreAuthorize("hasAuthority('platform:firstleg:smart-loading:assign')")
|
||||
@BusinessAudit(event = "COLOAD_GROUP_CANCEL", resourceType = "COLOAD_GROUP",
|
||||
resourceId = "#groupId", description = "整组取消同柜不可拆组")
|
||||
resourceId = "#inboundCode", description = "按入仓码整组取消同柜不可拆组")
|
||||
@Operation(summary = "整组取消同柜不可拆组",
|
||||
description = "仅 ACTIVE 组允许取消;不提供单成员编辑,修改成员必须取消后重建。")
|
||||
public ApiResponse<GroupSnapshot> cancel(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@PathVariable @Min(1) long groupId,
|
||||
@PathVariable @Size(min = 1, max = 40) String inboundCode,
|
||||
@RequestHeader("Idempotency-Key") String idempotencyKey,
|
||||
@Valid @RequestBody CancelRequest request) {
|
||||
@Valid @RequestBody CancelByInboundCodeRequest request) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.cancel(groupId, request.expectedVersion(), request.reason(),
|
||||
return ApiResponse.success(service.cancelByInboundCode(inboundCode, request.reason(),
|
||||
idempotencyKey, user.userId(), user.username()));
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -18,8 +18,7 @@ public final class ColoadGroupModels {
|
||||
) {
|
||||
}
|
||||
|
||||
public record CancelRequest(
|
||||
@NotNull @Min(0) Integer expectedVersion,
|
||||
public record CancelByInboundCodeRequest(
|
||||
@Size(max = 500) String reason
|
||||
) {
|
||||
}
|
||||
|
||||
+35
-11
@@ -65,25 +65,30 @@ public class ColoadGroupService implements ColoadGroupAssignmentPort {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public GroupSnapshot cancel(long groupId, int expectedVersion, String reason,
|
||||
String idempotencyKey, long operatorId, String operatorName) {
|
||||
if (groupId <= 0 || expectedVersion < 0) throw badRequest("组ID或版本不合法");
|
||||
public GroupSnapshot cancelByInboundCode(String inboundCode, String reason,
|
||||
String idempotencyKey, long operatorId,
|
||||
String operatorName) {
|
||||
String code = normalizedInboundCode(inboundCode);
|
||||
String key = key(idempotencyKey);
|
||||
String normalizedReason = trim(reason);
|
||||
String requestHash = sha256("CANCEL|" + groupId + '|' + expectedVersion + '|'
|
||||
String requestHash = sha256("CANCEL_BY_INBOUND_CODE|" + code + '|'
|
||||
+ Objects.toString(normalizedReason, ""));
|
||||
CommandClaim claim = claim(operatorId, "CANCEL", key, requestHash);
|
||||
if (claim.replayGroupId() != null) return requiredSnapshot(claim.replayGroupId());
|
||||
|
||||
long groupId = requiredCurrentGroupId(code);
|
||||
GroupRow group = requiredLocked(groupId);
|
||||
if (!"ACTIVE".equals(group.getGroupStatus())) {
|
||||
throw conflict("只有未锁定的同柜不可拆组可以整组取消");
|
||||
}
|
||||
if (!Objects.equals(group.getVersion(), expectedVersion)
|
||||
|| mapper.cancel(groupId, expectedVersion, operatorId, trim(operatorName)) != 1) {
|
||||
GroupSnapshot before = snapshot(group);
|
||||
int expectedVersion = group.getVersion();
|
||||
if (mapper.cancel(groupId, expectedVersion, operatorId, trim(operatorName)) != 1) {
|
||||
throw conflict("组版本已变化,请刷新后重试");
|
||||
}
|
||||
mapper.closeMembers(groupId);
|
||||
if (mapper.closeMembers(groupId) != before.members().size()) {
|
||||
throw conflict("同柜不可拆组成员状态已变化,请刷新后重试");
|
||||
}
|
||||
history(groupId, "CANCEL", "ACTIVE", "CANCELLED", null, key,
|
||||
normalizedReason, operatorId, operatorName);
|
||||
complete(claim.commandId(), groupId);
|
||||
@@ -92,8 +97,7 @@ public class ColoadGroupService implements ColoadGroupAssignmentPort {
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public BusinessSummary queryByInboundCode(String inboundCode) {
|
||||
String code = trim(inboundCode);
|
||||
if (code == null || code.length() > 40) throw badRequest("inboundCode不能为空且不能超过40字符");
|
||||
String code = normalizedInboundCode(inboundCode);
|
||||
var groups = mapper.groupsByInboundCode(code).stream()
|
||||
.filter(row -> row.getGroupId() != null && CURRENT_GROUP_STATUSES.contains(row.getGroupStatus()))
|
||||
.toList();
|
||||
@@ -118,6 +122,24 @@ public class ColoadGroupService implements ColoadGroupAssignmentPort {
|
||||
return new BusinessSummary(status, members.size(), members);
|
||||
}
|
||||
|
||||
private long requiredCurrentGroupId(String inboundCode) {
|
||||
var groups = mapper.groupsByInboundCode(inboundCode).stream()
|
||||
.filter(row -> row.getGroupId() != null && CURRENT_GROUP_STATUSES.contains(row.getGroupStatus()))
|
||||
.toList();
|
||||
long distinctGroups = groups.stream().map(row -> row.getGroupId()).distinct().limit(2).count();
|
||||
if (distinctGroups == 0) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "入仓码未关联有效同柜不可拆组");
|
||||
}
|
||||
if (distinctGroups > 1) throw conflict("入仓码关联多个有效同柜不可拆组");
|
||||
return groups.get(0).getGroupId();
|
||||
}
|
||||
|
||||
private static String normalizedInboundCode(String inboundCode) {
|
||||
String code = trim(inboundCode);
|
||||
if (code == null || code.length() > 40) throw badRequest("inboundCode不能为空且不能超过40字符");
|
||||
return code;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<InternalOrderGroupInfo> queryInternalByOrderIds(List<Long> requestedOrderIds) {
|
||||
List<Long> orderIds = normalizedOrderIds(requestedOrderIds, 1, 200);
|
||||
@@ -331,8 +353,10 @@ public class ColoadGroupService implements ColoadGroupAssignmentPort {
|
||||
|
||||
private void history(long groupId, String action, String fromStatus, String toStatus, Long planId,
|
||||
String operationId, String remark, long operatorId, String operatorName) {
|
||||
mapper.insertHistory(IdWorker.getId(), groupId, action, fromStatus, toStatus, planId,
|
||||
operationId, trim(remark), operatorId, trim(operatorName));
|
||||
if (mapper.insertHistory(IdWorker.getId(), groupId, action, fromStatus, toStatus, planId,
|
||||
operationId, trim(remark), operatorId, trim(operatorName)) != 1) {
|
||||
throw conflict("同柜不可拆组审计历史写入冲突");
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Long> normalizedOrderIds(List<Long> source, int minimum, int maximum) {
|
||||
|
||||
Reference in New Issue
Block a user