测试环境库存查询报错;

This commit is contained in:
王奎兴
2026-05-25 20:04:29 +08:00
parent 4d563c1394
commit b7335b33fb
10 changed files with 396 additions and 0 deletions
@@ -243,4 +243,12 @@ public class ReservationMaterialInventoryDO extends MaterialBaseDO {
@ApiModelProperty("LOT编号")
@Excel(name = "LOT编号")
private String lotNumber;
@ApiModelProperty("入库时间 ")
@Excel(name = "入库时间 ")
private String createTimeStart;
@ApiModelProperty("入库时间 ")
@Excel(name = "入库时间 ")
private String createTimeEnd;
}
@@ -184,4 +184,12 @@ public class ReservationMaterialInventoryDTO extends MaterialBaseDTO {
@Excel(name = "冻结数量大于0条件")
private String greaterThanFreezeQuantity;
@ApiModelProperty("入库时间 ")
@Excel(name = "入库时间 ")
private String createTimeStart;
@ApiModelProperty("入库时间 ")
@Excel(name = "入库时间 ")
private String createTimeEnd;
}
@@ -5,6 +5,8 @@ import com.mhd.oms.domain.reservationInMaterialDetail.repository.po.ReservationI
import com.mhd.oms.domain.reservationStockInOrder.entity.ReservationStockInOrder;
import com.mhd.oms.domain.reservationStockInOrder.repository.po.ReservationStockInOrderPO;
import com.mhd.oms.domain.reservationStockInOrder.repository.todo.ReservationStockInOrderDO;
import com.mhd.oms.domain.reservationStockInOrder.repository.vo.DeliveryDataDTO;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -45,4 +47,13 @@ public interface IReservationStockInOrderService extends IService<ReservationSto
List<ReservationStockInOrderPO> queryNoticePrint(ReservationStockInOrderDO stockInOrderDO);
List<ReservationInMaterialDetailPO> queryNoticePrintDetail(ReservationStockInOrderDO stockInOrderDTO);
/**
* 解析Excel文件并获取出库数据
* @param file Excel文件
* @param sheetName 工作表名称(出库导入/参考数据)
* @return 出库数据DTO
* @throws Exception 解析异常
*/
DeliveryDataDTO parseExcelFile(MultipartFile file, String sheetName) throws Exception;
}
@@ -0,0 +1,210 @@
package com.mhd.oms.domain.reservationStockInOrder.repository.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.mhd.oms.domain.reservationStockInOrder.repository.vo.CustomerDeliveryDetail;
import com.mhd.oms.domain.reservationStockInOrder.repository.vo.DeliveryHeader;
import com.mhd.oms.domain.reservationStockInOrder.repository.vo.ProductDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Excel解析监听器
*/
public class DeliveryExcelListener extends AnalysisEventListener<Object> {
private static final Logger LOGGER = LoggerFactory.getLogger(DeliveryExcelListener.class);
// 数据存储
private DeliveryHeader deliveryHeader = new DeliveryHeader();
private List<ProductDetail> productDetailList = new ArrayList<>();
private List<CustomerDeliveryDetail> customerDeliveryDetailList = new ArrayList<>();
// 解析状态标记
private boolean isProductDetail = false; // 是否在解析货品明细
private boolean isCustomerDetail = false; // 是否在解析客户配送明细
@Override
public void invoke(Object data, AnalysisContext context) {
try {
// 将数据转为数组(Excel行数据)
Object[] rowData = (Object[]) data;
// 1. 解析表头信息(第1行)
if (context.readRowHolder().getRowIndex() == 0) {
parseHeaderInfo(rowData);
}
// 2. 识别数据区域(根据关键字判断)
else if (context.readRowHolder().getRowIndex() == 1) {
if (rowData[0] != null && "货品明细".equals(rowData[0].toString().trim())) {
isProductDetail = true;
isCustomerDetail = false;
}
}
else if (context.readRowHolder().getRowIndex() == 7) {
// 解析纪录合共(第8行,索引为7
parseTotalRecord(rowData);
}
else if (context.readRowHolder().getRowIndex() == 8) {
if (rowData[0] != null && "客户配送明细".equals(rowData[0].toString().trim())) {
isProductDetail = false;
isCustomerDetail = true;
}
}
else if (context.readRowHolder().getRowIndex() == 30) {
// 解析发票张数(第31行,索引为30)
parseInvoiceCount(rowData);
}
// 3. 解析货品明细(第4-7行,索引3-6)
else if (isProductDetail && context.readRowHolder().getRowIndex() >= 3 && context.readRowHolder().getRowIndex() <= 6) {
parseProductDetail(rowData);
}
// 4. 解析客户配送明细(第11-30行,索引10-29)
else if (isCustomerDetail && context.readRowHolder().getRowIndex() >= 10 && context.readRowHolder().getRowIndex() <= 29) {
parseCustomerDeliveryDetail(rowData);
}
} catch (ExcelDataConvertException e) {
LOGGER.error("Excel数据转换异常,行号:{},列号:{}",
context.readRowHolder().getRowIndex() + 1,
e.getColumnIndex() + 1);
} catch (Exception e) {
LOGGER.error("Excel解析异常,行号:{}",
context.readRowHolder().getRowIndex() + 1, e);
}
}
/**
* 解析表头信息(第1行)
*/
private void parseHeaderInfo(Object[] rowData) {
// 送货日期(第2列,索引1
if (rowData[1] != null) {
deliveryHeader.setDeliveryDate((Date) rowData[1]);
}
// 送货线号(第4列,索引3
if (rowData[3] != null) {
deliveryHeader.setDeliveryLineNo(Integer.parseInt(rowData[3].toString()));
}
// 车次(第6列,索引5
if (rowData[5] != null) {
deliveryHeader.setTrainNumber(Integer.parseInt(rowData[5].toString()));
}
}
/**
* 解析纪录合共(第8行)
*/
private void parseTotalRecord(Object[] rowData) {
// 纪录合共-货品总数量(第2列,索引1)
if (rowData[1] != null) {
deliveryHeader.setTotalRecordCount(Integer.parseInt(rowData[1].toString()));
}
// 总箱数(第5列,索引4
if (rowData[4] != null) {
deliveryHeader.setTotalBoxCount(Integer.parseInt(rowData[4].toString()));
}
// 总支数(第6列,索引5
if (rowData[5] != null) {
deliveryHeader.setTotalPieceCount(Integer.parseInt(rowData[5].toString()));
}
}
/**
* 解析发票张数(第31行)
*/
private void parseInvoiceCount(Object[] rowData) {
// 发票张数(第2列,索引1
if (rowData[1] != null) {
deliveryHeader.setInvoiceCount(Integer.parseInt(rowData[1].toString()));
}
// 小计-总箱数(第5列,索引4
if (rowData[4] != null) {
deliveryHeader.setSubtotalBoxCount(Integer.parseInt(rowData[4].toString()));
}
// 小计-总支数(第6列,索引5
if (rowData[5] != null) {
deliveryHeader.setSubtotalPieceCount(Integer.parseInt(rowData[5].toString()));
}
// 小计-总金额(第7列,索引6
if (rowData[6] != null) {
deliveryHeader.setSubtotalAmount(new BigDecimal(rowData[6].toString()));
}
}
/**
* 解析货品明细
*/
private void parseProductDetail(Object[] rowData) {
ProductDetail productDetail = new ProductDetail();
// 货品编号(第1列,索引0
if (rowData[0] != null) {
productDetail.setProductCode(rowData[0].toString().trim());
}
// 货品简称(第2列,索引1
if (rowData[1] != null) {
productDetail.setProductName(rowData[1].toString().trim());
}
// 箱数(第5列,索引4
if (rowData[4] != null) {
productDetail.setBoxCount(Integer.parseInt(rowData[4].toString()));
}
// 支数(第6列,索引5
if (rowData[5] != null) {
productDetail.setPieceCount(Integer.parseInt(rowData[5].toString()));
}
productDetailList.add(productDetail);
}
/**
* 解析客户配送明细
*/
private void parseCustomerDeliveryDetail(Object[] rowData) {
CustomerDeliveryDetail customerDetail = new CustomerDeliveryDetail();
// 类别(第1列,索引0
if (rowData[0] != null) {
customerDetail.setCategory(rowData[0].toString().trim());
}
// 发票编号(第2列,索引1
if (rowData[1] != null) {
customerDetail.setInvoiceNo(rowData[1].toString().trim());
}
// 客户编号(第3列,索引2
if (rowData[2] != null) {
customerDetail.setCustomerCode(rowData[2].toString().trim());
}
// 客户名称(第4列,索引3
if (rowData[3] != null) {
customerDetail.setCustomerName(rowData[3].toString().trim());
}
// 箱数(第5列,索引4
if (rowData[4] != null) {
customerDetail.setBoxCount(Integer.parseInt(rowData[4].toString()));
}
// 包数(第6列,索引5
if (rowData[5] != null) {
customerDetail.setPackageCount(Integer.parseInt(rowData[5].toString()));
}
// 金额(第7列,索引6
if (rowData[6] != null) {
customerDetail.setAmount(new BigDecimal(rowData[6].toString()));
}
customerDeliveryDetailList.add(customerDetail);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
LOGGER.info("Excel解析完成,共解析货品明细:{}条,客户配送明细:{}条",
productDetailList.size(), customerDeliveryDetailList.size());
}
// Getter方法(供Service层获取解析后的数据)
public DeliveryHeader getDeliveryHeader() { return deliveryHeader; }
public List<ProductDetail> getProductDetailList() { return productDetailList; }
public List<CustomerDeliveryDetail> getCustomerDeliveryDetailList() { return customerDeliveryDetailList; }
}
@@ -1,17 +1,22 @@
package com.mhd.oms.domain.reservationStockInOrder.repository.persistence;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mhd.oms.domain.reservationInMaterialDetail.repository.po.ReservationInMaterialDetailPO;
import com.mhd.oms.domain.reservationStockInOrder.entity.ReservationStockInOrder;
import com.mhd.oms.domain.reservationStockInOrder.repository.facade.IReservationStockInOrderService;
import com.mhd.oms.domain.reservationStockInOrder.repository.listener.DeliveryExcelListener;
import com.mhd.oms.domain.reservationStockInOrder.repository.mapper.ReservationStockInOrderMapper;
import com.mhd.oms.domain.reservationStockInOrder.repository.po.ReservationStockInOrderPO;
import com.mhd.oms.domain.reservationStockInOrder.repository.todo.ReservationStockInOrderDO;
import com.mhd.oms.domain.reservationStockInOrder.repository.vo.DeliveryDataDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@@ -93,4 +98,35 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
return stockInOrderMapper.queryNoticePrintDetail(stockInOrderDO);
}
@Override
public DeliveryDataDTO parseExcelFile(MultipartFile file, String sheetName) throws Exception {
// 校验文件
if (file.isEmpty()) {
throw new IllegalArgumentException("上传的Excel文件不能为空");
}
// 校验工作表名称
if (!"出库导入".equals(sheetName) && !"参考数据".equals(sheetName)) {
throw new IllegalArgumentException("工作表名称必须为'出库导入'或'参考数据'");
}
// 使用EasyExcel解析Excel
DeliveryExcelListener listener = new DeliveryExcelListener();
try (InputStream inputStream = file.getInputStream()) {
EasyExcel.read(inputStream, listener)
.sheet(sheetName) // 指定工作表
.headRowNumber(0) // 无固定表头,从第1行开始解析
.doRead();
}
// 封装DTO返回
DeliveryDataDTO deliveryDataDTO = new DeliveryDataDTO();
deliveryDataDTO.setDeliveryHeader(listener.getDeliveryHeader());
deliveryDataDTO.setProductDetailList(listener.getProductDetailList());
deliveryDataDTO.setCustomerDeliveryDetailList(listener.getCustomerDeliveryDetailList());
return deliveryDataDTO;
}
}
@@ -0,0 +1,26 @@
package com.mhd.oms.domain.reservationStockInOrder.repository.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 客户配送明细实体类
*/
@Data
public class CustomerDeliveryDetail {
// 类别
private String category;
// 发票编号
private String invoiceNo;
// 客户编号
private String customerCode;
// 客户名称
private String customerName;
// 箱数
private Integer boxCount;
// 包数
private Integer packageCount;
// 金额
private BigDecimal amount;
}
@@ -0,0 +1,18 @@
package com.mhd.oms.domain.reservationStockInOrder.repository.vo;
import lombok.Data;
import java.util.List;
/**
* 出库数据DTO(包含表头、货品明细、客户配送明细)
*/
@Data
public class DeliveryDataDTO {
// 表头信息
private DeliveryHeader deliveryHeader;
// 货品明细列表
private List<ProductDetail> productDetailList;
// 客户配送明细列表
private List<CustomerDeliveryDetail> customerDeliveryDetailList;
}
@@ -0,0 +1,33 @@
package com.mhd.oms.domain.reservationStockInOrder.repository.vo;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 出库表头信息(包含送货日期、纪录合共、发票张数等)
*/
@Data
public class DeliveryHeader {
// 送货日期
private Date deliveryDate;
// 送货线号
private Integer deliveryLineNo;
// 车次
private Integer trainNumber;
// 纪录合共-货品总数量
private Integer totalRecordCount;
// 纪录合共-总箱数
private Integer totalBoxCount;
// 纪录合共-总支数
private Integer totalPieceCount;
// 发票张数
private Integer invoiceCount;
// 小计-总箱数
private Integer subtotalBoxCount;
// 小计-总支数
private Integer subtotalPieceCount;
// 小计-总金额
private BigDecimal subtotalAmount;
}
@@ -0,0 +1,19 @@
package com.mhd.oms.domain.reservationStockInOrder.repository.vo;
import lombok.Data;
/**
* 货品明细实体类
*/
@Data
public class ProductDetail {
// 货品编号
private String productCode;
// 货品简称
private String productName;
// 箱数
private Integer boxCount;
// 支数
private Integer pieceCount;
}
@@ -4,9 +4,11 @@ import com.mhd.common.core.web.controller.BaseController;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.core.web.page.TableDataInfo;
import com.mhd.oms.domain.reservationInMaterialDetail.repository.po.ReservationInMaterialDetailPO;
import com.mhd.oms.domain.reservationStockInOrder.repository.facade.IReservationStockInOrderService;
import com.mhd.oms.domain.reservationStockInOrder.repository.po.ReservationStockInOrderPO;
import com.mhd.oms.domain.reservationStockInOrder.repository.todo.ReservationStockInOrderDO;
import com.mhd.oms.domain.reservationStockInOrder.repository.todo.ReservationStockInOrderDTO;
import com.mhd.oms.domain.reservationStockInOrder.repository.vo.DeliveryDataDTO;
import com.mhd.oms.domain.reservationStockInOrder.service.ReservationStockInOrderApplicationService;
import com.mhd.oms.domain.reservationStockInOrder.service.ReservationStockInOrderAssembler;
import com.mhd.system.api.domain.InMaterialDetail;
@@ -15,6 +17,8 @@ import com.mhd.system.api.domain.StockInOrder;
import com.mhd.system.api.domain.StockInOrderTZPD;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@@ -37,6 +41,8 @@ public class ReservationStockInOrderApi extends BaseController {
@Resource
private ReservationStockInOrderAssembler stockInOrderAssembler;
@Autowired
private IReservationStockInOrderService reservationStockInOrderService;
/**
* 分页查询入库单列表
@@ -183,4 +189,25 @@ public class ReservationStockInOrderApi extends BaseController {
return AjaxResult.success(result);
}
/**
* 上传并解析Excel文件
* @param file Excel文件
* @param sheetName 工作表名称(出库导入/参考数据)
* @return 解析后的出库数据
*/
@PostMapping("/parseExcel")
public ResponseEntity<DeliveryDataDTO> parseExcel(
@RequestParam("file") MultipartFile file,
@RequestParam("sheetName") String sheetName) {
try {
DeliveryDataDTO deliveryDataDTO = reservationStockInOrderService.parseExcelFile(file, sheetName);
return new ResponseEntity<>(deliveryDataDTO, HttpStatus.OK);
} catch (IllegalArgumentException e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}