1. 修复主数据的物料信息ZT前缀时,存在层级判断错误的问题

This commit is contained in:
chenbowen
2025-12-15 14:26:03 +08:00
parent 7defbbed90
commit d2471d3d8a
13 changed files with 393 additions and 14 deletions

View File

@@ -91,6 +91,14 @@ public class MaterialHasPropertiesController {
return success(BeanUtils.toBean(pageResult, MaterialHasPropertiesRespVO.class));
}
@PostMapping("/batch-save")
@Operation(summary = "批量保存物料持有属性(全量替换)")
@PreAuthorize("@ss.hasPermission('base:material-has-properties:update')")
public CommonResult<MaterialHasPropertiesBatchSaveRespVO> batchSave(@Valid @RequestBody MaterialHasPropertiesBatchSaveReqVO reqVO) {
MaterialHasPropertiesBatchSaveRespVO resp = materialHasPropertiesService.batchSave(reqVO);
return success(resp);
}
@GetMapping("/export-excel")
@Operation(summary = "导出物料持有属性 Excel")
@PreAuthorize("@ss.hasPermission('base:material-has-properties:export')")

View File

@@ -0,0 +1,32 @@
package com.zt.plat.module.base.controller.admin.materialhasproperties.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "物料持有属性批量保存单项 Request VO")
@Data
public class MaterialHasPropertiesBatchItemReqVO {
@Schema(description = "主键ID", example = "6800")
private Long id;
@Schema(description = "属性ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "8607")
@NotNull(message = "属性ID不能为空")
private Long propertiesId;
@Schema(description = "计量单位ID-默认计量单位", example = "23731")
private Long unitId;
@Schema(description = "属性值", requiredMode = Schema.RequiredMode.REQUIRED)
private String value;
@Schema(description = "是否关键属性-关键属性表示物料唯一性")
private Integer isKey;
@Schema(description = "是否计量定价")
private Integer isMetering;
@Schema(description = "排序号")
private Long sort;
}

View File

@@ -0,0 +1,22 @@
package com.zt.plat.module.base.controller.admin.materialhasproperties.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Schema(description = "管理后台 - 物料持有属性批量保存 Request VO")
@Data
public class MaterialHasPropertiesBatchSaveReqVO {
@Schema(description = "物料信息 ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "物料信息 ID 不能为空")
private Long infomationId;
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
@Valid
private List<MaterialHasPropertiesBatchItemReqVO> properties = new ArrayList<>();
}

View File

@@ -0,0 +1,15 @@
package com.zt.plat.module.base.controller.admin.materialhasproperties.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Schema(description = "管理后台 - 物料持有属性批量保存 Response VO")
@Data
public class MaterialHasPropertiesBatchSaveRespVO {
@Schema(description = "行级错误列表(为空表示全部成功)")
private List<RowValidationErrorVO> rowErrors = new ArrayList<>();
}

View File

@@ -0,0 +1,19 @@
package com.zt.plat.module.base.controller.admin.materialhasproperties.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Schema(description = "行级校验错误信息")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RowValidationErrorVO {
@Schema(description = "错误所在行1 开始)")
private Integer rowIndex;
@Schema(description = "错误提示")
private String message;
}

View File

@@ -65,14 +65,7 @@ public class MaterialInfomationServiceImpl implements MaterialInfomationService
validateMaterialClassForBinding(createReqVO.getClassesId());
MaterialInfomationDO materialInfomation = BeanUtils.toBean(createReqVO, MaterialInfomationDO.class);
materialInfomationMapper.insert(materialInfomation);
if (createReqVO.getClassesId() != null) {
MaterialHasClassesDO relation = MaterialHasClassesDO.builder()
.classesId(createReqVO.getClassesId())
.infomationId(materialInfomation.getId())
.build();
materialHasClassesMapper.insert(relation);
materialInfomation.setClassesId(createReqVO.getClassesId());
}
bindMaterialClassIfAbsent(materialInfomation.getId(), createReqVO.getClassesId());
return CollUtil.getFirst(buildRespList(Collections.singletonList(materialInfomation)));
}
@@ -85,13 +78,27 @@ public class MaterialInfomationServiceImpl implements MaterialInfomationService
materialInfomationMapper.updateById(updateObj);
materialHasClassesMapper.delete(new LambdaUpdateWrapper<MaterialHasClassesDO>()
.eq(MaterialHasClassesDO::getInfomationId, updateReqVO.getId()));
if (updateReqVO.getClassesId() != null) {
MaterialHasClassesDO relation = MaterialHasClassesDO.builder()
.classesId(updateReqVO.getClassesId())
.infomationId(updateReqVO.getId())
.build();
materialHasClassesMapper.insert(relation);
bindMaterialClassIfAbsent(updateReqVO.getId(), updateReqVO.getClassesId());
}
/**
* 绑定物料与分类关系(若已存在则跳过),避免唯一索引冲突
*/
private void bindMaterialClassIfAbsent(Long materialId, Long classesId) {
if (materialId == null || classesId == null) {
return;
}
Long exists = materialHasClassesMapper.selectCount(new LambdaQueryWrapperX<MaterialHasClassesDO>()
.eq(MaterialHasClassesDO::getInfomationId, materialId)
.eq(MaterialHasClassesDO::getClassesId, classesId));
if (exists != null && exists > 0) {
return;
}
MaterialHasClassesDO relation = MaterialHasClassesDO.builder()
.classesId(classesId)
.infomationId(materialId)
.build();
materialHasClassesMapper.insert(relation);
}
@Override

View File

@@ -59,4 +59,11 @@ public interface MaterialHasPropertiesService {
*/
PageResult<MaterialHasPropertiesDO> getMaterialHasPropertiesPage(MaterialHasPropertiesPageReqVO pageReqVO);
/**
* 批量保存物料属性(全量替换指定物料的属性关系)
* @param batchReqVO 请求参数
* @return 行级校验错误(为空表示成功)
*/
MaterialHasPropertiesBatchSaveRespVO batchSave(MaterialHasPropertiesBatchSaveReqVO batchReqVO);
}

View File

@@ -1,6 +1,7 @@
package com.zt.plat.module.base.service.materialhasproperties;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@@ -14,6 +15,7 @@ import com.zt.plat.framework.common.pojo.PageParam;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.base.dal.dao.materialhasproperties.MaterialHasPropertiesMapper;
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.framework.common.util.collection.CollectionUtils.convertList;
@@ -89,4 +91,55 @@ public class MaterialHasPropertiesServiceImpl implements MaterialHasPropertiesSe
return materialHasPropertiesMapper.selectPage(pageReqVO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public MaterialHasPropertiesBatchSaveRespVO batchSave(MaterialHasPropertiesBatchSaveReqVO batchReqVO) {
MaterialHasPropertiesBatchSaveRespVO resp = new MaterialHasPropertiesBatchSaveRespVO();
Long infoId = batchReqVO.getInfomationId();
if (infoId == null) {
resp.getRowErrors().add(new RowValidationErrorVO(0, "物料信息 ID 不能为空"));
return resp;
}
// 全量替换:先删除该物料的已有属性
materialHasPropertiesMapper.delete(new LambdaQueryWrapperX<MaterialHasPropertiesDO>()
.eq(MaterialHasPropertiesDO::getInfomationId, infoId));
List<MaterialHasPropertiesBatchItemReqVO> properties = batchReqVO.getProperties();
if (CollUtil.isEmpty(properties)) {
return resp;
}
// 去重并按提交顺序插入
Set<String> dedupKeys = new LinkedHashSet<>();
for (int i = 0; i < properties.size(); i++) {
MaterialHasPropertiesBatchItemReqVO item = properties.get(i);
String propIdStr = item.getPropertiesId() == null ? null : String.valueOf(item.getPropertiesId());
if (StrUtil.isBlank(propIdStr)) {
resp.getRowErrors().add(new RowValidationErrorVO(i + 1, "属性 ID 不能为空"));
continue;
}
if (StrUtil.isBlank(item.getValue())) {
resp.getRowErrors().add(new RowValidationErrorVO(i + 1, "属性值不能为空"));
continue;
}
String key = propIdStr;
if (!dedupKeys.add(key)) {
// 重复的属性直接跳过后续插入,避免唯一冲突
continue;
}
MaterialHasPropertiesDO entity = MaterialHasPropertiesDO.builder()
.infomationId(infoId)
.propertiesId(item.getPropertiesId())
.unitId(item.getUnitId())
.value(item.getValue())
.isKey(item.getIsKey())
.isMetering(item.getIsMetering())
.sort(item.getSort() == null ? (long) (i + 1) : item.getSort())
.build();
materialHasPropertiesMapper.insert(entity);
}
return resp;
}
}