Browse Source

装箱导入

java8
han\hanst 3 weeks ago
parent
commit
c7205682b9
  1. 321
      src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelServiceImpl.java
  2. BIN
      src/main/resources/templates/packing-template.xlsx

321
src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelServiceImpl.java

@ -1357,103 +1357,210 @@ public class CoDelExcelServiceImpl implements CoDelExcelService {
deleteEmptyRow(sheet);
// 获取行数
int rows = sheet.getPhysicalNumberOfRows();
// 遍历每一行从第二行开始
int groupSeqNo = 0;
BigDecimal boxQty = BigDecimal.ZERO;
BigDecimal grossWeight = BigDecimal.ZERO;
BigDecimal netWeight = BigDecimal.ZERO;
// 根据图片分析Excel列位置
// 列A (索引0): 序号 (itemNo) - 对应发货通知单明细的序号
// 列B (索引1): 箱数 (boxQty) - 需要检测是否合并来判断是否合箱
// 列C (索引2): SKU/PN
// 列D (索引3): SO
// 列E (索引4): 数量 (qty)
// 列F (索引5): 卷数 (rolls)
// 列G (索引6): 毛重 (grossWeight)
// 列H (索引7): 发票号 (invoice)
// 遍历每一行从第二行开始第一行是表头
int groupSeqNo = 0; // 箱子的组号
for (int j = 1; j < rows; j++) {
// 创建对象
EcssCoDelPalletData excelData = new EcssCoDelPalletData();
// 获得该行
XSSFRow row = sheet.getRow(j);
if (row.getCell(1) != null && !inData.getCmcInvoice().equals(row.getCell(1).getStringCellValue())) {
if (row == null) {
continue;
}
if (row.getCell(6) == null) {
throw new RuntimeException("第" + j + "行的PN不能为空!");
// 验证发票号是否匹配列H索引7
if (row.getCell(7) != null && !inData.getCmcInvoice().equals(getStringCellValue(row, 7))) {
continue;
}
// 验证必填字段
if (row.getCell(0) == null) {
throw new RuntimeException("第" + (j + 1) + "行的序号不能为空!");
}
if (row.getCell(7) == null) {
throw new RuntimeException("第" + j + "行的数量不能为空!");
if (row.getCell(2) == null) {
throw new RuntimeException("第" + (j + 1) + "行的SKU/PN不能为空!");
}
if (row.getCell(4) == null) {
throw new RuntimeException("第" + (j + 1) + "行的数量不能为空!");
}
// 创建对象
EcssCoDelPalletData excelData = new EcssCoDelPalletData();
// 为对象赋值
excelData.setSite(inData.getSite()); // site
excelData.setBuNo(inData.getBuNo()); // bu
excelData.setSite(inData.getSite());
excelData.setBuNo(inData.getBuNo());
excelData.setDelNo(inData.getDelNo());
excelData.setPoNo(getStringCellValue(row, 5));
excelData.setPn(getStringCellValue(row, 6));
List<PartData> parts = coDelMapper.getPartNo(excelData.getSite(), excelData.getPn(),currentUser.getUsername(),inData.getBuNo());
if (parts.isEmpty()) {
throw new RuntimeException("导入失败:物料:" + excelData.getPn() + "不存在!");
// 读取序号对应发货通知单明细的itemNo
Integer notifyDetailItemNo = getIntegerCellValue(row, 0);
excelData.setNotifyDetailItemNo(notifyDetailItemNo);
// 读取SKU/PN
excelData.setPn(getStringCellValue(row, 2));
// 读取SO
//excelData.setPoNo(getStringCellValue(row, 3));
// 读取数量
excelData.setQty(getNumericCellValueOrDefault(row, 4, "数量"));
// 读取箱数列B索引1- 用于判断是否合箱
BigDecimal boxQty = getNumericCellValueOrDefault(row, 1);
// 读取卷数列F索引5
BigDecimal rolls = getNumericCellValueOrDefault(row, 5);
// 读取毛重列G索引6
BigDecimal grossWeight = getNumericCellValueOrDefault(row, 6);
// 验证合并单元格的一致性如果箱数列合并卷数和毛重列也必须合并
boolean boxQtyMerged = isCellInMergedRegion(sheet, j, 1);
boolean rollsMerged = isCellInMergedRegion(sheet, j, 5);
boolean grossWeightMerged = isCellInMergedRegion(sheet, j, 6);
if (boxQtyMerged != rollsMerged || boxQtyMerged != grossWeightMerged) {
throw new RuntimeException("第" + (j + 1) + "行错误:箱数、卷数、毛重列的合并状态必须一致!" +
"箱数列" + (boxQtyMerged ? "已合并" : "未合并") +
",卷数列" + (rollsMerged ? "已合并" : "未合并") +
",毛重列" + (grossWeightMerged ? "已合并" : "未合并"));
}
excelData.setPartNo(parts.get(0).getPartNo());
excelData.setQty(getNumericCellValueOrDefault(row, 7, "Qty (pcs)"));
excelData.setBoxQty(getNumericCellValueOrDefault(row, 2));
excelData.setRolls(getNumericCellValueOrDefault(row, 8));
excelData.setGrossWeight(getNumericCellValueOrDefault(row, 3));
excelData.setNetWeight(getNumericCellValueOrDefault(row, 4));
if (excelData.getBoxQty() == null && excelData.getGrossWeight() == null && excelData.getNetWeight() == null) {
excelData.setGroupSeqNo(groupSeqNo);
// 判断是否是新的箱子
// 1. 如果箱数列有值且不在合并区域中或者是合并区域的第一行则是新箱子
// 2. 如果箱数列没有值或者在合并区域中但不是第一行则属于上一个箱子
if (boxQty != null && !isMergedCellButNotFirst(sheet, j, 1)) {
// 新的箱子
groupSeqNo++;
excelData.setBoxQty(boxQty);
excelData.setRolls(rolls);
excelData.setGrossWeight(grossWeight);
excelData.setNetWeight(netWeight);
} else {
groupSeqNo++;
excelData.setGroupSeqNo(groupSeqNo);
boxQty = excelData.getBoxQty();
grossWeight = excelData.getGrossWeight();
netWeight = excelData.getNetWeight();
// 属于上一个箱子合箱使用上一行的箱数卷数毛重
if (j > 1) {
// 从上一个已添加的数据获取信息
if (!excelList.isEmpty()) {
EcssCoDelPalletData lastData = excelList.get(excelList.size() - 1);
excelData.setBoxQty(lastData.getBoxQty());
excelData.setRolls(lastData.getRolls());
excelData.setGrossWeight(lastData.getGrossWeight());
}
}
}
excelData.setGroupSeqNo(groupSeqNo);
// 验证物料是否存在
List<PartData> parts = coDelMapper.getPartNo(excelData.getSite(), excelData.getPn(),
currentUser.getUsername(), inData.getBuNo());
if (parts.isEmpty()) {
throw new RuntimeException("导入失败:第" + (j + 1) + "行,物料:" + excelData.getPn() + "不存在!");
}
excelData.setPartNo(parts.get(0).getPartNo());
// 验证物料在当前工厂是否存在
List<PartData> checkPart = coDelMapper.checkPart(excelData.getSite(), excelData.getPartNo());
if (checkPart.isEmpty()) {
throw new RuntimeException("导入失败:物料:" + excelData.getPartNo() + "在当前工厂不存在!");
throw new RuntimeException("导入失败:第" + (j + 1) + "行,物料:" + excelData.getPartNo() + "在当前工厂不存在!");
}
excelList.add(excelData);
}
// 验证导入数据的序号和数量是否与发货通知单明细匹配
validateImportDataWithNotifyDetail(excelList, inData);
// 获取发货通知单明细用于填充PO等信息
List<EcssCoDelNotifyDetailData> notifyDetailList = coDelMapper.searchEcssCoDelNotifyDetail(inData);
Map<Integer, EcssCoDelNotifyDetailData> notifyDetailMap = new HashMap<>();
for (EcssCoDelNotifyDetailData detailData : notifyDetailList) {
notifyDetailMap.put(detailData.getItemNo(), detailData);
}
// 根据序号从发货通知单明细中获取PO等信息
for (EcssCoDelPalletData palletData : excelList) {
EcssCoDelNotifyDetailData notifyDetail = notifyDetailMap.get(palletData.getNotifyDetailItemNo());
if (notifyDetail != null) {
// 从发货通知单明细中获取PO
palletData.setPoNo(notifyDetail.getCustomerPO());
}
}
} catch (NullPointerException e) {
throw new RuntimeException("导入失败:网络错误,请重新上传文档");
} catch (Exception e) {
throw new RuntimeException("导入失败:" + e.getMessage());
}
// 如果是沃尔玛订单按照pn分组同一个pn是一个EcssCoDelPalletHeaderData
// 如果是非沃尔玛订单按照序号分组同一个序号是一个EcssCoDelPalletHeaderData
Map<Integer, List<EcssCoDelPalletData>> palletListMap = new HashMap<>();
Map<Integer, List<EcssCoDelPalletData>> palletListMap2 = new HashMap<>();
for (EcssCoDelPalletData itemData : excelList){
if (palletListMap2.containsKey(itemData.getGroupSeqNo())) {
palletListMap2.get(itemData.getGroupSeqNo()).add(itemData);
// 按groupSeqNo分组同一个groupSeqNo是同一个箱子
Map<Integer, List<EcssCoDelPalletData>> palletListMap = new LinkedHashMap<>();
for (EcssCoDelPalletData itemData : excelList) {
if (palletListMap.containsKey(itemData.getGroupSeqNo())) {
palletListMap.get(itemData.getGroupSeqNo()).add(itemData);
} else {
List<EcssCoDelPalletData> palletDataList = new ArrayList<>();
palletDataList.add(itemData);
palletListMap2.put(itemData.getGroupSeqNo(),palletDataList);
palletListMap.put(itemData.getGroupSeqNo(), palletDataList);
}
}
EcssWalMartOrder task = new EcssWalMartOrder();
List<EcssCoDelPalletHeaderData> headerList = new ArrayList<>();
// 保存装箱数据
List<EcssCoDelBoxListData> boxList = new ArrayList<>();
List<EcssCoDelPalletDetailData> detailList = new ArrayList<>();
int seqNo = 0;
for (Map.Entry<Integer, List<EcssCoDelPalletData>> entry : palletListMap2.entrySet()) {
for (Map.Entry<Integer, List<EcssCoDelPalletData>> entry : palletListMap.entrySet()) {
seqNo++;
// 保存箱子信息
EcssCoDelBoxListData boxListData = new EcssCoDelBoxListData();
boxListData.setSite(inData.getSite());
boxListData.setBuNo(inData.getBuNo());
boxListData.setDelNo(inData.getDelNo());
boxListData.setItemNo(seqNo);
boxListData.setGrossWeight(entry.getValue().get(0).getGrossWeight());
boxListData.setNetWeight(entry.getValue().get(0).getNetWeight());
boxListData.setBoxQty(entry.getValue().get(0).getBoxQty());
// 箱数取第一条记录的箱数同一箱内所有明细的箱数都相同
BigDecimal boxQty = entry.getValue().get(0).getBoxQty();
boxListData.setBoxQty(boxQty);
// 毛重如果是合箱则毛重已经在合并单元格中直接取第一条记录的毛重
// 如果不是合箱每行有各自的毛重不需要汇总因为一行就是一个箱子
BigDecimal grossWeight = entry.getValue().get(0).getGrossWeight();
boxListData.setGrossWeight(grossWeight);
// 卷数如果是合箱则毛重已经在合并单元格中直接取第一条记录的卷数
// 如果不是合箱每行有各自的卷数不需要汇总因为一行就是一个箱子
BigDecimal totalRolls = entry.getValue().get(0).getRolls();
boxListData.setRolls(totalRolls);
// 净重计算净重 = 毛重 - 箱数/2
BigDecimal netWeight = BigDecimal.ZERO;
if (grossWeight != null && boxQty != null) {
netWeight = grossWeight.subtract(boxQty.divide(new BigDecimal("2"), 6, RoundingMode.HALF_UP));
}
boxListData.setNetWeight(netWeight);
boxListData.setCreateBy(currentUser.getUsername());
boxList.add(boxListData);
int i=0;
// 保存箱子内的明细
int itemNo = 0;
for (EcssCoDelPalletData thisData : entry.getValue()) {
itemNo++;
EcssCoDelPalletDetailData detailData = new EcssCoDelPalletDetailData();
detailData.setSite(thisData.getSite());
detailData.setBuNo(thisData.getBuNo());
detailData.setDelNo(thisData.getDelNo());
detailData.setSeqNo(seqNo);
detailData.setItemNo(i + 1);
i++;
detailData.setSeqNo(seqNo); // 箱号
detailData.setItemNo(itemNo); // 箱内明细行号
detailData.setNotifyDetailItemNo(thisData.getNotifyDetailItemNo()); // 对应的发货通知单明细序号
detailData.setPartNo(thisData.getPartNo());
detailData.setPn(thisData.getPn());
detailData.setQty(thisData.getQty());
@ -1464,32 +1571,16 @@ public class CoDelExcelServiceImpl implements CoDelExcelService {
detailList.add(detailData);
}
}
// 保存到数据库
for (EcssCoDelBoxListData boxData : boxList) {
coDelMapper.saveCodelBoxList(boxData);
}
Map<String, BigDecimal> palletDetailMap = new HashMap<>();
for (EcssCoDelPalletDetailData ecssCoDelPalletDetailData : detailList) {
coDelMapper.saveCodelPalletDetail(ecssCoDelPalletDetailData);
if (!palletDetailMap.containsKey(ecssCoDelPalletDetailData.getPn())) {
palletDetailMap.put(ecssCoDelPalletDetailData.getPn(), ecssCoDelPalletDetailData.getQty());
} else {
palletDetailMap.put(ecssCoDelPalletDetailData.getPn(), palletDetailMap.get(ecssCoDelPalletDetailData.getPn()).add(ecssCoDelPalletDetailData.getQty()));
}
}
List<EcssCoDelNotifyDetailData> ecssCoDelNotifyDetail = coDelMapper.searchEcssCoDelNotifyDetail(inData);
Map<String, BigDecimal> notifyDetailMap = new HashMap<>();
for (EcssCoDelNotifyDetailData detailData : ecssCoDelNotifyDetail) {
if (!notifyDetailMap.containsKey(detailData.getPn())) {
notifyDetailMap.put(detailData.getPn(), detailData.getQty());
} else {
notifyDetailMap.put(detailData.getPn(), notifyDetailMap.get(detailData.getPn()).add(detailData.getQty()));
}
}
for (Map.Entry<String, BigDecimal> entry : palletDetailMap.entrySet()) {
if (notifyDetailMap.get(entry.getKey()).compareTo(entry.getValue())!=0) {
throw new RuntimeException("物料["+entry.getKey()+"]的数量和发货通知单数量不一致!");
}
for (EcssCoDelPalletDetailData detailData : detailList) {
coDelMapper.saveCodelPalletDetail(detailData);
}
// 处理栈板记录
palletHeaderSave(inData.getSite(), inData.getBuNo(), inData.getDelNo(), palletRecords, currentUser);
@ -1499,6 +1590,88 @@ public class CoDelExcelServiceImpl implements CoDelExcelService {
coDelMapper.updateEcssDelDetailForModify(inData);
}
/**
* 验证导入数据的序号和数量是否与发货通知单明细匹配
* 规则导入数据中同一个序号的数量总和必须等于发货通知单明细中该序号的数量
*/
private void validateImportDataWithNotifyDetail(List<EcssCoDelPalletData> excelList, EcssCoDelNotifyHeaderData inData) {
// 获取发货通知单明细
List<EcssCoDelNotifyDetailData> notifyDetailList = coDelMapper.searchEcssCoDelNotifyDetail(inData);
// 将发货通知单明细按itemNo分组
Map<Integer, EcssCoDelNotifyDetailData> notifyDetailMap = new HashMap<>();
for (EcssCoDelNotifyDetailData detailData : notifyDetailList) {
notifyDetailMap.put(detailData.getItemNo(), detailData);
}
// 将导入数据按notifyDetailItemNo分组并汇总数量
Map<Integer, BigDecimal> importQtyMap = new HashMap<>();
for (EcssCoDelPalletData palletData : excelList) {
Integer itemNo = palletData.getNotifyDetailItemNo();
BigDecimal qty = palletData.getQty();
if (importQtyMap.containsKey(itemNo)) {
importQtyMap.put(itemNo, importQtyMap.get(itemNo).add(qty));
} else {
importQtyMap.put(itemNo, qty);
}
}
// 验证每个序号的数量是否匹配
for (Map.Entry<Integer, BigDecimal> entry : importQtyMap.entrySet()) {
Integer itemNo = entry.getKey();
BigDecimal importQty = entry.getValue();
EcssCoDelNotifyDetailData notifyDetail = notifyDetailMap.get(itemNo);
if (notifyDetail == null) {
throw new RuntimeException("序号[" + itemNo + "]在发货通知单明细中不存在!");
}
BigDecimal notifyQty = notifyDetail.getQty();
if (notifyQty.compareTo(importQty) != 0) {
throw new RuntimeException("序号[" + itemNo + "]的数量不一致!" +
"发货通知单数量:" + notifyQty.setScale(0, RoundingMode.HALF_UP) + ",导入数量:" + importQty.setScale(0,RoundingMode.HALF_UP));
}
}
// 验证是否有发货通知单明细没有对应的导入数据
for (EcssCoDelNotifyDetailData notifyDetail : notifyDetailList) {
if (!importQtyMap.containsKey(notifyDetail.getItemNo())) {
throw new RuntimeException("发货通知单明细序号[" + notifyDetail.getItemNo() +
"]没有对应的装箱数据!");
}
}
}
/**
* 判断单元格是否在合并区域中
*/
private boolean isCellInMergedRegion(XSSFSheet sheet, int row, int column) {
int numberOfMergedRegions = sheet.getNumMergedRegions();
for (int i = 0; i < numberOfMergedRegions; i++) {
org.apache.poi.ss.util.CellRangeAddress mergedRegion = sheet.getMergedRegion(i);
if (mergedRegion.isInRange(row, column)) {
return true;
}
}
return false;
}
/**
* 判断单元格是否在合并区域中但不是第一行
*/
private boolean isMergedCellButNotFirst(XSSFSheet sheet, int row, int column) {
int numberOfMergedRegions = sheet.getNumMergedRegions();
for (int i = 0; i < numberOfMergedRegions; i++) {
org.apache.poi.ss.util.CellRangeAddress mergedRegion = sheet.getMergedRegion(i);
if (mergedRegion.isInRange(row, column)) {
// 如果在合并区域中且不是第一行
return row != mergedRegion.getFirstRow();
}
}
return false;
}
private void palletHeaderSave(String site,String buNo,String delNo, String palletRecords, SysUserEntity currentUser) {
List<Map<String, Object>> palletRecordList = new ArrayList<>();
if (palletRecords != null && !palletRecords.isEmpty()) {

BIN
src/main/resources/templates/packing-template.xlsx

Loading…
Cancel
Save