Browse Source

按标签查询库存

dev
常熟吴彦祖 21 hours ago
parent
commit
1c6934121d
  1. 27
      src/main/java/com/gaotao/modules/warehouse/controller/LabelInventoryStockController.java
  2. 19
      src/main/java/com/gaotao/modules/warehouse/dao/LabelInventoryStockMapper.java
  3. 22
      src/main/java/com/gaotao/modules/warehouse/entity/dto/LabelInventoryStockQueryDto.java
  4. 23
      src/main/java/com/gaotao/modules/warehouse/entity/vo/LabelInventoryStockRow.java
  5. 10
      src/main/java/com/gaotao/modules/warehouse/service/LabelInventoryStockService.java
  6. 49
      src/main/java/com/gaotao/modules/warehouse/service/impl/LabelInventoryStockServiceImpl.java
  7. 50
      src/main/resources/mapper/warehouse/LabelInventoryStockMapper.xml

27
src/main/java/com/gaotao/modules/warehouse/controller/LabelInventoryStockController.java

@ -0,0 +1,27 @@
package com.gaotao.modules.warehouse.controller;
import com.gaotao.common.utils.PageUtils;
import com.gaotao.common.utils.R;
import com.gaotao.modules.warehouse.entity.dto.LabelInventoryStockQueryDto;
import com.gaotao.modules.warehouse.service.LabelInventoryStockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** 新版库存管理查询入口,与仍供旧页面使用的inventory_stock接口隔离 - rqrq */
@RestController
@RequestMapping("/warehouse")
public class LabelInventoryStockController {
@Autowired
private LabelInventoryStockService labelInventoryStockService;
/** 页面查询及分批导出共用POST,分页统一返回page,Controller不处理聚合或业务校验 - rqrq */
@PostMapping("getLabelInventoryStockList")
public R getLabelInventoryStockList(@RequestBody LabelInventoryStockQueryDto query) {
// 委托Service按请求工厂校验并查询标签汇总失败交由统一异常处理 - rqrq
PageUtils page = labelInventoryStockService.getLabelInventoryStockList(query);
return R.ok().put("page", page);
}
}

19
src/main/java/com/gaotao/modules/warehouse/dao/LabelInventoryStockMapper.java

@ -0,0 +1,19 @@
package com.gaotao.modules.warehouse.dao;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gaotao.modules.warehouse.entity.dto.LabelInventoryStockQueryDto;
import com.gaotao.modules.warehouse.entity.vo.LabelInventoryStockRow;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/** 标签库存汇总独立只读Mapper,不接入旧库存更新流程 - rqrq */
@Mapper
public interface LabelInventoryStockMapper {
/** 统计分组后的库存行数;与列表共用筛选,避免SQL Server的带ORDER BY子查询计数错误 - rqrq */
long countLabelInventoryStock(@Param("query") LabelInventoryStockQueryDto query);
/** 按六个库存维度聚合后分页;NOLOCK允许脏读,仅供查询和导出,不用于库存扣减依据 - rqrq */
IPage<LabelInventoryStockRow> getLabelInventoryStockList(
Page<LabelInventoryStockRow> page, @Param("query") LabelInventoryStockQueryDto query);
}

22
src/main/java/com/gaotao/modules/warehouse/entity/dto/LabelInventoryStockQueryDto.java

@ -0,0 +1,22 @@
package com.gaotao.modules.warehouse.entity.dto;
import lombok.Data;
/** 标签库存汇总查询入参,仅用于只读页面及导出,不映射inventory_stock - rqrq */
@Data
public class LabelInventoryStockQueryDto {
/** 页面明确传入的标签工厂编码,默认来自当前用户site;精确匹配handling_unit.site,必填不落库 - rqrq */
private String site;
/** 仓库筛选,精确匹配handling_unit.warehouse_id;空值不过滤,不落库 - rqrq */
private String warehouseId;
/** 物料编码筛选,沿用原页面包含匹配;空值不过滤,不落库 - rqrq */
private String partNo;
/** 批次筛选,沿用原页面包含匹配;空值不过滤,不落库 - rqrq */
private String batchNo;
/** 库位筛选,沿用原页面包含匹配;空值不过滤,不落库 - rqrq */
private String locationId;
/** 汇总结果页码,从1开始;页面和分批导出共用,不落库 - rqrq */
private Integer page = 1;
/** 每页汇总行数,默认20,最大1000以支持分批导出;不是标签条数,不落库 - rqrq */
private Integer size = 20;
}

23
src/main/java/com/gaotao/modules/warehouse/entity/vo/LabelInventoryStockRow.java

@ -0,0 +1,23 @@
package com.gaotao.modules.warehouse.entity.vo;
import lombok.Data;
import java.math.BigDecimal;
/** handling_unit分组后的只读库存行,供库存管理页面和导出消费,不落库 - rqrq */
@Data
public class LabelInventoryStockRow {
/** 分组工厂,来源handling_unit.site;保持标签实际工厂,不转换父site - rqrq */
private String site;
/** 分组仓库,来源handling_unit.warehouse_id;不落库 - rqrq */
private String warehouseId;
/** 分组物料编码,来源handling_unit.part_no;不落库 - rqrq */
private String partNo;
/** 分组批次,来源handling_unit.batch_no;不落库 - rqrq */
private String batchNo;
/** 分组库位,来源handling_unit.location_id;不落库 - rqrq */
private String locationId;
/** 分组WDR,来源handling_unit.wdr,空值保持原值,不混并不同WDR - rqrq */
private String wdr;
/** 现有库存:同组在库标签qty之和,沿用物料库存单位;含冻结/预留,不等同可用库存 - rqrq */
private BigDecimal qtyOnHand = BigDecimal.ZERO;
}

10
src/main/java/com/gaotao/modules/warehouse/service/LabelInventoryStockService.java

@ -0,0 +1,10 @@
package com.gaotao.modules.warehouse.service;
import com.gaotao.common.utils.PageUtils;
import com.gaotao.modules.warehouse.entity.dto.LabelInventoryStockQueryDto;
/** 库存管理新版页面的标签聚合查询,不负责库存写入或旧库存接口兼容 - rqrq */
public interface LabelInventoryStockService {
/** 校验工厂/分页并返回标签库存聚合分页;失败抛业务异常,不静默返回错误库存 - rqrq */
PageUtils getLabelInventoryStockList(LabelInventoryStockQueryDto query);
}

49
src/main/java/com/gaotao/modules/warehouse/service/impl/LabelInventoryStockServiceImpl.java

@ -0,0 +1,49 @@
package com.gaotao.modules.warehouse.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gaotao.common.exception.XJException;
import com.gaotao.common.utils.PageUtils;
import com.gaotao.modules.warehouse.dao.LabelInventoryStockMapper;
import com.gaotao.modules.warehouse.entity.dto.LabelInventoryStockQueryDto;
import com.gaotao.modules.warehouse.entity.vo.LabelInventoryStockRow;
import com.gaotao.modules.warehouse.service.LabelInventoryStockService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/** 只读标签库存查询:不写表、不调用IFS/WCS,NOLOCK的非一致读风险只限查询结果 - rqrq */
@Slf4j
@Service
public class LabelInventoryStockServiceImpl implements LabelInventoryStockService {
@Autowired
private LabelInventoryStockMapper labelInventoryStockMapper;
/** 必须使用请求site,保留旧筛选的精确/包含语义;限制单批规模,不影响业务库存更新 - rqrq */
@Override
public PageUtils getLabelInventoryStockList(LabelInventoryStockQueryDto query) {
if (query == null || StringUtils.isBlank(query.getSite())) {
throw new XJException("工厂编码不能为空");
}
if (query.getPage() == null || query.getPage() < 1) {
throw new XJException("页码必须大于0");
}
if (query.getSize() == null || query.getSize() < 1 || query.getSize() > 1000) {
throw new XJException("每页数量必须在1到1000之间,请分批查询或导出");
}
// 仅清理查询输入两端空格不推断父工厂不增加冻结/预留/立库状态限制 - rqrq
query.setSite(query.getSite().trim());
query.setWarehouseId(StringUtils.trimToNull(query.getWarehouseId()));
query.setPartNo(StringUtils.trimToNull(query.getPartNo()));
query.setBatchNo(StringUtils.trimToNull(query.getBatchNo()));
query.setLocationId(StringUtils.trimToNull(query.getLocationId()));
// 单独统计聚合行数避免分页插件将含ORDER BY的原SQL包成SQL Server不支持的计数子查询 - rqrq
long total = labelInventoryStockMapper.countLabelInventoryStock(query);
Page<LabelInventoryStockRow> page = new Page<>(query.getPage(), query.getSize(), false);
page.setTotal(total);
// Mapper按相同筛选先SUM再分页失败直接传播前端结束loading并展示错误不返回伪造库存 - rqrq
IPage<LabelInventoryStockRow> result = labelInventoryStockMapper.getLabelInventoryStockList(page, query);
return new PageUtils(result);
}
}

50
src/main/resources/mapper/warehouse/LabelInventoryStockMapper.xml

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gaotao.modules.warehouse.dao.LabelInventoryStockMapper">
<!-- 列表和计数共用筛选,均按请求site精确查询;无锁读取风险见下方说明 - rqrq -->
<sql id="labelInventoryFilter">
WHERE h.site = #{query.site}
AND h.in_stock_flag = 'Y'
<if test="query.warehouseId != null and query.warehouseId != ''">
AND h.warehouse_id = #{query.warehouseId}
</if>
<if test="query.partNo != null and query.partNo != ''">
AND h.part_no LIKE '%' + #{query.partNo} + '%'
</if>
<if test="query.batchNo != null and query.batchNo != ''">
AND h.batch_no LIKE '%' + #{query.batchNo} + '%'
</if>
<if test="query.locationId != null and query.locationId != ''">
AND h.location_id LIKE '%' + #{query.locationId} + '%'
</if>
</sql>
<!-- 只统计库存分组,不统计标签数;计数子查询不含ORDER BY,兼容SQL Server - rqrq -->
<select id="countLabelInventoryStock" resultType="java.lang.Long">
SELECT COUNT_BIG(1)
FROM (
SELECT 1 AS groupValue
FROM handling_unit h WITH (NOLOCK)
<include refid="labelInventoryFilter"/>
GROUP BY h.site, h.warehouse_id, h.part_no, h.batch_no, h.location_id, h.wdr
) inventoryGroups
</select>
<!--
现有库存以标签在库标记Y为唯一状态口径,保留冻结/预留标签,不关联栈板或inventory_stock。
按用户要求使用NOLOCK:并发更新时允许脏读、漏读或重复读取,统计/导出不是一致性快照,禁止作为扣库存依据。
必须先GROUP BY再分页,ORDER BY覆盖全部分组键,避免同库存维度跨页顺序不确定。 - rqrq
-->
<select id="getLabelInventoryStockList" resultType="com.gaotao.modules.warehouse.entity.vo.LabelInventoryStockRow">
SELECT h.site AS site,
h.warehouse_id AS warehouseId,
h.part_no AS partNo,
h.batch_no AS batchNo,
h.location_id AS locationId,
h.wdr AS wdr,
SUM(ISNULL(h.qty, 0)) AS qtyOnHand
FROM handling_unit h WITH (NOLOCK)
<include refid="labelInventoryFilter"/>
GROUP BY h.site, h.warehouse_id, h.part_no, h.batch_no, h.location_id, h.wdr
ORDER BY h.site, h.warehouse_id, h.part_no, h.batch_no, h.location_id, h.wdr
</select>
</mapper>
Loading…
Cancel
Save