fix:物料批次导入模板及导入

This commit is contained in:
shusir
2026-03-12 18:06:14 +08:00
parent 309c958043
commit c2aa950ad0
9 changed files with 231 additions and 4 deletions

View File

@@ -62,4 +62,11 @@ public interface SupplierService {
*/ */
PageResult<SupplierDO> getSupplierPage(SupplierPageReqVO pageReqVO); PageResult<SupplierDO> getSupplierPage(SupplierPageReqVO pageReqVO);
/**
* 获得供应商列表
*
* @param supplierNames 供应商名称数组
* @return 供应商列表
*/
List<SupplierDO> getSuppliersByNames(List<String> supplierNames);
} }

View File

@@ -1,6 +1,7 @@
package com.zt.plat.module.qms.office.supplier.service; package com.zt.plat.module.qms.office.supplier.service;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zt.plat.module.qms.office.supplier.controller.vo.SupplierExtendRespVO; import com.zt.plat.module.qms.office.supplier.controller.vo.SupplierExtendRespVO;
import com.zt.plat.module.qms.office.supplier.controller.vo.SupplierPageReqVO; import com.zt.plat.module.qms.office.supplier.controller.vo.SupplierPageReqVO;
import com.zt.plat.module.qms.office.supplier.controller.vo.SupplierRespVO; import com.zt.plat.module.qms.office.supplier.controller.vo.SupplierRespVO;
@@ -90,4 +91,11 @@ public class SupplierServiceImpl implements SupplierService {
return supplierMapper.selectPage(pageReqVO); return supplierMapper.selectPage(pageReqVO);
} }
@Override
public List<SupplierDO> getSuppliersByNames(List<String> supplierNames) {
return supplierMapper.selectList(Wrappers.lambdaQuery(SupplierDO.class)
.in(SupplierDO::getName, supplierNames));
}
} }

View File

@@ -1,9 +1,17 @@
package com.zt.plat.module.qms.resource.material.controller.admin; package com.zt.plat.module.qms.resource.material.controller.admin;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.zt.plat.framework.common.util.http.HttpUtils;
import com.zt.plat.framework.datapermission.core.annotation.DeptDataPermissionIgnore; import com.zt.plat.framework.datapermission.core.annotation.DeptDataPermissionIgnore;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchPageReqVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchPageReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchRespVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchRespVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchSaveReqVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchSaveReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.importer.MaterialBatchImportExcelVO;
import com.zt.plat.module.qms.resource.material.controller.vo.resp.MaterialBatchImportRespVO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialBatchDO; import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialBatchDO;
import com.zt.plat.module.qms.resource.material.service.MaterialBatchService; import com.zt.plat.module.qms.resource.material.service.MaterialBatchService;
import com.zt.plat.module.qms.resource.material.valid.AddGroup; import com.zt.plat.module.qms.resource.material.valid.AddGroup;
@@ -20,6 +28,10 @@ import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.*; import jakarta.validation.*;
import jakarta.servlet.http.*; import jakarta.servlet.http.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.io.IOException; import java.io.IOException;
@@ -33,6 +45,8 @@ import static com.zt.plat.framework.common.pojo.CommonResult.success;
import com.zt.plat.framework.excel.core.util.ExcelUtils; import com.zt.plat.framework.excel.core.util.ExcelUtils;
import com.zt.plat.framework.apilog.core.annotation.ApiAccessLog; import com.zt.plat.framework.apilog.core.annotation.ApiAccessLog;
import org.springframework.web.multipart.MultipartFile;
import static com.zt.plat.framework.apilog.core.enums.OperateTypeEnum.*; import static com.zt.plat.framework.apilog.core.enums.OperateTypeEnum.*;
@Tag(name = "管理后台 - 物料批次") @Tag(name = "管理后台 - 物料批次")
@@ -132,4 +146,46 @@ public class MaterialBatchController implements BusinessControllerMarker {
return success(BeanUtils.toBean(list, MaterialBatchRespVO.class)); return success(BeanUtils.toBean(list, MaterialBatchRespVO.class));
} }
@GetMapping("/get-import-template")
@Operation(summary = "获得物料批次导入模板")
public void importTemplate(HttpServletResponse response) throws IOException {
List<MaterialBatchImportExcelVO> samples = Arrays.asList(
MaterialBatchImportExcelVO.builder()
.productName("无水硼砂")
.productCode("W11174909")
.productModelNo("95%")
.supplier("供应商 1")
.manufacturerDate(LocalDate.parse("2026-03-15"))
.dueDate(LocalDate.parse("2026-08-11"))
.inboundQuantity(BigDecimal.valueOf(100))
.location("1 号货架")
.remark("模板数据,导入时请删除!")
.build(),
MaterialBatchImportExcelVO.builder()
.productName("氧化钙")
.productCode("W10102372")
.productModelNo("AR500g/瓶")
.supplier("供应商 2")
.manufacturerDate(LocalDate.parse("2026-04-16"))
.dueDate(LocalDate.parse("2026-09-18"))
.inboundQuantity(BigDecimal.valueOf(200))
.location("2 号货架")
.remark("模板数据,导入时请删除!")
.build()
);
ExcelUtils.write(response, "物料批次导入模板.xls", "物料批次导入",
MaterialBatchImportExcelVO.class, samples);
}
@PostMapping("/import")
@Operation(summary = "导入物料批次")
@Parameter(name = "file", description = "Excel 文件", required = true)
public CommonResult<MaterialBatchImportRespVO> importMaterialBatch(@RequestParam("file") MultipartFile file) throws IOException {
List<MaterialBatchImportExcelVO> importList = ExcelUtils.read(file, MaterialBatchImportExcelVO.class, 0);
MaterialBatchImportRespVO respVO = materialBatchService.importMaterialBatchList(importList);
return success(respVO);
}
} }

View File

@@ -0,0 +1,50 @@
package com.zt.plat.module.qms.resource.material.controller.vo.importer;
import com.alibaba.excel.annotation.ExcelProperty;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 物料批次导入 Request VO")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = false)
public class MaterialBatchImportExcelVO {
@ExcelProperty("物料名称")
private String productName;
@ExcelProperty("物料编码")
private String productCode;
@ExcelProperty("物料型号")
private String productModelNo;
@ExcelProperty("供应商")
private String supplier;
@ExcelProperty("生产日期")
private LocalDate manufacturerDate;
@ExcelProperty("到期日期")
private LocalDate dueDate;
@ExcelProperty("数量")
private BigDecimal inboundQuantity;
@ExcelProperty("存放位置描述")
private String location;
@ExcelProperty("备注")
private String remark;
}

View File

@@ -0,0 +1,24 @@
package com.zt.plat.module.qms.resource.material.controller.vo.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Schema(description = "管理后台 - 物料批次导入 Response VO")
@Data
public class MaterialBatchImportRespVO {
@Schema(description = "导入成功的批次编号列表", requiredMode = Schema.RequiredMode.REQUIRED)
private List<String> successBatchNos;
@Schema(description = "导入失败的批次集合key 为行号或标识value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
private Map<String, String> failureBatches;
@Schema(description = "导入成功的记录数", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer successCount;
@Schema(description = "导入失败的记录数", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer failureCount;
}

View File

@@ -6,6 +6,8 @@ import com.zt.plat.module.qms.enums.LockType;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchPageReqVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchPageReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchRespVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchRespVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchSaveReqVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchSaveReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.importer.MaterialBatchImportExcelVO;
import com.zt.plat.module.qms.resource.material.controller.vo.resp.MaterialBatchImportRespVO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialBatchDO; import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialBatchDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDetailDO; import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDetailDO;
import jakarta.validation.*; import jakarta.validation.*;
@@ -189,4 +191,12 @@ public interface MaterialBatchService {
* @param id 流程id * @param id 流程id
*/ */
void createVerifyBatchAssignsByLfcId(Long id); void createVerifyBatchAssignsByLfcId(Long id);
/**
* 导入物料批次列表
*
* @param importList 导入数据列表
* @return 导入结果
*/
MaterialBatchImportRespVO importMaterialBatchList(List<MaterialBatchImportExcelVO> importList);
} }

View File

@@ -17,12 +17,16 @@ import com.zt.plat.module.qms.core.code.SequenceUtil;
import com.zt.plat.module.qms.core.constant.DataTypeConstant; import com.zt.plat.module.qms.core.constant.DataTypeConstant;
import com.zt.plat.module.qms.enums.AdjustType; import com.zt.plat.module.qms.enums.AdjustType;
import com.zt.plat.module.qms.enums.LockType; import com.zt.plat.module.qms.enums.LockType;
import com.zt.plat.module.qms.office.supplier.dal.dataobject.SupplierDO;
import com.zt.plat.module.qms.office.supplier.service.SupplierService;
import com.zt.plat.module.qms.resource.material.constant.MaterialConstants; import com.zt.plat.module.qms.resource.material.constant.MaterialConstants;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchPageReqVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchPageReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchRespVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchRespVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchSaveReqVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchSaveReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialProductRespVO; import com.zt.plat.module.qms.resource.material.controller.vo.MaterialProductRespVO;
import com.zt.plat.module.qms.resource.material.controller.vo.importer.MaterialBatchImportExcelVO;
import com.zt.plat.module.qms.resource.material.controller.vo.query.MaterialProductQueryVO; import com.zt.plat.module.qms.resource.material.controller.vo.query.MaterialProductQueryVO;
import com.zt.plat.module.qms.resource.material.controller.vo.resp.MaterialBatchImportRespVO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialBatchDO; import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialBatchDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDO; import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDetailDO; import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDetailDO;
@@ -42,10 +46,7 @@ import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Collections; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -74,6 +75,8 @@ public class MaterialBatchServiceImpl implements MaterialBatchService {
private MaterialLifecycleService materialLifecycleService; private MaterialLifecycleService materialLifecycleService;
@Autowired @Autowired
private BpmProcessInstanceApi bpmProcessInstanceApi; private BpmProcessInstanceApi bpmProcessInstanceApi;
@Autowired
private SupplierService supplierService;
@Override @Override
public MaterialBatchRespVO createMaterialBatch(MaterialBatchSaveReqVO createReqVO) { public MaterialBatchRespVO createMaterialBatch(MaterialBatchSaveReqVO createReqVO) {
@@ -519,6 +522,60 @@ public class MaterialBatchServiceImpl implements MaterialBatchService {
materialBatchMapper.insertBatch(gongs); materialBatchMapper.insertBatch(gongs);
} }
@Override
public MaterialBatchImportRespVO importMaterialBatchList(List<MaterialBatchImportExcelVO> importList) {
if (CollUtil.isEmpty(importList)) throw new ServiceException(1_032_160_000, "导入数据不能为空");
log.info("导入数据:{}", importList);
List<String> successBatchNos = new ArrayList<>();
Map<String, String> failureBatches = new LinkedHashMap<>();
// 检验
for (MaterialBatchImportExcelVO batch : importList) {
if (StrUtil.isEmpty(batch.getProductCode())) throw new ServiceException(1_032_160_000, "物料编码不能为空");
if (batch.getInboundQuantity() == null || batch.getInboundQuantity().compareTo(BigDecimal.ZERO) < 0)
throw new ServiceException(1_032_160_000, "批次数量不能小于0");
}
// 获取大类id 每个物料都得校验是否存在
Set<String> pdtCodes = importList.stream().map(MaterialBatchImportExcelVO::getProductCode).collect(Collectors.toSet());
List<MaterialProductDO> products = materialProductService.getProductListByPdtCodes(new ArrayList<>(pdtCodes));
if (CollUtil.isEmpty(products)) throw new ServiceException(1_032_160_000, "未找到对应的物料");
Map<String, MaterialProductDO> productDOMapByCode = products.stream().collect(Collectors.toMap(MaterialProductDO::getCode, Function.identity()));
if (pdtCodes.size() != products.size()) {
List<String> notFoundCodes = new ArrayList<>();
for (String pdtCode : pdtCodes) {
if (!productDOMapByCode.containsKey(pdtCode)) {
notFoundCodes.add(pdtCode);
}
}
if (CollUtil.isNotEmpty(notFoundCodes)) {
throw new ServiceException(1_032_160_000, "未找到以下物料:" + String.join(", ", notFoundCodes));
}
}
// 获取供应商
Set<String> supplierNames = importList.stream().map(MaterialBatchImportExcelVO::getSupplier).filter(Objects::nonNull).collect(Collectors.toSet());
if (CollUtil.isNotEmpty(supplierNames)) {
List<SupplierDO> suppliers = supplierService.getSuppliersByNames(new ArrayList<>(supplierNames));
if (CollUtil.isEmpty(suppliers)) throw new ServiceException(1_032_160_000, "未找到对应的供应商");
Map<String, SupplierDO> supplierDOMapByName = suppliers.stream().collect(Collectors.toMap(SupplierDO::getName, Function.identity()));
if (supplierNames.size() != suppliers.size()) {
List<String> notFoundNames = new ArrayList<>();
for (String supplierName : supplierNames) {
if (!supplierDOMapByName.containsKey(supplierName)) {
notFoundNames.add(supplierName);
}
}
if (CollUtil.isNotEmpty(notFoundNames)) {
throw new ServiceException(1_032_160_000, "未找到以下供应商:" + String.join(", ", notFoundNames));
}
}
}
return new MaterialBatchImportRespVO()
.setSuccessBatchNos(successBatchNos)
.setFailureBatches(failureBatches)
.setSuccessCount(successBatchNos.size())
.setFailureCount(failureBatches.size());
}
private void lockBatchOrGongReturnExchangeCount(LockType lockType, List<MaterialBatchDO> batchOrGongDOS, Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatOrGongId) { private void lockBatchOrGongReturnExchangeCount(LockType lockType, List<MaterialBatchDO> batchOrGongDOS, Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatOrGongId) {
for (MaterialBatchDO batOrGong : batchOrGongDOS) { for (MaterialBatchDO batOrGong : batchOrGongDOS) {
MaterialLifecycleDetailDO detailDO = lifecycleDetailDOMapByBatOrGongId.get(batOrGong.getId()); MaterialLifecycleDetailDO detailDO = lifecycleDetailDOMapByBatOrGongId.get(batOrGong.getId());

View File

@@ -148,4 +148,12 @@ public interface MaterialProductService {
* @return 是否是审核的分类 * @return 是否是审核的分类
*/ */
Boolean checkIsVerifyCategoryByPdtId(Long productId); Boolean checkIsVerifyCategoryByPdtId(Long productId);
/**
* 根据pdtCodes获取大类数据
*
* @param pdtCodes pdtCodes
* @return 物料数据
*/
List<MaterialProductDO> getProductListByPdtCodes(List<String> pdtCodes);
} }

View File

@@ -478,4 +478,11 @@ public class MaterialProductServiceImpl implements MaterialProductService {
return "1".equals(verifyCalibrateFlag); return "1".equals(verifyCalibrateFlag);
} }
@Override
public List<MaterialProductDO> getProductListByPdtCodes(List<String> pdtCodes) {
return materialProductMapper.selectList(Wrappers.lambdaQuery(MaterialProductDO.class)
.in(MaterialProductDO::getCode, pdtCodes));
}
} }