Browse Source

feat(check): 新增年度盘点报告功能

- 在 CountHeader 实体中添加年中盘点(MID_YEAR)和年末盘点(YEAR_END)类型定义
- 在 PhysicalInventoryController 中新增 generateYearInventoryReport 接口用于生成年度盘点报告
- 在 PhysicalInventoryMapper 中新增多个查询方法支持年度盘点报告的数据统计和批量插入
- 在 Mapper XML 文件中添加相应的 SQL 查询语句和条件判断逻辑
- 在 PhysicalInventoryService 中定义年度盘点报告服务接口
- 在 PhysicalInventoryServiceImpl 中实现完整的年度盘点报告生成功能,包括数据校验、批量插入等逻辑
master
常熟吴彦祖 6 months ago
parent
commit
43662468cf
  1. 9
      src/main/java/com/gaotao/modules/check/controller/PhysicalInventoryController.java
  2. 9
      src/main/java/com/gaotao/modules/check/entity/CountHeader.java
  3. 25
      src/main/java/com/gaotao/modules/check/mapper/PhysicalInventoryMapper.java
  4. 8
      src/main/java/com/gaotao/modules/check/service/PhysicalInventoryService.java
  5. 69
      src/main/java/com/gaotao/modules/check/service/impl/PhysicalInventoryServiceImpl.java
  6. 118
      src/main/resources/mapper/check/PhysicalInventoryMapper.xml

9
src/main/java/com/gaotao/modules/check/controller/PhysicalInventoryController.java

@ -494,6 +494,15 @@ public class PhysicalInventoryController {
physicalInventoryService.updateSysIfCount(site, value);
return R.ok();
}
/**
* @Description 生成年度盘点报告年中/年末在盘点模式下按在库标签生成已完成单 - rqrq
* @author rqrq
*/
@PostMapping("/generateYearInventoryReport")
public R generateYearInventoryReport(@RequestBody java.util.Map<String, Object> query) {
return physicalInventoryService.generateYearInventoryReport(query);
}
// ==================== 自动盘盈盘亏处理 ==================== - rqrq

9
src/main/java/com/gaotao/modules/check/entity/CountHeader.java

@ -22,7 +22,7 @@ import java.util.Date;
* <p><b>核心字段说明</b></p>
* <ul>
* <li><b>count_no</b>盘点单号格式CT + yyyyMMdd + 4位序号</li>
* <li><b>count_type</b>盘点类型CYCLE=循环盘点MANUAL=手工盘点DAILY=日常盘点 - rqrq</li>
* <li><b>count_type</b>盘点类型CYCLE=循环盘点MANUAL=手工盘点DAILY=日常盘点MID_YEAR=年中盘点YEAR_END=年末盘点 - rqrq</li>
* <li><b>status</b>盘点状态控制盘点单的生命周期</li>
* <li><b>count_percent</b>循环盘点百分比仅循环盘点使用</li>
* </ul>
@ -73,6 +73,9 @@ public class CountHeader {
* <ul>
* <li>CYCLE = 循环盘点按百分比自动选取标签</li>
* <li>MANUAL = 手工盘点用户手动选择物料</li>
* <li>DAILY = 日常盘点 WCS RFID</li>
* <li>MID_YEAR = 年中盘点年度盘点报告- rqrq</li>
* <li>YEAR_END = 年末盘点年度盘点报告- rqrq</li>
* </ul>
*/
@TableField("count_type")
@ -174,6 +177,10 @@ public class CountHeader {
public static final String COUNT_TYPE_MANUAL = "MANUAL";
/** 盘点类型:日常盘点(WCS日常RFID盘点)- rqrq */
public static final String COUNT_TYPE_DAILY = "DAILY";
/** 盘点类型:年中盘点(年度盘点报告,写入 count_header.count_type)- rqrq */
public static final String COUNT_TYPE_MID_YEAR = "MID_YEAR";
/** 盘点类型:年末盘点(年度盘点报告,写入 count_header.count_type)- rqrq */
public static final String COUNT_TYPE_YEAR_END = "YEAR_END";
/** 状态:草稿 */
public static final String STATUS_DRAFT = "DRAFT";

25
src/main/java/com/gaotao/modules/check/mapper/PhysicalInventoryMapper.java

@ -478,6 +478,31 @@ public interface PhysicalInventoryMapper extends BaseMapper<CountHeader> {
* @author rqrq
*/
int insertCountHeader(@Param("header") CountHeader header);
/**
* @Description 在库且未盘点标签数量年度盘点报告校验- rqrq
*/
int countInStockUncountedLabels(@Param("site") String site);
/**
* @Description 在库且未盘点标签号前 20 - rqrq
*/
List<String> listInStockUncountedUnitIdsTop(@Param("site") String site);
/**
* @Description 在库且已盘点标签数in_stock_flag=Y count_flag=Y年度报告准入 - rqrq
*/
int countHandlingUnitInStock(@Param("site") String site);
/**
* @Description 年度盘点报告符合条件标签批量插入 count_label - rqrq
*/
int insertYearReportCountLabelFromHandlingUnit(@Param("site") String site, @Param("countNo") String countNo, @Param("username") String username);
/**
* @Description 年度盘点报告符合条件标签批量插入 count_result - rqrq
*/
int insertYearReportCountResultFromHandlingUnit(@Param("site") String site, @Param("countNo") String countNo, @Param("username") String username);
/**
* @Description 删除盘点主表 - rqrq

8
src/main/java/com/gaotao/modules/check/service/PhysicalInventoryService.java

@ -1,6 +1,7 @@
package com.gaotao.modules.check.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gaotao.common.utils.R;
import com.gaotao.modules.automatedWarehouse.entity.WmsOrderTaskData;
import com.gaotao.modules.automatedWarehouse.entity.WmsOrderTaskDetailData;
import com.gaotao.modules.check.entity.*;
@ -407,5 +408,12 @@ public interface PhysicalInventoryService {
*/
void updateSysIfCount(String site, String value);
/**
* @Description 年度盘点报告校验盘点模式与未盘点标签生成已完成盘点单及 count_label/count_result不写 count_pallet- rqrq
* @param query siteusernamecountTypeMID_YEAR/YEAR_ENDremarkforceContinue可选二次提交
* @return R 成功 put row(countNo/labelCount/resultCount)未盘点拦截 code=460
* @author rqrq
*/
R generateYearInventoryReport(java.util.Map<String, Object> query);
}

69
src/main/java/com/gaotao/modules/check/service/impl/PhysicalInventoryServiceImpl.java

@ -11,6 +11,7 @@ import com.gaotao.modules.automatedWarehouse.mapper.WcsIntegrationMapper;
import com.gaotao.modules.check.entity.*;
import com.gaotao.modules.check.mapper.PhysicalInventoryMapper;
import com.gaotao.modules.check.service.PhysicalInventoryService;
import com.gaotao.common.utils.R;
import com.gaotao.modules.trans.entity.TransNoControl;
import com.gaotao.modules.trans.service.TransNoControlService;
import com.gaotao.modules.api.entity.NotifyDataToWcs;
@ -2721,4 +2722,72 @@ public class PhysicalInventoryServiceImpl extends ServiceImpl<PhysicalInventoryM
log.info("该任务还有{}个明细未完成,等待其他托盘盘点", uncompleteCount);
}
}
/**
* @Description 年度盘点报告盘点模式校验未盘点在库标签提示code=460 可二次 forceContinue写入已完成头表及 label/result - rqrq
* @author rqrq
*/
@Override
@Transactional(rollbackFor = Exception.class)
public R generateYearInventoryReport(Map<String, Object> query) {
String site = query.get("site") != null ? String.valueOf(query.get("site")).trim() : "";
String username = query.get("username") != null ? String.valueOf(query.get("username")).trim() : "";
String countType = query.get("countType") != null ? String.valueOf(query.get("countType")).trim() : "";
String remark = query.get("remark") != null ? String.valueOf(query.get("remark")).trim() : "";
Object fc = query.get("forceContinue");
boolean forceContinue = Boolean.TRUE.equals(fc)
|| "true".equalsIgnoreCase(String.valueOf(fc));
if (!StringUtils.hasText(site)) {
return R.error("工厂编码不能为空");
}
if (!StringUtils.hasText(username)) {
return R.error("操作用户不能为空");
}
if (!CountHeader.COUNT_TYPE_MID_YEAR.equals(countType) && !CountHeader.COUNT_TYPE_YEAR_END.equals(countType)) {
return R.error("盘点报告类型无效,请选择年中盘点或年末盘点");
}
if (!"Y".equals(baseMapper.getSysIfCount(site))) {
return R.error("当前未开启盘点模式,无法生成年度盘点报告");
}
int inStockCnt = baseMapper.countHandlingUnitInStock(site);
if (inStockCnt <= 0) {
return R.error("没有在库且已盘点(in_stock_flag=Y 且 count_flag=Y)的标签,无法生成年度盘点报告"); // 业务口径 - rqrq
}
int uncounted = baseMapper.countInStockUncountedLabels(site);
if (uncounted > 0 && !forceContinue) {
List<String> ids = baseMapper.listInStockUncountedUnitIdsTop(site);
String sample = ids.isEmpty() ? "" : String.join("、", ids);
String msg = String.format("存在未盘点在库标签共 %d 条,前 20 个标签号:%s。是否仍要继续生成?", uncounted, sample);
return R.error(460, msg).put("uncountedTotal", uncounted).put("uncountedUnitIds", ids);
}
TransNoControl transData = transNoService.getTransNo(site, "PD", 10);
String countNo = transData.getNewTransNo();
CountHeader header = new CountHeader();
header.setSite(site);
header.setCountNo(countNo);
header.setCountType(countType);
header.setStatus(CountHeader.STATUS_COMPLETED);
header.setCountPercent(null);
header.setApplyUser(username);
header.setReleaseUser(username);
header.setCompleteUser(username);
header.setRemark(StringUtils.hasText(remark) ? remark : "年度盘点报告");
header.setCreatedBy(username);
baseMapper.insertCountHeader(header);
int labelRows = baseMapper.insertYearReportCountLabelFromHandlingUnit(site, countNo, username);
int resultRows = baseMapper.insertYearReportCountResultFromHandlingUnit(site, countNo, username);
Map<String, Object> row = new HashMap<>();
row.put("countNo", countNo);
row.put("labelCount", labelRows);
row.put("resultCount", resultRows);
log.info("年度盘点报告生成完成 - rqrq,site={},countNo={},labelCount={},resultCount={}", site, countNo, labelRows, resultRows);
return R.ok().put("row", row);
}
}

118
src/main/resources/mapper/check/PhysicalInventoryMapper.xml

@ -26,6 +26,8 @@
WHEN 'CYCLE' THEN '循环盘点'
WHEN 'MANUAL' THEN '手工盘点'
WHEN 'DAILY' THEN '日常盘点'
WHEN 'MID_YEAR' THEN '年中盘点'
WHEN 'YEAR_END' THEN '年末盘点'
ELSE h.count_type
END AS countTypeDesc,
CASE h.status
@ -118,7 +120,7 @@
h.remark,
h.created_by AS createdBy,
h.created_date AS createdDate,
CASE h.count_type WHEN 'CYCLE' THEN '循环盘点' WHEN 'MANUAL' THEN '手工盘点' WHEN 'DAILY' THEN '日常盘点' ELSE h.count_type END AS countTypeDesc,
CASE h.count_type WHEN 'CYCLE' THEN '循环盘点' WHEN 'MANUAL' THEN '手工盘点' WHEN 'DAILY' THEN '日常盘点' WHEN 'MID_YEAR' THEN '年中盘点' WHEN 'YEAR_END' THEN '年末盘点' ELSE h.count_type END AS countTypeDesc,
CASE h.status WHEN 'DRAFT' THEN '草稿' WHEN 'RELEASED' THEN '已下达' WHEN 'CHECKING' THEN '盘点中' WHEN 'APPROVED' THEN '已审批' WHEN 'COMPLETED' THEN '已完成' WHEN 'CANCELLED' THEN '已取消' ELSE h.status END AS statusDesc,
(SELECT COUNT(1) FROM count_label WHERE site = h.site AND count_no = h.count_no) AS totalLabelCount,
(SELECT COUNT(1) FROM count_label WHERE site = h.site AND count_no = h.count_no AND count_flag = 'Y') AS checkedLabelCount,
@ -878,11 +880,119 @@
WHERE site = #{header.site} AND count_no = #{header.countNo}
</update>
<!-- rqrq - 插入盘点主表 -->
<!-- rqrq - 插入盘点主表(可选写入下达/完成人时间,供日常盘点与年度盘点报告等)-->
<insert id="insertCountHeader">
INSERT INTO count_header (site, count_no, count_type, status, count_percent, apply_user, apply_date, remark, created_by, created_date)
INSERT INTO count_header (site, count_no, count_type, status, count_percent, apply_user, apply_date, remark, created_by, created_date
<if test="header.releaseUser != null and header.releaseUser != ''">
, release_user, release_date
</if>
<if test="header.completeUser != null and header.completeUser != ''">
, complete_user, complete_date
</if>
)
VALUES (#{header.site}, #{header.countNo}, #{header.countType}, #{header.status}, #{header.countPercent},
#{header.applyUser}, GETDATE(), #{header.remark}, #{header.createdBy}, GETDATE())
#{header.applyUser}, GETDATE(), #{header.remark}, #{header.createdBy}, GETDATE()
<if test="header.releaseUser != null and header.releaseUser != ''">
, #{header.releaseUser}, GETDATE()
</if>
<if test="header.completeUser != null and header.completeUser != ''">
, #{header.completeUser}, GETDATE()
</if>
)
</insert>
<!-- rqrq - 在库且未盘点标签数量(in_stock_flag=Y 且 count_flag 非 Y)-->
<select id="countInStockUncountedLabels" resultType="int">
SELECT COUNT(1)
FROM handling_unit h WITH (NOLOCK)
WHERE h.site = #{site}
AND h.in_stock_flag = 'Y'
AND ISNULL(h.count_flag, 'N') &lt;&gt; 'Y'
</select>
<!-- rqrq - 在库且未盘点标签号前 20 条(年度盘点报告提示)-->
<select id="listInStockUncountedUnitIdsTop" resultType="java.lang.String">
SELECT TOP 20 h.unit_id
FROM handling_unit h WITH (NOLOCK)
WHERE h.site = #{site}
AND h.in_stock_flag = 'Y'
AND ISNULL(h.count_flag, 'N') &lt;&gt; 'Y'
ORDER BY h.unit_id
</select>
<!-- rqrq - 在库且已盘点标签总数(年度报告准入条数,须 in_stock_flag 与 count_flag 均为 Y)-->
<select id="countHandlingUnitInStock" resultType="int">
SELECT COUNT(1)
FROM handling_unit h WITH (NOLOCK)
WHERE h.site = #{site}
AND h.in_stock_flag = 'Y'
AND h.count_flag = 'Y'
</select>
<!-- rqrq - 年度盘点报告:仅 in_stock_flag=Y 且 count_flag=Y;从 handling_unit 写入 count_label,pallet_id 固定 * -->
<insert id="insertYearReportCountLabelFromHandlingUnit">
INSERT INTO count_label (
site, count_no, unit_id, part_no, qty,
batch_no, location_id, warehouse_id, wdr, pallet_id,
label_type, count_flag, count_date, count_user,
created_by, created_date
)
SELECT
h.site,
#{countNo},
h.unit_id,
h.part_no,
h.qty,
h.batch_no,
h.location_id,
h.warehouse_id,
h.wdr,
'*',
'ASSIGNED',
'Y',
COALESCE(h.last_count_date, h.modified_date, h.created_date, GETDATE()),
'SYSTEM',
#{username},
GETDATE()
FROM handling_unit h WITH (NOLOCK)
WHERE h.site = #{site}
AND h.in_stock_flag = 'Y'
AND h.count_flag = 'Y'
</insert>
<!-- rqrq - 年度盘点报告:仅 in_stock_flag=Y 且 count_flag=Y;写入 count_result,结果均为 OK、无差异(count_date NOT NULL,须兜底)-->
<insert id="insertYearReportCountResultFromHandlingUnit">
INSERT INTO count_result (
site, count_no, unit_id, part_no, qty,
batch_no, location_id, warehouse_id, wdr, pallet_id,
count_date, count_user, count_result, diff_qty,
handle_flag, handle_type, remark,
created_by, created_date
)
SELECT
h.site,
#{countNo},
h.unit_id,
h.part_no,
h.qty,
h.batch_no,
h.location_id,
h.warehouse_id,
h.wdr,
'*',
COALESCE(h.last_count_date, h.modified_date, h.created_date, GETDATE()),
'SYSTEM',
'OK',
0,
'Y',
'',
N'年度盘点报告(无差异)',
#{username},
GETDATE()
FROM handling_unit h WITH (NOLOCK)
WHERE h.site = #{site}
AND h.in_stock_flag = 'Y'
AND h.count_flag = 'Y'
</insert>
<!-- rqrq - 删除盘点主表 -->

Loading…
Cancel
Save