Bladeren bron

新增
1、出入库导入功能

liangwenxuan 4 maanden geleden
bovenliggende
commit
ec4ff10821

+ 22 - 8
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/MaterialIoController.java

@@ -296,17 +296,31 @@ public class MaterialIoController {
         return success(materialIoService.getInventoryFlow(reqVO));
     }
 
-    @GetMapping("/import-template")
-    @Operation(summary = "下载入库导入模板")
+    @GetMapping("/inbound/import-template")
+    @Operation(summary = "下载入库导入模板")
     @TenantIgnore
-    public void importTemplate(HttpServletResponse response) throws IOException {
-        materialIoService.exportImportTemplate(response);
+    public void inboundImportTemplate(HttpServletResponse response) throws IOException {
+        materialIoService.exportInboundImportTemplate(response);
     }
 
-    @PostMapping("/import")
-    @Operation(summary = "导入出入库数据")
+    @GetMapping("/outbound/import-template")
+    @Operation(summary = "下载出库导入模板")
     @TenantIgnore
-    public CommonResult<ImportResultVO> importMaterialIo(@RequestParam("file") MultipartFile file) {
-        return success(materialIoService.importMaterialIo(file));
+    public void outboundImportTemplate(HttpServletResponse response) throws IOException {
+        materialIoService.exportOutboundImportTemplate(response);
+    }
+
+    @PostMapping("/inbound/import")
+    @Operation(summary = "导入入库数据")
+    @TenantIgnore
+    public CommonResult<ImportResultVO> importInbound(@RequestParam("file") MultipartFile file) throws IOException {
+        return success(materialIoService.importInbound(file));
+    }
+
+    @PostMapping("/outbound/import")
+    @Operation(summary = "导入出库数据")
+    @TenantIgnore
+    public CommonResult<ImportResultVO> importOutbound(@RequestParam("file") MultipartFile file) throws IOException {
+        return success(materialIoService.importOutbound(file));
     }
 }

+ 21 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/MarkSupportElderlyBillsPaidReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 标记供养长者账单为已缴费 Request VO")
+@Data
+public class MarkSupportElderlyBillsPaidReqVO {
+
+    @Schema(description = "账单月,格式:yyyy-MM", required = true)
+    @NotBlank(message = "账单月不能为空")
+    private String billingMonth;
+
+    @Schema(description = "机构id", required = true)
+    @NotNull(message = "机构id不能为空")
+    private Long tenantId;
+}
+

+ 2 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/MaterialIoService.java

@@ -84,8 +84,8 @@ public interface MaterialIoService {
 
     void exportOutboundImportTemplate(HttpServletResponse response) throws IOException;
 
-    ImportResultVO importInbound(MultipartFile file);
+    ImportResultVO importInbound(MultipartFile file) throws IOException;
 
-    ImportResultVO importOutbound(MultipartFile file);
+    ImportResultVO importOutbound(MultipartFile file) throws IOException;
 
 }

+ 125 - 46
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/MaterialIoServiceImpl.java

@@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ImportResultVO;
-import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.MaterialIoImportExcelVO;
 import cn.iocoder.yudao.module.system.util.ImportUtil;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.MaterialInBalanceListReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.MaterialInBalanceRespVO;
@@ -2322,76 +2321,155 @@ public class MaterialIoServiceImpl implements MaterialIoService {
     }
 
     @Override
-    public void exportImportTemplate(HttpServletResponse response) throws IOException {
-        ExcelUtils.write(response, "物资出入库导入模板.xlsx", "模板", MaterialIoImportExcelVO.class, Collections.emptyList());
+    public void exportInboundImportTemplate(HttpServletResponse response) throws IOException {
+        ExcelUtils.write(response, "物资入库导入模板.xlsx", "模板", MaterialInboundImportExcelVO.class, Collections.emptyList());
+    }
+
+    @Override
+    public void exportOutboundImportTemplate(HttpServletResponse response) throws IOException {
+        ExcelUtils.write(response, "物资出库导入模板.xlsx", "模板", MaterialOutboundImportExcelVO.class, Collections.emptyList());
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public ImportResultVO importMaterialIo(MultipartFile file) {
-        List<MaterialIoImportExcelVO> rows = ExcelUtils.read(file, MaterialIoImportExcelVO.class);
+    public ImportResultVO importInbound(MultipartFile file) throws IOException {
+        List<MaterialInboundImportExcelVO> rows = ExcelUtils.read(file, MaterialInboundImportExcelVO.class);
         int success = 0;
-        int rowNum = 1;
         List<ImportResultVO.RowError> failures = new ArrayList<>();
+        Map<String, List<MaterialInboundImportExcelVO>> grouped = new LinkedHashMap<>();
 
-        for (MaterialIoImportExcelVO row : rows) {
+        int rowNum = 1;
+        for (MaterialInboundImportExcelVO row : rows) {
             rowNum++;
+            if (StringUtils.isBlank(row.getOrderNo())) {
+                ImportUtil.addFailure(failures, rowNum, null, row.getMaterialId() == null ? null : String.valueOf(row.getMaterialId()), "单据号不能为空");
+                continue;
+            }
+            grouped.computeIfAbsent(row.getOrderNo().trim(), k -> new ArrayList<>()).add(row);
+        }
+
+        for (Map.Entry<String, List<MaterialInboundImportExcelVO>> entry : grouped.entrySet()) {
             try {
-                MaterialIoOrderSaveReqVO reqVO = buildImportReq(row);
-                if ("IN".equalsIgnoreCase(reqVO.getBizType())) {
-                    inbound(reqVO);
-                } else if ("OUT".equalsIgnoreCase(reqVO.getBizType())) {
-                    outbound(reqVO);
-                } else {
-                    throw new IllegalArgumentException("业务类型仅支持 IN 或 OUT");
-                }
+                inbound(buildInboundReq(entry.getValue()));
                 success++;
             } catch (Exception e) {
-                ImportUtil.addFailure(failures, rowNum, null,
-                        row.getMaterialId() == null ? null : String.valueOf(row.getMaterialId()),
-                        e.getMessage(), e);
+                ImportUtil.addFailure(failures, null, null, entry.getKey(), e.getMessage(), e);
             }
         }
         return ImportUtil.buildResult(success, failures);
     }
 
-    private MaterialIoOrderSaveReqVO buildImportReq(MaterialIoImportExcelVO row) {
-        if (row.getBizType() == null) {
-            throw new IllegalArgumentException("业务类型不能为空");
-        }
-        if (row.getOrderDate() == null) {
-            throw new IllegalArgumentException("单据日期不能为空");
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public ImportResultVO importOutbound(MultipartFile file) throws IOException {
+        List<MaterialOutboundImportExcelVO> rows = ExcelUtils.read(file, MaterialOutboundImportExcelVO.class);
+        int success = 0;
+        List<ImportResultVO.RowError> failures = new ArrayList<>();
+        Map<String, List<MaterialOutboundImportExcelVO>> grouped = new LinkedHashMap<>();
+
+        int rowNum = 1;
+        for (MaterialOutboundImportExcelVO row : rows) {
+            rowNum++;
+            if (StringUtils.isBlank(row.getOrderNo())) {
+                ImportUtil.addFailure(failures, rowNum, null, row.getMaterialId() == null ? null : String.valueOf(row.getMaterialId()), "单据号不能为空");
+                continue;
+            }
+            grouped.computeIfAbsent(row.getOrderNo().trim(), k -> new ArrayList<>()).add(row);
         }
-        if (row.getMaterialId() == null) {
-            throw new IllegalArgumentException("物资ID不能为空");
+
+        for (Map.Entry<String, List<MaterialOutboundImportExcelVO>> entry : grouped.entrySet()) {
+            try {
+                outbound(buildOutboundReq(entry.getValue()));
+                success++;
+            } catch (Exception e) {
+                ImportUtil.addFailure(failures, null, null, entry.getKey(), e.getMessage(), e);
+            }
         }
-        if (row.getQuantity() == null || row.getQuantity() <= 0) {
-            throw new IllegalArgumentException("数量必须大于0");
+        return ImportUtil.buildResult(success, failures);
+    }
+
+    private MaterialIoOrderSaveReqVO buildInboundReq(List<MaterialInboundImportExcelVO> groupRows) {
+        MaterialInboundImportExcelVO head = groupRows.get(0);
+        if (head.getOrderDate() == null) {
+            throw new IllegalArgumentException("单据日期不能为空");
         }
+        MaterialIoOrderSaveReqVO reqVO = new MaterialIoOrderSaveReqVO();
+        reqVO.setBizType("IN");
+        reqVO.setOrderDate(head.getOrderDate());
+        reqVO.setRemark(head.getRemark());
+        reqVO.setTenantId(TenantContextHolder.getTenantId());
 
-        MaterialIoOrderItemSaveReqVO item = new MaterialIoOrderItemSaveReqVO();
-        item.setMaterialId(row.getMaterialId());
-        item.setInboundItemId(row.getInboundItemId());
-        item.setRefInStoreId(row.getRefInStoreId());
-        item.setQuantity(row.getQuantity());
-        item.setInUnitPrice(row.getInUnitPrice());
-        item.setSaleUnitPrice(row.getSaleUnitPrice());
-        item.setAmount(row.getAmount());
-        item.setProduceDate(row.getProduceDate());
+        List<MaterialIoOrderItemSaveReqVO> items = new ArrayList<>();
+        for (MaterialInboundImportExcelVO row : groupRows) {
+            if (!Objects.equals(head.getOrderDate(), row.getOrderDate())) {
+                throw new IllegalArgumentException("同单号的单据日期必须一致");
+            }
+            if (!Objects.equals(StringUtils.trimToEmpty(head.getRemark()), StringUtils.trimToEmpty(row.getRemark()))) {
+                throw new IllegalArgumentException("同单号的备注必须一致");
+            }
+            if (row.getMaterialId() == null || row.getQuantity() == null || row.getQuantity() <= 0) {
+                throw new IllegalArgumentException("入库明细物资ID与数量必须填写且数量大于0");
+            }
+            MaterialIoOrderItemSaveReqVO item = new MaterialIoOrderItemSaveReqVO();
+            item.setMaterialId(row.getMaterialId());
+            item.setRefInStoreId(row.getRefInStoreId());
+            item.setQuantity(row.getQuantity());
+            item.setInUnitPrice(row.getInUnitPrice());
+            item.setAmount(row.getAmount());
+            item.setProduceDate(row.getProduceDate());
+            items.add(item);
+        }
+        reqVO.setItems(items);
+        return reqVO;
+    }
 
+    private MaterialIoOrderSaveReqVO buildOutboundReq(List<MaterialOutboundImportExcelVO> groupRows) {
+        MaterialOutboundImportExcelVO head = groupRows.get(0);
+        if (head.getOrderDate() == null) {
+            throw new IllegalArgumentException("单据日期不能为空");
+        }
+        if (head.getOutDeptId() == null) {
+            throw new IllegalArgumentException("领用部门ID不能为空");
+        }
         MaterialIoOrderSaveReqVO reqVO = new MaterialIoOrderSaveReqVO();
-        reqVO.setBizType(row.getBizType().trim().toUpperCase());
-        reqVO.setOrderDate(row.getOrderDate());
-        reqVO.setRemark(row.getRemark());
-        reqVO.setOutDeptId(row.getOutDeptId());
-        reqVO.setOutUser(row.getOutUser());
-        reqVO.setOutReason(row.getOutReason());
+        reqVO.setBizType("OUT");
+        reqVO.setOrderDate(head.getOrderDate());
+        reqVO.setOutDeptId(head.getOutDeptId());
+        reqVO.setOutUser(head.getOutUser());
+        reqVO.setOutReason(head.getOutReason());
+        reqVO.setRemark(head.getRemark());
         reqVO.setTenantId(TenantContextHolder.getTenantId());
-        reqVO.setItems(Collections.singletonList(item));
 
-        if ("OUT".equals(reqVO.getBizType()) && row.getInboundItemId() == null) {
-            throw new IllegalArgumentException("出库导入时,入库批次明细ID不能为空");
+        List<MaterialIoOrderItemSaveReqVO> items = new ArrayList<>();
+        for (MaterialOutboundImportExcelVO row : groupRows) {
+            if (!Objects.equals(head.getOrderDate(), row.getOrderDate())) {
+                throw new IllegalArgumentException("同单号的单据日期必须一致");
+            }
+            if (!Objects.equals(head.getOutDeptId(), row.getOutDeptId())) {
+                throw new IllegalArgumentException("同单号的领用部门ID必须一致");
+            }
+            if (!Objects.equals(StringUtils.trimToEmpty(head.getOutUser()), StringUtils.trimToEmpty(row.getOutUser()))) {
+                throw new IllegalArgumentException("同单号的领用人必须一致");
+            }
+            if (!Objects.equals(StringUtils.trimToEmpty(head.getOutReason()), StringUtils.trimToEmpty(row.getOutReason()))) {
+                throw new IllegalArgumentException("同单号的出库原因必须一致");
+            }
+            if (!Objects.equals(StringUtils.trimToEmpty(head.getRemark()), StringUtils.trimToEmpty(row.getRemark()))) {
+                throw new IllegalArgumentException("同单号的备注必须一致");
+            }
+            if (row.getMaterialId() == null || row.getInboundItemId() == null || row.getQuantity() == null || row.getQuantity() <= 0) {
+                throw new IllegalArgumentException("出库明细物资ID、入库批次明细ID、数量必须填写且数量大于0");
+            }
+            MaterialIoOrderItemSaveReqVO item = new MaterialIoOrderItemSaveReqVO();
+            item.setMaterialId(row.getMaterialId());
+            item.setInboundItemId(row.getInboundItemId());
+            item.setQuantity(row.getQuantity());
+            item.setSaleUnitPrice(row.getSaleUnitPrice());
+            item.setAmount(row.getAmount());
+            item.setProduceDate(row.getProduceDate());
+            items.add(item);
         }
+        reqVO.setItems(items);
         return reqVO;
     }
 
@@ -2427,3 +2505,4 @@ public class MaterialIoServiceImpl implements MaterialIoService {
 
 }
 
+