no message
parent
126414e875
commit
90a27ac851
|
|
@ -17,6 +17,9 @@ public class LogDTO implements Serializable {
|
||||||
/**内容*/
|
/**内容*/
|
||||||
private String logContent;
|
private String logContent;
|
||||||
|
|
||||||
|
/** 返回 */
|
||||||
|
private String returnData;
|
||||||
|
|
||||||
/**日志类型(0:操作日志;1:登录日志;2:定时任务) */
|
/**日志类型(0:操作日志;1:登录日志;2:定时任务) */
|
||||||
private Integer logType;
|
private Integer logType;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.jeecg.common.aspect;
|
package org.jeecg.common.aspect;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson.serializer.PropertyFilter;
|
import com.alibaba.fastjson.serializer.PropertyFilter;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
|
@ -28,6 +29,7 @@ import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
@ -71,10 +73,10 @@ public class AutoLogAspect {
|
||||||
|
|
||||||
LogDTO dto = new LogDTO();
|
LogDTO dto = new LogDTO();
|
||||||
AutoLog syslog = method.getAnnotation(AutoLog.class);
|
AutoLog syslog = method.getAnnotation(AutoLog.class);
|
||||||
if(syslog != null){
|
if (syslog != null) {
|
||||||
//update-begin-author:taoyan date:
|
//update-begin-author:taoyan date:
|
||||||
String content = syslog.value();
|
String content = syslog.value();
|
||||||
if(syslog.module()== ModuleType.ONLINE){
|
if (syslog.module() == ModuleType.ONLINE) {
|
||||||
content = getOnlineLogContent(obj, content);
|
content = getOnlineLogContent(obj, content);
|
||||||
}
|
}
|
||||||
//注解上的描述,操作日志内容
|
//注解上的描述,操作日志内容
|
||||||
|
|
@ -95,13 +97,16 @@ public class AutoLogAspect {
|
||||||
|
|
||||||
//获取request
|
//获取request
|
||||||
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
|
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
|
||||||
|
//请求的url
|
||||||
|
dto.setRequestUrl(request.getRequestURL().toString());
|
||||||
//请求的参数
|
//请求的参数
|
||||||
dto.setRequestParam(getReqestParams(request,joinPoint));
|
dto.setRequestParam(getReqestParams(request, joinPoint));
|
||||||
|
dto.setReturnData(handlerResult(obj));
|
||||||
//设置IP地址
|
//设置IP地址
|
||||||
dto.setIp(IpUtils.getIpAddr(request));
|
dto.setIp(IpUtils.getIpAddr(request));
|
||||||
//获取登录用户信息
|
//获取登录用户信息
|
||||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
if(sysUser!=null){
|
if (sysUser != null) {
|
||||||
dto.setUserid(sysUser.getUsername());
|
dto.setUserid(sysUser.getUsername());
|
||||||
dto.setUsername(sysUser.getRealname());
|
dto.setUsername(sysUser.getRealname());
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +121,7 @@ public class AutoLogAspect {
|
||||||
/**
|
/**
|
||||||
* 获取操作类型
|
* 获取操作类型
|
||||||
*/
|
*/
|
||||||
private int getOperateType(String methodName,int operateType) {
|
private int getOperateType(String methodName, int operateType) {
|
||||||
if (operateType > 0) {
|
if (operateType > 0) {
|
||||||
return operateType;
|
return operateType;
|
||||||
}
|
}
|
||||||
|
|
@ -126,11 +131,11 @@ public class AutoLogAspect {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param request: request
|
||||||
|
* @param joinPoint: joinPoint
|
||||||
* @Description: 获取请求参数
|
* @Description: 获取请求参数
|
||||||
* @author: scott
|
* @author: scott
|
||||||
* @date: 2020/4/16 0:10
|
* @date: 2020/4/16 0:10
|
||||||
* @param request: request
|
|
||||||
* @param joinPoint: joinPoint
|
|
||||||
* @Return: java.lang.String
|
* @Return: java.lang.String
|
||||||
*/
|
*/
|
||||||
private String getReqestParams(HttpServletRequest request, JoinPoint joinPoint) {
|
private String getReqestParams(HttpServletRequest request, JoinPoint joinPoint) {
|
||||||
|
|
@ -140,7 +145,7 @@ public class AutoLogAspect {
|
||||||
Object[] paramsArray = joinPoint.getArgs();
|
Object[] paramsArray = joinPoint.getArgs();
|
||||||
// java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
|
// java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
|
||||||
// https://my.oschina.net/mengzhang6/blog/2395893
|
// https://my.oschina.net/mengzhang6/blog/2395893
|
||||||
Object[] arguments = new Object[paramsArray.length];
|
Object[] arguments = new Object[paramsArray.length];
|
||||||
for (int i = 0; i < paramsArray.length; i++) {
|
for (int i = 0; i < paramsArray.length; i++) {
|
||||||
if (paramsArray[i] instanceof BindingResult || paramsArray[i] instanceof ServletRequest || paramsArray[i] instanceof ServletResponse || paramsArray[i] instanceof MultipartFile) {
|
if (paramsArray[i] instanceof BindingResult || paramsArray[i] instanceof ServletRequest || paramsArray[i] instanceof ServletResponse || paramsArray[i] instanceof MultipartFile) {
|
||||||
//ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
|
//ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
|
||||||
|
|
@ -154,7 +159,7 @@ public class AutoLogAspect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Object o, String name, Object value) {
|
public boolean apply(Object o, String name, Object value) {
|
||||||
int length = 500;
|
int length = 500;
|
||||||
if(value!=null && value.toString().length()>length){
|
if (value != null && value.toString().length() > length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !(value instanceof MultipartFile);
|
return !(value instanceof MultipartFile);
|
||||||
|
|
@ -168,7 +173,7 @@ public class AutoLogAspect {
|
||||||
// 请求的方法参数值
|
// 请求的方法参数值
|
||||||
Object[] args = joinPoint.getArgs();
|
Object[] args = joinPoint.getArgs();
|
||||||
// 请求的方法参数名称
|
// 请求的方法参数名称
|
||||||
StandardReflectionParameterNameDiscoverer u=new StandardReflectionParameterNameDiscoverer();
|
StandardReflectionParameterNameDiscoverer u = new StandardReflectionParameterNameDiscoverer();
|
||||||
String[] paramNames = u.getParameterNames(method);
|
String[] paramNames = u.getParameterNames(method);
|
||||||
if (args != null && paramNames != null) {
|
if (args != null && paramNames != null) {
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
|
@ -179,24 +184,46 @@ public class AutoLogAspect {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String handlerResult(Object result) {
|
||||||
|
if (result == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String resultStr;
|
||||||
|
try {
|
||||||
|
if (result instanceof String) {
|
||||||
|
resultStr = (String) result;
|
||||||
|
} else {
|
||||||
|
resultStr = JSON.toJSONString(result);// 如果返回结果非String类型,转换成JSON格式的字符串
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultStr.length() > 10000) {
|
||||||
|
resultStr = resultStr.substring(0, 10000);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
resultStr = result.toString();
|
||||||
|
}
|
||||||
|
return resultStr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* online日志内容拼接
|
* online日志内容拼接
|
||||||
|
*
|
||||||
* @param obj
|
* @param obj
|
||||||
* @param content
|
* @param content
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private String getOnlineLogContent(Object obj, String content){
|
private String getOnlineLogContent(Object obj, String content) {
|
||||||
if (obj instanceof Result){
|
if (obj instanceof Result) {
|
||||||
Result res = (Result)obj;
|
Result res = (Result) obj;
|
||||||
String msg = res.getMessage();
|
String msg = res.getMessage();
|
||||||
String tableName = res.getOnlTable();
|
String tableName = res.getOnlTable();
|
||||||
if(oConvertUtils.isNotEmpty(tableName)){
|
if (oConvertUtils.isNotEmpty(tableName)) {
|
||||||
content+=",表名:"+tableName;
|
content += ",表名:" + tableName;
|
||||||
}
|
}
|
||||||
if(res.isSuccess()){
|
if (res.isSuccess()) {
|
||||||
content+= ","+(oConvertUtils.isEmpty(msg)?"操作成功":msg);
|
content += "," + (oConvertUtils.isEmpty(msg) ? "操作成功" : msg);
|
||||||
}else{
|
} else {
|
||||||
content+= ","+(oConvertUtils.isEmpty(msg)?"操作失败":msg);
|
content += "," + (oConvertUtils.isEmpty(msg) ? "操作失败" : msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return content;
|
return content;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<!-- 保存日志11 -->
|
<!-- 保存日志11 -->
|
||||||
<insert id="saveLog" parameterType="Object">
|
<insert id="saveLog" parameterType="Object">
|
||||||
insert into sys_log (id, log_type, log_content, method, operate_type, request_url, request_type, request_param, ip, userid, username, cost_time, create_time,create_by, tenant_id, client_type)
|
insert into sys_log (id, log_type, log_content, method, operate_type, request_url, request_type, request_param,return_data, ip, userid, username, cost_time, create_time,create_by, tenant_id, client_type)
|
||||||
values(
|
values(
|
||||||
#{dto.id,jdbcType=VARCHAR},
|
#{dto.id,jdbcType=VARCHAR},
|
||||||
#{dto.logType,jdbcType=INTEGER},
|
#{dto.logType,jdbcType=INTEGER},
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#{dto.requestUrl,jdbcType=VARCHAR},
|
#{dto.requestUrl,jdbcType=VARCHAR},
|
||||||
#{dto.requestType,jdbcType=VARCHAR},
|
#{dto.requestType,jdbcType=VARCHAR},
|
||||||
#{dto.requestParam,jdbcType=VARCHAR},
|
#{dto.requestParam,jdbcType=VARCHAR},
|
||||||
|
#{dto.returnData,jdbcType=VARCHAR},
|
||||||
#{dto.ip,jdbcType=VARCHAR},
|
#{dto.ip,jdbcType=VARCHAR},
|
||||||
#{dto.userid,jdbcType=VARCHAR},
|
#{dto.userid,jdbcType=VARCHAR},
|
||||||
#{dto.username,jdbcType=VARCHAR},
|
#{dto.username,jdbcType=VARCHAR},
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,24 @@ public interface PointMapper extends BaseMapper<Point> {
|
||||||
List<Point> queryPoints(@Param("pointCode") String pointCode, @Param("status") Integer status, @Param("areaCode") String areaCode);
|
List<Point> queryPoints(@Param("pointCode") String pointCode, @Param("status") Integer status, @Param("areaCode") String areaCode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询同SKU、批次、PO的库位
|
* 查询库位信息
|
||||||
*
|
*
|
||||||
* @param itemId 物料ID
|
* @param itemId 商品ID
|
||||||
* @param propC1 批次号
|
* @param whCode 仓库编号
|
||||||
* @param whCode 仓库编码
|
* @param projects 项目编号
|
||||||
|
* @param taskNos 任务编号
|
||||||
|
* @param propC1List 批次号
|
||||||
|
* @param propC3List 外部库存状态
|
||||||
|
* @param areaCode 库区编号
|
||||||
* @return List<Point>
|
* @return List<Point>
|
||||||
*/
|
*/
|
||||||
List<Point> findPointsWithSkuBatchPo(@Param("itemId") Long itemId, @Param("propC1") String propC1, @Param("whCode") String whCode,@Param("areaCode") String areaCode);
|
List<Point> findPointsWithSkuBatchPo(@Param("itemId") Long itemId,
|
||||||
|
@Param("whCode") String whCode,
|
||||||
|
@Param("projects") List<String> projects,
|
||||||
|
@Param("taskNos") List<String> taskNos,
|
||||||
|
@Param("propC1List") List<String> propC1List,
|
||||||
|
@Param("propC3List") List<String> propC3List,
|
||||||
|
@Param("areaCode") String areaCode);
|
||||||
|
|
||||||
// 查询同一巷道占用数量
|
// 查询同一巷道占用数量
|
||||||
@Select("SELECT COUNT(id) FROM base_point WHERE col_num = #{colNum} AND layer_num = #{layerNum} AND status = 1")
|
@Select("SELECT COUNT(id) FROM base_point WHERE col_num = #{colNum} AND layer_num = #{layerNum} AND status = 1")
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,6 @@
|
||||||
WHERE inv.item_id = #{itemId}
|
WHERE inv.item_id = #{itemId}
|
||||||
AND bp1.status = 0
|
AND bp1.status = 0
|
||||||
AND ba.area_code = #{areaCode}
|
AND ba.area_code = #{areaCode}
|
||||||
<choose>
|
|
||||||
<when test="propC1 != null and propC1 != ''">
|
|
||||||
AND inv.prop_c1 = #{propC1}
|
|
||||||
</when>
|
|
||||||
<otherwise>
|
|
||||||
AND (inv.prop_c1 IS NULL OR inv.prop_c1 = '')
|
|
||||||
</otherwise>
|
|
||||||
</choose>
|
|
||||||
<choose>
|
<choose>
|
||||||
<when test="whCode != null and whCode != ''">
|
<when test="whCode != null and whCode != ''">
|
||||||
AND inv.wh_code = #{whCode}
|
AND inv.wh_code = #{whCode}
|
||||||
|
|
@ -41,5 +33,49 @@
|
||||||
AND (inv.wh_code IS NULL OR inv.wh_code = '')
|
AND (inv.wh_code IS NULL OR inv.wh_code = '')
|
||||||
</otherwise>
|
</otherwise>
|
||||||
</choose>
|
</choose>
|
||||||
|
<choose>
|
||||||
|
<when test="projects != null and !projects.isEmpty()">
|
||||||
|
AND inv.project IN
|
||||||
|
<foreach collection="projects" item="project" open="(" separator="," close=")">
|
||||||
|
#{project}
|
||||||
|
</foreach>
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
AND (inv.project IS NULL OR inv.project = '')
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
<choose>
|
||||||
|
<when test="taskNos != null and !taskNos.isEmpty()">
|
||||||
|
AND inv.task_no IN
|
||||||
|
<foreach collection="taskNos" item="taskNo" open="(" separator="," close=")">
|
||||||
|
#{taskNo}
|
||||||
|
</foreach>
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
AND (inv.task_no IS NULL OR inv.task_no = '')
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
<choose>
|
||||||
|
<when test="propC1List != null and !propC1List.isEmpty()">
|
||||||
|
AND inv.prop_c1 IN
|
||||||
|
<foreach collection="propC1List" item="propC1" open="(" separator="," close=")">
|
||||||
|
#{propC1}
|
||||||
|
</foreach>
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
AND (inv.prop_c1 IS NULL OR inv.prop_c1 = '')
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
<choose>
|
||||||
|
<when test="propC3List != null and !propC3List.isEmpty()">
|
||||||
|
AND inv.prop_c3 IN
|
||||||
|
<foreach collection="propC3List" item="propC3" open="(" separator="," close=")">
|
||||||
|
#{propC3}
|
||||||
|
</foreach>
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
AND (inv.prop_c3 IS NULL OR inv.prop_c3 = '')
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -3,6 +3,8 @@ package org.cpte.modules.base.service;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.cpte.modules.base.entity.Point;
|
import org.cpte.modules.base.entity.Point;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.cpte.modules.receive.entity.Asn;
|
||||||
|
import org.cpte.modules.receive.entity.AsnDetail;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -97,4 +99,19 @@ public interface IPointService extends IService<Point> {
|
||||||
* @return List<Point>
|
* @return List<Point>
|
||||||
*/
|
*/
|
||||||
List<Point> queryPoints(String pointCode, Integer status, String areaCode);
|
List<Point> queryPoints(String pointCode, Integer status, String areaCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询物料聚集库位
|
||||||
|
*
|
||||||
|
* @param itemId 物料
|
||||||
|
* @param whCode 仓库代码
|
||||||
|
* @param projects 项目号
|
||||||
|
* @param taskNos 任务号
|
||||||
|
* @param propC1List 批次
|
||||||
|
* @param propC3List 外部库存状态
|
||||||
|
* @param areaCode 库区编码
|
||||||
|
* @return List<Point>
|
||||||
|
*/
|
||||||
|
List<Point> findClusterPoint(Long itemId, String whCode, List<String> projects, List<String> taskNos, List<String> propC1List, List<String> propC3List, String areaCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,4 +153,9 @@ public class PointServiceImpl extends ServiceImpl<PointMapper, Point> implements
|
||||||
return pointMapper.queryPoints(pointCode, status, areaCode);
|
return pointMapper.queryPoints(pointCode, status, areaCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Point> findClusterPoint(Long itemId, String whCode, List<String> projects, List<String> taskNos, List<String> propC1List, List<String> propC3List, String areaCode) {
|
||||||
|
return pointMapper.findPointsWithSkuBatchPo(itemId, whCode,projects,taskNos, propC1List, propC3List, areaCode);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bindStock(Stock stock, Point point) {
|
public void bindStock(Stock stock, Point point) {
|
||||||
stock.setPointId(point.getId());
|
stock.setPointId(point == null ? null : point.getId());
|
||||||
stock.setStatus(CommonStatusEnum.USED.getValue());
|
stock.setStatus(CommonStatusEnum.USED.getValue());
|
||||||
stockMapper.updateById(stock);
|
stockMapper.updateById(stock);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,11 @@ public interface GeneralConstant {
|
||||||
*/
|
*/
|
||||||
String PICK_ORDER_NO = "pick_order_no";
|
String PICK_ORDER_NO = "pick_order_no";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移位规则编码
|
||||||
|
*/
|
||||||
|
String MOVE_ORDER_NO = "move_order_no";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TES任务下发接口
|
* TES任务下发接口
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import lombok.Getter;
|
||||||
@Getter
|
@Getter
|
||||||
public enum TaskTypeEnum {
|
public enum TaskTypeEnum {
|
||||||
PICK(1, "出库"),
|
PICK(1, "出库"),
|
||||||
|
MOVE(2, "移位"),
|
||||||
;
|
;
|
||||||
|
|
||||||
TaskTypeEnum(Integer value, String desc) {
|
TaskTypeEnum(Integer value, String desc) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package org.cpte.modules.conveyorLine.service.impl;
|
package org.cpte.modules.conveyorLine.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
@ -24,6 +22,7 @@ import org.cpte.modules.receive.entity.Asn;
|
||||||
import org.cpte.modules.receive.entity.AsnDetail;
|
import org.cpte.modules.receive.entity.AsnDetail;
|
||||||
import org.cpte.modules.receive.mapper.AsnDetailMapper;
|
import org.cpte.modules.receive.mapper.AsnDetailMapper;
|
||||||
import org.cpte.modules.receive.mapper.AsnMapper;
|
import org.cpte.modules.receive.mapper.AsnMapper;
|
||||||
|
import org.cpte.modules.shipping.entity.PickDetail;
|
||||||
import org.cpte.modules.shipping.entity.Task;
|
import org.cpte.modules.shipping.entity.Task;
|
||||||
import org.cpte.modules.shipping.mapper.TaskMapper;
|
import org.cpte.modules.shipping.mapper.TaskMapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
@ -81,17 +80,18 @@ public class IConveyorLineServiceImpl implements IConveyorLineService {
|
||||||
validateParams(scanTrayRequest);
|
validateParams(scanTrayRequest);
|
||||||
|
|
||||||
//工作站
|
//工作站
|
||||||
Point srcPoint = pointMapper.queryByPointCode(scanTrayRequest.getStation());
|
Point station = pointMapper.queryByPointCode(scanTrayRequest.getStation());
|
||||||
|
|
||||||
//容器
|
//容器
|
||||||
Stock stock = stockMapper.queryByStockCode(scanTrayRequest.getStockCode());
|
Stock stock = stockMapper.queryByStockCode(scanTrayRequest.getStockCode());
|
||||||
|
|
||||||
//验证入库信息
|
//验证入库信息
|
||||||
AsnDetail asnDetail = asnDetailMapper.queryByStockCode(stock.getId(), AsnStatusEnum.CREATED.getValue());
|
List<AsnDetail> asnDetails = asnDetailMapper.queryByStockCode(stock.getId(), AsnStatusEnum.CREATED.getValue());
|
||||||
if (asnDetail == null) {
|
if (CollectionUtils.isEmpty(asnDetails)) {
|
||||||
throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘,无入库信息");
|
throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘,无入库任务");
|
||||||
}
|
}
|
||||||
Asn asn = asnMapper.selectById(asnDetail.getAsnId());
|
Asn asn = asnMapper.selectById(asnDetails.get(0).getAsnId());
|
||||||
|
AsnDetail asnDetail = asnDetails.get(0);
|
||||||
//验证托盘是否有库存
|
//验证托盘是否有库存
|
||||||
if (inventoryMapper.queryByStockId(stock.getId()) != null) {
|
if (inventoryMapper.queryByStockId(stock.getId()) != null) {
|
||||||
throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘已入库");
|
throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘已入库");
|
||||||
|
|
@ -102,39 +102,53 @@ public class IConveyorLineServiceImpl implements IConveyorLineService {
|
||||||
throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘已扫描,请勿重复扫描");
|
throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘已扫描,请勿重复扫描");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//项目号、任务号、批次号、外部库存状态
|
||||||
|
List<String> projects = asnDetails.stream().map(AsnDetail::getProject).filter(StringUtils::isNotBlank).distinct().toList();
|
||||||
|
List<String> taskNos = asnDetails.stream().map(AsnDetail::getTaskNo).filter(StringUtils::isNotBlank).distinct().toList();
|
||||||
|
List<String> propC1List = asnDetails.stream().map(AsnDetail::getPropC1).filter(StringUtils::isNotBlank).distinct().toList();
|
||||||
|
List<String> propC3List = asnDetails.stream().map(AsnDetail::getPropC3).filter(StringUtils::isNotBlank).distinct().toList();
|
||||||
|
|
||||||
|
|
||||||
//通过算法获取目标点位
|
//通过算法获取目标点位
|
||||||
Point dstPoint = allocatePoint(asn, asnDetail, srcPoint);
|
Point dstPoint = allocatePoint(asn.getOrderType(), asnDetail.getItemId(), asn.getWhCode(), projects, taskNos, propC1List, propC3List, station);
|
||||||
|
|
||||||
//锁定目标库位
|
//锁定目标库位
|
||||||
pointService.bindPoint(dstPoint);
|
pointService.bindPoint(dstPoint);
|
||||||
|
|
||||||
//验证通过,生成Tes任务
|
//验证通过,生成Tes任务
|
||||||
iAgvTaskService.createAgvTask(asnDetail.getId(), stock.getStockCode(), srcPoint.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.TES.getValue());
|
iAgvTaskService.createAgvTask(asn.getId(), stock.getStockCode(), station.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.TES.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 智能库位分配库位
|
* 智能库位分配库位
|
||||||
*
|
*
|
||||||
* @param asnDetail 入库明细
|
* @param orderType 单据类型
|
||||||
|
* @param itemId 物料
|
||||||
|
* @param whCode 仓库代码
|
||||||
|
* @param projects 项目号
|
||||||
|
* @param taskNos 任务号
|
||||||
|
* @param propC1List 批次号
|
||||||
|
* @param propC3List 外部库存状态
|
||||||
|
* @param station 工作站
|
||||||
* @return 目标库位
|
* @return 目标库位
|
||||||
*/
|
*/
|
||||||
private Point allocatePoint(Asn asn, AsnDetail asnDetail, Point station) {
|
private Point allocatePoint(Integer orderType, Long itemId, String whCode, List<String> projects, List<String> taskNos, List<String> propC1List, List<String> propC3List, Point station) {
|
||||||
String areaCode = "";
|
String areaCode = "";
|
||||||
if (Set.of(0, 1, 2, 3).contains(asn.getOrderType())) {
|
if (Set.of(0, 1, 2, 3).contains(orderType)) {
|
||||||
areaCode = AreaTypeEnum.CPCCQ.getValue();
|
areaCode = AreaTypeEnum.CPCCQ.getValue();
|
||||||
} else {
|
} else {
|
||||||
areaCode = AreaTypeEnum.MJCCQ.getValue();
|
areaCode = AreaTypeEnum.MJCCQ.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
//1.优先寻找同物料/同批次/同PO聚集库位
|
//1.优先寻找同物料/同仓库/同项目号/同任务号/同批次/同外部库存状态
|
||||||
List<Point> availablePoints = findClusterPoint(asn, asnDetail, areaCode);
|
List<Point> availablePoints = pointService.findClusterPoint(itemId, whCode, projects, taskNos, propC1List, propC3List, areaCode);
|
||||||
if (CollectionUtils.isEmpty(availablePoints)) {
|
if (CollectionUtils.isEmpty(availablePoints)) {
|
||||||
//2.获取所有可用库位
|
//2.获取所有可用库位
|
||||||
availablePoints = pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), areaCode);
|
availablePoints = pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), areaCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PointScore> scoredPoints = availablePoints.stream()
|
List<PointScore> scoredPoints = availablePoints.stream()
|
||||||
.map(point -> calculateEnhancedLocationScore(point, station, asn, asnDetail))
|
.map(point -> clusterPointScore(point, station, itemId, whCode, projects, taskNos, propC1List, propC3List))
|
||||||
.sorted(Comparator.comparing(PointScore::getScore).reversed())
|
.sorted(Comparator.comparing(PointScore::getScore).reversed())
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
|
@ -149,42 +163,30 @@ public class IConveyorLineServiceImpl implements IConveyorLineService {
|
||||||
* 寻找物料聚集库位
|
* 寻找物料聚集库位
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private List<Point> findClusterPoint(Asn asn, AsnDetail asnDetail, String areaCode) {
|
|
||||||
return pointMapper.findPointsWithSkuBatchPo(asnDetail.getItemId(), asnDetail.getPropC1(), asn.getWhCode(), areaCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增强版库位评分计算
|
* 库位评分计算
|
||||||
* 新增:通道类型深度策略 + 物料聚集加分
|
|
||||||
*/
|
*/
|
||||||
private PointScore calculateEnhancedLocationScore(Point point, Point station, Asn asn, AsnDetail asnDetail) {
|
private PointScore clusterPointScore(Point point, Point station, Long itemId, String whCode, List<String> projects, List<String> taskNos, List<String> propC1List, List<String> propC3List) {
|
||||||
double totalScore = 0.0;
|
double totalScore;
|
||||||
|
|
||||||
// 1. 距离评分 - 考虑从入库口到库位的距离
|
// 1. 距离评分 - 考虑从入库口到库位的距离
|
||||||
double distanceScore = calculateClusterDistanceCost(point, station);
|
double distanceScore = calculateClusterDistanceCost(point, station) * 0.3;// 权重30%
|
||||||
totalScore += distanceScore * 0.3; // 权重从40%降到30%
|
|
||||||
log.info("【{}】距离评分: {}", point.getPointCode(), totalScore);
|
|
||||||
|
|
||||||
// 2. 通道深度策略评分 - 新增核心策略
|
// 2. 通道深度策略评分 - 新增核心策略
|
||||||
double channelDepthScore = calculateChannelDepthScore(point);
|
double channelDepthScore = calculateChannelDepthScore(point) * 0.25; // 权重25%
|
||||||
totalScore += channelDepthScore * 0.25; // 新增25%权重
|
|
||||||
log.info("【{}】通道深度评分: {}", point.getPointCode(), totalScore);
|
|
||||||
|
|
||||||
// 3. 通道类型评分 - 双通道优先
|
// 3. 通道类型评分 - 双通道优先
|
||||||
double channelScore = calculateChannelScore(point);
|
double channelScore = calculateChannelScore(point) * 0.15; // 权重15%
|
||||||
totalScore += channelScore * 0.15; // 权重从20%降到15%
|
|
||||||
log.info("【{}】通道类型评分: {}", point.getPointCode(), totalScore);
|
|
||||||
|
|
||||||
// 4. 均衡评分 - 避免热点区域
|
// 4. 均衡评分 - 避免热点区域
|
||||||
double balanceScore = calculateBalanceScore(point);
|
double balanceScore = calculateBalanceScore(point) * 0.1; // 权重10%
|
||||||
totalScore += balanceScore * 0.1; // 权重从15%降到10%
|
|
||||||
log.info("【{}】均衡评分: {}", point.getPointCode(), totalScore);
|
|
||||||
|
|
||||||
// 5. 物料聚集潜力评分 - 新增
|
// 5. 物料聚集潜力评分 - 新增
|
||||||
double clusterPotentialScore = calculateClusterPotentialScore(point, asn, asnDetail);
|
double clusterPotentialScore = calculateClusterPotentialScore(point, itemId, whCode, projects, taskNos, propC1List, propC3List) * 0.2; // 权重20%
|
||||||
totalScore += clusterPotentialScore * 0.2; // 新增20%权重
|
|
||||||
log.info("【{}】物料聚集潜力评分: {}", point.getPointCode(), totalScore);
|
|
||||||
|
|
||||||
|
totalScore = distanceScore + channelDepthScore + channelScore + balanceScore + clusterPotentialScore;
|
||||||
|
log.info("【{}】库位总分:{} - 距离评分: {} - 通道深度策略评分: {} - 通道类型评分: {} - 均衡评分: {} - 物料聚集评分: {}", point.getPointCode(), totalScore, distanceScore, channelDepthScore, channelScore, balanceScore, clusterPotentialScore);
|
||||||
return new PointScore(point, totalScore);
|
return new PointScore(point, totalScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -250,38 +252,66 @@ public class IConveyorLineServiceImpl implements IConveyorLineService {
|
||||||
/**
|
/**
|
||||||
* 计算物料聚集潜力评分
|
* 计算物料聚集潜力评分
|
||||||
* 检查周围库位是否有相同特征的货物
|
* 检查周围库位是否有相同特征的货物
|
||||||
|
* 新增货物特性评分:物料、仓库代码、项目号、任务号、批次号、外部库存状态
|
||||||
*/
|
*/
|
||||||
private double calculateClusterPotentialScore(Point point, Asn asn, AsnDetail asnDetail) {
|
private double calculateClusterPotentialScore(Point point, Long itemId, String whCode,
|
||||||
|
List<String> projects, List<String> taskNos,
|
||||||
|
List<String> propC1List,
|
||||||
|
List<String> propC3List) {
|
||||||
double score = 0.0;
|
double score = 0.0;
|
||||||
|
|
||||||
// 检查同一巷道相邻库位
|
// 检查同一巷道相邻库位
|
||||||
int minDepth, maxDepth;
|
int minDepth, maxDepth;
|
||||||
if (point.getIzDoubleLane().equals(1)) {
|
if (point.getIzDoubleLane().equals(1)) {
|
||||||
// 双通道:考虑整个巷道所有位置(1-7)
|
// 双通道:考虑整个巷道所有位置(1-7)
|
||||||
// 因为双通道可以从两端操作,所有位置都算邻居
|
|
||||||
minDepth = 1;
|
minDepth = 1;
|
||||||
maxDepth = 7;
|
maxDepth = 7;
|
||||||
} else {
|
} else {
|
||||||
// 单通道:只考虑同一侧的位置(从当前深度向前)
|
// 单通道:只考虑同一侧的位置(从当前深度向前)
|
||||||
// 因为只能从一端操作,后面的位置不算邻居
|
minDepth = Integer.parseInt(point.getRowNum());
|
||||||
minDepth = Integer.parseInt(point.getRowNum()); // 从当前位置开始
|
maxDepth = 7;
|
||||||
maxDepth = 7; // 到最深位置
|
|
||||||
}
|
}
|
||||||
List<Inventory> neighbors = inventoryMapper.findNeighborPoints(point.getColNum(), point.getLayerNum(), String.valueOf(minDepth), String.valueOf(maxDepth));
|
|
||||||
|
|
||||||
|
List<Inventory> neighbors = inventoryMapper.findNeighborPoints(
|
||||||
|
point.getColNum(), point.getLayerNum(), String.valueOf(minDepth), String.valueOf(maxDepth));
|
||||||
|
|
||||||
for (Inventory neighbor : neighbors) {
|
for (Inventory neighbor : neighbors) {
|
||||||
if (neighbor.getItemId() != null) {
|
if (neighbor.getItemId() != null) {
|
||||||
// 同SKU加分
|
// 同SKU加分
|
||||||
if (neighbor.getItemId().equals(asnDetail.getItemId())) {
|
if (neighbor.getItemId().equals(itemId)) {
|
||||||
score += 15;
|
score += 20;
|
||||||
// 同批次额外加分
|
|
||||||
if (asnDetail.getPropC1() != null && asnDetail.getPropC1().equals(neighbor.getPropC1())) {
|
// 同仓库代码加分
|
||||||
|
if (whCode != null && whCode.equals(neighbor.getWhCode())) {
|
||||||
score += 10;
|
score += 10;
|
||||||
// 同PO额外加分
|
}
|
||||||
if (asn.getWhCode() != null && asn.getWhCode().equals(neighbor.getWhCode())) {
|
|
||||||
score += 5;
|
// 同批次号加分
|
||||||
}
|
if (CollectionUtils.isNotEmpty(propC1List) &&
|
||||||
|
StringUtils.isNotBlank(neighbor.getPropC1()) &&
|
||||||
|
propC1List.contains(neighbor.getPropC1())) {
|
||||||
|
score += 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同项目号加分
|
||||||
|
if (CollectionUtils.isNotEmpty(projects) &&
|
||||||
|
StringUtils.isNotBlank(neighbor.getProject()) &&
|
||||||
|
projects.contains(neighbor.getProject())) {
|
||||||
|
score += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同任务号加分
|
||||||
|
if (CollectionUtils.isNotEmpty(taskNos) &&
|
||||||
|
StringUtils.isNotBlank(neighbor.getTaskNo()) &&
|
||||||
|
taskNos.contains(neighbor.getTaskNo())) {
|
||||||
|
score += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同外部库存状态加分
|
||||||
|
if (CollectionUtils.isNotEmpty(propC3List) &&
|
||||||
|
StringUtils.isNotBlank(neighbor.getPropC3()) &&
|
||||||
|
propC3List.contains(neighbor.getPropC3())) {
|
||||||
|
score += 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -291,6 +321,7 @@ public class IConveyorLineServiceImpl implements IConveyorLineService {
|
||||||
return Math.min(score, 100);
|
return Math.min(score, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算距离评分
|
* 计算距离评分
|
||||||
* 基于入库口位置和库位坐标计算最短路径距离
|
* 基于入库口位置和库位坐标计算最短路径距离
|
||||||
|
|
|
||||||
|
|
@ -86,30 +86,46 @@ public class Inventory implements Serializable {
|
||||||
@Schema(description = "入库记录ID")
|
@Schema(description = "入库记录ID")
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private java.lang.Long receiveRecordId;
|
private java.lang.Long receiveRecordId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 外部仓库
|
* 外部仓库
|
||||||
*/
|
*/
|
||||||
@Excel(name = "外部仓库", width = 15)
|
@Excel(name = "外部仓库", width = 15)
|
||||||
@Schema(description = "外部仓库")
|
@Schema(description = "外部仓库")
|
||||||
private java.lang.String whCode;
|
private java.lang.String whCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目号
|
||||||
|
*/
|
||||||
|
@Schema(description = "项目号")
|
||||||
|
private java.lang.String project;
|
||||||
|
/**
|
||||||
|
* 任务号
|
||||||
|
*/
|
||||||
|
@Schema(description = "任务号")
|
||||||
|
private java.lang.String taskNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批次号
|
* 批次号
|
||||||
*/
|
*/
|
||||||
@Excel(name = "批次号", width = 15)
|
@Excel(name = "批次号", width = 15)
|
||||||
@Schema(description = "批次号")
|
@Schema(description = "批次号")
|
||||||
private java.lang.String propC1;
|
private java.lang.String propC1;
|
||||||
/**
|
|
||||||
* 序列号
|
|
||||||
*/
|
|
||||||
@Excel(name = "序列号", width = 15)
|
|
||||||
@Schema(description = "序列号")
|
|
||||||
private java.lang.String propC2;
|
|
||||||
/**
|
/**
|
||||||
* 外部库存状态
|
* 外部库存状态
|
||||||
*/
|
*/
|
||||||
@Excel(name = "外部库存状态", width = 15)
|
@Excel(name = "外部库存状态", width = 15)
|
||||||
@Schema(description = "外部库存状态")
|
@Schema(description = "外部库存状态")
|
||||||
private java.lang.String propC3;
|
private java.lang.String propC3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列号
|
||||||
|
*/
|
||||||
|
@Excel(name = "序列号", width = 15)
|
||||||
|
@Schema(description = "序列号")
|
||||||
|
private java.lang.String propC2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 库存状态
|
* 库存状态
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -29,13 +29,13 @@ public interface InventoryMapper extends BaseMapper<Inventory> {
|
||||||
/**
|
/**
|
||||||
* 查询库存列表
|
* 查询库存列表
|
||||||
*
|
*
|
||||||
* @param itemIds 物料ID
|
* @param itemIds 物料ID
|
||||||
* @param propC1List 批次号
|
* @param propC1List 批次号
|
||||||
* @param propC3List 外部库存状态
|
* @param propC3List 外部库存状态
|
||||||
* @param whCodeList 外部仓库
|
* @param whCodeList 外部仓库
|
||||||
* @return List<Inventory>
|
* @return List<Inventory>
|
||||||
*/
|
*/
|
||||||
List<Inventory> queryInventory(@Param("itemIds") List<Long> itemIds, @Param("propC1List") List<String> propC1List, @Param("propC3List") List<String> propC3List, @Param("whCodeList") List<String> whCodeList);
|
List<Inventory> queryInventory(@Param("itemIds") List<Long> itemIds, @Param("propC1List") List<String> propC1List, @Param("propC3List") List<String> propC3List, @Param("whCodeList") List<String> whCodeList);
|
||||||
|
|
||||||
// 查询相邻库位(同一巷道,深度±3范围内)
|
// 查询相邻库位(同一巷道,深度±3范围内)
|
||||||
@Select("SELECT di.* " +
|
@Select("SELECT di.* " +
|
||||||
|
|
@ -46,10 +46,16 @@ public interface InventoryMapper extends BaseMapper<Inventory> {
|
||||||
" AND bp.row_num BETWEEN #{minDepth} AND #{maxDepth} " +
|
" AND bp.row_num BETWEEN #{minDepth} AND #{maxDepth} " +
|
||||||
" AND bp.status = 1")
|
" AND bp.status = 1")
|
||||||
List<Inventory> findNeighborPoints(@Param("colNum") String colNum,
|
List<Inventory> findNeighborPoints(@Param("colNum") String colNum,
|
||||||
@Param("layerNum") String layerNum,
|
@Param("layerNum") String layerNum,
|
||||||
@Param("minDepth") String minDepth,
|
@Param("minDepth") String minDepth,
|
||||||
@Param("maxDepth") String maxDepth);
|
@Param("maxDepth") String maxDepth);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据库位ID集合查询
|
||||||
|
*
|
||||||
|
* @param pointIds 库位ID集合
|
||||||
|
* @return List<Inventory>
|
||||||
|
*/
|
||||||
|
List<Inventory> queryByPointIds(@Param("pointIds") List<Long> pointIds);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,4 +46,13 @@
|
||||||
</choose>
|
</choose>
|
||||||
ORDER BY create_time
|
ORDER BY create_time
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="queryByPointIds" resultType="org.cpte.modules.inventory.entity.Inventory">
|
||||||
|
SELECT * FROM data_inventory
|
||||||
|
WHERE quantity > 0
|
||||||
|
AND point_id IN
|
||||||
|
<foreach collection="pointIds" item="pointId" open="(" separator="," close=")">
|
||||||
|
#{pointId}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -23,11 +23,10 @@ public interface IInventoryService extends IService<Inventory> {
|
||||||
* @param stockId 容器
|
* @param stockId 容器
|
||||||
* @param receivedQty 收货数量
|
* @param receivedQty 收货数量
|
||||||
* @param asn 入库单
|
* @param asn 入库单
|
||||||
* @param asnDetail 入库明细
|
|
||||||
* @param receiveRecord 入库记录
|
* @param receiveRecord 入库记录
|
||||||
* @return Inventory
|
* @return Inventory
|
||||||
*/
|
*/
|
||||||
Inventory createInventory(Long stockId, BigDecimal receivedQty, Asn asn, AsnDetail asnDetail, ReceiveRecord receiveRecord);
|
Inventory createInventory(Long stockId, BigDecimal receivedQty, Asn asn, ReceiveRecord receiveRecord);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据库存ID查询库存
|
* 根据库存ID查询库存
|
||||||
|
|
|
||||||
|
|
@ -37,24 +37,26 @@ public class InventoryServiceImpl extends ServiceImpl<InventoryMapper, Inventory
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Inventory createInventory(Long stockId, BigDecimal receivedQty, Asn asn, AsnDetail asnDetail, ReceiveRecord receiveRecord) {
|
public Inventory createInventory(Long stockId, BigDecimal receivedQty, Asn asn, ReceiveRecord receiveRecord) {
|
||||||
Inventory inventory = Inventory.builder()
|
Inventory inventory = Inventory.builder()
|
||||||
.itemId(asnDetail.getItemId())
|
.itemId(receiveRecord.getItemId())
|
||||||
.pointId(receiveRecord.getToPointId())
|
.pointId(receiveRecord.getToPointId())
|
||||||
.stockId(asnDetail.getStockId())
|
.stockId(receiveRecord.getStockId())
|
||||||
.quantity(receivedQty)
|
.quantity(receivedQty)
|
||||||
.queuedQty(BigDecimal.ZERO)
|
.queuedQty(BigDecimal.ZERO)
|
||||||
.receiveRecordId(receiveRecord.getId())
|
.receiveRecordId(receiveRecord.getId())
|
||||||
|
.project(receiveRecord.getProject())
|
||||||
|
.taskNo(receiveRecord.getTaskNo())
|
||||||
.whCode(asn.getWhCode())
|
.whCode(asn.getWhCode())
|
||||||
.propC1(asnDetail.getPropC1())
|
.propC1(receiveRecord.getPropC1())
|
||||||
.propC2(asnDetail.getPropC2())
|
.propC2(receiveRecord.getPropC2())
|
||||||
.propC3(asnDetail.getPropC3())
|
.propC3(receiveRecord.getPropC3())
|
||||||
.status(InventoryStatusEnum.AVAILABLE.getValue())
|
.status(InventoryStatusEnum.AVAILABLE.getValue())
|
||||||
.propD1(asnDetail.getPropD1())
|
.propD1(receiveRecord.getPropD1())
|
||||||
.description(asnDetail.getDescription())
|
.description(receiveRecord.getDescription())
|
||||||
.tenantId(asnDetail.getTenantId())
|
.tenantId(receiveRecord.getTenantId())
|
||||||
.sysOrgCode(asnDetail.getSysOrgCode())
|
.sysOrgCode(receiveRecord.getSysOrgCode())
|
||||||
.createBy(asnDetail.getCreateBy())
|
.createBy(receiveRecord.getCreateBy())
|
||||||
.createTime(new Date())
|
.createTime(new Date())
|
||||||
.build();
|
.build();
|
||||||
return this.save(inventory) ? inventory : null;
|
return this.save(inventory) ? inventory : null;
|
||||||
|
|
|
||||||
|
|
@ -97,12 +97,38 @@ public class InventoryLog implements Serializable {
|
||||||
@Schema(description = "容器ID")
|
@Schema(description = "容器ID")
|
||||||
@Dict(dictTable = "base_stock", dicCode = "id", dicText = "stock_code")
|
@Dict(dictTable = "base_stock", dicCode = "id", dicText = "stock_code")
|
||||||
private java.lang.Long stockId;
|
private java.lang.Long stockId;
|
||||||
|
/**
|
||||||
|
* 外部仓库
|
||||||
|
*/
|
||||||
|
@Excel(name = "外部仓库", width = 15)
|
||||||
|
@Schema(description = "外部仓库")
|
||||||
|
private java.lang.String whCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目号
|
||||||
|
*/
|
||||||
|
@Schema(description = "项目号")
|
||||||
|
private java.lang.String project;
|
||||||
|
/**
|
||||||
|
* 任务号
|
||||||
|
*/
|
||||||
|
@Schema(description = "任务号")
|
||||||
|
private java.lang.String taskNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批次号
|
* 批次号
|
||||||
*/
|
*/
|
||||||
@Excel(name = "批次号", width = 15)
|
@Excel(name = "批次号", width = 15)
|
||||||
@Schema(description = "批次号")
|
@Schema(description = "批次号")
|
||||||
private java.lang.String propC1;
|
private java.lang.String propC1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部库存状态
|
||||||
|
*/
|
||||||
|
@Excel(name = "外部库存状态", width = 15)
|
||||||
|
@Schema(description = "外部库存状态")
|
||||||
|
private java.lang.String propC3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 变动数量
|
* 变动数量
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,10 @@ public class InventoryLogServiceImpl extends ServiceImpl<InventoryLogMapper, Inv
|
||||||
.stockId(inventory.getStockId())
|
.stockId(inventory.getStockId())
|
||||||
.businessNo(businessNo)
|
.businessNo(businessNo)
|
||||||
.businessDetailId(businessDetailId)
|
.businessDetailId(businessDetailId)
|
||||||
|
.project(inventory.getProject())
|
||||||
|
.taskNo(inventory.getTaskNo())
|
||||||
.propC1(inventory.getPropC1())
|
.propC1(inventory.getPropC1())
|
||||||
|
.propC3(inventory.getPropC3())
|
||||||
.description(description)
|
.description(description)
|
||||||
//计算变动前后数量: 变动前数量 = 库存数量 - 变动数量
|
//计算变动前后数量: 变动前数量 = 库存数量 - 变动数量
|
||||||
.beforeQty(BigDecimalUtil.subtract(inventory.getQuantity(), changeQty, 0))
|
.beforeQty(BigDecimalUtil.subtract(inventory.getQuantity(), changeQty, 0))
|
||||||
|
|
|
||||||
|
|
@ -91,18 +91,7 @@ public class AsnDetail implements Serializable {
|
||||||
@Excel(name = "单位", width = 15)
|
@Excel(name = "单位", width = 15)
|
||||||
@Schema(description = "单位")
|
@Schema(description = "单位")
|
||||||
private java.lang.String unit;
|
private java.lang.String unit;
|
||||||
/**
|
|
||||||
* 项目号
|
|
||||||
*/
|
|
||||||
@Excel(name = "项目号", width = 15)
|
|
||||||
@Schema(description = "项目号")
|
|
||||||
private java.lang.String project;
|
|
||||||
/**
|
|
||||||
* 任务号
|
|
||||||
*/
|
|
||||||
@Excel(name = "任务号", width = 15)
|
|
||||||
@Schema(description = "任务号")
|
|
||||||
private java.lang.String taskNo;
|
|
||||||
/**
|
/**
|
||||||
* 需求数量
|
* 需求数量
|
||||||
*/
|
*/
|
||||||
|
|
@ -123,6 +112,18 @@ public class AsnDetail implements Serializable {
|
||||||
@Schema(description = "状态")
|
@Schema(description = "状态")
|
||||||
@Dict(dicCode = "asn_status")
|
@Dict(dicCode = "asn_status")
|
||||||
private java.lang.Integer status;
|
private java.lang.Integer status;
|
||||||
|
/**
|
||||||
|
* 项目号
|
||||||
|
*/
|
||||||
|
@Excel(name = "项目号", width = 15)
|
||||||
|
@Schema(description = "项目号")
|
||||||
|
private java.lang.String project;
|
||||||
|
/**
|
||||||
|
* 任务号
|
||||||
|
*/
|
||||||
|
@Excel(name = "任务号", width = 15)
|
||||||
|
@Schema(description = "任务号")
|
||||||
|
private java.lang.String taskNo;
|
||||||
/**
|
/**
|
||||||
* 批次号
|
* 批次号
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
@ -68,21 +69,41 @@ public class ReceiveRecord implements Serializable {
|
||||||
*/
|
*/
|
||||||
@Schema(description = "收货数量")
|
@Schema(description = "收货数量")
|
||||||
private java.math.BigDecimal receivedQty;
|
private java.math.BigDecimal receivedQty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部仓库
|
||||||
|
*/
|
||||||
|
@Schema(description = "外部仓库")
|
||||||
|
private java.lang.String whCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目号
|
||||||
|
*/
|
||||||
|
@Schema(description = "项目号")
|
||||||
|
private java.lang.String project;
|
||||||
|
/**
|
||||||
|
* 任务号
|
||||||
|
*/
|
||||||
|
@Schema(description = "任务号")
|
||||||
|
private java.lang.String taskNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批次号
|
* 批次号
|
||||||
*/
|
*/
|
||||||
@Schema(description = "批次号")
|
@Schema(description = "批次号")
|
||||||
private java.lang.String propC1;
|
private java.lang.String propC1;
|
||||||
/**
|
|
||||||
* 序列号
|
|
||||||
*/
|
|
||||||
@Schema(description = "序列号")
|
|
||||||
private java.lang.String propC2;
|
|
||||||
/**
|
/**
|
||||||
* 外部库存状态
|
* 外部库存状态
|
||||||
*/
|
*/
|
||||||
@Schema(description = "外部库存状态")
|
@Schema(description = "外部库存状态")
|
||||||
private java.lang.String propC3;
|
private java.lang.String propC3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列号
|
||||||
|
*/
|
||||||
|
@Schema(description = "序列号")
|
||||||
|
private java.lang.String propC2;
|
||||||
/**
|
/**
|
||||||
* 生产日期
|
* 生产日期
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public interface AsnDetailMapper extends BaseMapper<AsnDetail> {
|
||||||
* @return AsnDetail
|
* @return AsnDetail
|
||||||
*/
|
*/
|
||||||
@Select("select * from data_asn_detail where stock_id = #{stockId} and status = #{status} for update")
|
@Select("select * from data_asn_detail where stock_id = #{stockId} and status = #{status} for update")
|
||||||
AsnDetail queryByStockCode(@Param("stockId") Long stockId, @Param("status") Integer status);
|
List<AsnDetail> queryByStockCode(@Param("stockId") Long stockId, @Param("status") Integer status);
|
||||||
|
|
||||||
@Select("select MAX(line_no) from data_asn_detail where asn_id = #{asnId} ")
|
@Select("select MAX(line_no) from data_asn_detail where asn_id = #{asnId} ")
|
||||||
Integer queryMaxLineNoByAsnId(@Param("asnId") Long asnId);
|
Integer queryMaxLineNoByAsnId(@Param("asnId") Long asnId);
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,10 @@ public interface IAsnService extends IService<Asn> {
|
||||||
/**
|
/**
|
||||||
* 收货操作
|
* 收货操作
|
||||||
*
|
*
|
||||||
* @param asnDetailId 入库明细ID
|
* @param asnId 入库单ID
|
||||||
* @param pointCode 目标库位
|
* @param pointCode 目标库位
|
||||||
*/
|
*/
|
||||||
void receiveGoods(Long asnDetailId, String pointCode);
|
void receiveGoods(Long asnId, String pointCode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 入库任务回传
|
* 入库任务回传
|
||||||
|
|
|
||||||
|
|
@ -93,10 +93,6 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
||||||
throw new RuntimeException("请新增入库明细");
|
throw new RuntimeException("请新增入库明细");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asnDetailList.size() > 1) {
|
|
||||||
throw new RuntimeException("入库明细只允许新增一条");
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomicInteger lineNoCounter = new AtomicInteger(1);
|
AtomicInteger lineNoCounter = new AtomicInteger(1);
|
||||||
for (AsnDetail entity : asnDetailList) {
|
for (AsnDetail entity : asnDetailList) {
|
||||||
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
|
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
|
||||||
|
|
@ -207,57 +203,65 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void receiveGoods(Long asnDetailId, String pointCode) {
|
public void receiveGoods(Long asnId, String pointCode) {
|
||||||
//入库明细任务
|
//入库任务
|
||||||
AsnDetail asnDetail = asnDetailMapper.selectById(asnDetailId);
|
Asn asn = asnMapper.selectById(asnId);
|
||||||
if (asnDetail == null) {
|
if (asn == null) {
|
||||||
throw new RuntimeException("未匹配到入库任务【" + asnDetailId + "】");
|
throw new RuntimeException("未匹配到入库任务【" + asnId + "】");
|
||||||
}
|
}
|
||||||
|
if (asn.getStatus() != 1) {
|
||||||
|
throw new RuntimeException("入库任务【" + asnId + "】已收货");
|
||||||
|
}
|
||||||
|
List<AsnDetail> asnDetails = asnDetailMapper.selectByMainId(asnId);
|
||||||
//验证容器是否入库
|
//验证容器是否入库
|
||||||
if (inventoryMapper.queryByStockId(asnDetail.getStockId()) != null) {
|
Stock stock = stockMapper.selectById(asnDetails.get(0).getStockId());
|
||||||
throw new RuntimeException("【" + asnDetail.getStockId() + "】容器已入库");
|
if (inventoryMapper.queryByStockId(stock.getId()) != null) {
|
||||||
|
throw new RuntimeException("【" + stock.getStockCode() + "】容器已入库");
|
||||||
}
|
}
|
||||||
|
|
||||||
//入库单
|
|
||||||
Asn asn = this.getById(asnDetail.getAsnId());
|
|
||||||
|
|
||||||
//实际的存储位置
|
//实际的存储位置
|
||||||
Point dstPoint = pointMapper.queryByPointCode(pointCode);
|
Point dstPoint = pointMapper.queryByPointCode(pointCode);
|
||||||
|
|
||||||
//容器
|
|
||||||
Stock stock = stockMapper.selectById(asnDetail.getStockId());
|
|
||||||
|
|
||||||
//更新收货数量
|
//更新收货数量
|
||||||
BigDecimal receivedQty = BigDecimalUtil.add(asnDetail.getReceivedQty(), asnDetail.getOrderQty(), 0);
|
for (AsnDetail ad : asnDetails) {
|
||||||
asnDetail.setReceivedQty(receivedQty);
|
//已收货直接跳过
|
||||||
|
if (AsnStatusEnum.RECEIVED.getValue().equals(ad.getStatus())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal receivedQty = BigDecimalUtil.add(ad.getReceivedQty(), ad.getOrderQty(), 0);
|
||||||
|
ad.setReceivedQty(receivedQty);
|
||||||
|
|
||||||
|
//更新明细状态
|
||||||
|
if (receivedQty.compareTo(ad.getOrderQty()) >= 0) {
|
||||||
|
ad.setStatus(AsnStatusEnum.RECEIVED.getValue());
|
||||||
|
} else {
|
||||||
|
ad.setStatus(AsnStatusEnum.RECEIVING.getValue());
|
||||||
|
}
|
||||||
|
asnDetailMapper.updateById(ad);
|
||||||
|
|
||||||
|
//生成入库记录
|
||||||
|
ReceiveRecord receiveRecord = createReceiveRecord(ad, receivedQty, dstPoint.getId());
|
||||||
|
|
||||||
|
// 生成库存
|
||||||
|
Inventory inventory = iInventoryService.createInventory(stock.getId(), receivedQty, asn, receiveRecord);
|
||||||
|
|
||||||
|
//添加库存日志
|
||||||
|
iInventoryLogService.addInboundInventoryLog(inventory, ad.getToPointId(), receivedQty, asn.getOrderNo(), ad.getId(), ad.getDescription());
|
||||||
|
|
||||||
//更新明细状态
|
|
||||||
if (receivedQty.compareTo(asnDetail.getOrderQty()) >= 0) {
|
|
||||||
asnDetail.setStatus(AsnStatusEnum.RECEIVED.getValue());
|
|
||||||
} else {
|
|
||||||
asnDetail.setStatus(AsnStatusEnum.RECEIVING.getValue());
|
|
||||||
}
|
}
|
||||||
asnDetailMapper.updateById(asnDetail);
|
|
||||||
|
|
||||||
//生成入库记录
|
|
||||||
ReceiveRecord receiveRecord = createReceiveRecord(asnDetail, receivedQty, dstPoint.getId());
|
|
||||||
|
|
||||||
// 生成库存
|
|
||||||
Inventory inventory = iInventoryService.createInventory(stock.getId(), receivedQty, asn, asnDetail, receiveRecord);
|
|
||||||
|
|
||||||
//更新入库单
|
//更新入库单
|
||||||
refreshAsn(asn, asnDetailMapper.selectByMainId(asn.getId()));
|
refreshAsn(asn, asnDetails);
|
||||||
|
|
||||||
//更新容器状态和位置
|
//更新容器状态和位置
|
||||||
iStockService.bindStock(stock, dstPoint);
|
iStockService.bindStock(stock, dstPoint);
|
||||||
iPointService.bindPoint(dstPoint);
|
iPointService.bindPoint(dstPoint);
|
||||||
|
|
||||||
//添加库存日志
|
|
||||||
iInventoryLogService.addInboundInventoryLog(inventory, asnDetail.getToPointId(), receivedQty, asn.getOrderNo(), asnDetail.getId(), asnDetail.getDescription());
|
|
||||||
|
|
||||||
//回传
|
//回传
|
||||||
receiveCallback(asn, asnDetail, stock);
|
// receiveCallback(asn, asnDetail, stock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -366,6 +370,8 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
||||||
.toPointId(dstPointId)
|
.toPointId(dstPointId)
|
||||||
.itemId(asnDetail.getItemId())
|
.itemId(asnDetail.getItemId())
|
||||||
.receivedQty(receivedQty)
|
.receivedQty(receivedQty)
|
||||||
|
.project(asnDetail.getProject())
|
||||||
|
.taskNo(asnDetail.getTaskNo())
|
||||||
.propC1(asnDetail.getPropC1())
|
.propC1(asnDetail.getPropC1())
|
||||||
.propC2(asnDetail.getPropC2())
|
.propC2(asnDetail.getPropC2())
|
||||||
.propC3(asnDetail.getPropC3())
|
.propC3(asnDetail.getPropC3())
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,9 @@ public class ISaiWmsServiceImpl implements ISaiWmsService {
|
||||||
if (inboundRequest.getType() == null) {
|
if (inboundRequest.getType() == null) {
|
||||||
throw new RuntimeException("任务类型(Type)必填");
|
throw new RuntimeException("任务类型(Type)必填");
|
||||||
}
|
}
|
||||||
if (inboundRequest.getType().equals(0)) {
|
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(inboundRequest.getType())) {
|
||||||
if (StringUtils.isBlank(inboundRequest.getLocationFrom())) {
|
if (StringUtils.isBlank(inboundRequest.getLocationFrom())) {
|
||||||
throw new RuntimeException("成品入库,起点(LocationFrom)必填");
|
throw new RuntimeException("起点(LocationFrom)必填");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +120,18 @@ public class ISaiWmsServiceImpl implements ISaiWmsService {
|
||||||
throw new RuntimeException("托盘号(Lpn)必填");
|
throw new RuntimeException("托盘号(Lpn)必填");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//验证明细中托盘只能是同一个,如果明细中托盘有不一样的则提示
|
||||||
|
Set<String> lpns = inboundRequest.getDetails().stream().map(InboundRequest.InboundDetail::getLpn).collect(Collectors.toSet());
|
||||||
|
if (lpns.size() > 1) {
|
||||||
|
throw new RuntimeException("明细中托盘只能是同一个");
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证明细中物料只能是同一种,如果明细中物料有不一样的则提示
|
||||||
|
Set<String> itemCodes = inboundRequest.getDetails().stream().map(InboundRequest.InboundDetail::getItem).collect(Collectors.toSet());
|
||||||
|
if (itemCodes.size() > 1) {
|
||||||
|
throw new RuntimeException("明细中物料只能是同一种");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -136,16 +148,30 @@ public class ISaiWmsServiceImpl implements ISaiWmsService {
|
||||||
throw new RuntimeException("【" + no + "】任务号已接收,请勿重复下发");
|
throw new RuntimeException("【" + no + "】任务号已接收,请勿重复下发");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取唯一的明细
|
// 获取明细
|
||||||
InboundRequest.InboundDetail detail = inboundRequest.getDetails().get(0);
|
List<InboundRequest.InboundDetail> detail = inboundRequest.getDetails();
|
||||||
|
|
||||||
// 验证基础数据
|
//获取明细中所有的物料
|
||||||
String srcPointCode = inboundRequest.getLocationFrom();
|
List<String> itemCodes = detail.stream().map(InboundRequest.InboundDetail::getItem).toList();
|
||||||
String itemCode = detail.getItem();
|
|
||||||
String stockCode = detail.getLpn();
|
|
||||||
|
|
||||||
Point srcPoint = iPointService.validatePoint(srcPointCode);
|
//获取存在的物料
|
||||||
Item item = itemService.validateItem(itemCode);
|
Map<String, Item> itemMap = itemService.queryByItemCodesToMap(itemCodes);
|
||||||
|
|
||||||
|
//获取数据库不存在的物料集合且去重
|
||||||
|
List<String> notExistItemCodes = itemCodes.stream().filter(itemCode -> !itemMap.containsKey(itemCode)).distinct().toList();
|
||||||
|
if (CollectionUtils.isNotEmpty(notExistItemCodes)) {
|
||||||
|
throw new RuntimeException("【" + notExistItemCodes + "】物料不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
//起点
|
||||||
|
Point srcPoint = null;
|
||||||
|
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(inboundRequest.getType())) {
|
||||||
|
String srcPointCode = inboundRequest.getLocationFrom();
|
||||||
|
srcPoint = iPointService.validatePoint(srcPointCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//托盘
|
||||||
|
String stockCode = detail.get(0).getLpn();
|
||||||
Stock stock = iStockService.validateStock(stockCode);
|
Stock stock = iStockService.validateStock(stockCode);
|
||||||
|
|
||||||
//获取输送线工作台点位,均衡分配点位任务-轮询方式
|
//获取输送线工作台点位,均衡分配点位任务-轮询方式
|
||||||
|
|
@ -153,10 +179,15 @@ public class ISaiWmsServiceImpl implements ISaiWmsService {
|
||||||
|
|
||||||
// 创建入库单和明细
|
// 创建入库单和明细
|
||||||
Asn createAsn = buildAsn(inboundRequest);
|
Asn createAsn = buildAsn(inboundRequest);
|
||||||
AsnDetail asnDetail = buildAsnDetail(detail, srcPoint, dstPoint, item, stock);
|
List<AsnDetail> createAsnDetails = new ArrayList<>();
|
||||||
|
for (InboundRequest.InboundDetail inboundDetail : inboundRequest.getDetails()) {
|
||||||
|
Item item = itemMap.get(inboundDetail.getItem());
|
||||||
|
AsnDetail asnDetail = buildAsnDetail(inboundDetail, srcPoint, dstPoint, item, stock);
|
||||||
|
createAsnDetails.add(asnDetail);
|
||||||
|
}
|
||||||
|
|
||||||
// 保存入库单和入库明细
|
// 保存入库单和入库明细
|
||||||
asnService.saveMain(createAsn, Collections.singletonList(asnDetail));
|
asnService.saveMain(createAsn, createAsnDetails);
|
||||||
|
|
||||||
//绑定容器和起点
|
//绑定容器和起点
|
||||||
iStockService.bindStock(stock, srcPoint);
|
iStockService.bindStock(stock, srcPoint);
|
||||||
|
|
@ -164,7 +195,8 @@ public class ISaiWmsServiceImpl implements ISaiWmsService {
|
||||||
//成品入库需要生成AGV
|
//成品入库需要生成AGV
|
||||||
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(createAsn.getOrderType())) {
|
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(createAsn.getOrderType())) {
|
||||||
//创建AGV任务
|
//创建AGV任务
|
||||||
iAgvTaskService.createAgvTask(asnDetail.getId(), stock.getStockCode(), srcPoint.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.HIK.getValue());
|
String srcPointCode = srcPoint == null ? null : srcPoint.getPointCode();
|
||||||
|
iAgvTaskService.createAgvTask(createAsn.getId(), stock.getStockCode(), srcPointCode, dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.HIK.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,7 +352,7 @@ public class ISaiWmsServiceImpl implements ISaiWmsService {
|
||||||
.orderQty(BigDecimal.valueOf(detail.getQty()))
|
.orderQty(BigDecimal.valueOf(detail.getQty()))
|
||||||
.receivedQty(BigDecimal.ZERO)
|
.receivedQty(BigDecimal.ZERO)
|
||||||
.stockId(stock.getId())
|
.stockId(stock.getId())
|
||||||
.fromPointId(srcPoint.getId())
|
.fromPointId(srcPoint == null ? null : srcPoint.getId())
|
||||||
.toPointId(dstPoint.getId())
|
.toPointId(dstPoint.getId())
|
||||||
.status(AsnStatusEnum.CREATED.getValue())
|
.status(AsnStatusEnum.CREATED.getValue())
|
||||||
.project(detail.getProject())
|
.project(detail.getProject())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package org.cpte.modules.serialNumber;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.cpte.modules.utils.CodeGeneratorUtil;
|
||||||
|
import org.jeecg.common.handler.IFillRuleHandler;
|
||||||
|
import org.jeecg.modules.system.mapper.SysFillRuleMapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class MoveSerialNumberRule implements IFillRuleHandler {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CodeGeneratorUtil codeGeneratorUtil;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SysFillRuleMapper sysFillRuleMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object execute(JSONObject params, JSONObject formData) {
|
||||||
|
String prefix = params.getString("code");
|
||||||
|
String code = codeGeneratorUtil.generateSerialNumber(prefix);
|
||||||
|
log.info("生成业务编号:{}", code);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateSerialNumber(String ruleCode) {
|
||||||
|
String ruleParams = sysFillRuleMapper.queryByRuleCode(ruleCode);
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(ruleParams);
|
||||||
|
String prefix = null;
|
||||||
|
if (jsonObject != null) {
|
||||||
|
prefix = jsonObject.getString("code");
|
||||||
|
} else {
|
||||||
|
prefix = "MK";
|
||||||
|
}
|
||||||
|
return codeGeneratorUtil.generateSerialNumber(prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,11 +10,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.cpte.modules.constant.GeneralConstant;
|
import org.cpte.modules.constant.GeneralConstant;
|
||||||
import org.cpte.modules.serialNumber.PickSerialNumberRule;
|
import org.cpte.modules.serialNumber.PickSerialNumberRule;
|
||||||
import org.cpte.modules.shipping.entity.Task;
|
|
||||||
import org.cpte.modules.shipping.mapper.PickMapper;
|
|
||||||
import org.cpte.modules.shipping.mapper.TaskMapper;
|
|
||||||
import org.cpte.modules.shipping.service.ITaskService;
|
|
||||||
import org.jeecg.config.shiro.IgnoreAuth;
|
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
||||||
import org.jeecgframework.poi.excel.entity.ExportParams;
|
import org.jeecgframework.poi.excel.entity.ExportParams;
|
||||||
|
|
|
||||||
|
|
@ -57,4 +57,12 @@ public interface ITaskService extends IService<Task> {
|
||||||
*/
|
*/
|
||||||
void generateAgvTask();
|
void generateAgvTask();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据需要移位的库位生成Task任务
|
||||||
|
*
|
||||||
|
* @param movePointIds 库位
|
||||||
|
* @return Task
|
||||||
|
*/
|
||||||
|
List<Task> bulidMoveTask(List<Long> movePointIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.apache.shiro.lang.util.StringUtils;
|
|
||||||
import org.cpte.modules.constant.GeneralConstant;
|
import org.cpte.modules.constant.GeneralConstant;
|
||||||
import org.cpte.modules.base.entity.Item;
|
import org.cpte.modules.base.entity.Item;
|
||||||
import org.cpte.modules.base.entity.Point;
|
import org.cpte.modules.base.entity.Point;
|
||||||
|
|
@ -14,7 +14,6 @@ import org.cpte.modules.base.service.IItemService;
|
||||||
import org.cpte.modules.base.service.IPointService;
|
import org.cpte.modules.base.service.IPointService;
|
||||||
import org.cpte.modules.base.service.IStockService;
|
import org.cpte.modules.base.service.IStockService;
|
||||||
import org.cpte.modules.constant.enums.*;
|
import org.cpte.modules.constant.enums.*;
|
||||||
import org.cpte.modules.conveyorLine.vo.PointScore;
|
|
||||||
import org.cpte.modules.inventory.entity.Inventory;
|
import org.cpte.modules.inventory.entity.Inventory;
|
||||||
import org.cpte.modules.inventory.mapper.InventoryMapper;
|
import org.cpte.modules.inventory.mapper.InventoryMapper;
|
||||||
import org.cpte.modules.inventory.service.IInventoryService;
|
import org.cpte.modules.inventory.service.IInventoryService;
|
||||||
|
|
@ -86,6 +85,7 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
@Autowired
|
@Autowired
|
||||||
private BatchUtil batchUtils;
|
private BatchUtil batchUtils;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取出库单Map
|
* 获取出库单Map
|
||||||
*
|
*
|
||||||
|
|
@ -315,9 +315,9 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
Map<Long, Item> itemMap = iItemService.queryByItemIdsToMap(itemIds);
|
Map<Long, Item> itemMap = iItemService.queryByItemIdsToMap(itemIds);
|
||||||
|
|
||||||
//筛选查询库存的条件(非空去重)批次、外部库存状态 、外部仓库
|
//筛选查询库存的条件(非空去重)批次、外部库存状态 、外部仓库
|
||||||
List<String> propC1List = pickDetails.stream().map(PickDetail::getPropC1).filter(StringUtils::hasText).distinct().toList();
|
List<String> propC1List = pickDetails.stream().map(PickDetail::getPropC1).filter(StringUtils::isNotBlank).distinct().toList();
|
||||||
List<String> propC3List = pickDetails.stream().map(PickDetail::getPropC3).filter(StringUtils::hasText).distinct().toList();
|
List<String> propC3List = pickDetails.stream().map(PickDetail::getPropC3).filter(StringUtils::isNotBlank).distinct().toList();
|
||||||
List<String> whCodeList = pickMap.values().stream().map(Pick::getWhCode).filter(StringUtils::hasText).distinct().toList();
|
List<String> whCodeList = pickMap.values().stream().map(Pick::getWhCode).filter(StringUtils::isNotBlank).distinct().toList();
|
||||||
|
|
||||||
//查询库存
|
//查询库存
|
||||||
List<Inventory> inventories = inventoryMapper.queryInventory(itemIds, propC1List, propC3List, whCodeList);
|
List<Inventory> inventories = inventoryMapper.queryInventory(itemIds, propC1List, propC3List, whCodeList);
|
||||||
|
|
@ -376,7 +376,7 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//智能排序,优先分配移位最小的库位
|
//智能排序,优先分配距离近、移位最少的库位
|
||||||
List<InventoryScore> scoredInventory = scoreInventories(matchedInventories);
|
List<InventoryScore> scoredInventory = scoreInventories(matchedInventories);
|
||||||
|
|
||||||
for (InventoryScore inventoryScore : scoredInventory) {
|
for (InventoryScore inventoryScore : scoredInventory) {
|
||||||
|
|
@ -416,9 +416,8 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
|
|
||||||
//移位任务
|
//移位任务
|
||||||
if (CollectionUtils.isNotEmpty(inventoryScore.getMovePoints())) {
|
if (CollectionUtils.isNotEmpty(inventoryScore.getMovePoints())) {
|
||||||
for (Point movePoint : inventoryScore.getMovePoints()) {
|
List<Long> movePointIds = inventoryScore.getMovePoints().stream().map(Point::getId).toList();
|
||||||
log.info("生成移位任务:原库位:{}", movePoint.getPointCode());
|
createToTask.addAll(iTaskService.bulidMoveTask(movePointIds));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.info("无移位任务");
|
log.info("无移位任务");
|
||||||
}
|
}
|
||||||
|
|
@ -486,7 +485,7 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
colLayerPointsMap.put(key, points);
|
colLayerPointsMap.put(key, points);
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取所以出库口的库位
|
//获取出库口的库位
|
||||||
List<Point> outPoints = iPointService.queryPoints(null, null, AreaTypeEnum.CK_DOCK.getValue());
|
List<Point> outPoints = iPointService.queryPoints(null, null, AreaTypeEnum.CK_DOCK.getValue());
|
||||||
|
|
||||||
//获取优化后的库存
|
//获取优化后的库存
|
||||||
|
|
@ -497,7 +496,10 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
List<Point> points = colLayerPointsMap.get(key);
|
List<Point> points = colLayerPointsMap.get(key);
|
||||||
return calculateMoveCount(inventory, currPoint, points, outPoints);
|
return calculateMoveCount(inventory, currPoint, points, outPoints);
|
||||||
})
|
})
|
||||||
.sorted(Comparator.comparing(InventoryScore::getScore).reversed())
|
//按分数倒序排序、移动次数升序排序
|
||||||
|
.sorted(Comparator.comparing(InventoryScore::getScore).reversed()
|
||||||
|
.thenComparing(score -> score.getMovePoints().size())
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -511,12 +513,14 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
* @return 库位位移次数
|
* @return 库位位移次数
|
||||||
*/
|
*/
|
||||||
private InventoryScore calculateMoveCount(Inventory inventory, Point currPoint, List<Point> points, List<Point> outPoints) {
|
private InventoryScore calculateMoveCount(Inventory inventory, Point currPoint, List<Point> points, List<Point> outPoints) {
|
||||||
double totalScore = 0.0;
|
// 位移分数
|
||||||
|
double moveScore;
|
||||||
|
//移位库位
|
||||||
|
List<Point> movePoints;
|
||||||
|
|
||||||
// 计算距离分数(权重30%)
|
// 计算距离分数(权重30%)
|
||||||
Point bestPoint = getBestOutboundPoint(currPoint, outPoints);
|
Point bestPoint = getBestOutboundPoint(currPoint, outPoints);
|
||||||
double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint);
|
double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint) * 0.3;
|
||||||
totalScore += distanceScore * 0.3;
|
|
||||||
|
|
||||||
// 目标库位的深度位转换为索引
|
// 目标库位的深度位转换为索引
|
||||||
int targetIndex = Integer.parseInt(currPoint.getRowNum()) - 1;
|
int targetIndex = Integer.parseInt(currPoint.getRowNum()) - 1;
|
||||||
|
|
@ -524,52 +528,46 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
//双通道
|
//双通道
|
||||||
if (currPoint.getIzDoubleLane().equals(1)) {
|
if (currPoint.getIzDoubleLane().equals(1)) {
|
||||||
// 计算左侧占用数
|
// 计算左侧占用数
|
||||||
int leftOccupied = 0;
|
List<Point> leftPoints = calculateUsedPoints(points, 0, targetIndex);
|
||||||
List<Point> leftPoints = new ArrayList<>();
|
|
||||||
for (int i = 0; i < targetIndex; i++) {
|
|
||||||
Point point = points.get(i);
|
|
||||||
if (point != null && point.getStatus().equals(CommonStatusEnum.USED.getValue())) {
|
|
||||||
leftOccupied++;
|
|
||||||
leftPoints.add(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算右侧占用数
|
// 计算右侧占用数
|
||||||
int rightOccupied = 0;
|
List<Point> rightPoints = calculateUsedPoints(points, targetIndex + 1, points.size());
|
||||||
List<Point> rightPoints = new ArrayList<>();
|
|
||||||
for (int i = targetIndex + 1; i < points.size(); i++) {
|
|
||||||
Point point = points.get(i);
|
|
||||||
if (point != null && point.getStatus().equals(CommonStatusEnum.USED.getValue())) {
|
|
||||||
rightOccupied++;
|
|
||||||
rightPoints.add(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//取两个集合中,元素最少的那个集合
|
//取两个集合中,元素最少的那个集合
|
||||||
List<Point> movePoints = leftOccupied < rightOccupied ? leftPoints : rightPoints;
|
movePoints = leftPoints.size() < rightPoints.size() ? leftPoints : rightPoints;
|
||||||
// 取最小值,移位越小分数越高
|
moveScore = (100.0 / (movePoints.size() + 1)) * 0.7;
|
||||||
int minOccupied = Math.min(leftOccupied, rightOccupied);
|
|
||||||
if (minOccupied == 0) {
|
|
||||||
minOccupied = 1; // 设置默认值防止除以0
|
|
||||||
}
|
|
||||||
totalScore += 100.0 / minOccupied * 0.7;
|
|
||||||
return new InventoryScore(inventory, totalScore, bestPoint, movePoints);
|
|
||||||
} else {
|
} else {
|
||||||
// 单通道,计算目标位置左侧的占用数
|
movePoints = calculateUsedPoints(points, 0, targetIndex);
|
||||||
int leftOccupied = 0;
|
moveScore = (100.0 / (movePoints.size() + 1)) * 0.7;
|
||||||
List<Point> movePoints = new ArrayList<>();
|
|
||||||
for (int i = 0; i < targetIndex; i++) {
|
|
||||||
Point point = points.get(i);
|
|
||||||
if (point != null && point.getStatus().equals(CommonStatusEnum.USED.getValue())) {
|
|
||||||
leftOccupied++;
|
|
||||||
movePoints.add(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (leftOccupied == 0) {
|
|
||||||
leftOccupied = 1;
|
|
||||||
}
|
|
||||||
totalScore += 100.0 / leftOccupied * 0.7;
|
|
||||||
return new InventoryScore(inventory, totalScore, bestPoint, movePoints);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//库位得分 = 距离得分 + 移动得分
|
||||||
|
double totalScore = distanceScore + moveScore;
|
||||||
|
|
||||||
|
log.info("【{}】库位距离评分: {}-移位评分: {}-总得分: {}-移位次数: {}",
|
||||||
|
currPoint.getPointCode(), distanceScore, moveScore, totalScore, movePoints.size());
|
||||||
|
|
||||||
|
return new InventoryScore(inventory, totalScore, bestPoint, movePoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巷道库位使用情况
|
||||||
|
*
|
||||||
|
* @param points 当前巷道所有库位
|
||||||
|
* @param start 巷道起始库位
|
||||||
|
* @param end 巷道结束库位
|
||||||
|
* @return List<Point>
|
||||||
|
*/
|
||||||
|
private List<Point> calculateUsedPoints(List<Point> points, int start, int end) {
|
||||||
|
List<Point> usedPoints = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = start; i < end && i < points.size(); i++) {
|
||||||
|
Point point = points.get(i);
|
||||||
|
if (point != null && point.getStatus().equals(CommonStatusEnum.USED.getValue())) {
|
||||||
|
usedPoints.add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return usedPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,15 @@ import org.cpte.modules.agvTask.service.IAgvTaskService;
|
||||||
import org.cpte.modules.base.entity.Item;
|
import org.cpte.modules.base.entity.Item;
|
||||||
import org.cpte.modules.base.entity.Point;
|
import org.cpte.modules.base.entity.Point;
|
||||||
import org.cpte.modules.base.entity.Stock;
|
import org.cpte.modules.base.entity.Stock;
|
||||||
import org.cpte.modules.constant.enums.AgvVendorEnum;
|
import org.cpte.modules.base.mapper.PointMapper;
|
||||||
import org.cpte.modules.constant.enums.BusinessTypeEnum;
|
import org.cpte.modules.base.service.IItemService;
|
||||||
import org.cpte.modules.constant.enums.InventoryStatusEnum;
|
import org.cpte.modules.base.service.IPointService;
|
||||||
|
import org.cpte.modules.base.service.IStockService;
|
||||||
|
import org.cpte.modules.constant.GeneralConstant;
|
||||||
|
import org.cpte.modules.constant.enums.*;
|
||||||
import org.cpte.modules.inventory.entity.Inventory;
|
import org.cpte.modules.inventory.entity.Inventory;
|
||||||
import org.cpte.modules.inventory.mapper.InventoryMapper;
|
import org.cpte.modules.inventory.mapper.InventoryMapper;
|
||||||
|
import org.cpte.modules.serialNumber.MoveSerialNumberRule;
|
||||||
import org.cpte.modules.shipping.entity.Task;
|
import org.cpte.modules.shipping.entity.Task;
|
||||||
import org.cpte.modules.shipping.mapper.TaskMapper;
|
import org.cpte.modules.shipping.mapper.TaskMapper;
|
||||||
import org.cpte.modules.shipping.service.ITaskService;
|
import org.cpte.modules.shipping.service.ITaskService;
|
||||||
|
|
@ -38,18 +42,33 @@ import java.util.stream.Collectors;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements ITaskService {
|
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements ITaskService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PointMapper pointMapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TaskMapper taskMapper;
|
private TaskMapper taskMapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private InventoryMapper inventoryMapper;
|
private InventoryMapper inventoryMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IItemService iItemService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPointService iPointService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IStockService iStockService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IAgvTaskService agvTaskService;
|
private IAgvTaskService agvTaskService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private BatchUtil batchUtils;
|
private BatchUtil batchUtils;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MoveSerialNumberRule moveSerialNumberRule;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Task createTask(String taskNo, Integer taskType, Item item, Point fromPoint, Point toPoint, Stock stock, Long pickId, Long pickDetailId, Long inventoryId, BigDecimal planQty, Integer izAll) {
|
public Task createTask(String taskNo, Integer taskType, Item item, Point fromPoint, Point toPoint, Stock stock, Long pickId, Long pickDetailId, Long inventoryId, BigDecimal planQty, Integer izAll) {
|
||||||
|
|
@ -146,7 +165,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
|
||||||
Integer izAll = allSplit ? 1 : 0;
|
Integer izAll = allSplit ? 1 : 0;
|
||||||
log.info("任务分组:{}", key);
|
log.info("任务分组:{}", key);
|
||||||
if (!groupToAgvTaskMap.containsKey(key)) {
|
if (!groupToAgvTaskMap.containsKey(key)) {
|
||||||
AgvTask agvTask = agvTaskService.bulidAgvTask(null, key.getStockCode(), key.getFromPointCode(), key.getToPointCode(), null, BusinessTypeEnum.OUTBOUND.getValue(),izAll, AgvVendorEnum.TES.getValue());
|
AgvTask agvTask = agvTaskService.bulidAgvTask(null, key.getStockCode(), key.getFromPointCode(), key.getToPointCode(), null, BusinessTypeEnum.OUTBOUND.getValue(), izAll, AgvVendorEnum.TES.getValue());
|
||||||
createToAgvTaskList.add(agvTask);
|
createToAgvTaskList.add(agvTask);
|
||||||
groupToAgvTaskMap.put(key, agvTask); // 建立映射
|
groupToAgvTaskMap.put(key, agvTask); // 建立映射
|
||||||
log.info("创建AGV任务:{}", agvTask);
|
log.info("创建AGV任务:{}", agvTask);
|
||||||
|
|
@ -180,4 +199,48 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Task> bulidMoveTask(List<Long> movePointIds) {
|
||||||
|
List<Task> moveList = new ArrayList<>();
|
||||||
|
List<Inventory> moveInventoryList = inventoryMapper.queryByPointIds(movePointIds);
|
||||||
|
|
||||||
|
//移位物料
|
||||||
|
List<Long> moveItemIds = moveInventoryList.stream().map(Inventory::getItemId).distinct().toList();
|
||||||
|
Map<Long, Item> moveItemMap = iItemService.queryByItemIdsToMap(moveItemIds);
|
||||||
|
|
||||||
|
//移位库位
|
||||||
|
List<Long> fromPointIds = moveInventoryList.stream().map(Inventory::getPointId).distinct().toList();
|
||||||
|
Map<Long, Point> fromPointMap = iPointService.queryByPointIdsToMap(fromPointIds);
|
||||||
|
|
||||||
|
//移位容器
|
||||||
|
List<Long> stockIds = moveInventoryList.stream().map(Inventory::getStockId).distinct().toList();
|
||||||
|
Map<Long, Stock> stockMap = iStockService.queryByStockIdsToMap(stockIds);
|
||||||
|
|
||||||
|
for (Inventory inv : moveInventoryList) {
|
||||||
|
|
||||||
|
//判读改点位是否有出库任务
|
||||||
|
Item moveItem = moveItemMap.get(inv.getItemId());
|
||||||
|
Point fromPoint = fromPointMap.get(inv.getPointId());
|
||||||
|
Stock stock = stockMap.get(inv.getStockId());
|
||||||
|
String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO);
|
||||||
|
//根据算法找到最优的目标库位
|
||||||
|
Point toPoint=null;
|
||||||
|
Task moveTask = this.bulidTask(taskNo, TaskTypeEnum.MOVE.getValue(), moveItem, fromPoint, toPoint, stock, null, null, inv.getId(), inv.getQuantity(), 0);
|
||||||
|
moveList.add(moveTask);
|
||||||
|
log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity());
|
||||||
|
inv.setStatus(InventoryStatusEnum.TRANSFER.getValue());
|
||||||
|
inventoryMapper.updateById(inv);
|
||||||
|
}
|
||||||
|
return moveList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择最优移位目标
|
||||||
|
*/
|
||||||
|
private Point findBestMovePoint(){
|
||||||
|
// 1. 获取所有可用库位
|
||||||
|
//List<Point> availablePoints = pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), areaCode);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,10 +229,10 @@ public class ITesAgvServiceImpl implements ITesAgvService {
|
||||||
*
|
*
|
||||||
* @param agvTask 任务
|
* @param agvTask 任务
|
||||||
*/
|
*/
|
||||||
private void handleEnd(Long asnDetailId, AgvTask agvTask) {
|
private void handleEnd(Long asnId, AgvTask agvTask) {
|
||||||
if (BusinessTypeEnum.INBOUND.getValue().equals(agvTask.getType())) {
|
if (BusinessTypeEnum.INBOUND.getValue().equals(agvTask.getType())) {
|
||||||
//收货
|
//收货
|
||||||
iAsnService.receiveGoods(asnDetailId, agvTask.getEndCode());
|
iAsnService.receiveGoods(asnId, agvTask.getEndCode());
|
||||||
} else if (BusinessTypeEnum.OUTBOUND.getValue().equals(agvTask.getType())) {
|
} else if (BusinessTypeEnum.OUTBOUND.getValue().equals(agvTask.getType())) {
|
||||||
//拣货
|
//拣货
|
||||||
Point endPoint = iPointService.validatePoint(agvTask.getEndCode());
|
Point endPoint = iPointService.validatePoint(agvTask.getEndCode());
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ public class ElevatorMapUtil {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
dataMap = new ConcurrentHashMap<>();
|
dataMap = new ConcurrentHashMap<>();
|
||||||
List<String> CKJBK01 = Arrays.asList("DT001", "DT002");
|
List<String> ST102 = Arrays.asList("DT001", "DT002");
|
||||||
List<String> CKJBK02 = Arrays.asList("DT003", "DT004");
|
List<String> ST104 = Arrays.asList("DT003", "DT004");
|
||||||
// 初始化Map
|
// 初始化Map
|
||||||
dataMap.put("CKJBK01", CKJBK01);
|
dataMap.put("ST102", ST102);
|
||||||
dataMap.put("CKJBK02", CKJBK02);
|
dataMap.put("ST104", ST104);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ package org.cpte.modules.utils;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.HashMap;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
|
||||||
public class test {
|
public class test {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,11 @@ public class SysLog implements Serializable {
|
||||||
*/
|
*/
|
||||||
private String method;
|
private String method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回参数
|
||||||
|
*/
|
||||||
|
private String returnData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作人用户名称
|
* 操作人用户名称
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,9 @@ public class ShardingSysLog implements Serializable {
|
||||||
*/
|
*/
|
||||||
private String logContent;
|
private String logContent;
|
||||||
|
|
||||||
|
/** 返回 */
|
||||||
|
private String returnData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日志类型(1登录日志,2操作日志)
|
* 日志类型(1登录日志,2操作日志)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue