From 6972fccd1c5275e703812a06868235692bbd54cf Mon Sep 17 00:00:00 2001 From: "HUOJIN\\92525" Date: Thu, 13 Nov 2025 16:56:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=A5=E5=BA=93=E5=8D=95=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=E3=80=81AGV=E4=BB=BB=E5=8A=A1=E7=94=9F=E6=88=90=E3=80=81?= =?UTF-8?q?=E4=B8=8B=E5=8F=91=E3=80=81=E4=B8=8A=E6=8A=A5=20TES=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=94=9F=E6=88=90=E3=80=81=E4=B8=8B=E5=8F=91=E3=80=81?= =?UTF-8?q?=E4=B8=8A=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jeecg/common/aspect/AutoLogAspect.java | 3 - .../org/jeecg/config/shiro/ShiroConfig.java | 28 +++ .../cpte/modules/agvTask/entity/AgvTask.java | 7 + .../modules/agvTask/mapper/AgvTaskMapper.java | 25 ++- .../agvTask/service/IAgvTaskService.java | 17 +- .../service/impl/AgvTaskServiceImpl.java | 5 +- .../base/controller/AreaController.java | 1 - .../cpte/modules/base/mapper/AreaMapper.java | 16 ++ .../cpte/modules/base/mapper/ItemMapper.java | 22 ++- .../cpte/modules/base/mapper/PointMapper.java | 29 ++- .../cpte/modules/base/mapper/StockMapper.java | 20 +- .../modules/base/mapper/xml/PointMapper.xml | 16 +- .../modules/base/service/IPointService.java | 12 -- .../base/service/impl/AreaServiceImpl.java | 9 +- .../base/service/impl/ItemServiceImpl.java | 15 +- .../base/service/impl/PointServiceImpl.java | 40 +--- .../base/service/impl/StockServiceImpl.java | 18 +- .../cpte/modules/constant/CommonConstant.java | 6 + .../modules/constant/enums/AreaTypeEnum.java | 2 + .../constant/enums/AsnOrderTypeEnum.java | 32 +++ .../cpte/modules/constant/enums/BaseEnum.java | 97 ++++++++++ .../constant/enums/InventoryLogEnum.java | 40 ++++ .../impl/IConveyorLineServiceImpl.java | 52 +++-- .../service/impl/IHikAgvServiceImpl.java | 4 +- .../modules/inventory/entity/Inventory.java | 10 +- .../inventory/mapper/InventoryMapper.java | 4 +- .../inventory/service/IInventoryService.java | 19 +- .../service/impl/InventoryServiceImpl.java | 37 +++- .../controller/InventoryLogController.java | 182 ++++++++++++++++++ .../inventoryLog/entity/InventoryLog.java | 174 +++++++++++++++++ .../mapper/InventoryLogMapper.java | 17 ++ .../mapper/xml/InventoryLogMapper.xml | 5 + .../service/IInventoryLogService.java | 126 ++++++++++++ .../service/impl/InventoryLogServiceImpl.java | 181 +++++++++++++++++ .../cpte/modules/quartz/job/HikAgvJob.java | 17 +- .../receive/controller/AsnController.java | 2 +- .../receive/mapper/AsnDetailMapper.java | 2 +- .../modules/receive/mapper/AsnMapper.java | 5 +- .../modules/receive/service/IAsnService.java | 74 +++---- .../receive/service/impl/AsnServiceImpl.java | 96 +++++---- .../service/impl/ISaiWmsServiceImpl.java | 50 +++-- .../service/impl/ITesAgvServiceImpl.java | 12 +- .../cpte/modules/utils/CodeGeneratorUtil.java | 51 +++-- .../org/cpte/modules/utils/SmartEnumUtil.java | 163 ++++++++++++++++ .../modules/monitor/service/RedisService.java | 86 ++++++--- .../service/impl/RedisServiceImpl.java | 47 +++++ 46 files changed, 1583 insertions(+), 293 deletions(-) create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/CommonConstant.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AsnOrderTypeEnum.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/BaseEnum.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/InventoryLogEnum.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/controller/InventoryLogController.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/entity/InventoryLog.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/mapper/InventoryLogMapper.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/mapper/xml/InventoryLogMapper.xml create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/IInventoryLogService.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/impl/InventoryLogServiceImpl.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/SmartEnumUtil.java diff --git a/cpte-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java b/cpte-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java index 1ee2801..7befb15 100644 --- a/cpte-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java +++ b/cpte-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java @@ -104,9 +104,6 @@ public class AutoLogAspect { if(sysUser!=null){ dto.setUserid(sysUser.getUsername()); dto.setUsername(sysUser.getRealname()); - }else { - dto.setUserid("赛意"); - dto.setUsername("赛意"); } //耗时 dto.setCostTime(time); diff --git a/cpte-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/cpte-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java index b821302..94ba5b1 100644 --- a/cpte-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java +++ b/cpte-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java @@ -27,6 +27,7 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.*; import org.springframework.core.env.Environment; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.*; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.filter.DelegatingFilterProxy; @@ -389,4 +390,31 @@ public class ShiroConfig { return seg.startsWith("/") ? seg : "/"+seg; } + + @Bean + public HashOperations hashOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForHash(); + } + + @Bean + public ValueOperations valueOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForValue(); + } + + @Bean + public ListOperations listOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForList(); + } + + @Bean + public SetOperations setOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForSet(); + } + + @Bean + public ZSetOperations zSetOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForZSet(); + } + + } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/entity/AgvTask.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/entity/AgvTask.java index 02a15c6..3fc67fc 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/entity/AgvTask.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/entity/AgvTask.java @@ -38,6 +38,13 @@ public class AgvTask implements Serializable { @Schema(description = "id") private java.lang.String id; + /** + * 业务ID + */ + @Excel(name = "业务ID", width = 15) + @Schema(description = "业务ID") + private java.lang.String businessDetailId; + /** * 载具编号 */ diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java index 057c8f4..7dd03e3 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java @@ -15,13 +15,32 @@ import java.util.List; */ public interface AgvTaskMapper extends BaseMapper { /** - * 验证AGV任务是否存在 + * 根据容器编码验证AGV任务是否存在 * * @param carrierCode 容器 * @param agvVendor 供应商;AGV/TES */ - @Select(value = "select count(id) from data_agv_task where carrier_code = #{carrierCode} and agv_vendor = #{agvVendor} and status in (1,2,3) ") - Long existsAGVTask(@Param("carrierCode") String carrierCode, @Param("agvVendor") String agvVendor); + @Select(value = "select count(id) from data_agv_task where carrier_code = #{carrierCode} and agv_vendor = #{agvVendor} and status in (1,2,3) for update ") + Long existsByStockCode(@Param("carrierCode") String carrierCode, @Param("agvVendor") String agvVendor); + + /** + * 根据起点编码验证AGV任务是否存在 + * + * @param startCode 起点 + * @param agvVendor 供应商;AGV/TES + */ + @Select(value = "select count(id) from data_agv_task where start_code = #{startCode} and agv_vendor = #{agvVendor} and status in (2,3) for update ") + Long existsByStartCode(@Param("startCode") String startCode, @Param("agvVendor") String agvVendor); + + + /** + * 根据终点编码验证AGV任务是否存在 + * + * @param endCode 终点 + * @param agvVendor 供应商;AGV/TES + */ + @Select(value = "select count(id) from data_agv_task where end_code = #{pointCode} and agv_vendor = #{agvVendor} and status in (2,3) for update ") + Long existsByEndCode(@Param("pointCode") String endCode, @Param("agvVendor") String agvVendor); /** * 查询AGV任务列表 diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/IAgvTaskService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/IAgvTaskService.java index 5099a4c..d82784a 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/IAgvTaskService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/IAgvTaskService.java @@ -15,14 +15,15 @@ public interface IAgvTaskService extends IService { /** * 创建agvTask任务 * - * @param status 状态 - * @param carrierCode 容器 - * @param startCode 起点 - * @param endCode 终点 - * @param taskType 任务类型 - * @param type 业务类型 - * @param agvVendor 供应商 + * @param businessDetailId 业务ID + * @param status 状态 + * @param carrierCode 容器 + * @param startCode 起点 + * @param endCode 终点 + * @param taskType 任务类型 + * @param type 业务类型 + * @param agvVendor 供应商 */ - AgvTask createAgvTask(Integer status, String carrierCode, String startCode, String endCode, String taskType, String type, String agvVendor); + AgvTask createAgvTask(String businessDetailId, Integer status, String carrierCode, String startCode, String endCode, String taskType, String type, String agvVendor); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/impl/AgvTaskServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/impl/AgvTaskServiceImpl.java index 08516c8..e57bf34 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/impl/AgvTaskServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/impl/AgvTaskServiceImpl.java @@ -24,12 +24,13 @@ public class AgvTaskServiceImpl extends ServiceImpl impl @Override @Transactional(rollbackFor = Exception.class) - public AgvTask createAgvTask(Integer status, String carrierCode, String startCode, String endCode, String taskType, String type, String agvVendor) { - Integer priority = 99; + public AgvTask createAgvTask(String businessDetailId, Integer status, String carrierCode, String startCode, String endCode, String taskType, String type, String agvVendor) { + int priority = 99; if (AgvVendorEnum.TES.getValue().equals(agvVendor)) { priority = 3; } AgvTask agvTask = AgvTask.builder() + .businessDetailId(businessDetailId) .carrierCode(carrierCode) .type(type) .status(status) diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/controller/AreaController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/controller/AreaController.java index a5cd34c..185b231 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/controller/AreaController.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/controller/AreaController.java @@ -48,7 +48,6 @@ public class AreaController extends JeecgController { * @param req * @return */ - //@AutoLog(value = "库区-分页列表查询") @Operation(summary = "库区-分页列表查询") @GetMapping(value = "/list") public Result> queryPageList(Area area, diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/AreaMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/AreaMapper.java index ca730b3..295c6bd 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/AreaMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/AreaMapper.java @@ -14,5 +14,21 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @Version: V1.0 */ public interface AreaMapper extends BaseMapper { + /** + * 通过库区编码查询库区信息 + * + * @param areaCode 库区编码 + * @return Area + */ + @Select("select * from base_area where area_code = #{areaCode}") + Area queryByAreaCode(@Param("areaCode") String areaCode); + /** + * 通过库区编码查询库区信息 + * + * @param areaCodes 库区编号集合 + * @return List + */ + @Select("select * from base_area where area_code in (#{areaCodes})") + List queryByAreaCodes(@Param("areaCodes") List areaCodes); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/ItemMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/ItemMapper.java index c54b31a..5119691 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/ItemMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/ItemMapper.java @@ -1,19 +1,35 @@ package org.cpte.modules.base.mapper; -import java.util.List; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.cpte.modules.base.entity.Item; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.cpte.modules.receive.entity.Asn; + +import java.util.List; /** * @Description: 物料 * @author: cpte - * @Date: 2025-10-27 + * @Date: 2025-10-27 * @Version: V1.0 */ public interface ItemMapper extends BaseMapper { + /** + * 通过物料编码查询物料信息 + * + * @param itemCode 物料编号 + * @return Item + */ + @Select("select * from base_item where item_code = #{itemCode}") + Item queryByItemCode(@Param("itemCode") String itemCode); + /** + * 通过物料编码查询物料信息 + * + * @param itemCodes 物料编号集合 + * @return List + */ + @Select("select * from base_item where item_code in (#{itemCodes})") + List queryByItemCodes(@Param("itemCodes") List itemCodes); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/PointMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/PointMapper.java index deae1ce..b3719a2 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/PointMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/PointMapper.java @@ -3,15 +3,42 @@ package org.cpte.modules.base.mapper; import java.util.List; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import org.cpte.modules.base.entity.Point; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * @Description: 库位 * @author: cpte - * @Date: 2025-10-28 + * @Date: 2025-10-28 * @Version: V1.0 */ public interface PointMapper extends BaseMapper { + /** + * 通过库位编码查询库位信息 + * + * @param pointCode 库位编号 + * @return Point + */ + @Select("select * from base_point where point_code = #{pointCode}") + Point queryByPointCode(@Param("pointCode") String pointCode); + /** + * 通过库位编码查询库位信息 + * + * @param pointCodes 库位编号集合 + * @return List + */ + @Select("select * from base_point where point_code in (#{pointCodes})") + List queryByPointCodes(@Param("pointCodes") List pointCodes); + + /** + * 查询库位信息 + * + * @param pointCode 库位编号 + * @param status 状态 + * @param areaCode 库区编号 + * @return List + */ + List queryPoints(@Param("pointCode") String pointCode, @Param("status") Integer status, @Param("areaCode") String areaCode); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/StockMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/StockMapper.java index a8c6f49..f22e649 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/StockMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/StockMapper.java @@ -5,12 +5,30 @@ import org.apache.ibatis.annotations.Select; import org.cpte.modules.base.entity.Stock; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; + /** * @Description: 容器 * @author: cpte - * @Date: 2025-10-28 + * @Date: 2025-10-28 * @Version: V1.0 */ public interface StockMapper extends BaseMapper { + /** + * 通过容器编码查询容器信息 + * + * @param stockCode 容器编号 + * @return Stock + */ + @Select("select * from base_stock where stock_code = #{stockCode}") + Stock queryByStockCode(@Param("stockCode") String stockCode); + /** + * 通过容器编码查询容器信息 + * + * @param stockCodes 容器编号集合 + * @return List + */ + @Select("select * from base_stock where stock_code in (#{stockCodes})") + List queryByStockCodes(@Param("stockCodes") List stockCodes); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/xml/PointMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/xml/PointMapper.xml index 567cae3..68a4280 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/xml/PointMapper.xml +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/xml/PointMapper.xml @@ -1,5 +1,19 @@ - + \ No newline at end of file diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IPointService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IPointService.java index 296dfb9..48a4253 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IPointService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IPointService.java @@ -34,16 +34,4 @@ public interface IPointService extends IService { * @return Map */ Map queryByPointCodesToMap(List pointCodes); - - - /** - * 查询库位信息 - * - * @param pointCode 库位编码 - * @param status 状态 - * @param areaName 区域名称 - * @return List - */ - List queryPoints(String pointCode, Integer status, String areaName); - } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/AreaServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/AreaServiceImpl.java index 55657ea..d6b92de 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/AreaServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/AreaServiceImpl.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.cpte.modules.base.entity.Area; import org.cpte.modules.base.mapper.AreaMapper; import org.cpte.modules.base.service.IAreaService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -17,12 +18,12 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @Service public class AreaServiceImpl extends ServiceImpl implements IAreaService { + @Autowired + private AreaMapper areaMapper; + @Override public Area validateArea(String areaCode) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(Area::getAreaCode, areaCode).or().eq(Area::getAreaName, areaCode); - - Area area = this.getOne(queryWrapper); + Area area = areaMapper.queryByAreaCode(areaCode); if (area == null) { throw new RuntimeException("系统无【" + areaCode + "】库区,请维护"); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/ItemServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/ItemServiceImpl.java index 7fe3d9c..134d523 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/ItemServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/ItemServiceImpl.java @@ -24,6 +24,9 @@ import java.util.Map; @Service public class ItemServiceImpl extends ServiceImpl implements IItemService { + @Autowired + private ItemMapper itemMapper; + /** * 验证物料 * @@ -32,9 +35,7 @@ public class ItemServiceImpl extends ServiceImpl implements II */ @Override public Item validateItem(String itemCode) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(Item::getItemCode, itemCode); - Item item = this.getOne(queryWrapper); + Item item = itemMapper.queryByItemCode(itemCode); if (item == null) { throw new RuntimeException("系统无【" + itemCode + "】物料,请维护"); } @@ -54,13 +55,7 @@ public class ItemServiceImpl extends ServiceImpl implements II * @return List */ public List queryByItemCodes(List itemCodes) { - if (CollectionUtils.isEmpty(itemCodes)) { - return Collections.emptyList(); - } - //查询物料 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(Item::getItemCode, itemCodes); - return this.list(queryWrapper); + return itemMapper.queryByItemCodes(itemCodes); } /** diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/PointServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/PointServiceImpl.java index df233af..f4a90ce 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/PointServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/PointServiceImpl.java @@ -31,6 +31,9 @@ public class PointServiceImpl extends ServiceImpl implements @Autowired private IAreaService iAreaService; + @Autowired + private PointMapper pointMapper; + /** * 验证库位 * @@ -39,9 +42,7 @@ public class PointServiceImpl extends ServiceImpl implements */ @Override public Point validatePoint(String pointCode) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(Point::getPointCode, pointCode); - Point point = this.getOne(queryWrapper); + Point point = pointMapper.queryByPointCode(pointCode); if (point == null) { throw new RuntimeException("系统无【" + pointCode + "】库位,请维护"); } @@ -61,13 +62,7 @@ public class PointServiceImpl extends ServiceImpl implements * @return List */ public List queryByPointCodes(List pointCodes) { - if (CollectionUtils.isEmpty(pointCodes)) { - return Collections.emptyList(); - } - //查询库位 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(Point::getPointCode, pointCodes); - return this.list(queryWrapper); + return pointMapper.queryByPointCodes(pointCodes); } /** @@ -89,29 +84,4 @@ public class PointServiceImpl extends ServiceImpl implements } return PointMap; } - - @Override - public List queryPoints(String pointCode, Integer status, String areaName) { - //查询库位 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - //点位编码 - if (StringUtils.isNotBlank(pointCode)) { - queryWrapper.eq(Point::getPointCode, pointCode); - } - - //状态 - if (status != null) { - queryWrapper.eq(Point::getStatus, status); - } - - //库区 - if (StringUtils.isNotBlank(areaName)) { - Area area = iAreaService.validateArea(areaName); - queryWrapper.eq(Point::getAreaId, area.getId()); - } - - - return this.list(queryWrapper); - } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/StockServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/StockServiceImpl.java index 8c421e4..ca33022 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/StockServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/StockServiceImpl.java @@ -27,6 +27,9 @@ import java.util.Objects; @Service public class StockServiceImpl extends ServiceImpl implements IStockService { + @Autowired + private StockMapper stockMapper; + /** * 验证容器 * @@ -35,16 +38,14 @@ public class StockServiceImpl extends ServiceImpl implements */ @Override public Stock validateStock(String StockCode) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(Stock::getStockCode, StockCode); - Stock stock = this.getOne(queryWrapper); + Stock stock = stockMapper.queryByStockCode(StockCode); if (stock == null) { throw new RuntimeException("系统无【" + StockCode + "】容器,请维护"); } - if(stock.getIzActive()==0){ + if (stock.getIzActive() == 0) { throw new RuntimeException("此【" + StockCode + "】容器已禁用"); } - if(stock.getDelFlag()==1){ + if (stock.getDelFlag() == 1) { throw new RuntimeException("此【" + StockCode + "】容器已删除"); } return stock; @@ -58,12 +59,7 @@ public class StockServiceImpl extends ServiceImpl implements * @return List */ public List queryByStockCodes(List stockCodes) { - if (CollectionUtils.isEmpty(stockCodes)) { - return Collections.emptyList(); - } - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(Stock::getStockCode, stockCodes); - return this.list(queryWrapper); + return stockMapper.queryByStockCodes(stockCodes); } /** diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/CommonConstant.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/CommonConstant.java new file mode 100644 index 0000000..d68ded8 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/CommonConstant.java @@ -0,0 +1,6 @@ +package org.cpte.modules.constant; + +public interface CommonConstant { + //入库输送线任务均衡索引 + String RK_DOCK_TASK_INDEX = "rk_dock_task_index"; +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AreaTypeEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AreaTypeEnum.java index 490f2a9..f011766 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AreaTypeEnum.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AreaTypeEnum.java @@ -11,6 +11,8 @@ public enum AreaTypeEnum { CTQ("CTQ", "拆托区"), + CPCCQ("CPCCQ", "成品存储区"), + RK_DOCK("RK_DOCK", "入库输送线接驳口"), CK_DOCK("CK_DOCK", "出库输送线接驳口"), diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AsnOrderTypeEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AsnOrderTypeEnum.java new file mode 100644 index 0000000..1b75ce7 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AsnOrderTypeEnum.java @@ -0,0 +1,32 @@ +package org.cpte.modules.constant.enums; + +import lombok.Getter; + +@Getter +public enum AsnOrderTypeEnum { + PRODUCT(0, "成品入库"), + + ACCESSORY(1, "配件入库"), + + PRODUCT_UNPALLETIZE(2, "成品拆托入库"), + + ACCESSORY_UNPALLETIZE(3, "配件拆托入库"), + + + ; + + AsnOrderTypeEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + /** + * 值 + */ + final Integer value; + + /** + * 描述 + */ + final String desc; +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/BaseEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/BaseEnum.java new file mode 100644 index 0000000..73a1b92 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/BaseEnum.java @@ -0,0 +1,97 @@ +package org.cpte.modules.constant.enums; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONAware; +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.CaseFormat; +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Objects; + +/** + * 枚举类接口 + * + * @Author YouChain: 胡克 + * @Date 2018-07-17 21:22:12 + * @Email huoj@youchain56.com + */ +public interface BaseEnum { + + /** + * 获取枚举类的值 + * + * @return + */ + Object getValue(); + + /** + * 获取枚举类的说明 + * + * @return String + */ + String getDesc(); + + /** + * 比较参数是否与枚举类的value相同 + * + * @param value + * @return boolean + */ + default boolean equalsValue(Object value) { + return Objects.equals(getValue(), value); + } + + /** + * 比较枚举类是否相同 + * + * @param baseEnum + * @return boolean + */ + default boolean equals(BaseEnum baseEnum) { + return Objects.equals(getValue(), baseEnum.getValue()) && Objects.equals(getDesc(), baseEnum.getDesc()); + } + + /** + * 返回枚举类的说明 + * + * @param clazz 枚举类类对象 + * @return + */ + static String getInfo(Class clazz) { + BaseEnum[] enums = clazz.getEnumConstants(); + LinkedHashMap json = new LinkedHashMap<>(enums.length); + for (BaseEnum e : enums) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("value", new DeletedQuotationAware(e.getValue())); + jsonObject.put("desc", new DeletedQuotationAware(e.getDesc())); + json.put(e.toString(), jsonObject); + } + + String enumJson = JSON.toJSONString(json, true); + enumJson = enumJson.replaceAll("\"", ""); + enumJson = enumJson.replaceAll("\t", "  "); + enumJson = enumJson.replaceAll("\n", "
"); + String prefix = "
export const " + CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, clazz.getSimpleName() + " =
"); + return prefix + enumJson + "
"; + } + + @Data + class DeletedQuotationAware implements JSONAware { + + private String value; + + public DeletedQuotationAware(Object value) { + if (value instanceof String) { + this.value = "'" + value + "'"; + } else { + this.value = value.toString(); + } + } + + @Override + public String toJSONString() { + return value; + } + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/InventoryLogEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/InventoryLogEnum.java new file mode 100644 index 0000000..0bbfc3b --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/InventoryLogEnum.java @@ -0,0 +1,40 @@ +package org.cpte.modules.constant.enums; + +import lombok.Getter; + +@Getter +public enum InventoryLogEnum { + INBOUND(1, "入库"), + + ALLOC(2, "分配"), + + UNALLOC(3, "取消分配"), + + PICK(4, "拣货"), + + UNPICK(5, "退拣"), + + OUTBOUND(6, "出库"), + + ADJUST(7, "库存调整"), + + MOVE(8, "库内移位"), + + CHECK(9, "盘点调整"), + + ; + + /** + * 值 + */ + private final Integer value; + /** + * 描述 + */ + private final String desc; + + InventoryLogEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/impl/IConveyorLineServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/impl/IConveyorLineServiceImpl.java index 3e27773..df29f09 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/impl/IConveyorLineServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/impl/IConveyorLineServiceImpl.java @@ -3,58 +3,80 @@ package org.cpte.modules.conveyorLine.service.impl; import lombok.extern.slf4j.Slf4j; import org.cpte.modules.agvTask.mapper.AgvTaskMapper; import org.cpte.modules.agvTask.service.IAgvTaskService; +import org.cpte.modules.base.entity.Point; import org.cpte.modules.base.entity.Stock; +import org.cpte.modules.base.mapper.PointMapper; import org.cpte.modules.base.mapper.StockMapper; -import org.cpte.modules.base.service.IStockService; -import org.cpte.modules.constant.enums.AgvStatusEnum; -import org.cpte.modules.constant.enums.AgvVendorEnum; -import org.cpte.modules.constant.enums.AsnStatusEnum; -import org.cpte.modules.constant.enums.BusinessTypeEnum; +import org.cpte.modules.constant.enums.*; import org.cpte.modules.conveyorLine.request.ScanTrayRequest; import org.cpte.modules.conveyorLine.service.IConveyorLineService; +import org.cpte.modules.inventory.mapper.InventoryMapper; import org.cpte.modules.receive.entity.AsnDetail; import org.cpte.modules.receive.mapper.AsnDetailMapper; -import org.cpte.modules.receive.service.IAsnService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; @Service @Slf4j public class IConveyorLineServiceImpl implements IConveyorLineService { + @Autowired + private PointMapper pointMapper; + + @Autowired + private StockMapper stockMapper; + @Autowired private AsnDetailMapper asnDetailMapper; @Autowired - private IStockService iStockService; + private AgvTaskMapper agvTaskMapper; @Autowired - private AgvTaskMapper agvTaskMapper; + private InventoryMapper inventoryMapper; + @Autowired private IAgvTaskService iAgvTaskService; @Override + @Transactional(rollbackFor = Exception.class) public void scanTray(ScanTrayRequest scanTrayRequest) { - //验证托盘 - Stock stock = iStockService.validateStock(scanTrayRequest.getStockCode()); + //容器 + Stock stock = stockMapper.queryByStockCode(scanTrayRequest.getStockCode()); //验证入库信息 AsnDetail asnDetail = asnDetailMapper.queryByStockCode(stock.getId(), AsnStatusEnum.CREATED.getValue()); if (asnDetail == null) { throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘,无入库信息"); } - //验证当前托盘是否有库存 - //通过算法获取目标点位 - String endCode = "CCQ01"; + //验证托盘是否有库存 + if (inventoryMapper.queryByStockId(stock.getId()) != null) { + throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘已入库"); + } //验证当前托盘是否生成了TES任务 - if (agvTaskMapper.existsAGVTask(stock.getStockCode(), AgvVendorEnum.TES.getValue()) > 0) { + if (agvTaskMapper.existsByStockCode(stock.getStockCode(), AgvVendorEnum.TES.getValue()) > 0) { throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘已扫描,请勿重复扫描"); } + + //通过算法获取目标点位 + List dstPointList = pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), AreaTypeEnum.CPCCQ.getValue()); + if (dstPointList.isEmpty()) { + throw new RuntimeException("【" + AreaTypeEnum.CPCCQ.getDesc() + "】无空闲库位"); + } + Point dstPoint = dstPointList.get(0); + + //锁定目标库位 + dstPoint.setStatus(CommonStatusEnum.USED.getValue()); + pointMapper.updateById(dstPoint); + //验证通过,生成Tes任务 - iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), stock.getStockCode(), null, endCode, null, BusinessTypeEnum.INBOUND.getValue(), AgvVendorEnum.TES.getValue()); + iAgvTaskService.createAgvTask(asnDetail.getId(), AgvStatusEnum.CREATED.getValue(), stock.getStockCode(), null, dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), AgvVendorEnum.TES.getValue()); } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/impl/IHikAgvServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/impl/IHikAgvServiceImpl.java index 3ac8883..39097f9 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/impl/IHikAgvServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/impl/IHikAgvServiceImpl.java @@ -176,11 +176,11 @@ public class IHikAgvServiceImpl implements IHikAgvService { * @param agvTask 任务 */ private void handleResend(AgvTask agvTask) { - Long count = agvTaskMapper.existsAGVTask(agvTask.getCarrierCode(),AgvVendorEnum.HIK.getValue()); + Long count = agvTaskMapper.existsByStockCode(agvTask.getCarrierCode(),AgvVendorEnum.HIK.getValue()); if (count > 0) { throw new RuntimeException("任务已重新生成,请勿重复操作! "); } - AgvTask newAgvTask = iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), agvTask.getCarrierCode(), agvTask.getStartCode(), agvTask.getEndCode(), null, agvTask.getType(),AgvVendorEnum.HIK.getValue()); + AgvTask newAgvTask = iAgvTaskService.createAgvTask(agvTask.getBusinessDetailId(),AgvStatusEnum.CREATED.getValue(), agvTask.getCarrierCode(), agvTask.getStartCode(), agvTask.getEndCode(), null, agvTask.getType(),AgvVendorEnum.HIK.getValue()); switch (agvTask.getType()) { case "INBOUND": case "OUTBOUND": diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/entity/Inventory.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/entity/Inventory.java index 2af61a3..36b9684 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/entity/Inventory.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/entity/Inventory.java @@ -37,9 +37,9 @@ public class Inventory implements Serializable { /** * ID */ - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) @Schema(description = "ID") - private java.lang.Integer id; + private java.lang.String id; /** * 物料ID */ @@ -73,6 +73,12 @@ public class Inventory implements Serializable { @Excel(name = "分配数", width = 15) @Schema(description = "分配数") private java.math.BigDecimal queuedQty; + /** + * 入库记录ID + */ + @Excel(name = "入库记录ID", width = 15) + @Schema(description = "入库记录ID") + private java.lang.String receiveRecordId; /** * 外部仓库 */ diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java index 9954987..89e2056 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java @@ -21,6 +21,6 @@ public interface InventoryMapper extends BaseMapper { * @param stockId 容器 * @return 库存数据 */ - @Select("select * from data_inventory where stock_id = #{stockId} ") - Inventory selectByStockId(@Param("stockId") String stockId); + @Select("select * from data_inventory where stock_id = #{stockId} and quantity>0 for update") + Inventory queryByStockId(@Param("stockId") String stockId); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java index db49287..af8a6e4 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java @@ -2,13 +2,28 @@ package org.cpte.modules.inventory.service; import org.cpte.modules.inventory.entity.Inventory; import com.baomidou.mybatisplus.extension.service.IService; +import org.cpte.modules.receive.entity.Asn; +import org.cpte.modules.receive.entity.AsnDetail; +import org.cpte.modules.receive.entity.ReceiveRecord; + +import java.math.BigDecimal; /** * @Description: 库存表 * @author: cpte - * @Date: 2025-11-08 + * @Date: 2025-11-08 * @Version: V1.0 */ public interface IInventoryService extends IService { - + /** + * 创建库存 + * + * @param stockId 容器 + * @param receivedQty 收货数量 + * @param asn 入库单 + * @param asnDetail 入库明细 + * @param receiveRecord 入库记录 + * @return Inventory + */ + Inventory createInventory(String stockId, BigDecimal receivedQty, Asn asn, AsnDetail asnDetail, ReceiveRecord receiveRecord); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java index 9568e50..4bbd7c8 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java @@ -1,19 +1,52 @@ package org.cpte.modules.inventory.service.impl; +import org.cpte.modules.constant.enums.InventoryStatusEnum; import org.cpte.modules.inventory.entity.Inventory; import org.cpte.modules.inventory.mapper.InventoryMapper; import org.cpte.modules.inventory.service.IInventoryService; +import org.cpte.modules.receive.entity.Asn; +import org.cpte.modules.receive.entity.AsnDetail; +import org.cpte.modules.receive.entity.ReceiveRecord; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.Date; /** * @Description: 库存表 * @author: cpte - * @Date: 2025-11-08 + * @Date: 2025-11-08 * @Version: V1.0 */ @Service public class InventoryServiceImpl extends ServiceImpl implements IInventoryService { - + @Override + @Transactional(rollbackFor = Exception.class) + public Inventory createInventory(String stockId, BigDecimal receivedQty, Asn asn, AsnDetail asnDetail, ReceiveRecord receiveRecord) { + Inventory inventory = Inventory.builder() + .itemId(asnDetail.getItemId()) + .pointId(receiveRecord.getPointId()) + .stockId(asnDetail.getStockId()) + .quantity(receivedQty) + .queuedQty(BigDecimal.ZERO) + .receiveRecordId(receiveRecord.getId()) + .whCode(asn.getWhCode()) + .propC1(asnDetail.getPropC1()) + .propC2(asnDetail.getPropC2()) + .propC3(asnDetail.getPropC3()) + .status(InventoryStatusEnum.AVAILABLE.getValue()) + .propD1(asnDetail.getPropD1()) + .description(asnDetail.getDescription()) + .tenantId(asnDetail.getTenantId()) + .sysOrgCode(asnDetail.getSysOrgCode()) + .createBy(asnDetail.getCreateBy()) + .createTime(new Date()) + .build(); + this.save(inventory); + return inventory; + } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/controller/InventoryLogController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/controller/InventoryLogController.java new file mode 100644 index 0000000..399213d --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/controller/InventoryLogController.java @@ -0,0 +1,182 @@ +package org.cpte.modules.inventoryLog.controller; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.system.query.QueryRuleEnum; +import org.jeecg.common.util.oConvertUtils; +import org.cpte.modules.inventoryLog.entity.InventoryLog; +import org.cpte.modules.inventoryLog.service.IInventoryLogService; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; + +import org.jeecgframework.poi.excel.ExcelImportUtil; +import org.jeecgframework.poi.excel.def.NormalExcelConstants; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; +import org.jeecg.common.system.base.controller.JeecgController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.servlet.ModelAndView; +import com.alibaba.fastjson.JSON; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.jeecg.common.aspect.annotation.AutoLog; +import org.apache.shiro.authz.annotation.RequiresPermissions; + /** + * @Description: 库存日志 + * @author: cpte + * @Date: 2025-11-10 + * @Version: V1.0 + */ +@Tag(name="库存日志") +@RestController +@RequestMapping("/inventoryLog") +@Slf4j +public class InventoryLogController extends JeecgController { + @Autowired + private IInventoryLogService inventoryLogService; + + /** + * 分页列表查询 + * + * @param inventoryLog + * @param pageNo + * @param pageSize + * @param req + * @return + */ + //@AutoLog(value = "库存日志-分页列表查询") + @Operation(summary="库存日志-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(InventoryLog inventoryLog, + @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, + @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, + HttpServletRequest req) { + + + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(inventoryLog, req.getParameterMap()); + Page page = new Page(pageNo, pageSize); + IPage pageList = inventoryLogService.page(page, queryWrapper); + return Result.OK(pageList); + } + + /** + * 添加 + * + * @param inventoryLog + * @return + */ + @AutoLog(value = "库存日志-添加") + @Operation(summary="库存日志-添加") + @RequiresPermissions("inventoryLog:data_inventory_log:add") + @PostMapping(value = "/add") + public Result add(@RequestBody InventoryLog inventoryLog) { + inventoryLogService.save(inventoryLog); + + return Result.OK("添加成功!"); + } + + /** + * 编辑 + * + * @param inventoryLog + * @return + */ + @AutoLog(value = "库存日志-编辑") + @Operation(summary="库存日志-编辑") + @RequiresPermissions("inventoryLog:data_inventory_log:edit") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) + public Result edit(@RequestBody InventoryLog inventoryLog) { + inventoryLogService.updateById(inventoryLog); + return Result.OK("编辑成功!"); + } + + /** + * 通过id删除 + * + * @param id + * @return + */ + @AutoLog(value = "库存日志-通过id删除") + @Operation(summary="库存日志-通过id删除") + @RequiresPermissions("inventoryLog:data_inventory_log:delete") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name="id",required=true) String id) { + inventoryLogService.removeById(id); + return Result.OK("删除成功!"); + } + + /** + * 批量删除 + * + * @param ids + * @return + */ + @AutoLog(value = "库存日志-批量删除") + @Operation(summary="库存日志-批量删除") + @RequiresPermissions("inventoryLog:data_inventory_log:deleteBatch") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { + this.inventoryLogService.removeByIds(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } + + /** + * 通过id查询 + * + * @param id + * @return + */ + //@AutoLog(value = "库存日志-通过id查询") + @Operation(summary="库存日志-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name="id",required=true) String id) { + InventoryLog inventoryLog = inventoryLogService.getById(id); + if(inventoryLog==null) { + return Result.error("未找到对应数据"); + } + return Result.OK(inventoryLog); + } + + /** + * 导出excel + * + * @param request + * @param inventoryLog + */ + @RequiresPermissions("inventoryLog:data_inventory_log:exportXls") + @RequestMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, InventoryLog inventoryLog) { + return super.exportXls(request, inventoryLog, InventoryLog.class, "库存日志"); + } + + /** + * 通过excel导入数据 + * + * @param request + * @param response + * @return + */ + @RequiresPermissions("inventoryLog:data_inventory_log:importExcel") + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, InventoryLog.class); + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/entity/InventoryLog.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/entity/InventoryLog.java new file mode 100644 index 0000000..2ff49c0 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/entity/InventoryLog.java @@ -0,0 +1,174 @@ +package org.cpte.modules.inventoryLog.entity; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableLogic; +import lombok.*; +import org.jeecg.common.constant.ProvinceCityArea; +import org.jeecg.common.util.SpringContextUtils; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.jeecg.common.aspect.annotation.Dict; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.experimental.Accessors; + +/** + * @Description: 库存日志 + * @author: cpte + * @Date: 2025-11-10 + * @Version: V1.0 + */ +@Data +@TableName("data_inventory_log") +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "库存日志") +public class InventoryLog implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "id") + private java.lang.String id; + /** + * 日志类型:1入库,2分配,3取消分配,4拣货,5退拣,6.出库,7库存调整,8库位转移,9盘点调整 + */ + @Excel(name = "日志类型", width = 15) + @Schema(description = "日志类型") + @Dict(dicCode = "inventory_log_type") + private java.lang.Integer logType; + /** + * 业务单号 + */ + @Excel(name = "业务单号", width = 15) + @Schema(description = "业务单号") + private java.lang.String businessNo; + /** + * 业务明细ID + */ + @Excel(name = "业务明细ID", width = 15) + @Schema(description = "业务明细ID") + private java.lang.String businessDetailId; + /** + * 库存ID + */ + @Excel(name = "库存ID", width = 15) + @Schema(description = "库存ID") + private java.lang.String inventoryId; + /** + * 物料ID + */ + @Excel(name = "物料ID", width = 15) + @Schema(description = "物料ID") + @Dict(dictTable = "base_item", dicCode = "id", dicText = "item_code") + private java.lang.String itemId; + /** + * 原库位置 + */ + @Excel(name = "原库位置", width = 15) + @Schema(description = "原库位置") + @Dict(dictTable = "base_point", dicCode = "id", dicText = "point_code") + private java.lang.String fromPointId; + + /** + * 目标库位 + */ + @Excel(name = "目标库位", width = 15) + @Schema(description = "目标库位") + @Dict(dictTable = "base_point", dicCode = "id", dicText = "point_code") + private java.lang.String toPointId; + /** + * 容器ID + */ + @Excel(name = "容器ID", width = 15) + @Schema(description = "容器ID") + @Dict(dictTable = "base_stock", dicCode = "id", dicText = "stock_code") + private java.lang.String stockId; + /** + * 批次号 + */ + @Excel(name = "批次号", width = 15) + @Schema(description = "批次号") + private java.lang.String propC1; + /** + * 变动数量 + */ + @Excel(name = "变动数量", width = 15) + @Schema(description = "变动数量") + private java.math.BigDecimal changeQty; + /** + * 变动前数量 + */ + @Excel(name = "变动前数量", width = 15) + @Schema(description = "变动前数量") + private java.math.BigDecimal beforeQty; + /** + * 变动后数量 + */ + @Excel(name = "变动后数量", width = 15) + @Schema(description = "变动后数量") + private java.math.BigDecimal afterQty; + /** + * 变动前已分配数量 + */ + @Excel(name = "变动前已分配数量", width = 15) + @Schema(description = "变动前已分配数量") + private java.math.BigDecimal beforeAllocatedQty; + /** + * 变动后已分配数量 + */ + @Excel(name = "变动后已分配数量", width = 15) + @Schema(description = "变动后已分配数量") + private java.math.BigDecimal afterAllocatedQty; + /** + * 描述 + */ + @Excel(name = "描述", width = 15) + @Schema(description = "描述") + private java.lang.String description; + /** + * 所属部门 + */ + @Schema(description = "所属部门") + private java.lang.String sysOrgCode; + /** + * 租户ID + */ + @Excel(name = "租户ID", width = 15) + @Schema(description = "租户ID") + private java.lang.Integer tenantId; + /** + * 创建人 + */ + @Schema(description = "创建人") + private java.lang.String createBy; + /** + * 创建日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建日期") + private java.util.Date createTime; + /** + * 更新人 + */ + @Schema(description = "更新人") + private java.lang.String updateBy; + /** + * 更新日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "更新日期") + private java.util.Date updateTime; +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/mapper/InventoryLogMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/mapper/InventoryLogMapper.java new file mode 100644 index 0000000..77ffef9 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/mapper/InventoryLogMapper.java @@ -0,0 +1,17 @@ +package org.cpte.modules.inventoryLog.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; +import org.cpte.modules.inventoryLog.entity.InventoryLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @Description: 库存日志 + * @author: cpte + * @Date: 2025-11-10 + * @Version: V1.0 + */ +public interface InventoryLogMapper extends BaseMapper { + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/mapper/xml/InventoryLogMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/mapper/xml/InventoryLogMapper.xml new file mode 100644 index 0000000..7e7a27f --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/mapper/xml/InventoryLogMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/IInventoryLogService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/IInventoryLogService.java new file mode 100644 index 0000000..64329ca --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/IInventoryLogService.java @@ -0,0 +1,126 @@ +package org.cpte.modules.inventoryLog.service; + +import org.cpte.modules.inventory.entity.Inventory; +import org.cpte.modules.inventoryLog.entity.InventoryLog; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.math.BigDecimal; + +/** + * @Description: 库存日志 + * @author: cpte + * @Date: 2025-11-10 + * @Version: V1.0 + */ +public interface IInventoryLogService extends IService { + + /** + * 添加库存日志 + * + * @param inventoryLog 日志实体 + */ + void addInventoryLog(InventoryLog inventoryLog); + + /** + * 添加入库库存日志 + * + * @param inventory 库存 + * @param srcPointId 原库位 + * @param changeQty 变动数量 + * @param businessNo 业务单号 + * @param businessDetailId 业务明细ID + * @param description 描述 + */ + void addInboundInventoryLog(Inventory inventory, String srcPointId, BigDecimal changeQty, String businessNo, String businessDetailId, String description); + + /** + * 添加出库库存日志 + * + * @param inventory 库存 + * @param changeQty 变动数量 + * @param businessNo 业务单号 + * @param businessDetailId 业务明细ID + * @param description 描述 + */ + void addOutboundInventoryLog(Inventory inventory, BigDecimal changeQty, String businessNo, String businessDetailId, String description); + + + /** + * 添加分配库存日志 + * + * @param inventory 库存 + * @param AllocatedQty 分配数量 + * @param businessNo 业务单号 + * @param businessDetailId 业务明细ID + * @param description 描述 + */ + void addAllocInventoryLog(Inventory inventory, BigDecimal AllocatedQty, String businessNo, String businessDetailId, String description); + + + /** + * 添加取消分配库存日志 + * + * @param inventory 库存 + * @param cancelQty 取消分配数量 + * @param businessNo 业务单号 + * @param businessDetailId 业务明细ID + * @param description 描述 + */ + void addUnAllocInventoryLog(Inventory inventory, BigDecimal cancelQty, String businessNo, String businessDetailId, String description); + + + /** + * 添加拣货库存日志 + * + * @param inventory 库存 + * @param changeQty 变动数量 + * @param businessNo 业务单号 + * @param businessDetailId 业务明细ID + * @param description 描述 + */ + void addPickInventoryLog(Inventory inventory, BigDecimal changeQty, String businessNo, String businessDetailId, String description); + + /** + * 添加退拣库存日志-拣货后取消,库存回退 + * + * @param inventory 库存 + * @param returnQty 退回数量 + * @param businessNo 业务单号 + * @param businessDetailId 业务明细ID + * @param description 描述 + */ + void addUnPickInventoryLog(Inventory inventory, BigDecimal returnQty, String businessNo, String businessDetailId, String description); + + /** + * 添加库存调整库存日志 + * + * @param inventory 库存 + * @param adjustQty 调整数量 + * @param businessNo 业务单号 + * @param description 描述 + */ + void addAdjustInventoryLog(Inventory inventory, BigDecimal adjustQty, String businessNo, String description); + + /** + * 添加库内移位存日志 + * + * @param inventory 库存 + * @param toPointId 目标库位 + * @param moveQty 移位数量 + * @param businessNo 业务单号 + * @param description 描述 + */ + void addMoveInventoryLog(Inventory inventory, String toPointId, BigDecimal moveQty, String businessNo, String description); + + /** + * 添加库存盘点库存日志 + * + * @param inventory 库存 + * @param actualQty 实际数量 + * @param systemQty 系统数量 + * @param businessNo 业务单号 + * @param description 描述 + */ + void addCheckInventoryLog(Inventory inventory, BigDecimal actualQty, BigDecimal systemQty, String businessNo, String description); + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/impl/InventoryLogServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/impl/InventoryLogServiceImpl.java new file mode 100644 index 0000000..62a213a --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/impl/InventoryLogServiceImpl.java @@ -0,0 +1,181 @@ +package org.cpte.modules.inventoryLog.service.impl; + +import lombok.extern.slf4j.Slf4j; +import org.cpte.modules.constant.enums.InventoryLogEnum; +import org.cpte.modules.inventory.entity.Inventory; +import org.cpte.modules.inventoryLog.entity.InventoryLog; +import org.cpte.modules.inventoryLog.mapper.InventoryLogMapper; +import org.cpte.modules.inventoryLog.service.IInventoryLogService; +import org.cpte.modules.utils.BigDecimalUtil; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @Description: 库存日志 + * @author: cpte + * @Date: 2025-11-10 + * @Version: V1.0 + */ +@Service +@Slf4j +public class InventoryLogServiceImpl extends ServiceImpl implements IInventoryLogService { + + @Override + @Transactional(rollbackFor = Exception.class) + public void addInventoryLog(InventoryLog inventoryLog) { + try { + this.save(inventoryLog); + log.debug("库存变动日志记录成功,库存ID: {}, 变动数量: {}", + inventoryLog.getInventoryId(), inventoryLog.getChangeQty()); + } catch (Exception e) { + log.error("记录库存变动日志失败,库存ID: {}", inventoryLog.getInventoryId(), e); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addInboundInventoryLog(Inventory inventory,String srcPointId, BigDecimal changeQty, String businessNo, String businessDetailId, String description) { + InventoryLog inventoryLog = buildInventoryLog(inventory, changeQty, businessNo, businessDetailId, description); + // 入库类型 + inventoryLog.setLogType(InventoryLogEnum.INBOUND.getValue()); + inventoryLog.setFromPointId(srcPointId); + addInventoryLog(inventoryLog); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addOutboundInventoryLog(Inventory inventory, BigDecimal changeQty, String businessNo, String businessDetailId, String description) { + InventoryLog inventoryLog = buildInventoryLog(inventory, changeQty, businessNo, businessDetailId, description); + // 出库数量为负数 + inventoryLog.setChangeQty(changeQty.negate()); + inventoryLog.setAfterQty(inventory.getQuantity()); + // 出库类型 + inventoryLog.setLogType(InventoryLogEnum.OUTBOUND.getValue()); + addInventoryLog(inventoryLog); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addAllocInventoryLog(Inventory inventory, BigDecimal AllocatedQty, String businessNo, String businessDetailId, String description) { + InventoryLog inventoryLog = buildInventoryLog(inventory, AllocatedQty, businessNo, businessDetailId, description); + //出库分配 + inventoryLog.setLogType(InventoryLogEnum.ALLOC.getValue()); + //实际数量不变 + inventoryLog.setChangeQty(BigDecimal.ZERO); + inventoryLog.setBeforeAllocatedQty(BigDecimalUtil.subtract(inventory.getQueuedQty(), AllocatedQty, 0)); + inventoryLog.setAfterAllocatedQty(inventory.getQueuedQty()); + addInventoryLog(inventoryLog); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addUnAllocInventoryLog(Inventory inventory, BigDecimal cancelQuantity, String businessNo, String businessDetailId, String description) { + InventoryLog inventoryLog = buildInventoryLog(inventory, BigDecimal.ZERO, businessNo, businessDetailId, description); + inventoryLog.setLogType(InventoryLogEnum.UNALLOC.getValue()); + // 实际数量不变 + inventoryLog.setChangeQty(BigDecimal.ZERO); + inventoryLog.setBeforeAllocatedQty(BigDecimalUtil.add(inventory.getQueuedQty(), cancelQuantity, 0)); + inventoryLog.setAfterAllocatedQty(inventory.getQueuedQty()); + addInventoryLog(inventoryLog); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addPickInventoryLog(Inventory inventory, BigDecimal changeQty, String businessNo, String businessDetailId, String description) { + InventoryLog inventoryLog = buildInventoryLog(inventory, changeQty, businessNo, businessDetailId, description); + // 拣货类型 + inventoryLog.setLogType(InventoryLogEnum.PICK.getValue()); + // 出库数量为负数 + inventoryLog.setChangeQty(changeQty.negate()); + inventoryLog.setAfterQty(inventory.getQuantity()); + addInventoryLog(inventoryLog); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addUnPickInventoryLog(Inventory inventory, BigDecimal returnQuantity, String businessNo, String businessDetailId, String description) { + InventoryLog inventoryLog = buildInventoryLog(inventory, returnQuantity, businessNo, businessDetailId, description); + //退拣 + inventoryLog.setLogType(InventoryLogEnum.UNPICK.getValue()); + inventoryLog.setChangeQty(returnQuantity); // 正数表示增加库存 + inventoryLog.setAfterQty(inventory.getQuantity()); + addInventoryLog(inventoryLog); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addAdjustInventoryLog(Inventory inventory, BigDecimal adjustQuantity, String businessNo, String description) { + InventoryLog inventoryLog = buildInventoryLog(inventory, adjustQuantity, businessNo, null, description); + inventoryLog.setLogType(InventoryLogEnum.ADJUST.getValue()); // 调整类型 + inventoryLog.setChangeQty(adjustQuantity); // 可正可负 + inventoryLog.setAfterQty(inventory.getQuantity()); + addInventoryLog(inventoryLog); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addMoveInventoryLog(Inventory inventory, String toPointId, BigDecimal moveQty, String businessNo, String description) { + InventoryLog inventoryLog = buildInventoryLog(inventory, BigDecimal.ZERO, businessNo, null, description); + inventoryLog.setLogType(InventoryLogEnum.MOVE.getValue()); + //目标库位 + inventoryLog.setToPointId(toPointId); + // 数量不变,只是位置变化 + inventoryLog.setChangeQty(BigDecimal.ZERO); + addInventoryLog(inventoryLog); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public void addCheckInventoryLog(Inventory inventory, BigDecimal actualQty, BigDecimal systemQty, String businessNo, String description) { + // 调整数量=实际数量-系统数量 + BigDecimal adjustQuantity = BigDecimalUtil.subtract(actualQty, systemQty, 0); + InventoryLog inventoryLog = buildInventoryLog(inventory, adjustQuantity, businessNo, null, description); + inventoryLog.setLogType(InventoryLogEnum.CHECK.getValue()); + inventoryLog.setChangeQty(adjustQuantity); + inventoryLog.setBeforeQty(systemQty); + inventoryLog.setAfterQty(actualQty); + addInventoryLog(inventoryLog); + } + + + /** + * 构建库存日志 + * + * @param inventory 库存 + * @param changeQty 变动数量 + * @param businessNo 业务单号 + * @param businessDetailId 业务单明细ID + * @param description 描述 + * @return InventoryLog + */ + private InventoryLog buildInventoryLog(Inventory inventory, BigDecimal changeQty, String businessNo, String businessDetailId, String description) { + + return InventoryLog.builder() + .inventoryId(inventory.getId()) + .itemId(inventory.getItemId()) + .toPointId(inventory.getPointId()) + .stockId(inventory.getStockId()) + .businessNo(businessNo) + .businessDetailId(businessDetailId) + .propC1(inventory.getPropC1()) + .description(description) + //计算变动前后数量: 变动前数量 = 库存数量 - 变动数量 + .beforeQty(BigDecimalUtil.subtract(inventory.getQuantity(), changeQty, 0)) + .changeQty(changeQty) + .afterQty(inventory.getQuantity()) + // 分配数量变动 + .afterAllocatedQty(inventory.getQueuedQty()) + .beforeAllocatedQty(inventory.getQueuedQty()) + .sysOrgCode(inventory.getSysOrgCode()) + .tenantId(inventory.getTenantId()) + .createBy(inventory.getCreateBy()) + .createTime(new Date()) + .build(); + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/HikAgvJob.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/HikAgvJob.java index ec96925..c5e7219 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/HikAgvJob.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/HikAgvJob.java @@ -25,14 +25,21 @@ public class HikAgvJob implements Job { public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 查询待执行任务 List agvTaskList = agvTaskMapper.queryAgvTaskList(AgvStatusEnum.CREATED.getValue(), AgvVendorEnum.HIK.getValue()); + if (agvTaskList.isEmpty()) { + return; + } String taskSubmitUrl = "http://localhost:8000/cpte-wms/rcs/rtas/api/robot/controller/task/submit"; for (AgvTask agvTask : agvTaskList) { try { - hikAgvService.sendHikAgvTask( - taskSubmitUrl, - hikAgvService.generateHikAgvTaskJson(agvTask), - agvTask - ); + // 判断起点无任务才允许下发 + boolean isStartCodeAvailable = agvTaskMapper.existsByStartCode(agvTask.getStartCode(), AgvVendorEnum.HIK.getValue()) == 0; + if (isStartCodeAvailable) { + hikAgvService.sendHikAgvTask( + taskSubmitUrl, + hikAgvService.generateHikAgvTaskJson(agvTask), + agvTask + ); + } } catch (Exception e) { log.error("发送AGV任务失败,任务ID: {}", agvTask.getId(), e); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/controller/AsnController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/controller/AsnController.java index 2f6ebab..fa8ed29 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/controller/AsnController.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/controller/AsnController.java @@ -99,7 +99,7 @@ public class AsnController { @PostMapping(value = "/add") public Result add(@RequestBody AsnPage asnPage) { Asn asn = new Asn(); - asn.setOrderNo(codeGeneratorUtil.generateCode("RK")); + asn.setOrderNo(codeGeneratorUtil.generateSerialNumber("RK")); BeanUtils.copyProperties(asnPage, asn); asnService.saveMain(asn, asnPage.getAsnDetailList()); return Result.OK("添加成功!"); diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java index be98659..b586d2d 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java @@ -40,6 +40,6 @@ public interface AsnDetailMapper extends BaseMapper { * @param status 状态 * @return AsnDetail */ - @Select("select * from data_asn_detail where stock_id = #{stockId} and status = #{status} ") + @Select("select * from data_asn_detail where stock_id = #{stockId} and status = #{status} for update") AsnDetail queryByStockCode(@Param("stockId") String stockId, @Param("status") Integer status); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnMapper.java index 5af8b53..31675ad 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnMapper.java @@ -1,12 +1,9 @@ package org.cpte.modules.receive.mapper; -import java.util.List; - import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.cpte.modules.receive.entity.Asn; import com.baomidou.mybatisplus.core.mapper.BaseMapper; - /** * @Description: 入库单 * @author: cpte @@ -20,7 +17,7 @@ public interface AsnMapper extends BaseMapper { * @param no 任务号 * @return Asn */ - @Select("select * from data_asn where no = #{no}") + @Select("select * from data_asn where no = #{no} for update ") Asn queryByNo(@Param("no") String no); diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java index 04466b2..957d488 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java @@ -3,6 +3,7 @@ package org.cpte.modules.receive.service; import org.cpte.modules.receive.entity.AsnDetail; import org.cpte.modules.receive.entity.Asn; import com.baomidou.mybatisplus.extension.service.IService; + import java.io.Serializable; import java.math.BigDecimal; import java.util.Collection; @@ -11,46 +12,47 @@ import java.util.List; /** * @Description: 入库单 * @author: cpte - * @Date: 2025-11-03 + * @Date: 2025-11-03 * @Version: V1.0 */ public interface IAsnService extends IService { - /** - * 添加一对多 - * - * @param asn - * @param asnDetailList - */ - public void saveMain(Asn asn,List asnDetailList) ; - - /** - * 修改一对多 - * - * @param asn - * @param asnDetailList - */ - public void updateMain(Asn asn,List asnDetailList); - - /** - * 删除一对多 - * - * @param id - */ - public void delMain (String id); - - /** - * 批量删除一对多 - * - * @param idList - */ - public void delBatchMain (Collection idList); + /** + * 添加一对多 + * + * @param asn + * @param asnDetailList + */ + public void saveMain(Asn asn, List asnDetailList); - /** - * 收货操作 - * - * @param stockCode 容器 - */ - void receiveGoods(String stockCode); + /** + * 修改一对多 + * + * @param asn + * @param asnDetailList + */ + public void updateMain(Asn asn, List asnDetailList); + + /** + * 删除一对多 + * + * @param id + */ + public void delMain(String id); + + /** + * 批量删除一对多 + * + * @param idList + */ + public void delBatchMain(Collection idList); + + /** + * 收货操作 + * + * @param asnDetailId 入库明细ID + * @param pointCode 目标库位 + */ + void receiveGoods(String asnDetailId, String pointCode); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java index b8b99fb..703b55b 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java @@ -8,9 +8,10 @@ import org.cpte.modules.base.mapper.StockMapper; import org.cpte.modules.base.service.IStockService; import org.cpte.modules.constant.enums.AsnStatusEnum; import org.cpte.modules.constant.enums.CommonStatusEnum; -import org.cpte.modules.constant.enums.InventoryStatusEnum; import org.cpte.modules.inventory.entity.Inventory; import org.cpte.modules.inventory.mapper.InventoryMapper; +import org.cpte.modules.inventory.service.IInventoryService; +import org.cpte.modules.inventoryLog.service.IInventoryLogService; import org.cpte.modules.receive.entity.Asn; import org.cpte.modules.receive.entity.AsnDetail; import org.cpte.modules.receive.entity.ReceiveRecord; @@ -19,7 +20,6 @@ import org.cpte.modules.receive.mapper.AsnMapper; import org.cpte.modules.receive.mapper.ReceiveRecordMapper; import org.cpte.modules.receive.service.IAsnService; import org.cpte.modules.utils.BigDecimalUtil; -import org.jeecg.common.constant.CommonSendStatus; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; @@ -56,7 +56,9 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS @Autowired private InventoryMapper inventoryMapper; @Autowired - private IStockService iStockService; + private IInventoryService iInventoryService; + @Autowired + private IInventoryLogService iInventoryLogService; @Override @Transactional(rollbackFor = Exception.class) @@ -131,7 +133,7 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS @Transactional(rollbackFor = Exception.class) public void delMain(String id) { Asn asn = this.getById(id); - if(!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())){ + if (!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())) { throw new RuntimeException("操作失败:【" + asn.getOrderNo() + "】入库单,非创建状态不允许删除"); } asnDetailMapper.deleteByMainId(id); @@ -144,30 +146,43 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS List orderNoList = new ArrayList<>(); for (Serializable id : idList) { Asn asn = this.getById(id); - if(!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())){ + if (!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())) { orderNoList.add(asn.getOrderNo()); continue; } asnDetailMapper.deleteByMainId(id.toString()); asnMapper.deleteById(id); } - if(!orderNoList.isEmpty()){ + if (!orderNoList.isEmpty()) { throw new RuntimeException("操作失败:【" + orderNoList + "】入库单,非创建状态不允许删除"); } } @Override @Transactional(rollbackFor = Exception.class) - public void receiveGoods(String stockCode) { - //验证容器 - Stock stock = iStockService.validateStock(stockCode); - AsnDetail asnDetail = asnDetailMapper.queryByStockCode(stock.getId(), AsnStatusEnum.CREATED.getValue()); + public void receiveGoods(String asnDetailId, String pointCode) { + //入库明细任务 + AsnDetail asnDetail = asnDetailMapper.selectById(asnDetailId); if (asnDetail == null) { - throw new RuntimeException("【" + stockCode + "】托盘,无入库信息"); + throw new RuntimeException("未匹配到入库任务【" + asnDetailId + "】"); } + //入库单 Asn asn = this.getById(asnDetail.getAsnId()); + //实际的存储位置 + Point dstPoint = pointMapper.queryByPointCode(pointCode); + + //容器 + Stock stock = stockMapper.selectById(asnDetail.getStockId()); + + //验证当前托盘是否有库存 +/* Stock stock = stockMapper.selectById(asnDetail.getStockId()); + Inventory existingInventory = inventoryMapper.selectByStockId(stock.getId()); + if (existingInventory != null) { + throw new RuntimeException("【" + stock.getStockCode() + "】托盘已入库"); + }*/ + //更新收货数量 BigDecimal receivedQty = BigDecimalUtil.add(asnDetail.getReceivedQty(), asnDetail.getOrderQty(), 0); asnDetail.setReceivedQty(receivedQty); @@ -180,48 +195,30 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS } asnDetailMapper.updateById(asnDetail); - // 根据容器ID查询库存 - Inventory existingInventory = inventoryMapper.selectByStockId(asnDetail.getStockId()); - if (existingInventory != null) { - // 更新库存 - existingInventory.setQuantity(receivedQty); - existingInventory.setQueuedQty(BigDecimal.ZERO); - existingInventory.setStatus(InventoryStatusEnum.AVAILABLE.getValue()); - inventoryMapper.updateById(existingInventory); - } else { - //生成新库存 - Inventory inventory = Inventory.builder() - .itemId(asnDetail.getItemId()) - .pointId(asnDetail.getPointId()) - .stockId(asnDetail.getStockId()) - .quantity(receivedQty) - .queuedQty(BigDecimal.ZERO) - .whCode(asn.getWhCode()) - .propC1(asnDetail.getPropC1()) - .propC2(asnDetail.getPropC2()) - .propC3(asnDetail.getPropC3()) - .status(InventoryStatusEnum.AVAILABLE.getValue()) - .propD1(asnDetail.getPropD1()) - .description(asnDetail.getDescription()) - .tenantId(asnDetail.getTenantId()) - .sysOrgCode(asnDetail.getSysOrgCode()) - .createBy(asnDetail.getCreateBy()) - .createTime(new Date()) - .build(); - inventoryMapper.insert(inventory); - } + //生成入库记录 + ReceiveRecord receiveRecord = createReceiveRecord(asnDetail, receivedQty, dstPoint.getId()); - //更新容器状态和位置 - updateStockPoint(asnDetail.getStockId(), asnDetail.getPointId()); + // 生成库存 + Inventory inventory = iInventoryService.createInventory(stock.getId(), receivedQty, asn, asnDetail, receiveRecord); //更新入库单 refreshAsn(asn, asnDetailMapper.selectByMainId(asn.getId())); - //创建入库记录 + //更新容器状态和位置 + updateStockPoint(stock, dstPoint); + + //添加库存日志 + iInventoryLogService.addInboundInventoryLog(inventory, asnDetail.getPointId(), receivedQty, asn.getOrderNo(), asnDetail.getId(), asnDetail.getDescription()); + } + + /** + * 创建入库记录 + */ + public ReceiveRecord createReceiveRecord(AsnDetail asnDetail, BigDecimal receivedQty, String dstPointId) { ReceiveRecord receiveRecord = ReceiveRecord.builder() .asnDetailId(asnDetail.getId()) .stockId(asnDetail.getStockId()) - .pointId(asnDetail.getPointId()) + .pointId(dstPointId) .itemId(asnDetail.getItemId()) .receivedQty(receivedQty) .propC1(asnDetail.getPropC1()) @@ -235,22 +232,19 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS .createTime(new Date()) .build(); receiveRecordMapper.insert(receiveRecord); - - //TODO: 在此处添加库存操作日志 + return receiveRecord; } /** * 更新容器位置和状态 */ - private void updateStockPoint(String stockId, String pointId) { - Stock stock = stockMapper.selectById(stockId); - stock.setPointId(pointId); + private void updateStockPoint(Stock stock, Point point) { + stock.setPointId(point.getId()); stock.setStatus(CommonStatusEnum.USED.getValue()); stockMapper.updateById(stock); // 更新库位状态为占用 - Point point = pointMapper.selectById(pointId); point.setStatus(CommonStatusEnum.USED.getValue()); // 占用状态 pointMapper.updateById(point); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java index 9ae8364..9613499 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java @@ -5,9 +5,11 @@ import org.cpte.modules.agvTask.service.IAgvTaskService; import org.cpte.modules.base.entity.Item; import org.cpte.modules.base.entity.Point; import org.cpte.modules.base.entity.Stock; +import org.cpte.modules.base.mapper.PointMapper; import org.cpte.modules.base.service.IItemService; import org.cpte.modules.base.service.IPointService; import org.cpte.modules.base.service.IStockService; +import org.cpte.modules.constant.CommonConstant; import org.cpte.modules.constant.enums.*; import org.cpte.modules.receive.entity.Asn; import org.cpte.modules.receive.entity.AsnDetail; @@ -17,9 +19,11 @@ import org.cpte.modules.saiWms.request.InboundRequest; import org.cpte.modules.saiWms.service.ISaiWmsService; import org.cpte.modules.utils.CodeGeneratorUtil; import org.jeecg.common.config.TenantContext; +import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.oConvertUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; @@ -31,6 +35,9 @@ public class ISaiWmsServiceImpl implements ISaiWmsService { @Autowired private AsnMapper asnMapper; + @Autowired + private PointMapper pointMapper; + @Autowired private IItemService itemService; @@ -44,21 +51,26 @@ public class ISaiWmsServiceImpl implements ISaiWmsService { private IAsnService asnService; @Autowired - private IAgvTaskService iAgvTaskService ; + private IAgvTaskService iAgvTaskService; @Autowired private CodeGeneratorUtil codeGeneratorUtil; - @Override - public void inBoundTask(InboundRequest inboundRequest) { - //任务号 - String no = inboundRequest.getNo(); + @Autowired + private RedisUtil redisUtil; - // 验证任务号是否存在 - if (asnMapper.queryByNo(no) != null) { - throw new RuntimeException("【" + no + "】" + "任务号系统已接收,请勿重复下发"); + @Override + @Transactional(rollbackFor = Exception.class) + public void inBoundTask(InboundRequest inboundRequest) { + //验证任务号 + String no = inboundRequest.getNo(); + Asn asn = asnMapper.queryByNo(no); + if (asn != null) { + throw new RuntimeException("【" + no + "】任务号已接收,请勿重复下发"); } + //一个托盘一个任务,不允许一个多盘多个任务 + // 获取唯一的明细 InboundRequest.InboundDetail detail = inboundRequest.getDetails().get(0); @@ -71,12 +83,14 @@ public class ISaiWmsServiceImpl implements ISaiWmsService { Item item = itemService.validateItem(itemCode); Stock stock = iStockService.validateStock(stockCode); - //获取目标库位 - List dstPointList = iPointService.queryPoints(null, CommonStatusEnum.FREE.getValue(), AreaTypeEnum.RK_DOCK.getValue()); - if(dstPointList.isEmpty()){ + //获取输送线工作台点位,均衡分配点位任务-轮询方式 + List dstPointList = pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), AreaTypeEnum.RK_DOCK.getValue()); + if (dstPointList.isEmpty()) { throw new RuntimeException("【" + AreaTypeEnum.RK_DOCK.getDesc() + "】" + "无空闲库位"); } - Point dstPoint = dstPointList.get(0); + String key = CommonConstant.RK_DOCK_TASK_INDEX; + long currentIndex = redisUtil.incr(key, 1) % dstPointList.size(); + Point dstPoint = dstPointList.get((int) currentIndex); // 创建入库单和明细 Asn createAsn = buildAsn(inboundRequest); @@ -85,17 +99,21 @@ public class ISaiWmsServiceImpl implements ISaiWmsService { // 保存入库单和入库明细 asnService.saveMain(createAsn, Collections.singletonList(asnDetail)); - //创建AGV任务 - iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), stock.getStockCode(), srcPoint.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(),AgvVendorEnum.HIK.getValue()); + //成品入库需要生成AGV + if (AsnOrderTypeEnum.PRODUCT.getValue().equals(createAsn.getOrderType())) { + //创建AGV任务 + iAgvTaskService.createAgvTask(asnDetail.getId(), AgvStatusEnum.CREATED.getValue(), stock.getStockCode(), srcPoint.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), AgvVendorEnum.HIK.getValue()); + } } /** * 构建入库单 */ private Asn buildAsn(InboundRequest inboundRequest) { - int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0); + int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 1000); + String orderNo = (codeGeneratorUtil.generateSerialNumber("RK")); return Asn.builder() - .orderNo(codeGeneratorUtil.generateCode("RK")) + .orderNo(orderNo) .thirdPartyOrderNo(inboundRequest.getOrderNo()) .no(inboundRequest.getNo()) .whCode(inboundRequest.getWhCode()) diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java index 95680f1..5da7785 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java @@ -132,7 +132,6 @@ public class ITesAgvServiceImpl implements ITesAgvService { public void callBackTask(TesCallbackRequest tesCallbackRequest) { //根据任务ID查询任务 AgvTask agvTask = agvTaskMapper.selectById(tesCallbackRequest.getContent().getBizID()); - String stockCode=tesCallbackRequest.getContent().getPodID(); if (agvTask == null) { throw new RuntimeException("【" + tesCallbackRequest.getContent().getBizID() + "】任务不存在"); } @@ -140,7 +139,7 @@ public class ITesAgvServiceImpl implements ITesAgvService { switch (status) { case 4: //4.成功-任务完成 - handleEnd(stockCode,agvTask); + handleEnd(agvTask.getBusinessDetailId(), agvTask); break; case 6: //6.已取消-任务取消 @@ -158,8 +157,9 @@ public class ITesAgvServiceImpl implements ITesAgvService { * * @param agvTask 任务 */ - private void handleEnd(String stockCode,AgvTask agvTask) { - iAsnService.receiveGoods(stockCode); + private void handleEnd(String asnDetailId, AgvTask agvTask) { + //确认收货 + iAsnService.receiveGoods(asnDetailId, agvTask.getEndCode()); agvTask.setStatus(AgvStatusEnum.COMPLETED.getValue()); agvTask.setEndTime(new Date()); agvTaskMapper.updateById(agvTask); @@ -182,11 +182,11 @@ public class ITesAgvServiceImpl implements ITesAgvService { * @param agvTask 任务 */ private void handleResend(AgvTask agvTask) { - Long count = agvTaskMapper.existsAGVTask(agvTask.getCarrierCode(),AgvVendorEnum.TES.getValue()); + Long count = agvTaskMapper.existsByStockCode(agvTask.getCarrierCode(), AgvVendorEnum.TES.getValue()); if (count > 0) { throw new RuntimeException("任务已重新生成,请勿重复操作! "); } - AgvTask newAgvTask = iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), agvTask.getCarrierCode(), agvTask.getStartCode(), agvTask.getEndCode(), null, agvTask.getType(), AgvVendorEnum.TES.getValue()); + AgvTask newAgvTask = iAgvTaskService.createAgvTask(agvTask.getBusinessDetailId(), AgvStatusEnum.CREATED.getValue(), agvTask.getCarrierCode(), agvTask.getStartCode(), agvTask.getEndCode(), null, agvTask.getType(), AgvVendorEnum.TES.getValue()); switch (agvTask.getType()) { case "INBOUND": case "OUTBOUND": diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/CodeGeneratorUtil.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/CodeGeneratorUtil.java index f3ffc19..1923845 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/CodeGeneratorUtil.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/CodeGeneratorUtil.java @@ -1,17 +1,20 @@ package org.cpte.modules.utils; import com.alibaba.fastjson.JSONObject; -import jakarta.annotation.Resource; +import com.jeecg.weibo.exception.BusinessException; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.handler.IFillRuleHandler; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.CannotAcquireLockException; +import org.springframework.dao.DeadlockLoserDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; + import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.util.List; @Service @Slf4j @@ -29,33 +32,39 @@ public class CodeGeneratorUtil implements IFillRuleHandler { * @return 完整业务编号 */ @Transactional - public String generateCode(String type) { - String dateStr = LocalDate.now().format(DATE_FORMATTER); + public String generateSerialNumber(String type) { + try { + String dateStr = LocalDate.now().format(DATE_FORMATTER); - // 尝试更新当前序列号 - String updateSql = "UPDATE generator_sequence SET current_seq = current_seq + 1 WHERE type = ? AND date_str = ?"; - int updated = jdbcTemplate.update(updateSql, type, dateStr); + // 使用 SELECT FOR UPDATE 加锁查询并更新 + String lockAndUpdateSql = + "SELECT current_seq FROM generator_sequence WHERE type = ? AND date_str = ? FOR UPDATE"; - if (updated == 0) { - // 如果没有记录,则插入初始记录 - String insertSql = "INSERT IGNORE INTO generator_sequence (type, date_str, current_seq) VALUES (?, ?, 1)"; - jdbcTemplate.update(insertSql, type, dateStr); + List result = jdbcTemplate.queryForList(lockAndUpdateSql, Integer.class, type, dateStr); + + if (result.isEmpty()) { + // 插入初始值 + String insertSql = "INSERT INTO generator_sequence (type, date_str, current_seq) VALUES (?, ?, 1)"; + jdbcTemplate.update(insertSql, type, dateStr); + return type + dateStr + "000001"; + } else { + // 获取当前序列号并更新 + Integer currentSeq = result.get(0); + String updateSql = "UPDATE generator_sequence SET current_seq = current_seq + 1 WHERE type = ? AND date_str = ?"; + jdbcTemplate.update(updateSql, type, dateStr); + + String seqStr = String.format("%06d", currentSeq + 1); + return type + dateStr + seqStr; + } + } catch (CannotAcquireLockException e) { + throw new RuntimeException("系统繁忙,请稍后重试", e); } - - // 查询最新的序列号 - String selectSql = "SELECT current_seq FROM generator_sequence WHERE type = ? AND date_str = ?"; - Integer currentSeq = jdbcTemplate.queryForObject(selectSql, Integer.class, type, dateStr); - - // 格式化为6位数字 - String seqStr = String.format("%06d", currentSeq); - - return type + dateStr + seqStr; } @Override public Object execute(JSONObject params, JSONObject formData) { String prefix = params.getString("prefix"); - Object code = generateCode(prefix); + Object code = generateSerialNumber(prefix); log.info("生成业务编号:{}", code); return code; } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/SmartEnumUtil.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/SmartEnumUtil.java new file mode 100644 index 0000000..a25a3a1 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/SmartEnumUtil.java @@ -0,0 +1,163 @@ +package org.cpte.modules.utils; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.cpte.modules.constant.enums.BaseEnum; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 枚举工具类 + * + * @Author YouChain: 胡克 + * @Date 2017/10/10 18:17 + * @Email huoj@youchain56.com + */ +public class SmartEnumUtil { + + /** + * 校验参数与枚举类比较是否合法 + * + * @param value 参数 + * @param enumClass 枚举类必须实现BaseEnum接口 + * @return boolean + * @Author 胡克 + */ + public static boolean checkEnum(Object value, Class enumClass) { + if (null == value) { + return false; + } + return Stream.of(enumClass.getEnumConstants()).anyMatch(e -> e.equalsValue(value)); + } + + /** + * 创建一个具有唯一array值的数组,每个值不包含在其他给定的数组中。 + * + * @param enumClass + * @param exclude + * @param + * @return + */ + public static List differenceValueList(Class enumClass, T... exclude) { + HashSet valueSet = new HashSet<>(); + if (exclude != null) { + valueSet.addAll(Stream.of(exclude).map(BaseEnum::getValue).collect(Collectors.toSet())); + } + + return Stream.of(enumClass.getEnumConstants()) + .filter(e -> !valueSet.contains(e.getValue())) + .map(BaseEnum::getValue) + .collect(Collectors.toList()); + } + + /** + * 获取枚举类的说明 value : info 的形式 + * + * @param enumClass + * @return String + */ + public static String getEnumDesc(Class enumClass) { + BaseEnum[] enums = enumClass.getEnumConstants(); + // value : info 的形式 + StringBuilder sb = new StringBuilder(); + for (BaseEnum baseEnum : enums) { + sb.append(baseEnum.getValue()).append(":").append(baseEnum.getDesc()).append(","); + } + return sb.toString(); + } + + /** + * 获取与参数相匹配的枚举类实例的 说明 + * + * @param value 参数 + * @param enumClass 枚举类必须实现BaseEnum接口 + * @return String 如无匹配枚举则返回null + */ + public static String getEnumDescByValue(Object value, Class enumClass) { + if (null == value) { + return null; + } + return Stream.of(enumClass.getEnumConstants()) + .filter(e -> e.equalsValue(value)) + .findFirst() + .map(BaseEnum::getDesc) + .orElse(null); + } + + public static String getEnumDescByValueList(Collection values, Class enumClass) { + if (CollectionUtils.isEmpty(values)) { + return ""; + } + return Stream.of(enumClass.getEnumConstants()).filter(e -> values.contains(e.getValue())).map(BaseEnum::getDesc).collect(Collectors.joining(",")); + } + + /** + * 根据参数获取枚举类的实例 + * + * @param value 参数 + * @param enumClass 枚举类必须实现BaseEnum接口 + * @return BaseEnum 无匹配值返回null + * @Author 胡克 + */ + public static T getEnumByValue(Object value, Class enumClass) { + if (null == value) { + return null; + } + return Stream.of(enumClass.getEnumConstants()) + .filter(e -> e.equalsValue(value)) + .findFirst() + .orElse(null); + } + + /** + * 根据实例描述与获取枚举类的实例 + * + * @param desc 参数描述 + * @param enumClass 枚举类必须实现BaseEnum接口 + * @return BaseEnum 无匹配值返回null + * @Author 胡克 + */ + public static T getEnumByDesc(String desc, Class enumClass) { + return Stream.of(enumClass.getEnumConstants()) + .filter(e -> Objects.equals(e.getDesc(), desc)) + .findFirst() + .orElse(null); + } + + + public static T getEnumByName(String name, Class enumClass) { + return Stream.of(enumClass.getEnumConstants()) + .filter(e -> StringUtils.equalsIgnoreCase(e.toString(), name)) + .findFirst() + .orElse(null); + } + + + /** + * 根据lambda getter/setter 注入 + * + * @param list + * @param getter + * @param setter + * @param enumClass + * @param + */ + public static void inject(List list, Function getter, BiConsumer setter, Class enumClass) { + if (list == null || list.isEmpty()) { + return; + } + for (T t : list) { + Integer enumValue = getter.apply(t); + if (enumValue != null) { + setter.accept(t, getEnumDescByValue(enumValue, enumClass)); + } + } + } +} diff --git a/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java b/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java index 80a091e..b6693a3 100644 --- a/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java +++ b/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java @@ -1,11 +1,14 @@ package org.jeecg.modules.monitor.service; +import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import com.alibaba.fastjson.JSONArray; import org.jeecg.modules.monitor.domain.RedisInfo; import org.jeecg.modules.monitor.exception.RedisConnectException; +import org.springframework.util.CollectionUtils; /** * @Description: redis信息service接口 @@ -13,42 +16,61 @@ import org.jeecg.modules.monitor.exception.RedisConnectException; */ public interface RedisService { - /** - * 获取 redis 的详细信息 - * - * @return List + /** + * 获取 redis 的详细信息 + * + * @return List * @throws RedisConnectException - */ - List getRedisInfo() throws RedisConnectException; + */ + List getRedisInfo() throws RedisConnectException; - /** - * 获取 redis key 数量 - * - * @return Map + /** + * 获取 redis key 数量 + * + * @return Map * @throws RedisConnectException - */ - Map getKeysSize() throws RedisConnectException; + */ + Map getKeysSize() throws RedisConnectException; - /** - * 获取 redis 内存信息 - * - * @return Map + /** + * 获取 redis 内存信息 + * + * @return Map * @throws RedisConnectException - */ - Map getMemoryInfo() throws RedisConnectException; - /** - * 获取 报表需要个redis信息 - * @param type - * @return Map - * @throws RedisConnectException - */ - Map getMapForReport(String type) throws RedisConnectException ; + */ + Map getMemoryInfo() throws RedisConnectException; - /** - * 获取历史性能指标 - * @return - * @author chenrui - * @date 2024/5/14 14:57 - */ - Map>> getMetricsHistory(); + /** + * 获取 报表需要个redis信息 + * + * @param type + * @return Map + * @throws RedisConnectException + */ + Map getMapForReport(String type) throws RedisConnectException; + + /** + * 获取历史性能指标 + * + * @return + * @author chenrui + * @date 2024/5/14 14:57 + */ + Map>> getMetricsHistory(); + + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + void delete(String... key); + + void mset(String key, String hashKey, Object value); + + Object mget(String key, String hashKey); + + boolean getLock(String key, long expire); + + void unLock(String key); } diff --git a/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java b/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java index 8b08faa..f6a6e72 100644 --- a/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java +++ b/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java @@ -1,6 +1,7 @@ package org.jeecg.modules.monitor.service.impl; import java.util.*; +import java.util.concurrent.TimeUnit; import jakarta.annotation.Resource; @@ -12,12 +13,17 @@ import org.jeecg.common.util.oConvertUtils; import org.jeecg.modules.monitor.domain.RedisInfo; import org.jeecg.modules.monitor.exception.RedisConnectException; import org.jeecg.modules.monitor.service.RedisService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cglib.beans.BeanMap; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; /** * Redis 监控信息获取 @@ -28,9 +34,19 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class RedisServiceImpl implements RedisService { + @Autowired + private RedisTemplate redisTemplate; + @Resource private RedisConnectionFactory redisConnectionFactory; + + @Resource + private HashOperations redisHashOperations; + + @Resource + private ValueOperations redisValueOperations; + /** * redis信息 */ @@ -140,6 +156,37 @@ public class RedisServiceImpl implements RedisService { return REDIS_METRICS; } + @Override + public void delete(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { + redisTemplate.delete((Collection) CollectionUtils.arrayToList(key)); + } + } + } + + @Override + public void mset(String key, String hashKey, Object value) { + redisHashOperations.put(key, hashKey, value); + } + + @Override + public Object mget(String key, String hashKey) { + return redisHashOperations.get(key, hashKey); + } + + @Override + public boolean getLock(String key, long expire) { + return redisValueOperations.setIfAbsent(key, String.valueOf(System.currentTimeMillis()), expire, TimeUnit.MILLISECONDS); + } + + @Override + public void unLock(String key) { + redisValueOperations.getOperations().delete(key); + } + /** * 记录近一小时redis监控数据
* 60s一次,,记录存储keysize和内存