fix:预警配置功能调整,新增安全上下限,已读未读等功能

This commit is contained in:
zhengxuming
2025-07-17 14:54:32 +08:00
parent d5e38b8ab3
commit e58fefcab9
22 changed files with 480 additions and 260 deletions

View File

@@ -73,41 +73,40 @@ public class ForewarningTask {
/**
* 预警数据生成
* <p>
* 1、删除st_ivt_overdueforewarning、st_ivt_safetyforewarning表中的全部数据
* 2、查询st_ivt_forewarningconfig,获取正在启用的、未删除的配置
* 3、通过st_ivt_forewarningconfig表的id字段匹配上st_ivt_forewarningmaterial表的config_id字段获取对应的物料。赋值给
* 1、查询st_ivt_forewarningconfig获取正在启用的、未删除的配置
* 2、通过st_ivt_forewarningconfig表的id字段匹配上st_ivt_forewarningmaterial表的config_id字段获取对应的物料。赋值给
* StIvtForewarningconfigDto的tableData
* 4、循环,判断每条数据下的对应物料的安全库存数量、入库时间(以组盘时间为准)
* 3、循环,判断每条数据下的对应物料的安全库存数量、入库时间(以组盘时间为准)
* 其中库存表md_pb_groupplate实体类GroupPlate组盘时间create_time物料编码id material_id
* 5、 分别生成st_ivt_safetyforewarning(安全库存数量超期) 和 st_ivt_overdueforewarning安全库存天数超期) ,插入到对应数据库中
* 4、 分别生成st_ivt_safetyforewarning(安全库存数量超期) 和 st_ivt_overdueforewarning超期天数超期) ,插入到对应数据库中
*/
private void runTask() {
// 1. 删除st_ivt_overdueforewarning、st_ivt_safetyforewarning表中的全部数据
stIvtOverdueforewarningService.deleteAllNoParam();
stIvtSafetyforewarningService.deleteAllNoParam();
// stIvtOverdueforewarningService.deleteAllNoParam();
// stIvtSafetyforewarningService.deleteAllNoParam();
// 2. 查询st_ivt_forewarningconfig获取正在启用的、未删除的配置
List<StIvtForewarningconfig> configList = forewarningconfigService.list(new LambdaQueryWrapper<StIvtForewarningconfig>()
.eq(StIvtForewarningconfig::getIs_active,true)
.eq(StIvtForewarningconfig::getIs_delete,false));
.eq(StIvtForewarningconfig::getIs_active, true)
.eq(StIvtForewarningconfig::getIs_delete, false));
if (CollectionUtil.isEmpty(configList)) {
return;
}
List<String> configStringList =configList.stream().map(StIvtForewarningconfig::getId).collect(Collectors.toList());
List<String> configStringList = configList.stream().map(StIvtForewarningconfig::getId).collect(Collectors.toList());
// 获取配置文件下的所有物料
List<StIvtForewarningmaterial> materialList = stIvtForewarningmaterialService.list(new LambdaQueryWrapper<StIvtForewarningmaterial>()
.eq(StIvtForewarningmaterial::getIs_active,true)
.eq(StIvtForewarningmaterial::getIs_delete,false)
.in(StIvtForewarningmaterial::getConfig_id,configStringList));
.eq(StIvtForewarningmaterial::getIs_active, true)
.eq(StIvtForewarningmaterial::getIs_delete, false)
.in(StIvtForewarningmaterial::getConfig_id, configStringList));
List<String> materialIdList = materialList.stream().map(StIvtForewarningmaterial::getMaterial_id).collect(Collectors.toList());
List<String> storCodeList = configList.stream().map(StIvtForewarningconfig::getStor_code).collect(Collectors.toList());
Set<String> materialIdList = materialList.stream().map(StIvtForewarningmaterial::getMaterial_id).collect(Collectors.toSet());
Set<String> storCodeList = configList.stream().map(StIvtForewarningconfig::getStor_code).collect(Collectors.toSet());
// 查询库存信息
Map<String,Object> queryMap = new HashMap();
queryMap.put("stor_code_list",storCodeList);
queryMap.put("material_id_list",materialIdList);
Map<String, Object> queryMap = new HashMap();
queryMap.put("stor_code_list", storCodeList);
queryMap.put("material_id_list", materialIdList);
List<MdPbStoragevehicleextDto> mdPbStoragevehicleextDtos = mdPbStoragevehicleextMapper.queryAll(queryMap);
if (CollectionUtil.isEmpty(mdPbStoragevehicleextDtos)) {
return;
@@ -116,88 +115,107 @@ public class ForewarningTask {
for (StIvtForewarningconfig config : configList) {
//3. 通过st_ivt_forewarningconfig表的id字段匹配上st_ivt_forewarningmaterial表的config_id字段获取对应的物料
List<StIvtForewarningmaterial> configMaterialList = materialList.stream().
filter(a->config.getId().equals(a.getConfig_id())).collect(Collectors.toList());
filter(a -> config.getId().equals(a.getConfig_id())).collect(Collectors.toList());
// 按照struct_code对mdPbStoragevehicleextDtos进行分组
Map<String, List<MdPbStoragevehicleextDto>> structCodeGroupMap = mdPbStoragevehicleextDtos.stream()
.filter(a->config.getStor_code().equals(a.getStor_code()))
.collect(Collectors.groupingBy(MdPbStoragevehicleextDto::getStruct_code));
// 4. 循环,判断每条数据下的对应物料的安全库存数量、入库时间(以组盘时间为准)
for (StIvtForewarningmaterial material : configMaterialList) {
// 计算安全库存数量
BigDecimal totalQty = mdPbStoragevehicleextDtos.stream()
.filter(a -> config.getStor_code().equals(a.getStor_code())
&& material.getMaterial_id().equals(a.getMaterial_id()))
.map(MdPbStoragevehicleextDto::getQty)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 遍历structCodeGroupMap获取每个struct_code下的mdPbStoragevehicleextDtos
for (Map.Entry<String, List<MdPbStoragevehicleextDto>> entry : structCodeGroupMap.entrySet()) {
List<MdPbStoragevehicleextDto> mdPbStoragevehicleextDtoStructs = entry.getValue();
// 计算最早的组盘时间
LocalDateTime earliestPlate = null;
try {
earliestPlate = mdPbStoragevehicleextDtos.stream()
// 计算安全库存数量
BigDecimal totalQty = mdPbStoragevehicleextDtoStructs.stream()
.filter(a -> config.getStor_code().equals(a.getStor_code())
&& material.getMaterial_id().equals(a.getMaterial_id()))
.map(a -> {
try {
String createTimeStr = a.getCreate_time();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return LocalDateTime.parse(createTimeStr, formatter);
} catch (Exception ex) {
// 解析失败返回null
return null;
}
})
.filter(Objects::nonNull)
.min(LocalDateTime::compareTo)
.orElse(null);
} catch (Exception ex) {
// 处理整体异常
earliestPlate = null;
.map(MdPbStoragevehicleextDto::getQty)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 计算最早的组盘时间
LocalDateTime earliestPlate = null;
try {
earliestPlate = mdPbStoragevehicleextDtoStructs.stream()
.filter(a -> config.getStor_code().equals(a.getStor_code())
&& material.getMaterial_id().equals(a.getMaterial_id()))
.map(a -> {
try {
String createTimeStr = a.getCreate_time();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return LocalDateTime.parse(createTimeStr, formatter);
} catch (Exception ex) {
// 解析失败,返回null
return null;
}
})
.filter(Objects::nonNull)
.min(LocalDateTime::compareTo)
.orElse(null);
} catch (Exception ex) {
// 处理整体异常
earliestPlate = null;
}
// 计算 earliestPlate 与当前时间的天数差返回int类型
BigDecimal daysDiff = BigDecimal.ZERO;
if (earliestPlate != null) {
long millis = java.time.Duration.between(earliestPlate, LocalDateTime.now()).toMillis();
daysDiff = new BigDecimal(millis)
.divide(new BigDecimal(1000 * 60 * 60 * 24), 4, BigDecimal.ROUND_HALF_UP);
}
// 5. 分别生成st_ivt_safetyforewarning(安全库存数量超期) 和 st_ivt_overdueforewarning超期天数超期
// 安全库存数量超限
if ((config.getSafe_qty_lower_limit() != null && totalQty.compareTo(config.getSafe_qty_lower_limit()) < 0)
|| (config.getSafe_qty_upper_limit() != null && totalQty.compareTo(config.getSafe_qty_upper_limit()) > 0)) {
StIvtSafetyforewarning safety = new StIvtSafetyforewarning();
safety.setId(IdUtil.getSnowflake(1, 1).nextIdStr());
safety.setConfig_id(config.getId());
safety.setMaterial_code(material.getMaterial_code());
safety.setMaterial_name(material.getMaterial_name());
safety.setSect_code(mdPbStoragevehicleextDtoStructs.get(0).getSect_code());
safety.setSect_name(mdPbStoragevehicleextDtoStructs.get(0).getSect_name());
safety.setStruct_code(mdPbStoragevehicleextDtoStructs.get(0).getStruct_code());
safety.setStruct_name(mdPbStoragevehicleextDtoStructs.get(0).getStruct_name());
safety.setSafe_qty_lower_limit(config.getSafe_qty_lower_limit());
safety.setSafe_qty_upper_limit(config.getSafe_qty_upper_limit());
safety.setStor_code(config.getStor_code());
safety.setCurrent_qty(totalQty);
safety.setCreate_name("JOB");
safety.setCreate_time(DateUtil.now());
stIvtSafetyforewarningService.save(safety);
}
// 超期天数超期
if (config.getSafe_days() != null && daysDiff.compareTo(config.getSafe_days()) > 0) {
// 将 earliestPlate 转化成 yyyy-MM-dd HH:mm:ss 的String 类型
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String earliestPlateStr = earliestPlate.format(formatter);
StIvtOverdueforewarning overdue = new StIvtOverdueforewarning();
overdue.setId(IdUtil.getSnowflake(1, 1).nextIdStr());
overdue.setConfig_id(config.getId());
overdue.setMaterial_code(material.getMaterial_code());
overdue.setMaterial_name(material.getMaterial_name());
overdue.setOverdue_days(daysDiff);
overdue.setStor_code(config.getStor_code());
overdue.setSect_code(mdPbStoragevehicleextDtoStructs.get(0).getSect_code());
overdue.setSect_name(mdPbStoragevehicleextDtoStructs.get(0).getSect_name());
overdue.setStruct_code(mdPbStoragevehicleextDtoStructs.get(0).getStruct_code());
overdue.setStruct_name(mdPbStoragevehicleextDtoStructs.get(0).getStruct_name());
overdue.setSafe_days(config.getSafe_days());
overdue.setInsert_time(earliestPlateStr);
overdue.setCreate_name("JOB");
overdue.setCreate_time(DateUtil.now());
stIvtOverdueforewarningService.save(overdue);
}
}
// 计算 earliestPlate 与当前时间的天数差返回int类型
BigDecimal daysDiff = BigDecimal.ZERO;
if (earliestPlate != null) {
long millis = java.time.Duration.between(earliestPlate, LocalDateTime.now()).toMillis();
daysDiff = new BigDecimal(millis)
.divide(new BigDecimal(1000 * 60 * 60 * 24), 4, BigDecimal.ROUND_HALF_UP);
}
// 5. 分别生成st_ivt_safetyforewarning(安全库存数量超期) 和 st_ivt_overdueforewarning安全库存天数超期
// 安全库存数量超期
if (config.getSafe_qty() != null && totalQty.compareTo(config.getSafe_qty()) > 0) {
StIvtSafetyforewarning safety = new StIvtSafetyforewarning();
safety.setId(IdUtil.getSnowflake(1, 1).nextIdStr());
safety.setConfig_id(config.getId());
safety.setMaterial_code(material.getMaterial_code());
safety.setMaterial_name(material.getMaterial_name());
safety.setSafe_qty(config.getSafe_qty());
safety.setStor_code(config.getStor_code());
safety.setCurrent_qty(totalQty);
safety.setCreate_name("JOB");
safety.setCreate_time(DateUtil.now());
stIvtSafetyforewarningService.save(safety);
}
// 安全库存天数超期
if (config.getSafe_days() != null && daysDiff.compareTo(config.getSafe_days())>0) {
// 将 earliestPlate 转化成 yyyy-MM-dd HH:mm:ss 的String 类型
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String earliestPlateStr = earliestPlate.format(formatter);
StIvtOverdueforewarning overdue = new StIvtOverdueforewarning();
overdue.setId(IdUtil.getSnowflake(1, 1).nextIdStr());
overdue.setConfig_id(config.getId());
overdue.setMaterial_code(material.getMaterial_code());
overdue.setMaterial_name(material.getMaterial_name());
overdue.setOverdue_days(daysDiff);
overdue.setStor_code(config.getStor_code());
overdue.setSafe_days(config.getSafe_days());
overdue.setInsert_time(earliestPlateStr);
overdue.setCreate_name("JOB");
overdue.setCreate_time(DateUtil.now());
stIvtOverdueforewarningService.save(overdue);
}
}
}
}

View File

@@ -56,4 +56,12 @@ public class StIvtOverdueforewarningController {
stIvtOverdueforewarningService.deleteAll(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
@Log("将预警信息设置为已读")
//@SaCheckPermission("stIvtOverdueforewarning:del")
@PostMapping("/read")
public ResponseEntity<Object> read(@RequestBody Set<String> ids) {
stIvtOverdueforewarningService.read(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -56,4 +56,12 @@ public class StIvtSafetyforewarningController {
stIvtSafetyforewarningService.deleteAll(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
@Log("将预警信息设置为已读")
//@SaCheckPermission("stIvtOverdueforewarning:del")
@PostMapping("/read")
public ResponseEntity<Object> read(@RequestBody Set<String> ids) {
stIvtSafetyforewarningService.read(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -47,4 +47,10 @@ public interface IStIvtOverdueforewarningService extends IService<StIvtOverduefo
* 删除全部
*/
void deleteAllNoParam();
/**
* 已读全部
* @param ids /
*/
void read(Set<String> ids);
}

View File

@@ -43,4 +43,10 @@ public interface IStIvtSafetyforewarningService extends IService<StIvtSafetyfore
void deleteAll(Set<String> ids);
void deleteAllNoParam();
/**
* 已读全部
* @param ids /
*/
void read(Set<String> ids);
}

View File

@@ -32,10 +32,13 @@ private static final long serialVersionUID = 1L;
/** 仓库编码 */
private String stor_code;
/** 安全库存数量 */
private BigDecimal safe_qty;
/** 安全数量下限 */
private BigDecimal safe_qty_lower_limit;
/** 安全库存天数 */
/** 安全数量上限 */
private BigDecimal safe_qty_upper_limit;
/** 超期天数 */
private BigDecimal safe_days;
/** 备注 */

View File

@@ -35,9 +35,21 @@ private static final long serialVersionUID = 1L;
/** 物料名称 */
private String material_name;
/** 仓编码 */
/** 仓编码 */
private String stor_code;
/** 库区编码 */
private String sect_code;
/** 库区名称 */
private String sect_name;
/** 仓位编码 */
private String struct_code;
/** 仓位名称 */
private String struct_name;
/** 入库时间 */
private String insert_time;
@@ -53,6 +65,9 @@ private static final long serialVersionUID = 1L;
/** 是否删除 */
private String is_delete;
/** 是否已读 */
private Boolean is_read;
/** 创建id */
private String create_id;

View File

@@ -35,14 +35,29 @@ private static final long serialVersionUID = 1L;
/** 物料名称 */
private String material_name;
/** 仓编码 */
/** 仓编码 */
private String stor_code;
/** 库区编码 */
private String sect_code;
/** 库区名称 */
private String sect_name;
/** 仓位编码 */
private String struct_code;
/** 仓位名称 */
private String struct_name;
/** 当前数量 */
private BigDecimal current_qty;
/** 安全数量 */
private BigDecimal safe_qty;
/** 安全数量下限 */
private BigDecimal safe_qty_lower_limit;
/** 安全数量上限 */
private BigDecimal safe_qty_upper_limit;
/** 备注 */
private String remark;
@@ -50,6 +65,9 @@ private static final long serialVersionUID = 1L;
/** 是否删除 */
private String is_delete;
/** 是否已读 */
private Boolean is_read;
/** 创建id */
private String create_id;

View File

@@ -15,9 +15,13 @@
AND
config.stor_code = #{params.stor_code}
</if>
<if test="params.safe_qty != null">
<if test="params.safe_qty_lower_limit != null">
AND
config.safe_qty = #{params.safe_qty}
config.safe_qty_lower_limit = #{params.safe_qty_lower_limit}
</if>
<if test="params.safe_qty_upper_limit != null">
AND
config.safe_qty_upper_limit = #{params.safe_qty_upper_limit}
</if>
<if test="params.safe_days != null">
AND

View File

@@ -20,7 +20,11 @@
AND
forewarning.stor_code = #{params.stor_code}
</if>
<if test="params.is_read != null">
AND
forewarning.is_read = #{params.is_read}
</if>
</where>
ORDER BY forewarning.update_time Desc
ORDER BY is_read asc,forewarning.create_time Desc
</select>
</mapper>

View File

@@ -20,7 +20,11 @@
AND
forewarning.stor_code = #{params.stor_code}
</if>
<if test="params.is_read != null">
AND
forewarning.is_read = #{params.is_read}
</if>
</where>
ORDER BY forewarning.update_time Desc
ORDER BY is_read asc,forewarning.create_time Desc
</select>
</mapper>

View File

@@ -29,10 +29,13 @@ public class StIvtForewarningconfigDto implements Serializable {
/** 仓库名称 */
private String stor_name;
/** 安全库存数量 */
private BigDecimal safe_qty;
/** 安全数量下限 */
private BigDecimal safe_qty_lower_limit;
/** 安全库存天数 */
/** 安全数量上限 */
private BigDecimal safe_qty_upper_limit;
/** 超期天数 */
private BigDecimal safe_days;
/** 备注 */

View File

@@ -28,11 +28,23 @@ public class StIvtOverdueforewarningDto implements Serializable {
/** 物料名称 */
private String material_name;
/** 仓编码 */
/** 仓编码 */
private String stor_code;
private String stor_name;
/** 库区编码 */
private String sect_code;
/** 库区名称 */
private String sect_name;
/** 仓位编码 */
private String struct_code;
/** 仓位名称 */
private String struct_name;
/** 入库时间 */
private String insert_time;
@@ -48,6 +60,9 @@ public class StIvtOverdueforewarningDto implements Serializable {
/** 是否删除 */
private String is_delete;
/** 是否已读 */
private Boolean is_read;
/** 创建id */
private String create_id;

View File

@@ -28,16 +28,31 @@ public class StIvtSafetyforewarningDto implements Serializable {
/** 物料名称 */
private String material_name;
/** 仓编码 */
/** 仓编码 */
private String stor_code;
private String stor_name;
/** 库区编码 */
private String sect_code;
/** 库区名称 */
private String sect_name;
/** 仓位编码 */
private String struct_code;
/** 仓位名称 */
private String struct_name;
/** 当前数量 */
private BigDecimal current_qty;
/** 安全数量 */
private BigDecimal safe_qty;
/** 安全数量下限 */
private BigDecimal safe_qty_lower_limit;
/** 安全数量上限 */
private BigDecimal safe_qty_upper_limit;
/** 备注 */
private String remark;
@@ -45,6 +60,9 @@ public class StIvtSafetyforewarningDto implements Serializable {
/** 是否删除 */
private String is_delete;
/** 是否已读 */
private Boolean is_read;
/** 创建id */
private String create_id;

View File

@@ -3,6 +3,7 @@ package org.nl.wms.warehouse_manage.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -12,6 +13,8 @@ import org.nl.config.language.LangProcess;
import org.nl.common.domain.query.PageQuery;
import org.nl.common.exception.BadRequestException;
import org.nl.common.utils.SecurityUtils;
import org.nl.wms.warehouse_manage.enums.IOSConstant;
import org.nl.wms.warehouse_manage.inAndOut.service.dao.IOStorInv;
import org.nl.wms.warehouse_manage.service.IStIvtOverdueforewarningService;
import org.nl.wms.warehouse_manage.service.dao.mapper.StIvtOverdueforewarningMapper;
import org.nl.wms.warehouse_manage.service.dao.StIvtOverdueforewarning;
@@ -82,4 +85,17 @@ public class StIvtOverdueforewarningServiceImpl extends ServiceImpl<StIvtOverdue
stIvtOverdueforewarningMapper.deleteByMap(null);
}
@Override
public void read(Set<String> ids) {
this.update(
new UpdateWrapper<StIvtOverdueforewarning>().lambda()
.in(StIvtOverdueforewarning::getId, ids)
.eq(StIvtOverdueforewarning::getIs_read,false)
.set(StIvtOverdueforewarning::getIs_read, true)
.set(StIvtOverdueforewarning::getUpdate_id, SecurityUtils.getCurrentUserId())
.set(StIvtOverdueforewarning::getUpdate_name, SecurityUtils.getCurrentNickName())
.set(StIvtOverdueforewarning::getUpdate_time, DateUtil.now())
);
}
}

View File

@@ -3,6 +3,7 @@ package org.nl.wms.warehouse_manage.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -16,6 +17,8 @@ import org.nl.wms.basedata_manage.service.dao.BsrealStorattr;
import org.nl.wms.basedata_manage.service.dao.mapper.BsrealStorattrMapper;
import org.nl.wms.warehouse_manage.service.IStIvtSafetyforewarningService;
import org.nl.wms.warehouse_manage.service.dao.StIvtForewarningconfig;
import org.nl.wms.warehouse_manage.service.dao.StIvtOverdueforewarning;
import org.nl.wms.warehouse_manage.service.dao.StIvtSafetyforewarning;
import org.nl.wms.warehouse_manage.service.dao.mapper.StIvtForewarningconfigMapper;
import org.nl.wms.warehouse_manage.service.dao.mapper.StIvtSafetyforewarningMapper;
import org.nl.wms.warehouse_manage.service.dao.StIvtSafetyforewarning;
@@ -92,4 +95,17 @@ public class StIvtSafetyforewarningServiceImpl extends ServiceImpl<StIvtSafetyfo
stIvtSafetyforewarningMapper.deleteByMap(null);
}
@Override
public void read(Set<String> ids) {
this.update(
new UpdateWrapper<StIvtSafetyforewarning>().lambda()
.in(StIvtSafetyforewarning::getId, ids)
.eq(StIvtSafetyforewarning::getIs_read,false)
.set(StIvtSafetyforewarning::getIs_read, true)
.set(StIvtSafetyforewarning::getUpdate_id, SecurityUtils.getCurrentUserId())
.set(StIvtSafetyforewarning::getUpdate_name, SecurityUtils.getCurrentNickName())
.set(StIvtSafetyforewarning::getUpdate_time, DateUtil.now())
);
}
}