diff --git a/youchain-system/src/main/java/com/youchain/basicdata/rest/ImportDataController.java b/youchain-system/src/main/java/com/youchain/basicdata/rest/ImportDataController.java index a060517..3793024 100644 --- a/youchain-system/src/main/java/com/youchain/basicdata/rest/ImportDataController.java +++ b/youchain-system/src/main/java/com/youchain/basicdata/rest/ImportDataController.java @@ -19,56 +19,35 @@ import cn.hutool.poi.excel.ExcelReader; import cn.hutool.poi.excel.ExcelUtil; import com.youchain.annotation.AnonymousAccess; import com.youchain.annotation.Log; -import com.youchain.basicdata.domain.BigItem; -import com.youchain.basicdata.domain.Item; -import com.youchain.basicdata.domain.StockType; -import com.youchain.basicdata.repository.BigItemRepository; -import com.youchain.basicdata.repository.ItemRepository; +import com.youchain.basicdata.service.ImportAsnService; import com.youchain.basicdata.service.ImportDataService; -import com.youchain.basicdata.service.ItemService; -import com.youchain.basicdata.service.StockTypeService; -import com.youchain.basicdata.service.dto.BomAccountQueryCriteria; -import com.youchain.basicdata.service.dto.ItemDto; -import com.youchain.basicdata.service.dto.ItemQueryCriteria; import com.youchain.businessdata.domain.Asn; import com.youchain.businessdata.domain.PickDetail; import com.youchain.businessdata.domain.PickTicket; import com.youchain.businessdata.service.AsnService; import com.youchain.businessdata.service.PickDetailService; import com.youchain.businessdata.service.PickTicketService; -import com.youchain.businessdata.service.dto.AsnDto; import com.youchain.config.FileProperties; import com.youchain.exception.BadRequestException; -import com.youchain.exception.handler.ApiError; import com.youchain.exception.handler.ApiResult; -import com.youchain.modules.system.domain.DictDetail; -import com.youchain.modules.system.service.DictDetailService; -import com.youchain.modules.system.service.dto.DictQueryCriteria; import com.youchain.utils.BizStatus; import com.youchain.utils.CodeUtils; import com.youchain.utils.FileUtil; -import com.youchain.utils.UserUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.HttpServletResponse; import javax.transaction.Transactional; import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; -import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.OK; @@ -84,13 +63,11 @@ import static org.springframework.http.HttpStatus.OK; @RequestMapping("/api/importData") public class ImportDataController { private final FileProperties properties; - private final BigItemRepository bigItemRepository; - private final ItemRepository itemRepository; - private final ImportDataService importDataService; private final AsnService asnService; private final PickTicketService pickTicketService; private final PickDetailService pickDetailService; - private final CodeUtils codeUtils; + private final ImportDataService importDataService; + private final ImportAsnService importAsnService; @Log("导入完成品品番") @ApiOperation("导入完成品品番") @@ -253,9 +230,8 @@ public class ImportDataController { public ResponseEntity importAsn(@RequestParam("file") MultipartFile file, @RequestParam("templateType") String templateType) { log.info("开始导入"); long start = System.currentTimeMillis(); - importDataService.importAsn(file, templateType); + importAsnService.importAsn(file, templateType); log.info("导入结束,耗时:{}ms", (System.currentTimeMillis() - start)); return new ResponseEntity<>(ApiResult.success(OK.value(), "导入成功", null), HttpStatus.OK); - } } \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/ImportAsnService.java b/youchain-system/src/main/java/com/youchain/basicdata/service/ImportAsnService.java new file mode 100644 index 0000000..ce12236 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/ImportAsnService.java @@ -0,0 +1,12 @@ +package com.youchain.basicdata.service; + +import org.springframework.web.multipart.MultipartFile; + +public interface ImportAsnService { + /** + * 批量导入 + * @param file 文件 + * @param templateType 模板类型;1-标准模板;2-大物模板;3-发票箱单模板 + */ + void importAsn(MultipartFile file, String templateType); +} diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/ImportDataService.java b/youchain-system/src/main/java/com/youchain/basicdata/service/ImportDataService.java index 26d350e..af69cae 100644 --- a/youchain-system/src/main/java/com/youchain/basicdata/service/ImportDataService.java +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/ImportDataService.java @@ -56,11 +56,4 @@ public interface ImportDataService { void importCountMoveDetail(Long countId,List> readAll); - - /** - * 入库导入 - * - * @param file 上传文件 - */ - void importAsn(MultipartFile file, String templateType); } \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/impl/ImportAsnServiceImpl.java b/youchain-system/src/main/java/com/youchain/basicdata/service/impl/ImportAsnServiceImpl.java new file mode 100644 index 0000000..d493c2b --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/impl/ImportAsnServiceImpl.java @@ -0,0 +1,346 @@ +package com.youchain.basicdata.service.impl; + +import com.youchain.basicdata.domain.Area; +import com.youchain.basicdata.domain.BillType; +import com.youchain.basicdata.domain.Item; +import com.youchain.basicdata.repository.*; +import com.youchain.basicdata.service.*; +import com.youchain.businessdata.domain.Asn; +import com.youchain.businessdata.domain.AsnDetail; +import com.youchain.businessdata.inputJson.imports.BaseImport; +import com.youchain.businessdata.inputJson.imports.invoicePackingImport; +import com.youchain.businessdata.repository.*; +import com.youchain.businessdata.service.*; +import com.youchain.exception.BadRequestException; +import com.youchain.utils.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.sql.Timestamp; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ImportAsnServiceImpl implements ImportAsnService { + + private final AsnRepository asnRepository; + + private final AsnDetailRepository asnDetailRepository; + + private final BillTypeRepository billTypeRepository; + + private final AreaService areaService; + + private final ItemService itemService; + + private final AsnService asnService; + + @Override + @Transactional(rollbackFor = Exception.class) + public void importAsn(MultipartFile file, String templateType) { + + // 验证模板类型是否正确 + isValidTemplateType(file, templateType); + + // 根据模板类型进行不同的处理 + switch (templateType) { + case "template1": + baseImportTemplate(file); + break; + case "template2": + bigItemTemplate(file); + break; + case "template3": + invoicePackingTemplate(file); + break; + default: + throw new BadRequestException("不支持的模板类型: " + templateType); + } + } + + // 处理标准模板 + @Transactional + public void baseImportTemplate(MultipartFile file) { + // 读取sheet数据 + List dataList = FastExcelUtil.readExcelData(file, BaseImport.class, 0, 1); + + //批量导入 + importAsnData(dataList); + } + + //处理大物模板 + private void bigItemTemplate(MultipartFile file) { + // 获取发票号 + FastExcelCellListener reader = new FastExcelCellListener() + .addTargetCell(5, 55); // invoiceNo + Map cellValues = FastExcelUtil.readExcelCellValues(file, reader); + String invoiceNo = cellValues.get("5-55"); + + // 读取两个sheet的数据 + List sheet1Data = FastExcelUtil.readExcelData(file, BaseImport.class, 0, 21); + List sheet2Data = FastExcelUtil.readExcelData(file, BaseImport.class, 1, 21); + + //大物数据处理 + List dataList = bigItemDataProcess(invoiceNo, sheet1Data, sheet2Data); + + //批量导入数据 + importAsnData(dataList); + + } + + // 处理发票箱单模板 + private void invoicePackingTemplate(MultipartFile file) { + // 获取发票号 + FastExcelCellListener reader = new FastExcelCellListener().addTargetCell(2, 11); // invoiceNo + Map cellValues = FastExcelUtil.readExcelCellValues(file, reader); + String invoiceNo = cellValues.get("2-11"); + + // 读取sheet数据 + List sheetData1 = FastExcelUtil.readExcelData(file, invoicePackingImport.class, 0, 5); + + //发票箱单数据处理 + List dataList = invoicePackingDataProcess(invoiceNo, sheetData1); + + //批量导入 + importAsnData(dataList); + } + + /** + * 处理批量导入 + */ + private void importAsnData(List dataList) { + // TODO: 实现批量导入逻辑 + log.info("处理批量导入,数据条数: {}", dataList.size()); + + //获取文件中所有的托盘号 + List codes = dataList.stream().map(BaseImport::getCNo).collect(Collectors.toList()); + + //验证托盘号 + validateAsn(codes); + + //获取文件中所有的品番 + List itemCodes = dataList.stream().map(BaseImport::getPartNo).collect(Collectors.toList()); + + //验证品番 + Map exitItemMap = validateItem(itemCodes); + + //库区 + Area area = areaService.findByCode(BaseStatus.DEFAULT_AREA); + + //单据类型 + BillType billType = billTypeRepository.findByName(BaseStatus.RK); + + Map asnMap = new HashMap<>(); + List insertToAsn = new ArrayList<>();//批量新增ASN + List insertToAsnDetail = new ArrayList<>();//批量新增asnDetail + for (BaseImport data : dataList) { + String relatedBill1 = data.getInvoiceNo();//发票号 + String propC2 = data.getBoi();//税别 + String po = data.getPoNo();//订单号 + String itemCode = data.getPartNo();//品番 + String remark = data.getDescription();//描述 + Double orderQty = data.getQty();//数量 + String code = data.getCNo();//托盘号 + + //品番 + Item item = exitItemMap.get(itemCode); + + Asn asn; + if (asnMap.containsKey(code)) { + asn = asnMap.get(code); + asn.setOrderQuantity(asn.getOrderQuantity() + orderQty); + } else { + asn = Asn.builder() + .relatedBill1(relatedBill1) + .code(code) + .area(area) + .status(BizStatus.OPEN) + .orderDate(new Timestamp(new Date().getTime())) + .orderQuantity(orderQty) + .billType(billType) + .receivedQuantity(0d) + .putawayQuantity(0d) + .build(); + asnMap.put(code, asn); + insertToAsn.add(asn); + } + + AsnDetail asnDetail = AsnDetail.builder() + .propC2(propC2) + .po(po) + .item(item) + .remark(remark) + .orderQty(orderQty) + .asn(asn) + .status(BizStatus.OPEN) + .receivedQty(0d) + .moveQty(0d) + .putQty(0d) + .weight(0d) + .volume(0d) + .dept(item.getDept()) + .build(); + insertToAsnDetail.add(asnDetail); + } + if (!insertToAsn.isEmpty()) { + asnRepository.saveAll(insertToAsn); + } + if (!insertToAsnDetail.isEmpty()) { + asnDetailRepository.saveAll(insertToAsnDetail); + } + } + + //验证品番 + private Map validateItem(List itemCodes) { + Map exitItemMap = itemService.queryByItemCodesToMap(itemCodes); + if (exitItemMap.isEmpty()) { + throw new BadRequestException(itemCodes + "品番不存在或已失效"); + } + + List existingItemCodes = new ArrayList<>(exitItemMap.keySet()); + + // 获取两个集合的非交集说明品番不存在或失效,直接提示 + List difference = SmartStringUtil.getDifference(itemCodes, existingItemCodes); + + if (CollectionUtils.isNotEmpty(difference)) { + throw new BadRequestException(difference + "品番不存在或已失效"); + } + return exitItemMap; + } + + //验证ASN单号 + private void validateAsn(List codes) { + Map exitAsnMap = asnService.queryByasnCodesToMap(codes); + List existingAsnCodes = new ArrayList<>(exitAsnMap.keySet()); + // 获取两个集合的交集说明ASN重复导入了,直接提示 + List difference = SmartStringUtil.getIntersection(codes, existingAsnCodes); + if (CollectionUtils.isNotEmpty(difference)) { + //去重difference + difference = difference.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()); + throw new BadRequestException(difference + "托盘号已导入,请勿重复导入"); + } + } + + //验证模板是否使用正确 + private void isValidTemplateType(MultipartFile file, String templateType) { + // 根据模板类型进行不同的处理 + if ("template1".equals(templateType)) { + List requiredColumns = Arrays.asList("INVOICE NO.", "BOI", "PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY \n" + "(PCS)", "C/NO."); + List headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 0); + if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) { + throw new BadRequestException("标准导入模板不正确,请确认模板信息"); + } + } else if ("template2".equals(templateType)) { + List requiredColumns = Arrays.asList("BOI", "PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY \n" + "(PCS)"); + List sheet1Headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 20); + if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, sheet1Headers)) { + throw new BadRequestException("大物第1个Sheet目录模板不正确,请确认模板信息"); + } + + List requiredColumns2 = Collections.singletonList("C/NO."); + List sheet2Headers = FastExcelUtil.readHeadContent(file, requiredColumns2, 1, 20); + if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns2, sheet2Headers)) { + throw new BadRequestException("大物第2个Sheet目录模板不正确,请确认模板信息"); + } + + } else if ("template3".equals(templateType)) { + List requiredColumns = Arrays.asList("A-PROS\n" + "CASE NO", "KMT NO. PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY", "JOB NO"); + List headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 4); + if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) { + throw new BadRequestException("发票箱单导入模板不正确,请确认模板信息"); + } + } + } + + //大物数据处理 + private static List bigItemDataProcess(String invoiceNo, List sheet1, List sheet2) { + + //处理sheet1数据 + List sheet1Date = new ArrayList<>(); + for (BaseImport item : sheet1) { + if (item.getBoi().toUpperCase().contains("TOTAL")) { + break; // 不区分大小写 遇到TOTAL则停止添加 + } + sheet1Date.add(item); + } + + //处理sheet2数据 + List sheet2Date = new ArrayList<>(); + + // 用于记录上一个非 null 的 cNo 值 + String lastNonNullCNo = null; + for (BaseImport item : sheet2) { + String currentCNo = item.getCNo(); + + // 先检查是否遇到终止标志 + if (currentCNo != null && currentCNo.toUpperCase().contains("TOTAL")) { + break; + } + + if (currentCNo == null) { + // 处理空值:使用最近的非空值填充 + if (lastNonNullCNo != null) { + item.setCNo(lastNonNullCNo); + } + } else { + // 更新最近的非空值记录 + lastNonNullCNo = currentCNo; + } + + // 统一添加元素到列表(排除TOTAL情况) + sheet2Date.add(item); + } + + if (sheet1Date.size() != sheet2Date.size()) { + throw new BadRequestException("大物模板中数据行数不一致"); + } + + List dataList = new ArrayList<>(); + + for (int i = 0; i < sheet1Date.size(); i++) { + BaseImport t1 = sheet1Date.get(i);//sheet1中的列数据 + + BaseImport t2 = sheet2Date.get(i);//sheet2中的列数据 + + BaseImport baseImport = BaseImport.builder() + .invoiceNo(invoiceNo) + .boi(t1.getBoi()) + .poNo(t1.getPoNo()) + .partNo(t1.getPartNo()) + .description(t1.getDescription()) + .qty(t1.getQty()) + .cNo(t2.getCNo()) + .build(); + dataList.add(baseImport); + + } + return dataList; + } + + //发票箱单数据处理 + private static List invoicePackingDataProcess(String invoiceNo, List sheetData1) { + List dataList = new ArrayList<>(); + for (invoicePackingImport data : sheetData1) { + if (data.getCNo() == null) { + break; + } + BaseImport baseImport = BaseImport.builder() + .invoiceNo(invoiceNo) + .boi(data.getBoi()) + .poNo(data.getPoNo()) + .partNo(data.getPartNo()) + .description(data.getDescription()) + .qty(data.getQty()) + .cNo(data.getCNo()) + .build(); + dataList.add(baseImport); + } + return dataList; + } +} diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/impl/ImportDataServiceImpl.java b/youchain-system/src/main/java/com/youchain/basicdata/service/impl/ImportDataServiceImpl.java index 2ea7de8..0564b3c 100644 --- a/youchain-system/src/main/java/com/youchain/basicdata/service/impl/ImportDataServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/impl/ImportDataServiceImpl.java @@ -15,43 +15,28 @@ */ package com.youchain.basicdata.service.impl; -import cn.hutool.poi.excel.ExcelReader; -import cn.hutool.poi.excel.ExcelUtil; -import cn.idev.excel.FastExcel; -import com.sun.org.apache.xpath.internal.operations.Bool; import com.youchain.basicdata.domain.*; import com.youchain.basicdata.repository.*; import com.youchain.basicdata.service.*; -import com.youchain.basicdata.service.dto.AreaDto; -import com.youchain.basicdata.service.dto.AreaQueryCriteria; import com.youchain.basicdata.service.mapstruct.AreaMapper; import com.youchain.basicdata.service.mapstruct.PointMapper; import com.youchain.businessdata.domain.*; -import com.youchain.businessdata.inputJson.imports.AsnImportForm; +import com.youchain.businessdata.inputJson.imports.BaseImport; import com.youchain.businessdata.repository.*; import com.youchain.businessdata.service.*; import com.youchain.config.FileProperties; import com.youchain.exception.BadRequestException; import com.youchain.modules.system.domain.DictDetail; import com.youchain.modules.system.repository.DictDetailRepository; -import com.youchain.modules.system.repository.DictRepository; import com.youchain.utils.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import javax.persistence.EntityManager; -import javax.persistence.Query; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; import java.sql.Timestamp; import java.util.*; import java.util.stream.Collectors; @@ -431,186 +416,4 @@ public class ImportDataServiceImpl implements ImportDataService { } } } - - @Override - @Transactional(rollbackFor = Exception.class) - public void importAsn(MultipartFile file, String templateType) { - - // 验证模板类型是否有效 - if (!isValidTemplateType(templateType)) { - throw new BadRequestException("无效的模板类型: " + templateType); - } - - List dataList; - try { - dataList = FastExcel.read(file.getInputStream()).head(AsnImportForm.class) - .sheet() - .doReadSync(); - } catch (IOException e) { - throw new BadRequestException("数据格式存在问题,无法读取"); - } - if (CollectionUtils.isEmpty(dataList)) { - throw new BadRequestException("数据为空"); - } - - // 根据模板类型进行不同的处理 - switch (templateType) { - case "template1": - template1Import(dataList); - break; - case "template2": - template2Import(dataList); - break; - case "template3": - template3Import(dataList); - break; - default: - throw new BadRequestException("不支持的模板类型: " + templateType); - } - } - - /** - * 验证模板类型是否有效 - */ - private boolean isValidTemplateType(String templateType) { - return "template1".equals(templateType) || - "template2".equals(templateType) || - "template3".equals(templateType); - } - - /** - * 处理标准导入 - */ - private void template1Import(List dataList) { - // TODO: 实现标准导入逻辑 - log.info("处理标准导入,数据条数: {}", dataList.size()); - - //获取文件中所有的托盘号 - List codes = dataList.stream().map(AsnImportForm::getCNo).collect(Collectors.toList()); - - //验证托盘号 - validateAsn(codes); - - //获取文件中所有的品番 - List itemCodes = dataList.stream().map(AsnImportForm::getPartNo).collect(Collectors.toList()); - - //验证品番 - Map exitItemMap = validateItem(itemCodes); - - //库区 - Area area=areaService.findByCode(BaseStatus.DEFAULT_AREA); - - //单据类型 - BillType billType=billTypeRepository.findByName(BaseStatus.RK); - - Map asnMap = new HashMap<>(); - List insertToAsn=new ArrayList<>();//批量新增ASN - List insertToAsnDetail=new ArrayList<>(); - for (AsnImportForm data : dataList) { - String relatedBill1 = data.getInvoiceNo();//发票号 - String propC2 = data.getBoi();//税别 - String po = data.getPoNo();//订单号 - String itemCode = data.getPartNo();//品番 - String remark = data.getDescription();//描述 - Double orderQty = data.getQty();//数量 - String code = data.getCNo();//托盘号 - - //品番 - Item item=exitItemMap.get(itemCode); - - Asn asn = null; - if (asnMap.containsKey(code)) { - asn=asnMap.get(code); - asn.setOrderQuantity(asn.getOrderQuantity() + orderQty); - }else{ - - asn = Asn.builder() - .relatedBill1(relatedBill1) - .code(code) - .area(area) - .status(BizStatus.OPEN) - .orderDate(new Timestamp(new Date().getTime())) - .orderQuantity(orderQty) - .billType(billType) - .receivedQuantity(0d) - .putawayQuantity(0d) - .build(); - asnMap.put(code, asn); - insertToAsn.add(asn); - } - - AsnDetail asnDetail = AsnDetail.builder() - .propC2(propC2) - .po(po) - .item(item) - .remark( remark) - .orderQty(orderQty) - .asn(asn) - .status(BizStatus.OPEN) - .receivedQty(0d) - .moveQty(0d) - .putQty(0d) - .weight(0d) - .volume(0d) - .dept(item.getDept()) - .build(); - insertToAsnDetail.add(asnDetail); - } - if(!insertToAsn.isEmpty()){ - asnRepository.saveAll(insertToAsn); - } - if(!insertToAsnDetail.isEmpty()){ - asnDetailRepository.saveAll(insertToAsnDetail); - } - } - - /** - * 处理大物导入 - */ - private void template2Import(List dataList) { - // TODO: 实现大物导入逻辑 - log.info("处理大物导入,数据条数: {}", dataList.size()); - // 这里添加大物导入的具体业务逻辑 - } - - /** - * 处理发票箱单导入 - */ - private void template3Import(List dataList) { - // TODO: 实现发票箱单导入逻辑 - log.info("处理发票箱单导入,数据条数: {}", dataList.size()); - // 这里添加发票箱单导入的具体业务逻辑 - } - - //验证品番 - private Map validateItem(List itemCodes) { - Map exitItemMap = itemService.queryByItemCodesToMap(itemCodes); - if (exitItemMap.isEmpty()) { - throw new BadRequestException(itemCodes + "品番不存在或已失效"); - } - - List existingItemCodes = new ArrayList<>(exitItemMap.keySet()); - - // 获取两个集合的非交集说明品番不存在或失效,直接提示 - List difference = SmartStringUtil.getDifference(itemCodes, existingItemCodes); - - if (CollectionUtils.isNotEmpty(difference)) { - throw new BadRequestException(difference + "品番不存在或已失效"); - } - return exitItemMap; - } - - //验证ASN单号 - private void validateAsn(List codes) { - Map exitAsnMap = asnService.queryByasnCodesToMap(codes); - List existingAsnCodes = new ArrayList<>(exitAsnMap.keySet()); - // 获取两个集合的交集说明ASN重复导入了,直接提示 - List difference = SmartStringUtil.getIntersection(codes, existingAsnCodes); - if (CollectionUtils.isNotEmpty(difference)) { - //去重difference - difference = difference.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()); - throw new BadRequestException(difference + "托盘号已导入,请勿重复导入"); - } - } - } \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/AsnImportForm.java b/youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/BaseImport.java similarity index 63% rename from youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/AsnImportForm.java rename to youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/BaseImport.java index ddf32c3..5829305 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/AsnImportForm.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/BaseImport.java @@ -1,10 +1,21 @@ package com.youchain.businessdata.inputJson.imports; import cn.idev.excel.annotation.ExcelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; +/** + * @description: 基础导入 + * @author: youzhi.gao + * @date: 2020-04-01 15:01 + */ @Data -public class AsnImportForm { +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class BaseImport { @ExcelProperty("INVOICE NO.") private String invoiceNo; @@ -20,7 +31,7 @@ public class AsnImportForm { @ExcelProperty("DESCRIPTION") private String description; - @ExcelProperty("Q'TY") + @ExcelProperty("Q'TY \n" +"(PCS)") private Double qty; @ExcelProperty("C/NO.") diff --git a/youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/invoicePackingImport.java b/youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/invoicePackingImport.java new file mode 100644 index 0000000..dca96c6 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/businessdata/inputJson/imports/invoicePackingImport.java @@ -0,0 +1,41 @@ +package com.youchain.businessdata.inputJson.imports; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 发票箱单导入 + * @author: youzhi.gao + * @date: 2020-04-01 15:01 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class invoicePackingImport { + + @ExcelIgnore + private String invoiceNo; + + @ExcelProperty("JOB NO") + private String boi; + + @ExcelProperty("KMT NO. PO&LN NO.") + private String poNo; + + @ExcelProperty("PART NO.") + private String partNo; + + @ExcelProperty("DESCRIPTION") + private String description; + + @ExcelProperty("Q'TY") + private Double qty; + + @ExcelProperty("A-PROS\n" + "CASE NO") + private String cNo; +} diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AsnServiceImpl.java b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AsnServiceImpl.java index 6c2eab1..bbfb23e 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AsnServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AsnServiceImpl.java @@ -15,15 +15,10 @@ */ package com.youchain.businessdata.service.impl; -import cn.idev.excel.FastExcel; import com.google.common.collect.Maps; -import com.youchain.basicdata.domain.Item; import com.youchain.businessdata.domain.Asn; import com.youchain.businessdata.domain.AsnDetail; -import com.youchain.businessdata.inputJson.imports.AsnImportForm; import com.youchain.businessdata.repository.AsnDetailRepository; -import com.youchain.businessdata.service.AsnDetailService; -import com.youchain.exception.BadRequestException; import com.youchain.utils.*; import lombok.RequiredArgsConstructor; import com.youchain.businessdata.repository.AsnRepository; @@ -33,18 +28,12 @@ import com.youchain.businessdata.service.dto.AsnQueryCriteria; import com.youchain.businessdata.service.mapstruct.AsnMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.web.multipart.MultipartFile; -import java.text.SimpleDateFormat; import java.util.*; -import java.io.IOException; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; diff --git a/youchain-system/src/main/java/com/youchain/utils/FastExcelCellListener.java b/youchain-system/src/main/java/com/youchain/utils/FastExcelCellListener.java new file mode 100644 index 0000000..2886b4f --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/utils/FastExcelCellListener.java @@ -0,0 +1,75 @@ +package com.youchain.utils; + +import cn.idev.excel.context.AnalysisContext; +import cn.idev.excel.read.listener.ReadListener; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class FastExcelCellListener implements ReadListener> { + private final Map cellValues = new HashMap<>(); + private final Set targetCells = new HashSet<>(); + private boolean isCellRead = false; + + /** + * 添加目标单元格 + * @param row 行索引(从0开始) + * @param col 列索引(从0开始) + * @return 当前监听器实例,支持链式调用 + */ + public FastExcelCellListener addTargetCell(int row, int col) { + targetCells.add(row + "-" + col); + return this; + } + + @Override + public void invoke(Map data, AnalysisContext context) { + if (isCellRead) { + return; + } + int currentRowIndex = context.readRowHolder().getRowIndex()-1; + + for (String targetCell : targetCells) { + String[] parts = targetCell.split("-"); + int targetRow = Integer.parseInt(parts[0]); + int targetCol = Integer.parseInt(parts[1]); + + if (currentRowIndex == targetRow-1) { + String cellValue = data.get(targetCol-1); + if (cellValue != null) { + cellValues.put(targetCell, cellValue); + } + } + } + + // 检查是否所有目标单元格都已读取 + if (cellValues.size() == targetCells.size()) { + isCellRead = true; + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + // 可根据需要添加逻辑 + } + + /** + * 获取指定单元格的值 + * @param row 行索引(从0开始) + * @param col 列索引(从0开始) + * @return 单元格值 + */ + public String getCellValue(int row, int col) { + return cellValues.get(row + "-" + col); + } + + /** + * 获取所有单元格值 + * @return 所有单元格值的Map + */ + public Map getAllCellValues() { + return new HashMap<>(cellValues); + } +} diff --git a/youchain-system/src/main/java/com/youchain/utils/FastExcelUtil.java b/youchain-system/src/main/java/com/youchain/utils/FastExcelUtil.java index 8b64a89..9a88396 100644 --- a/youchain-system/src/main/java/com/youchain/utils/FastExcelUtil.java +++ b/youchain-system/src/main/java/com/youchain/utils/FastExcelUtil.java @@ -9,18 +9,21 @@ import cn.idev.excel.write.style.HorizontalCellStyleStrategy; import com.youchain.exception.BadRequestException; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.IndexedColors; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.MediaTypeFactory; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; +import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.Collection; -import java.util.List; +import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.ToLongFunction; @@ -98,16 +101,17 @@ public class FastExcelUtil { /** * 大数据导出 - * @param response 响应 - * @param fileName 文件名 - * @param sheetName sheet名称 - * @param head 头 + * + * @param response 响应 + * @param fileName 文件名 + * @param sheetName sheet名称 + * @param head 头 * @param pageQueryFunction 查询方法 - * @param convertFunction 转换方法 - * @param idExtractor id提取方法 - * @param pageSize 每页大小 - * @param 泛型 - * @param 泛型 + * @param convertFunction 转换方法 + * @param idExtractor id提取方法 + * @param pageSize 每页大小 + * @param 泛型 + * @param 泛型 */ public static void batchExportExcel(HttpServletResponse response, String fileName, String sheetName, Class head, BiFunction> pageQueryFunction, Function convertFunction, ToLongFunction idExtractor, int pageSize) { long startTime = System.currentTimeMillis(); @@ -141,4 +145,96 @@ public class FastExcelUtil { } + /** + * 从 Excel 文件中读取指定类型的数据 + * + * @param file 上传的 Excel 文件 + * @param clazz 数据映射的类(如 Template1.class) + * @param 数据类型 + * @return 解析后的数据列表 + */ + public static List readExcelData(MultipartFile file, Class clazz, int sheetNo, int headRowNumber) { + List dataList; + try { + dataList = FastExcel.read(file.getInputStream()).head(clazz) + .sheet(sheetNo) + .headRowNumber(headRowNumber) + .doReadSync(); + } catch (IOException e) { + throw new BadRequestException("数据格式存在问题,无法读取"); + } + if (CollectionUtils.isEmpty(dataList)) { + throw new BadRequestException("数据为空"); + } + return dataList; + } + + /** + * 读取Excel文件中指定位置的单元格值 + * + * @param file Excel文件 + * @param reader 指定行和列 + */ + public static Map readExcelCellValues(MultipartFile file, FastExcelCellListener reader) { + try { + FastExcel.read(file.getInputStream(), reader) + .sheet() + .doReadSync(); + } catch (IOException e) { + throw new BadRequestException("数据格式存在问题,无法读取"); + } + + return reader.getAllCellValues(); + } + + /** + * 读取 Excel 文件头部的所有内容(第一行) + * + * @param inputStream Excel 文件输入流 + * @return 头部内容列表 + */ + public static List readHeadContent(InputStream inputStream, int sheetNo, int headRowNumber) { + List data = FastExcel.read(inputStream) + .sheet(sheetNo) + .headRowNumber(headRowNumber) + .doReadSync(); + // 检查是否有数据 + if (data.isEmpty()) { + throw new BadRequestException("导入模板不正确,请确认模板信息"); + } + Object firstRow = data.get(0); + // 将头部内容转换为字符串列表 + if (firstRow instanceof Map) { + Map rowMap = (Map) firstRow; + return rowMap.values().stream() + .map(value -> value == null ? "" : value.toString()) + .collect(Collectors.toList()); + } else { + throw new BadRequestException("读取Excel头部内容格式异常"); + } + } + + /** + * 验证 Excel 文件头部是否包含指定的列名 + * + * @param requiredColumns 必需的列名列表 + * @return 验证结果,true 表示包含所有必需列 + */ + public static List readHeadContent(MultipartFile file, List requiredColumns, int sheetNo, int headRowNumber) { + if (requiredColumns.isEmpty()) { + return Collections.emptyList(); + } + try { + //判断头部内容是否包含所有必填列 + return readHeadContent(file.getInputStream(), sheetNo, headRowNumber); + } catch (IOException e) { + throw new BadRequestException("数据格式存在问题,无法读取"); + } + } + + private static String readHeadContent(File file, int headRowNumber) { + return ""; + } + + } diff --git a/youchain-system/src/main/java/com/youchain/utils/SmartStringUtil.java b/youchain-system/src/main/java/com/youchain/utils/SmartStringUtil.java index cc53fe8..0e3a336 100644 --- a/youchain-system/src/main/java/com/youchain/utils/SmartStringUtil.java +++ b/youchain-system/src/main/java/com/youchain/utils/SmartStringUtil.java @@ -32,4 +32,9 @@ public class SmartStringUtil { .filter(code -> !existingLocationCodesSet.contains(code)) .collect(Collectors.toList()); } + + public static boolean containsAllIgnoreCase(List requiredColumns, List headers) { + Set headersSet = new HashSet<>(headers); + return headersSet.containsAll(requiredColumns); + } } diff --git a/youchain-system/src/main/resources/config/application.yml b/youchain-system/src/main/resources/config/application.yml index 75f23a5..dd8b83e 100644 --- a/youchain-system/src/main/resources/config/application.yml +++ b/youchain-system/src/main/resources/config/application.yml @@ -27,7 +27,12 @@ spring: properties: hibernate: dialect: org.hibernate.dialect.MySQL5InnoDBDialect - + jdbc: + batch_size: 500 + batch_versioned_data: true + order_inserts: true + order_updates: true + generate_statistics: false redis: #数据库索引