feat: 实现子卷包装关系分组批量保存接口

This commit is contained in:
2026-08-17 21:09:16 +08:00
parent 312c3fe825
commit ad7608e050
4 changed files with 186 additions and 6 deletions

View File

@@ -38,6 +38,14 @@ public class SubPackageRelationController {
@Resource
private SubPackageRelationService subPackageRelationService;
@PostMapping("/batch-create")
@Operation(summary = "批量创建子卷包装关系")
@PreAuthorize("@ss.hasPermission('lms:sub-package-relation:create')")
public CommonResult<SubPackageRelationBatchCreateRespVO> batchCreateSubPackageRelation(
@Valid @RequestBody SubPackageRelationBatchCreateReqVO reqVO) {
return success(subPackageRelationService.batchCreateSubPackageRelation(reqVO));
}
@PostMapping("/create")
@Operation(summary = "创建子卷包装关系")
@PreAuthorize("@ss.hasPermission('lms:sub-package-relation:create')")

View File

@@ -41,8 +41,8 @@ public class SubPackageRelationBatchCreateRespVO {
@Schema(description = "客户端唯一标识")
private String clientKey;
/** 数据行号 */
@Schema(description = "数据行号")
/** 数据行号,从 1 开始 */
@Schema(description = "数据行号,从 1 开始")
private Integer rowIndex;
/** 错误编码 */

View File

@@ -14,6 +14,14 @@ import cn.code.nl.framework.common.pojo.PageParam;
*/
public interface SubPackageRelationService {
/**
* 批量创建子卷包装关系
*
* @param reqVO 批量创建信息
* @return 批量创建结果
*/
SubPackageRelationBatchCreateRespVO batchCreateSubPackageRelation(SubPackageRelationBatchCreateReqVO reqVO);
/**
* 创建子卷包装关系
*

View File

@@ -1,23 +1,25 @@
package cn.code.nl.module.lms.service.subpackagerelation;
import cn.hutool.core.collection.CollUtil;
import cn.code.nl.module.lms.dal.dataobject.boxtype.BoxTypeDO;
import cn.code.nl.module.lms.dal.mysql.boxtype.BoxTypeMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import cn.code.nl.module.lms.controller.admin.subpackagerelation.vo.*;
import cn.code.nl.module.lms.dal.dataobject.subpackagerelation.SubPackageRelationDO;
import cn.code.nl.framework.common.pojo.PageResult;
import cn.code.nl.framework.common.pojo.PageParam;
import cn.code.nl.framework.common.util.object.BeanUtils;
import cn.code.nl.module.lms.dal.mysql.subpackagerelation.SubPackageRelationMapper;
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList;
import static cn.code.nl.framework.common.util.collection.CollectionUtils.diffList;
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.*;
/**
@@ -27,11 +29,161 @@ import static cn.code.nl.module.lms.enums.ErrorCodeConstants.*;
*/
@Service
@Validated
@Slf4j
public class SubPackageRelationServiceImpl implements SubPackageRelationService {
/** 必填字段缺失错误码 */
private static final String REQUIRED_FIELD_MISSING = "REQUIRED_FIELD_MISSING";
/** 木箱类型不存在错误码 */
private static final String BOX_TYPE_NOT_FOUND = "BOX_TYPE_NOT_FOUND";
/** 木箱容量超限错误码 */
private static final String BOX_CAPACITY_EXCEEDED = "BOX_CAPACITY_EXCEEDED";
/** 分组保存失败错误码 */
private static final String GROUP_SAVE_FAILED = "GROUP_SAVE_FAILED";
/** 子卷包装关系数据访问对象 */
@Resource
private SubPackageRelationMapper subPackageRelationMapper;
/** 木箱类型数据访问对象 */
@Resource
private BoxTypeMapper boxTypeMapper;
/** 子卷包装关系分组独立事务保存服务 */
@Resource
private SubPackageRelationBatchSaveService batchSaveService;
/**
* 按木箱唯一码和木箱料号分组批量创建子卷包装关系
*/
@Override
public SubPackageRelationBatchCreateRespVO batchCreateSubPackageRelation(SubPackageRelationBatchCreateReqVO reqVO) {
List<SubPackageRelationBatchCreateRespVO.Failure> failures = new ArrayList<>();
List<BatchItemContext> validItems = new ArrayList<>();
for (int index = 0; index < reqVO.getItems().size(); index++) {
SubPackageRelationBatchCreateItemReqVO item = reqVO.getItems().get(index);
int rowIndex = index + 1;
if (item == null) {
failures.add(buildFailure(null, rowIndex, REQUIRED_FIELD_MISSING, "缺失字段item"));
continue;
}
List<String> missingFields = new ArrayList<>();
if (!StringUtils.hasText(item.getClientKey())) {
missingFields.add("clientKey");
}
if (!StringUtils.hasText(item.getPackageBoxSn())) {
missingFields.add("packageBoxSn");
}
if (!StringUtils.hasText(item.getBoxType())) {
missingFields.add("boxType");
}
if (!StringUtils.hasText(item.getQualityGuaranPeriod())) {
missingFields.add("qualityGuaranPeriod");
}
if (!StringUtils.hasText(item.getDateOfFgInbound())) {
missingFields.add("dateOfFgInbound");
}
if (!StringUtils.hasText(item.getContainerName())) {
missingFields.add("containerName");
}
if (!StringUtils.hasText(item.getStatus())) {
missingFields.add("status");
}
if (!CollUtil.isEmpty(missingFields)) {
failures.add(buildFailure(item.getClientKey(), rowIndex, REQUIRED_FIELD_MISSING,
"缺失字段:" + String.join("", missingFields)));
continue;
}
validItems.add(new BatchItemContext(item, rowIndex));
}
if (CollUtil.isEmpty(validItems)) {
return SubPackageRelationBatchCreateRespVO.builder()
.successCount(0)
.failureCount(failures.size())
.failures(failures)
.build();
}
Set<String> boxTypes = validItems.stream()
.map(context -> context.item().getBoxType())
.collect(Collectors.toCollection(LinkedHashSet::new));
Map<String, BoxTypeDO> boxTypeMap = boxTypeMapper.selectListByBoxTypes(boxTypes).stream()
.collect(Collectors.toMap(BoxTypeDO::getBoxType, Function.identity()));
Map<GroupKey, List<BatchItemContext>> groups = validItems.stream()
.collect(Collectors.groupingBy(context -> new GroupKey(context.item().getPackageBoxSn(),
context.item().getBoxType()), LinkedHashMap::new, Collectors.toList()));
int successCount = 0;
for (Map.Entry<GroupKey, List<BatchItemContext>> entry : groups.entrySet()) {
GroupKey key = entry.getKey();
List<BatchItemContext> group = entry.getValue();
BoxTypeDO boxType = boxTypeMap.get(key.boxType());
if (boxType == null) {
for (BatchItemContext context : group) {
failures.add(buildFailure(context.item().getClientKey(), context.rowIndex(), BOX_TYPE_NOT_FOUND,
"木箱类型 " + key.boxType() + " 不存在"));
}
continue;
}
Long existingCount = subPackageRelationMapper.selectCountByPackageBoxSnAndBoxType(
key.packageBoxSn(), key.boxType());
if (existingCount + group.size() > boxType.getMaxNum()) {
String message = String.format("木箱 %s类型 %s最多容纳 %d 个子卷,已有 %d 个,本次提交 %d 个",
key.packageBoxSn(), key.boxType(), boxType.getMaxNum(), existingCount, group.size());
for (BatchItemContext context : group) {
failures.add(buildFailure(context.item().getClientKey(), context.rowIndex(),
BOX_CAPACITY_EXCEEDED, message));
}
continue;
}
List<SubPackageRelationDO> saveGroup = new ArrayList<>();
for (BatchItemContext context : group) {
SubPackageRelationBatchCreateItemReqVO item = context.item();
SubPackageRelationDO relation = new SubPackageRelationDO();
relation.setPackageBoxSn(item.getPackageBoxSn());
relation.setBoxType(item.getBoxType());
relation.setBoxLength(item.getBoxLength());
relation.setBoxWidth(item.getBoxWidth());
relation.setBoxHigh(item.getBoxHigh());
relation.setQualityGuaranPeriod(item.getQualityGuaranPeriod());
relation.setDateOfFgInbound(item.getDateOfFgInbound());
relation.setContainerName(item.getContainerName());
relation.setStatus(item.getStatus());
saveGroup.add(relation);
}
try {
batchSaveService.saveGroup(saveGroup);
successCount += group.size();
} catch (Exception exception) {
log.error("木箱 {}(类型 {})保存失败", key.packageBoxSn(), key.boxType(), exception);
String message = String.format("木箱 %s类型 %s保存失败", key.packageBoxSn(), key.boxType());
for (BatchItemContext context : group) {
failures.add(buildFailure(context.item().getClientKey(), context.rowIndex(), GROUP_SAVE_FAILED,
message));
}
}
}
return SubPackageRelationBatchCreateRespVO.builder()
.successCount(successCount)
.failureCount(failures.size())
.failures(failures)
.build();
}
/**
* 构建批量创建失败信息
*/
private SubPackageRelationBatchCreateRespVO.Failure buildFailure(String clientKey, int rowIndex,
String errorCode, String message) {
return SubPackageRelationBatchCreateRespVO.Failure.builder()
.clientKey(clientKey)
.rowIndex(rowIndex)
.errorCode(errorCode)
.message(message)
.build();
}
@Override
public Long createSubPackageRelation(SubPackageRelationSaveReqVO createReqVO) {
// 插入
@@ -82,4 +234,16 @@ public class SubPackageRelationServiceImpl implements SubPackageRelationService
return subPackageRelationMapper.selectPage(pageReqVO);
}
/**
* 批量创建数据及其原始行号
*/
private record BatchItemContext(SubPackageRelationBatchCreateItemReqVO item, int rowIndex) {
}
/**
* 子卷包装关系分组键
*/
private record GroupKey(String packageBoxSn, String boxType) {
}
}