add:增加仓储服务,增加需求单至出库单流程

This commit is contained in:
zhangzq
2026-06-08 08:45:53 +08:00
parent ec9fce406c
commit 854a1714fe
45 changed files with 817 additions and 288 deletions

View File

@@ -1,4 +1,4 @@
package org.nl.common.domain.constantt;
package org.nl.common.domain.constant;
/**
* s

View File

@@ -49,9 +49,9 @@ import java.util.stream.Collectors;
public class GroupController {
@Autowired
private final IMdPbGroupplateService iMdPbGroupplateService;
private IMdPbGroupplateService iMdPbGroupplateService;
@Autowired
private final IMdPbStoragevehicleinfoService iMdPbStoragevehicleinfoService;
private IMdPbStoragevehicleinfoService iMdPbStoragevehicleinfoService;
@Autowired
private final MdPbGroupplateMapper mdPbGroupplateMapper;

View File

@@ -3,6 +3,7 @@ package org.nl.wms.basedata_manage.service.dao;
import lombok.Data;
import org.nl.wms.warehouse_manage.service.dao.GroupPlate;
import java.io.Serializable;
import java.math.BigDecimal;
/*
@@ -10,7 +11,7 @@ import java.math.BigDecimal;
* @Date 2023/5/4 19:49
*/
@Data
public class StructattrVechielDto extends GroupPlate {
public class StructattrVechielDto implements Serializable {
private static final long serialVersionUID = 1L;
/**
@@ -22,6 +23,8 @@ public class StructattrVechielDto extends GroupPlate {
* 仓位编码
*/
private String struct_code;
private String lock_type;
/**
* 库区标识
*/
@@ -31,70 +34,8 @@ public class StructattrVechielDto extends GroupPlate {
*/
private String stor_code;
/**
* 宽度
*/
private Integer w;
/**
* 高度
*/
private Integer h;
/**
* 深度(长度)
*/
private Integer l;
/**
* 承受重量
*/
private Integer weight;
/**
* 排
*/
private Integer row_num;
/**
* 列
*/
private Integer col_num;
/**
* 层
*/
private Integer layer_num;
/**
* 块
*/
private Integer block_num;
/**
* 超限货位关联的货位编号
*/
private String control_code;
/**
* 是否临时仓位
*/
private Boolean is_temp;
/**
* 是否启用
*/
private Boolean is_used;
/**
* 锁定类型
*/
private String lock_type;
/**
* 是否判断高度
*/
private String is_zdepth;
private String group_id;
/**
* 存储载具号
@@ -106,11 +47,29 @@ public class StructattrVechielDto extends GroupPlate {
*/
private String material_code;
/**
* 物料名称
*/
private String material_name;
private String material_id;
private String pcsn;
private BigDecimal qty;
private BigDecimal frozen_qty;
private String qty_unit_name;
private String qty_unit_id;
/**
* 来源单据号
*/
private String ext_code;
/**
* 来源单据类型
*/
private String ext_type;

View File

@@ -4,9 +4,9 @@
<select id="getCanuseIvt" resultType="com.alibaba.fastjson.JSONObject">
SELECT
ext.group_id as storagevehicleext_id,
ext.group_id,
ext.storagevehicle_code,
ext.material_id,
ext.material_code,
material.material_code,
material.material_name,
ext.pcsn,
@@ -318,7 +318,7 @@
ext.pcsn LIKE #{param.pcsn}
</if>
<if test="param.material_id_list != null and param.material_id_list.size() > 0">
AND ext.material_id in
AND ext.material_code in
<foreach collection="param.material_id_list" item="value" index="key" open="(" close=")" separator=",">
#{value}
</foreach>

View File

@@ -8,19 +8,22 @@
gro.create_time,
gro.qty_unit_name,
gro.qty_unit_id,
gro.material_id,
gro.material_code,
gro.pcsn,
gro.group_id,
gro.ext_code,
gro.ext_type,
gro.group_id,
mater.material_code,
gro.storagevehicle_code,
mater.material_id,
mater.material_name,
ivt.*
ivt.struct_code,
ivt.struct_id,
ivt.struct_name,
ivt.sect_code,
ivt.stor_code,
ivt.lock_type
FROM
st_ivt_structattr ivt
LEFT JOIN md_pb_groupplate gro ON ivt.storagevehicle_code = gro.storagevehicle_code
LEFT JOIN md_me_materialbase mater ON mater.material_id = gro.material_id
LEFT JOIN md_me_materialbase mater ON mater.material_code = gro.material_code
<where>
<if test="search != null and search != ''">
and (mater.material_code LIKE '%${search}%'
@@ -29,8 +32,8 @@
<if test="status != null and status != ''">
AND gro.status = #{status}
</if>
<if test="material_id != null and material_id != ''">
AND gro.material_id = #{material_id}
<if test="material_code != null and material_code != ''">
AND gro.material_code = #{material_code}
</if>
<if test="pcsn != null and pcsn != ''">
AND gro.pcsn = #{pcsn}

View File

@@ -1,5 +1,8 @@
package org.nl.wms.ext_manage.enums;
import java.util.Arrays;
import java.util.List;
/**
* @author Liuyx
* @date 2025年06月03日
@@ -26,4 +29,7 @@ public class EXTConstant {
* 中鼎查询库存接口地址
*/
public final static String QUERY_INVENTORY_ZD_API = "/app/restful/api/v3/wms/getInventoryList";
public static final List<String> ZD_STOR_SET = Arrays.asList("6001");
}

View File

@@ -2,6 +2,7 @@ package org.nl.wms.ext_manage.service;
import com.alibaba.fastjson.JSONObject;
import org.nl.wms.ext_manage.service.dto.ZDInventory;
import org.nl.wms.pm_manage.demand.service.dto.PmDemandDto;
import org.springframework.http.ResponseEntity;
import java.util.List;
@@ -18,15 +19,13 @@ public interface WmsToZDWmdService {
/**
* 生产领料需求单下发
* @param whereJson {
* data []
* }
* @return JSONObject {
* status: 200 / !=200
* message 信息
* }
*
* @param demands@return JSONObject {
* status: 200 / !=200
* message 信息
* }
*/
ResponseEntity syncDemandOrder(JSONObject whereJson);
ResponseEntity syncDemandOrder(List<PmDemandDto> demands);
/**
* 采购入库单下发

View File

@@ -126,7 +126,7 @@ public class ErpToWmsServiceImpl implements ErpToWmsService {
}
jsonMst.put("tableData",dtlArr);
// 调用出库单新增服务
iOutBillService.insertDtl(jsonMst);
iOutBillService.saveBill(jsonMst);
log.info("sendTask下发出库任务接口输出参数为-------------------" + ErpResponse.requestOk().toString());
return ErpResponse.requestOk();

View File

@@ -1,6 +1,7 @@
package org.nl.wms.ext_manage.service.impl;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
@@ -9,6 +10,7 @@ import org.nl.config.SpringContextHolder;
import org.nl.wms.ext_manage.enums.EXTConstant;
import org.nl.wms.ext_manage.service.WmsToZDWmdService;
import org.nl.wms.ext_manage.service.dto.ZDInventory;
import org.nl.wms.pm_manage.demand.service.dto.PmDemandDto;
import org.nl.wms.system_manage.enums.SysParamConstant;
import org.nl.wms.system_manage.service.param.dao.Param;
import org.nl.wms.system_manage.service.param.impl.SysParamServiceImpl;
@@ -16,20 +18,20 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
@Slf4j
public class WmsToZDWmdServiceImpl implements WmsToZDWmdService {
@Override
public ResponseEntity syncDemandOrder(JSONObject whereJson) {
log.info("syncDemandOrder生产领料需求单下发输入参数-------------------" + whereJson.toString());
public ResponseEntity syncDemandOrder(List<PmDemandDto> demands) {
log.info("syncDemandOrder生产领料需求单下发输入参数-------------------" + demands.size());
String url = SpringContextHolder.getBean(SysParamServiceImpl.class).findByCode(SysParamConstant.ZD_URL).getValue();
// TODO: add demand order API path to EXTConstant once endpoint is confirmed
try {
String resultMsg = HttpRequest.post(url)
.body(whereJson.toString())
.body(JSONArray.parseArray(JSON.toJSONString(demands)).toJSONString())
.execute().body();
JSONObject result = JSONObject.parseObject(resultMsg);
log.info("syncDemandOrder需求单下发输出参数-------------------" + result.toString());
@@ -58,10 +60,12 @@ public class WmsToZDWmdServiceImpl implements WmsToZDWmdService {
@Override
public ResponseEntity<List<ZDInventory>> queryInventory(String skuCode) {
List<ZDInventory> inventorys = new ArrayList<>();
log.info("queryInventory查询SKU库存输入参数skuCode={}", skuCode);
Param param = SpringContextHolder.getBean(SysParamServiceImpl.class).findByCode(SysParamConstant.ZD_URL);
if (param==null){
throw new BadRequestException("查询中鼎库存失败,接口地址未配置");
return new ResponseEntity<>(inventorys, HttpStatus.OK);
// throw new BadRequestException("查询中鼎库存失败,接口地址未配置");
}
String baseUrl = param.getValue();
String url = baseUrl + EXTConstant.QUERY_INVENTORY_ZD_API;
@@ -83,7 +87,7 @@ public class WmsToZDWmdServiceImpl implements WmsToZDWmdService {
if (respCode == null || respCode != 0) {
throw new BadRequestException("中鼎库存查询失败:" + result.getString("respMsg"));
}
List<ZDInventory> inventorys = result.getJSONArray("data").toJavaList(ZDInventory.class);
inventorys = result.getJSONArray("data").toJavaList(ZDInventory.class);
return new ResponseEntity<>(inventorys, HttpStatus.OK);
} catch (BadRequestException e) {
throw e;

View File

@@ -149,13 +149,6 @@ public class PdaIosOutServiceImpl implements PdaIosOutService {
private PdaPointTask pdaPointTask;
/**
* 入库服务服务
*/
@Autowired
private IInBillService iRawAssistIStorService;
@Override
public PdaResponse getDtl(JSONObject whereJson) {
return PdaResponse.requestParamOk(mdPbStoragevehicleextMapper.getIosDtl(whereJson));

View File

@@ -62,6 +62,7 @@ public class PmDemandController {
return new ResponseEntity<>(pmDemandService.queryInventory(skuCode), HttpStatus.OK);
}
@PostMapping("/allocate")
@Log("库存分配")
@Transactional(rollbackFor = Exception.class)
@@ -73,7 +74,8 @@ public class PmDemandController {
@PostMapping("/push")
@Log("需求单下发")
@Transactional(rollbackFor = Exception.class)
public ResponseEntity<Object> push(@RequestBody PmDemandDto pmDemandDto) {
public ResponseEntity<Object> push(@RequestBody List<PmDemandDto> pmDemandDtos) {
pmDemandService.pushDemand(pmDemandDtos);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -44,5 +44,5 @@ public interface IPmDemandService extends IService<PmDemand> {
* 4。当前
* @param pmDemandDto
*/
void pushDemand(PmDemandDto pmDemandDto);
void pushDemand(List<PmDemandDto> pmDemandDto);
}

View File

@@ -28,7 +28,7 @@ public class PmDemand extends Model<PmDemand> {
private Integer priority;
private Integer status;
private String status;
@TableField("work_order")
private String work_order;

View File

@@ -11,4 +11,5 @@ public class DemandInventryDto {
private BigDecimal qty;
private String houseCode;
private String houseName;
private String unitId;
}

View File

@@ -3,20 +3,21 @@ package org.nl.wms.pm_manage.demand.service.dto;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class PmDemandDto {
public class PmDemandDto implements Serializable {
private String id;
private String creator;
private String createTime;
private Integer priority;
private Integer status;
private String status;
private String workOrder;
private String skuCode;
private String skuName;
private BigDecimal qty;
private Integer qty;
private String unit;
private String targetArea;
private String productionLine;

View File

@@ -35,7 +35,7 @@ public class PmDemandParam {
private Integer priority;
@JsonProperty("Status")
private Integer status;
private String status;
@NotBlank(message = "工单编号不能为空")
@JsonProperty("WorkOrder")

View File

@@ -0,0 +1,18 @@
package org.nl.wms.pm_manage.demand.service.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum DemandStatus {
CREATE("0","生成"),
DIS("01","分配"),
SEND("10","下发"),
RUN("20","执行"),
FINISH("80","完成"),
CANCEL("90","取消"),
;
private String value;
private String desc;
}

View File

@@ -1,12 +1,20 @@
package org.nl.wms.pm_manage.demand.service.impl;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.nl.common.domain.query.PageQuery;
import org.nl.common.exception.BadRequestException;
import org.nl.wms.basedata_manage.service.IMdMeMaterialbaseService;
import org.nl.wms.basedata_manage.service.IMdPbMeasureunitService;
import org.nl.wms.basedata_manage.service.dao.MdMeMaterialbase;
import org.nl.wms.basedata_manage.service.dao.MdPbMeasureunit;
import org.nl.wms.ext_manage.enums.EXTConstant;
import org.nl.wms.ext_manage.service.WmsToZDWmdService;
import org.nl.wms.ext_manage.service.dto.ZDInventory;
import org.nl.wms.pm_manage.demand.service.IPmDemandService;
@@ -16,6 +24,8 @@ import org.nl.wms.pm_manage.demand.service.dto.DemandInventryDto;
import org.nl.wms.pm_manage.demand.service.dto.PmDemandDto;
import org.nl.wms.pm_manage.demand.service.dto.PmDemandParam;
import org.nl.wms.pm_manage.demand.service.dto.PmDemandQuery;
import org.nl.wms.pm_manage.demand.service.enums.DemandStatus;
import org.nl.wms.warehouse_manage.inAndOut.service.IOutBillService;
import org.nl.wms.warehouse_manage.inventory.IStInventoryService;
import org.nl.wms.warehouse_manage.inventory.dto.StInventoryDto;
import org.nl.wms.warehouse_manage.inventory.dto.StInventoryQuery;
@@ -25,7 +35,11 @@ import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.nl.common.domain.query.PageQuery.trimStringFields;
@@ -36,6 +50,12 @@ public class PmDemandServiceImpl extends ServiceImpl<PmDemandMapper, PmDemand> i
private IStInventoryService iStInventoryService;
@Autowired
private WmsToZDWmdService wmsToZDWmdService;
@Autowired
private IOutBillService iOutBillService;
@Autowired
private IMdMeMaterialbaseService iMdMeMaterialbaseService;
@Autowired
private IMdPbMeasureunitService iMdPbMeasureunitService;
@Override
public Page<PmDemandDto> queryPage(PmDemandQuery query, PageQuery pageQuery) {
@@ -115,7 +135,7 @@ public class PmDemandServiceImpl extends ServiceImpl<PmDemandMapper, PmDemand> i
throw new BadRequestException("需求单不存在");
}
demand.setInventory_dis(inventoryDis);
demand.setStatus(1);
demand.setStatus(DemandStatus.DIS.getValue());
this.updateById(demand);
}
@@ -129,7 +149,8 @@ public class PmDemandServiceImpl extends ServiceImpl<PmDemandMapper, PmDemand> i
demandDto.setSkuCode(dto.getMaterialCode());
demandDto.setSkuName(dto.getMaterialName());
demandDto.setQty(dto.getQty());
demandDto.setHouseCode(dto.getStructCode());
demandDto.setHouseCode(dto.getStorCode());
demandDto.setHouseName(dto.getStorName());
demandDto.setHouseName(dto.getStorName());
resultList.add(demandDto);
}
@@ -152,7 +173,74 @@ public class PmDemandServiceImpl extends ServiceImpl<PmDemandMapper, PmDemand> i
@Override
public void pushDemand(PmDemandDto pmDemandDto) {
public void pushDemand(List<PmDemandDto> pmDemandDtos) {
if (CollectionUtils.isEmpty(pmDemandDtos)){
throw new BadRequestException("下推失败,请求数据不能为空");
}
final long count = pmDemandDtos.stream().filter(a -> !a.getStatus().equals("01")).count();
if (count>0){
throw new BadRequestException("下推失败,单据状态不为已分配不能下推");
}
// 一次性分成两组
Map<Boolean, List<PmDemandDto>> partitioned = pmDemandDtos.stream()
.collect(Collectors.partitioningBy(a -> EXTConstant.ZD_STOR_SET
.contains(JSONObject.parseObject(a.getInventoryDis()).getString("horseCode"))));
List<PmDemandDto> zdDemands = partitioned.get(true);
List<PmDemandDto> otherDemands = partitioned.get(false);
if (!CollectionUtils.isEmpty(zdDemands)) {
wmsToZDWmdService.syncDemandOrder(zdDemands);
}
if (!CollectionUtils.isEmpty(otherDemands)) {
JSONObject billParam = convertDemandsToBillParam(otherDemands);
iOutBillService.saveBill(billParam);
this.update(new LambdaUpdateWrapper<PmDemand>()
.set(PmDemand::getStatus,DemandStatus.SEND.getValue())
.in(PmDemand::getId,pmDemandDtos.stream()
.map(PmDemandDto::getId).collect(Collectors.toList())));
}
}
private JSONObject convertDemandsToBillParam(List<PmDemandDto> demands) {
if (CollectionUtils.isEmpty(demands)) {
throw new BadRequestException("需求单数据为空");
}
PmDemandDto firstDemand = demands.get(0);
JSONObject inventoryDis = JSONObject.parseObject(firstDemand.getInventoryDis());
JSONObject billParam = new JSONObject();
billParam.put("stor_code", inventoryDis.getString("horseCode"));
billParam.put("biz_date", DateUtil.today());
billParam.put("bill_type", "010201");
billParam.put("remark", "需求单下推生成");
List<JSONObject> tableData = new ArrayList<>();
//查询物料id;
final List<MdMeMaterialbase> materialbases = iMdMeMaterialbaseService
.list(new LambdaQueryWrapper<MdMeMaterialbase>()
.in(MdMeMaterialbase::getMaterial_code,
demands.stream().map(PmDemandDto::getSkuCode).collect(Collectors.toList()))
.select(MdMeMaterialbase::getQty_unit_id,MdMeMaterialbase::getMaterial_id, MdMeMaterialbase::getMaterial_code));
Map<String, MdMeMaterialbase> codeToIdMap = materialbases.stream()
.collect(Collectors.toMap(
MdMeMaterialbase::getMaterial_code, Function.identity()));
for (PmDemandDto demand : demands) {
JSONObject detailRow = new JSONObject();
detailRow.put("material_code", demand.getSkuCode());
detailRow.put("material_id", codeToIdMap.get(demand.getSkuCode()).getMaterial_id());
detailRow.put("qty_unit_name", demand.getUnit());
detailRow.put("qty_unit_id", codeToIdMap.get(demand.getSkuCode()).getQty_unit_id());
detailRow.put("qty", demand.getQty());
detailRow.put("source_bill_code", demand.getWorkOrder());
detailRow.put("source_bill_type", "PM_DEMAND");
detailRow.put("source_billdtl_id", demand.getId());
detailRow.put("remark", "需求单:" + demand.getId());
tableData.add(detailRow);
}
billParam.put("tableData", tableData);
return billParam;
}
}

View File

@@ -54,7 +54,7 @@ public class OutBillController {
@PostMapping()
@Log("新增出库单")
public ResponseEntity<Object> insertDtl(@RequestBody JSONObject whereJson) {
iOutBillService.insertDtl(whereJson);
iOutBillService.saveBill(whereJson);
return new ResponseEntity<>(HttpStatus.CREATED);
}

View File

@@ -65,7 +65,7 @@ public interface IOutBillService extends IService<IOStorInv> {
* {bill_code=, stor_id=1473161852946092032, stor_code=01, stor_name=原材料库, bill_status=10, total_qty=2, detail_count=1, bill_type=010201, remark=, biz_date=2022-01-08, create_mode=, tableData=[{material_id=1309, material_code=090301010001, bill_status=10, material_name=碳化钨粉 02, pcsn=, quality_scode=02, ivt_level=01, is_active=1, plan_qty=2, qty_unit_name=千克\公斤, qty_unit_id=1, remark=, edit=true}]}
* /
*/
String insertDtl(JSONObject whereJson);
String saveBill(JSONObject whereJson);
/**
* 查询出库单明细

View File

@@ -22,4 +22,11 @@ public interface IOStorInvDisMapper extends BaseMapper<IOStorInvDis> {
//查询未出库单分配
List<IOStorInvDisDto> queryOutBillDisDtl(@Param("params") Map whereJson);
/**
* 批量插入分配明细
* @param list 分配明细列表
* @return 插入成功的记录数
*/
int batchSave(@Param("list") List<IOStorInvDis> list);
}

View File

@@ -47,7 +47,7 @@
LEFT JOIN sch_base_task task ON task.task_id = dis.task_id
LEFT JOIN md_pb_groupplate ext
ON ext.storagevehicle_code = dis.storagevehicle_code
and ext.material_id = dis.material_id and ext.pcsn = dis.pcsn
and ext.material_code = dis.material_code and ext.pcsn = dis.pcsn
where
1=1
<if test="params.iostorinvdtl_id != null">
@@ -60,4 +60,58 @@
</if>
</select>
<!-- 批量插入分配明细 -->
<insert id="batchSave" parameterType="list">
INSERT INTO st_ivt_iostorinvdis (
iostorinvdis_id,
iostorinv_id,
iostorinvdtl_id,
seq_no,
sect_id,
sect_code,
sect_name,
struct_id,
struct_code,
struct_name,
material_id,
material_code,
pcsn,
work_status,
task_id,
storagevehicle_code,
is_issued,
qty_unit_id,
qty_unit_name,
plan_qty,
real_qty,
point_code
) VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.iostorinvdis_id},
#{item.iostorinv_id},
#{item.iostorinvdtl_id},
#{item.seq_no},
#{item.sect_id},
#{item.sect_code},
#{item.sect_name},
#{item.struct_id},
#{item.struct_code},
#{item.struct_name},
#{item.material_id},
#{item.material_code},
#{item.pcsn},
#{item.work_status},
#{item.task_id},
#{item.storagevehicle_code},
#{item.is_issued},
#{item.qty_unit_id},
#{item.qty_unit_name},
#{item.plan_qty},
#{item.real_qty},
#{item.point_code}
)
</foreach>
</insert>
</mapper>

View File

@@ -2,13 +2,26 @@ package org.nl.wms.warehouse_manage.inAndOut.service.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.nl.wms.warehouse_manage.inAndOut.service.dao.IOStorInvDtl;
import java.util.List;
import java.util.Set;
/**
* @author dsh
* 2025/5/21
*/
@Mapper
public interface IOStorInvDtlMapper extends BaseMapper<IOStorInvDtl> {
/**
* 批量插入
* @param list
* @return
*/
int batchInsert(@Param("list") List<IOStorInvDtl> list);
int batchUpdateUnassignQty(@Param("dtlSet") Set<String> dtlSet, @Param("billStatus") String billStatus);
}

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.nl.wms.warehouse_manage.inAndOut.service.dao.mapper.IOStorInvDtlMapper">
<insert id="batchInsert" parameterType="java.util.List">
INSERT INTO st_ivt_iostorinvdtl (
iostorinvdtl_id,
iostorinv_id,
seq_no,
material_id,
material_code,
pcsn,
bill_status,
qty_unit_id,
qty_unit_name,
source_bill_code,
source_bill_type,
source_billdtl_id,
plan_qty,
remark,
assign_qty,
unassign_qty
) VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.iostorinvdtl_id},
#{item.iostorinv_id},
#{item.seq_no},
#{item.material_id},
#{item.material_code},
#{item.pcsn},
#{item.bill_status},
#{item.qty_unit_id},
#{item.qty_unit_name},
#{item.source_bill_code},
#{item.source_bill_type},
#{item.source_billdtl_id},
#{item.plan_qty},
#{item.remark},
#{item.assign_qty},
#{item.unassign_qty}
)
</foreach>
</insert>
<update id="batchUpdateUnassignQty">
UPDATE st_ivt_iostorinvdtl
SET assign_qty = 0,
unassign_qty = plan_qty,
bill_status = #{billStatus}
WHERE iostorinvdtl_id IN
<foreach collection="dtlSet" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
</mapper>

View File

@@ -50,7 +50,7 @@
<select id="getGroupPlate" resultType="org.nl.wms.warehouse_manage.service.dto.GroupPlateDto">
SELECT group_id,
storagevehicle_code,
gp.material_id,
gp.material_code,
pcsn,
gp.qty_unit_id,
gp.qty_unit_name,
@@ -60,7 +60,7 @@
status,ext_code,ext_type,
mater.material_name,mater.material_spec,mater.material_code
FROM md_pb_groupplate gp
LEFT JOIN md_me_materialbase mater ON mater.material_id = gp.material_id
LEFT JOIN md_me_materialbase mater ON mater.material_code = gp.material_code
<where>
gp.status = '01' and frozen_qty = 0
<if test="params.material_code != null">

View File

@@ -23,6 +23,7 @@ import org.nl.wms.basedata_manage.enums.BaseDataEnum;
import org.nl.wms.basedata_manage.service.IBsrealStorattrService;
import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.BsrealStorattr;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.basedata_manage.service.dao.mapper.MdPbStoragevehicleextMapper;
import org.nl.wms.basedata_manage.service.dto.*;
import org.nl.wms.sch_manage.enums.TaskStatus;
@@ -33,6 +34,10 @@ import org.nl.wms.sch_manage.service.dao.mapper.SchBasePointMapper;
import org.nl.wms.sch_manage.service.util.tasks.StOutTask;
import org.nl.wms.warehouse_manage.enums.IOSConstant;
import org.nl.wms.warehouse_manage.enums.IOSEnum;
import org.nl.wms.warehouse_manage.inventory.IStInventoryService;
import org.nl.wms.warehouse_manage.inventory.core.param.impl.AddInvParam;
import org.nl.wms.warehouse_manage.inventory.core.enums.InventoryChangeType;
import org.nl.wms.warehouse_manage.inventory.core.param.impl.OutDisReverseParam;
import org.nl.wms.warehouse_manage.service.IMdPbGroupplateService;
import org.nl.wms.warehouse_manage.inAndOut.service.IOutBillService;
import org.nl.wms.warehouse_manage.service.dao.GroupPlate;
@@ -44,6 +49,7 @@ import org.nl.wms.warehouse_manage.inAndOut.service.dao.mapper.IOStorInvDtlMappe
import org.nl.wms.warehouse_manage.inAndOut.service.dao.mapper.IOStorInvMapper;
import org.nl.wms.warehouse_manage.inAndOut.service.dto.IOStorInvDisDto;
import org.nl.wms.warehouse_manage.inAndOut.service.dto.IOStorInvDtlDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@@ -93,6 +99,8 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
@Resource
private IMdPbGroupplateService iMdPbGroupPlateService;
@Autowired
private IStInventoryService iStInventoryService;
@Override
@@ -245,30 +253,29 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
}
@Override
@Transactional(rollbackFor = Exception.class)
public String insertDtl(JSONObject map) {
public String saveBill(JSONObject map) {
//明细
JSONArray array = map.getJSONArray("tableData");
map.remove("tableData");
String currentUserId = SecurityUtils.getCurrentUserId();
String nickName = SecurityUtils.getCurrentNickName();
String user = map.getString("user");
if (ObjectUtil.isNotEmpty(user)) {
if ("erp".equals(user)) {
currentUserId = "2";
nickName = "ERP用户";
}
}
String now = DateUtil.now();
String iostorinv_id = IdUtil.getStringId();
String bill_code = CodeUtil.getNewCode("OUT_STORE_CODE");
BsrealStorattr bsrealStorattr = iBsrealStorattrService.findById((String) map.get("stor_id"));
final String storId = map.getString("stor_id");
BsrealStorattr bsrealStorattr;
if (!StringUtils.isEmpty(storId)){
bsrealStorattr = iBsrealStorattrService.findById(storId);
}else {
final String storCode = map.getString("stor_code");
if (StringUtils.isEmpty(storCode)){
throw new BadRequestException("生成出库单失败,仓库编码不能为空");
}
bsrealStorattr = iBsrealStorattrService.findByCode(storCode);
}
map.put("iostorinv_id", iostorinv_id);
map.put("bill_code", bill_code);
map.put("bill_code", CodeUtil.getNewCode("OUT_STORE_CODE"));
map.put("biz_date", map.getString("biz_date").substring(0, 10));
String bill_type = (String) map.get("bill_type");
map.put("bill_status", IOSEnum.BILL_STATUS.code("生成"));
map.put("io_type", IOSEnum.IO_TYPE.code("出库"));
map.put("detail_count", array.size() + "");
map.put("create_mode", IOSEnum.CREATE_MODE.code("PC产生"));
@@ -283,45 +290,42 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
map.put("is_delete", BaseDataEnum.IS_YES_NOT.code(""));
map.put("is_upload", BaseDataEnum.IS_YES_NOT.code(""));
// 主表重量
double qty = 0.0;
BigDecimal totalQty = BigDecimal.ZERO;
// 明细数
int num = array.size();
ArrayList<IOStorInvDtl> batchSave = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JSONObject row = array.getJSONObject(i);
// 校验计划数量不能为零
double plan_qty = row.getDoubleValue("qty");
if (Double.compare(plan_qty, 0.0) == 0) {
throw new BadRequestException("数量不能为0");
// 获取数量,使用 BigDecimal 保证精度
BigDecimal planQty = row.getBigDecimal("qty");
if (planQty == null || planQty.compareTo(BigDecimal.ZERO) == 0) {
throw new BadRequestException(String.format("创建失败,第%d行数量不能为0", i + 1));
}
JSONObject ioStorInvDtl = new JSONObject();
ioStorInvDtl.put("iostorinvdtl_id", IdUtil.getStringId());
ioStorInvDtl.put("iostorinv_id", iostorinv_id);
ioStorInvDtl.put("seq_no", (i + 1) + "");
ioStorInvDtl.put("material_id", row.getString("material_id"));
ioStorInvDtl.put("material_code", row.getString("material_code"));
ioStorInvDtl.put("pcsn", row.getString("pcsn"));
ioStorInvDtl.put("bill_status", IOSEnum.BILL_STATUS.code("生成"));
ioStorInvDtl.put("qty_unit_id", row.get("qty_unit_id"));
ioStorInvDtl.put("qty_unit_name", row.getString("qty_unit_name"));
ioStorInvDtl.put("source_bill_code", row.getString("source_bill_code"));
ioStorInvDtl.put("source_bill_type", row.getString("source_bill_type"));
ioStorInvDtl.put("source_billdtl_id", row.getString("source_billdtl_id"));
ioStorInvDtl.put("plan_qty", row.get("qty"));
ioStorInvDtl.put("remark", row.getString("remark"));
ioStorInvDtl.put("assign_qty", "0");
ioStorInvDtl.put("unassign_qty", row.get("qty"));
ioStorInvDtlMapper.insert(ioStorInvDtl.toJavaObject(IOStorInvDtl.class));
qty += ioStorInvDtl.getDoubleValue("plan_qty");
IOStorInvDtl detail = new IOStorInvDtl();
detail.setIostorinvdtl_id(IdUtil.getStringId());
detail.setIostorinv_id(iostorinv_id);
detail.setSeq_no(String.valueOf(i + 1));
detail.setMaterial_id(row.getString("material_id"));
detail.setMaterial_code(row.getString("material_code"));
detail.setPcsn(row.getString("pcsn"));
detail.setBill_status(IOSEnum.BILL_STATUS.code("生成"));
detail.setQty_unit_id(row.getString("qty_unit_id"));
detail.setQty_unit_name(row.getString("qty_unit_name"));
detail.setSource_bill_code(row.getString("source_bill_code"));
detail.setSource_bill_type(row.getString("source_bill_type"));
detail.setSource_billdtl_id(row.getString("source_billdtl_id"));
detail.setPlan_qty(planQty);
detail.setRemark(row.getString("remark"));
detail.setAssign_qty(BigDecimal.ZERO);
detail.setUnassign_qty(planQty);
batchSave.add(detail);
totalQty = totalQty.add(planQty);
}
map.put("total_qty", qty);
ioStorInvDtlMapper.batchInsert(batchSave);
map.put("total_qty", totalQty);
map.put("detail_count", num);
ioStorInvMapper.insert(map.toJavaObject(IOStorInv.class));
return iostorinv_id;
}
@@ -338,19 +342,17 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
@Override
@Transactional(rollbackFor = Exception.class)
public void allDiv(JSONObject whereJson) {
String currentUserId = SecurityUtils.getCurrentUserId();
String nickName = SecurityUtils.getCurrentNickName();
String now = DateUtil.now();
String sectCode = whereJson.getString("sect_code");
// TODO系统如果没有指定出库库区则由WMS手工分配
String iostorinv_id = whereJson.getString("iostorinv_id");
//查询主表信息
IOStorInv ioStorInv = ioStorInvMapper.selectById(iostorinv_id);
if (ObjectUtil.isEmpty(ioStorInv)) {
throw new BadRequestException("查不到出库单信息");
}
//查询生成和未分配完的明细
JSONObject queryDtl = new JSONObject();
queryDtl.put("bill_status", IOSEnum.BILL_STATUS.code("分配完"));
@@ -458,13 +460,7 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
@Override
@Transactional(rollbackFor = Exception.class)
public void allCancel(JSONObject whereJson) {
String currentUserId = SecurityUtils.getCurrentUserId();
String nickName = SecurityUtils.getCurrentNickName();
String now = DateUtil.now();
String iostorinv_id = whereJson.getString("iostorinv_id");
List<IOStorInvDis> ioStorInvDisList = ioStorInvDisMapper.selectList(new LambdaQueryWrapper<>(IOStorInvDis.class)
.le(IOStorInvDis::getWork_status,IOSEnum.INBILL_DIS_STATUS.code("未生成"))
.eq(IOStorInvDis::getIs_issued,BaseDataEnum.IS_YES_NOT.code(""))
@@ -475,53 +471,40 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
}
//需要更新的出入库单明细
Set<String> dtlSet = new HashSet<>();
for (IOStorInvDis ioStorInvDis:ioStorInvDisList){
//添加需要更新的明细标识
Set<String> structSet = new HashSet<>();
List<OutDisReverseParam> OutDisReverseParams = new ArrayList<>();
for (IOStorInvDis ioStorInvDis : ioStorInvDisList){
dtlSet.add(ioStorInvDis.getIostorinvdtl_id());
//更新库存 减冻结加可用
List<JSONObject> updateIvtList = new ArrayList<>();
JSONObject jsonIvt = new JSONObject();
jsonIvt.put("type", IOSConstant.UPDATE_IVT_TYPE_SUB_FROZEN_ADD_CANUSE);
jsonIvt.put("storagevehicle_code", ioStorInvDis.getStoragevehicle_code());
jsonIvt.put("material_id", ioStorInvDis.getMaterial_id());
jsonIvt.put("pcsn", ioStorInvDis.getPcsn());
jsonIvt.put("qty_unit_id", ioStorInvDis.getQty_unit_id());
jsonIvt.put("qty_unit_name", ioStorInvDis.getQty_unit_name());
jsonIvt.put("change_qty", ioStorInvDis.getPlan_qty());
updateIvtList.add(jsonIvt);
iMdPbGroupPlateService.updateIvt(updateIvtList);
final OutDisReverseParam param = OutDisReverseParam.builder()
.materialCode(ioStorInvDis.getMaterial_code())
.changeQty(ioStorInvDis.getPlan_qty())
.structCode(ioStorInvDis.getStruct_code())
.storagevehicleCode(ioStorInvDis.getStoragevehicle_code())
.build();
OutDisReverseParams.add(param);
structSet.add(ioStorInvDis.getStruct_code());
}
iStInventoryService.changeInventory(InventoryChangeType.OUT_DIS_REVERSE,OutDisReverseParams);
//解锁库位
JSONObject unlock_map = new JSONObject();
unlock_map.put("struct_code", ioStorInvDis.getStruct_code());
unlock_map.put("inv_type", null);
unlock_map.put("inv_id", null);
unlock_map.put("inv_code", null);
iStructattrService.updateStatusByCode("2",unlock_map);
//删除出入库单分配表
ioStorInvDisMapper.deleteById(ioStorInvDis.getIostorinvdis_id());
}
//更新出库明细单状态
for (String dtlId:dtlSet){
IOStorInvDtl ioStorInvDtl = ioStorInvDtlMapper.selectById(dtlId);
ioStorInvDtl.setAssign_qty(BigDecimal.ZERO);
ioStorInvDtl.setUnassign_qty(ioStorInvDtl.getPlan_qty());
ioStorInvDtl.setBill_status(IOSEnum.BILL_STATUS.code("生成"));
ioStorInvDtlMapper.updateById(ioStorInvDtl);
}
iStructattrService.update(new LambdaUpdateWrapper<Structattr>()
.set(Structattr::getInv_type,null)
.set(Structattr::getInv_id,null)
.set(Structattr::getInv_code,null)
.set(Structattr::getLock_type,IOSEnum.LOCK_TYPE.code("未锁定"))
.in(Structattr::getStruct_code,structSet));
//删除出入库单分配表
ioStorInvDisMapper.deleteBatchIds(ioStorInvDisList.stream()
.map(IOStorInvDis::getIostorinvdis_id)
.collect(Collectors.toList()));
//回滚明细中的已分配数
ioStorInvDtlMapper.batchUpdateUnassignQty(dtlSet,IOSEnum.BILL_STATUS.code("生成"));
//更新主表单据状态
IOStorInv ios = new IOStorInv();
ios.setIostorinv_id(iostorinv_id);
ios.setUpdate_optid(currentUserId);
ios.setUpdate_optname(nickName);
ios.setUpdate_time(now);
ios.setBill_status(IOSEnum.BILL_STATUS.code("生成"));
ioStorInvMapper.updateById(ios);
ioStorInvMapper.update(null, new LambdaUpdateWrapper<IOStorInv>()
.eq(IOStorInv::getIostorinv_id, iostorinv_id)
.set(IOStorInv::getUpdate_optid, SecurityUtils.getCurrentUserId())
.set(IOStorInv::getUpdate_optname, SecurityUtils.getCurrentNickName())
.set(IOStorInv::getUpdate_time, DateUtil.now())
.set(IOStorInv::getBill_status, IOSEnum.BILL_STATUS.code("生成")));
}
@Override
@@ -537,7 +520,6 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
if (ObjectUtil.isEmpty(ioStorInv)) {
throw new BadRequestException("查不到出库单信息");
}
//查询生成和未分配完的明细
JSONObject queryDtl = new JSONObject();
queryDtl.put("bill_status", IOSEnum.BILL_STATUS.code("分配完"));
@@ -571,6 +553,7 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
);
int seq_no = 1;
BigDecimal allocation_canuse_qty=BigDecimal.ZERO;
final List<IOStorInvDis> disSet = new ArrayList<>();
for (StrategyStructMaterialVO outAllocation : structMaterials) {
//分配明细
IOStorInvDis ioStorInvDis = new IOStorInvDis();
@@ -593,14 +576,6 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
ioStorInvDis.setQty_unit_name(outAllocation.getQty_unit_name());
ioStorInvDis.setWork_status(IOSEnum.INBILL_DIS_STATUS.code("未生成"));
ioStorInvDis.setPlan_qty(outAllocation.getFrozen_qty());
//锁定货位
JSONObject lock_map = new JSONObject();
lock_map.put("struct_code", outAllocation.getStruct_code());
lock_map.put("inv_id", ioStorInv.getIostorinv_id());
lock_map.put("inv_code", ioStorInv.getBill_code());
lock_map.put("inv_type", ioStorInv.getBill_type());
lock_map.put("lock_type", IOSEnum.LOCK_TYPE.code("出库锁"));
iStructattrService.updateStatusByCode("0",lock_map);
//更新组盘表冻结数量状态
iMdPbGroupPlateService.update(new LambdaUpdateWrapper<GroupPlate>()
.set(GroupPlate::getFrozen_qty, outAllocation.getFrozen_qty())
@@ -610,13 +585,24 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
.eq(GroupPlate::getMaterial_code, outAllocation.getMaterial_id())
.eq(GroupPlate::getStatus,IOSEnum.GROUP_PLATE_STATUS.code("入库")));
//生成分配明细
ioStorInvDisMapper.insert(ioStorInvDis);
disSet.add(ioStorInvDis);
allocation_canuse_qty = allocation_canuse_qty.add(outAllocation.getFrozen_qty());
//分配完成 结束分配
if (unassign_qty.doubleValue() <= 0){
break;
}
}
ioStorInvDisMapper.insert(ioStorInvDis);
//锁定货位
JSONObject lock_map = new JSONObject();
lock_map.put("struct_code", outAllocation.getStruct_code());
lock_map.put("inv_id", ioStorInv.getIostorinv_id());
lock_map.put("inv_code", ioStorInv.getBill_code());
lock_map.put("inv_type", ioStorInv.getBill_type());
lock_map.put("lock_type", IOSEnum.LOCK_TYPE.code("出库锁"));
iStructattrService.updateStatusByCode("0",lock_map);
//更新详情
dtl.setBill_status(IOSEnum.BILL_STATUS.code("分配完"));
dtl.setUnassign_qty(unassign_qty);

View File

@@ -1,5 +1,7 @@
package org.nl.wms.warehouse_manage.inventory;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
import org.nl.wms.warehouse_manage.inventory.core.enums.InventoryChangeType;
import org.nl.wms.warehouse_manage.inventory.dto.StInventoryDto;
import org.nl.wms.warehouse_manage.inventory.dto.StInventoryQuery;
@@ -10,6 +12,8 @@ import java.util.List;
*/
public interface IStInventoryService {
public List<StInventoryDto> queryInventory(StInventoryQuery query);
List<StInventoryDto> queryInventory(StInventoryQuery query);
<T extends InventoryParam> void changeInventory(InventoryChangeType<T> type, List<T> params);
}

View File

@@ -0,0 +1,38 @@
package org.nl.wms.warehouse_manage.inventory.core.enums;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
import org.nl.wms.warehouse_manage.inventory.core.param.impl.*;
//库存变动枚举类强制指定泛型T
public abstract class InventoryChangeType<T extends InventoryParam> {
//加库存可用数
public static final InventoryChangeType<AddInvParam> ADD_INV =
new InventoryChangeType<AddInvParam>(AddInvParam.class) {};
//减库存可用数
public static final InventoryChangeType<SubInvParam> SUB_INV =
new InventoryChangeType<SubInvParam>(SubInvParam.class) {};
//减库存可用数加冻结数
public static final InventoryChangeType<OutDisParam> OUT_DIS =
new InventoryChangeType<OutDisParam>(OutDisParam.class) {};
//OUT_DIS 反函数
public static final InventoryChangeType<OutDisReverseParam> OUT_DIS_REVERSE =
new InventoryChangeType<OutDisReverseParam>(OutDisReverseParam.class) {};
//减冻结数
public static final InventoryChangeType<OutFinishParam> OUT_FINS =
new InventoryChangeType<OutFinishParam>(OutFinishParam.class) {};
//入库相关不用处理,基于组盘
public static final InventoryChangeType<InDisParam> IN_DIS =
new InventoryChangeType<InDisParam>(InDisParam.class) {};
public static final InventoryChangeType<InDisParam> IN_DIS_REVERSE =
new InventoryChangeType<InDisParam>(InDisParam.class) {};
public static final InventoryChangeType<InFinishParam> IN_FINISH =
new InventoryChangeType<InFinishParam>(InFinishParam.class) {};
private final Class<T> paramClass;
public String getType() {
return paramClass.getSimpleName();
}
private InventoryChangeType(Class<T> paramClass) { this.paramClass = paramClass; }
}

View File

@@ -0,0 +1,9 @@
package org.nl.wms.warehouse_manage.inventory.core.param;
// 定
// 义参数接口
public interface InventoryParam {
InventoryParam validation();
}

View File

@@ -0,0 +1,23 @@
package org.nl.wms.warehouse_manage.inventory.core.param.impl;
import lombok.Data;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
import java.math.BigDecimal;
@Data
public class AddInvParam implements InventoryParam {
private String storagevehicleCode;
private String materialCode;
private String pcsn;
private BigDecimal qty;
private String extCode;
private String extType;
private String unitName;
private String remark;
@Override
public AddInvParam validation() {
return this;
}
}

View File

@@ -0,0 +1,10 @@
package org.nl.wms.warehouse_manage.inventory.core.param.impl;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
public class InDisParam implements InventoryParam {
@Override
public InDisParam validation() {
return this;
}
}

View File

@@ -0,0 +1,11 @@
package org.nl.wms.warehouse_manage.inventory.core.param.impl;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
public class InFinishParam implements InventoryParam {
@Override
public InFinishParam validation() {
return this;
}
}

View File

@@ -0,0 +1,23 @@
package org.nl.wms.warehouse_manage.inventory.core.param.impl;
import lombok.Data;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
import java.math.BigDecimal;
@Data
public class OutDisParam implements InventoryParam {
private String storagevehicleCode;
private String materialCode;
private String pcsn;
private BigDecimal qty;
private String extCode;
private String extType;
private String unitName;
private String remark;
@Override
public OutDisParam validation() {
return this;
}
}

View File

@@ -0,0 +1,29 @@
package org.nl.wms.warehouse_manage.inventory.core.param.impl;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.nl.wms.warehouse_manage.enums.IOSConstant;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
import java.math.BigDecimal;
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OutDisReverseParam implements InventoryParam {
private String storagevehicleCode;
private String structCode;
private String materialCode;
private BigDecimal changeQty;
private String pcsn;
@Override
public OutDisReverseParam validation() {
return this;
}
}

View File

@@ -0,0 +1,18 @@
package org.nl.wms.warehouse_manage.inventory.core.param.impl;
import lombok.Data;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
import java.math.BigDecimal;
@Data
public class OutFinishParam implements InventoryParam {
private String storagevehicleCode;
private String materialCode;
private String pcsn;
private BigDecimal qty;
@Override
public OutFinishParam validation() {
return this;
}
}

View File

@@ -0,0 +1,21 @@
package org.nl.wms.warehouse_manage.inventory.core.param.impl;
import lombok.Data;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
import java.math.BigDecimal;
@Data
public class SubInvParam implements InventoryParam {
private String storagevehicleCode;
private String materialCode;
private String pcsn;
private BigDecimal qty;
private String extCode;
private String extType;
private String unitName;
private String remark;
@Override
public SubInvParam validation() {
return this;
}
}

View File

@@ -1,6 +1,7 @@
package org.nl.wms.warehouse_manage.inventory.dao.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.nl.wms.warehouse_manage.inventory.dto.StInventoryDto;
import org.nl.wms.warehouse_manage.inventory.dto.StInventoryQuery;
@@ -13,5 +14,5 @@ import java.util.List;
@Mapper
public interface StInventoryMapper {
List<StInventoryDto> queryInventory(StInventoryQuery query);
List<StInventoryDto> queryInventory(@Param("query") StInventoryQuery query);
}

View File

@@ -3,17 +3,17 @@
<mapper namespace="org.nl.wms.warehouse_manage.inventory.dao.mapper.StInventoryMapper">
<select id="queryInventory" resultType="org.nl.wms.warehouse_manage.inventory.dto.StInventoryDto">
SELECT
s.stor_id,
s.stor_code,
s.stor_name,
g.material_code,
SUM(g.qty - g.frozen_qty) AS available_qty, -- 可用库存
SUM(g.qty) AS total_qty -- 总库存
s.stor_id as storId,
s.stor_code as storCode,
s.stor_name as storName,
g.material_code as materialCode,
SUM(g.frozen_qty) AS frozenQty, -- 可用库存
SUM(g.qty) AS qty -- 总库存
FROM md_pb_groupplate g
INNER JOIN st_ivt_structattr s
ON g.storagevehicle_code = s.storagevehicle_code
WHERE g.material_id = #{query.materialCode}
AND g.status != '03' -- 排除已移除/已禁用的组盘记录
WHERE g.material_code = #{query.materialCode}
AND g.status = '02' -- 排除已移除/已禁用的组盘记录
AND s.is_used = 1 -- 只统计启用的仓位
GROUP BY s.stor_id, s.stor_code, s.stor_name, g.material_code
ORDER BY s.stor_code;

View File

@@ -60,11 +60,13 @@ public class StInventoryDto {
* 库位名称
*/
private String storName;
private String storCode;
/**
* 区域名称
*/
private String sectName;
private String sectcode;
/**
* 物料编码

View File

@@ -1,27 +1,166 @@
package org.nl.wms.warehouse_manage.inventory.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nl.common.exception.BadRequestException;
import org.nl.common.utils.SecurityUtils;
import org.nl.wms.warehouse_manage.enums.IOSEnum;
import org.nl.wms.warehouse_manage.inventory.IStInventoryService;
import org.nl.wms.warehouse_manage.inventory.core.param.InventoryParam;
import org.nl.wms.warehouse_manage.inventory.core.enums.InventoryChangeType;
import org.nl.wms.warehouse_manage.inventory.core.param.impl.*;
import org.nl.wms.warehouse_manage.inventory.dao.mapper.StInventoryMapper;
import org.nl.wms.warehouse_manage.inventory.dto.StInventoryDto;
import org.nl.wms.warehouse_manage.inventory.dto.StInventoryQuery;
import org.nl.wms.warehouse_manage.service.IMdPbGroupplateService;
import org.nl.wms.warehouse_manage.service.dao.GroupPlate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.math.BigDecimal;
import java.util.List;
/**
* 库存查询服务
*/
@Service
@Slf4j
public class StInventoryServiceImpl implements IStInventoryService {
@Resource
private StInventoryMapper stInventoryMapper;
@Autowired
private IMdPbGroupplateService iMdPbGroupplateService;
@Override
public List<StInventoryDto> queryInventory(StInventoryQuery query){
List<StInventoryDto> result = stInventoryMapper.queryInventory(query);
return result;
};
}
@Override
public <T extends InventoryParam> void changeInventory(InventoryChangeType<T> typeEnum, List<T> params) {
final String type = typeEnum.getType();
params.forEach(a->a.validation());
//AddInvParam,SubInvParam,OutDisParam,OutFinishParam,InDisParam,InFinishParam
switch (type){
case "AddInvParam":
final List<AddInvParam> addInvParams = (List<AddInvParam>) params;
for (AddInvParam invParam : addInvParams) {
LambdaQueryWrapper<GroupPlate> query = new QueryWrapper<GroupPlate>().lambda()
.eq(GroupPlate::getStoragevehicle_code, invParam.getStoragevehicleCode())
.eq(GroupPlate::getMaterial_code, invParam.getMaterialCode());
if (!StringUtils.isEmpty(invParam.getPcsn())){
query.eq(GroupPlate::getPcsn,invParam.getPcsn());
}
GroupPlate groupPlate = iMdPbGroupplateService.getOne(query);
if (groupPlate == null){
throw new BadRequestException("库存增加失败,当前库存不存在");
}
iMdPbGroupplateService.update(new LambdaUpdateWrapper<GroupPlate>()
.set(GroupPlate::getQty,groupPlate.getQty().add(invParam.getQty()))
.set(GroupPlate::getRemark,invParam.getRemark())
.set(GroupPlate::getUpdate_time,DateUtil.now())
.eq(GroupPlate::getGroup_id,groupPlate.getGroup_id()));
}
break;
case "SubInvParam":
final List<SubInvParam> subInvParams = (List<SubInvParam>) params;
for (SubInvParam subInvParam : subInvParams) {
LambdaQueryWrapper<GroupPlate> query = new QueryWrapper<GroupPlate>().lambda()
.eq(GroupPlate::getStoragevehicle_code, subInvParam.getStoragevehicleCode())
.eq(GroupPlate::getMaterial_code, subInvParam.getMaterialCode());
if (!StringUtils.isEmpty(subInvParam.getPcsn())){
query.eq(GroupPlate::getPcsn,subInvParam.getPcsn());
}
GroupPlate groupPlate = iMdPbGroupplateService.getOne(query);
final BigDecimal qty = groupPlate.getQty().subtract(subInvParam.getQty());
if (groupPlate == null || qty.doubleValue() < 0){
throw new BadRequestException("库存扣减失败,当前库存不存在");
}
iMdPbGroupplateService.update(new LambdaUpdateWrapper<GroupPlate>()
.set(GroupPlate::getQty, qty)
.set(GroupPlate::getRemark,subInvParam.getRemark())
.set(GroupPlate::getUpdate_time,DateUtil.now())
.eq(GroupPlate::getGroup_id,groupPlate.getGroup_id()));
}
break;
case "OutDisParam":
final List<OutDisParam> outDisParams = (List<OutDisParam>) params;
for (OutDisParam outDisParam : outDisParams) {
LambdaQueryWrapper<GroupPlate> query = new QueryWrapper<GroupPlate>().lambda()
.eq(GroupPlate::getStoragevehicle_code, outDisParam.getStoragevehicleCode())
.eq(GroupPlate::getMaterial_code, outDisParam.getMaterialCode());
if (!StringUtils.isEmpty(outDisParam.getPcsn())){
query.eq(GroupPlate::getPcsn,outDisParam.getPcsn());
}
GroupPlate groupPlate = iMdPbGroupplateService.getOne(query);
if (groupPlate == null){
throw new BadRequestException("库存增加失败,当前库存不存在");
}
final BigDecimal qty = groupPlate.getQty().subtract(outDisParam.getQty());
if (qty.intValue() < 0) {
throw new BadRequestException("库存变动失败,可用数量-变动数量为负数"+groupPlate.getStoragevehicle_code());
}
final BigDecimal frozenQty = groupPlate.getFrozen_qty().add(outDisParam.getQty());
iMdPbGroupplateService.update(new LambdaUpdateWrapper<GroupPlate>()
.set(GroupPlate::getQty, qty)
.set(GroupPlate::getFrozen_qty,frozenQty)
.set(GroupPlate::getUpdate_time,DateUtil.now())
.eq(GroupPlate::getGroup_id,groupPlate.getGroup_id()));
}
break;
case "OutFinishParam":
final List<OutFinishParam> outFinishParams = (List<OutFinishParam>) params;
for (OutFinishParam outFinishParam : outFinishParams) {
final LambdaQueryWrapper<GroupPlate> queryWrapper = new QueryWrapper<GroupPlate>().lambda()
.eq(GroupPlate::getStoragevehicle_code, outFinishParam.getStoragevehicleCode())
.eq(GroupPlate::getMaterial_code, outFinishParam.getMaterialCode())
.eq(GroupPlate::getStatus, IOSEnum.GROUP_PLATE_STATUS.code("入库"));
if (!StringUtils.isEmpty(outFinishParam.getPcsn())){
queryWrapper.eq(GroupPlate::getPcsn, outFinishParam.getPcsn());
}
GroupPlate groupPlate = iMdPbGroupplateService.getOne(queryWrapper);
groupPlate.setFrozen_qty(groupPlate.getFrozen_qty().subtract(outFinishParam.getQty()));
groupPlate.setUpdate_id(SecurityUtils.getCurrentUserId());
groupPlate.setUpdate_name(SecurityUtils.getCurrentNickName());
groupPlate.setUpdate_time(DateUtil.now());
iMdPbGroupplateService.updateById(groupPlate);
}
break;
case "OutDisReverseParam":
final List<OutDisReverseParam> outFinishReverseParams = (List<OutDisReverseParam>) params;
for (OutDisReverseParam param : outFinishReverseParams) {
final LambdaQueryWrapper<GroupPlate> queryWrapper = new QueryWrapper<GroupPlate>().lambda()
.eq(GroupPlate::getStoragevehicle_code, param.getStoragevehicleCode())
.eq(GroupPlate::getMaterial_code, param.getMaterialCode())
.eq(GroupPlate::getStatus, IOSEnum.GROUP_PLATE_STATUS.code("入库"));
if (!StringUtils.isEmpty(param.getPcsn())){
queryWrapper.eq(GroupPlate::getPcsn, param.getPcsn());
}
GroupPlate groupPlate = iMdPbGroupplateService.getOne(queryWrapper);
groupPlate.setFrozen_qty(groupPlate.getFrozen_qty().subtract(param.getChangeQty()));
groupPlate.setQty(groupPlate.getQty().add(param.getChangeQty()));
groupPlate.setUpdate_id(SecurityUtils.getCurrentUserId());
groupPlate.setUpdate_name(SecurityUtils.getCurrentNickName());
groupPlate.setUpdate_time(DateUtil.now());
System.out.println("========="+groupPlate.getFrozen_qty()+"=========");
iMdPbGroupplateService.updateById(groupPlate);
}
break;
case "InDisParam":
break;
case "InFinishParam":
break;
default:
throw new BadRequestException(String.format("库存变动失败,当前变动类型%d未定义",type));
}
}
}

View File

@@ -23,7 +23,7 @@
LEFT JOIN st_ivt_moreorlessmst ios ON ios.mol_id = dtl.mol_id
LEFT JOIN md_me_materialbase material ON material.material_id = dtl.material_id
INNER JOIN md_pb_groupplate ext ON ext.storagevehicle_code = dtl.storagevehicle_code
AND ext.material_id = dtl.material_id AND dtl.pcsn = ext.pcsn
AND ext.material_code = dtl.material_code AND dtl.pcsn = ext.pcsn
<where>
ios.is_delete = '0'
<if test="param.mol_id != null and param.mol_id != ''">

View File

@@ -62,7 +62,7 @@ public class UpdateIvtUtils {
break;
case IOSConstant.UPDATE_IVT_TYPE_ADD_FROZEN :
// 加冻结减可用
updateAddFrozenIvt(where);
// updateAddFrozenIvt(where);
break;
case IOSConstant.UPDATE_IVT_TYPE_SUB_FROZEN :
// 减冻结
@@ -70,15 +70,15 @@ public class UpdateIvtUtils {
break;
case IOSConstant.UPDATE_IVT_TYPE_SUB_FROZEN_ADD_CANUSE :
// 减冻结加可用
updateSubFrozenAddIvt(where);
// updateSubFrozenAddIvt(where);
break;
case IOSConstant.UPDATE_IVT_TYPE_ADD_CANUSE_IVT :
// 加可用(加库存)
updateAddCanuseIvt(where);
// updateAddCanuseIvt(where);
break;
case IOSConstant.UPDATE_IVT_TYPE_SUB_CANUSE_IVT :
// 减可用(减库存)
updateSubCanuseIvt(where);
// updateSubCanuseIvt(where);
break;
default:
break;

View File

@@ -20,7 +20,10 @@
<rrOperation :crud="crud" />
</el-form>
</div>
<crudOperation :permission="permission" />
<div style="margin-bottom: 10px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
<crudOperation :permission="permission" />
<el-button size="mini" type="success" :disabled="!multipleSelection.length" @click="handleBatchPush">下推</el-button>
</div>
<el-dialog :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="900px">
<el-form ref="form" :model="form" :rules="rules" size="mini" label-width="110px" label-suffix=":" style="border: 1px solid #cfe0df;margin-top: 10px;padding: 10px;">
<el-row>
@@ -66,7 +69,7 @@
</div>
</el-dialog>
<el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small">
<el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="ID" width="220" show-overflow-tooltip />
<el-table-column prop="creator" label="操作人" min-width="100" show-overflow-tooltip />
@@ -86,11 +89,10 @@
<el-table-column prop="productionLine" label="产线" min-width="100" show-overflow-tooltip />
<el-table-column prop="sn" label="车辆序列号" min-width="140" show-overflow-tooltip />
<el-table-column prop="createAt" label="创建时间" min-width="160" show-overflow-tooltip />
<el-table-column label="操作" width="240px" align="center" fixed="right">
<el-table-column label="操作" width="180px" align="center" fixed="right">
<template slot-scope="scope">
<udOperation style="display: inline" :data="scope.row" :permission="permission" />
<el-button size="mini" type="warning" plain style="margin-left:4px;" @click="openAllocateDialog(scope.row)">分配</el-button>
<el-button size="mini" type="success" plain style="margin-left:4px;" :disabled="scope.row.status !== '01'" @click="handlePush(scope.row)">下发</el-button>
</template>
</el-table-column>
</el-table>
@@ -120,7 +122,7 @@ export default {
return {
permission: {},
statusOptions: [
{ value: 0, label: '生成' },
{ value: '0', label: '生成' },
{ value: '01', label: '分配' },
{ value: '10', label: '下发' },
{ value: '20', label: '执行' },
@@ -133,6 +135,7 @@ export default {
currentDemand: {},
inventoryList: [],
selectedInventory: [],
multipleSelection: [],
rules: {
creator: [{ required: true, message: '请输入操作人', trigger: 'blur' }],
createTime: [{ required: true, message: '请选择需求日期', trigger: 'change' }],
@@ -165,6 +168,9 @@ export default {
const map = { 0: '', '01': 'warning', '10': 'primary', '20': 'primary', '80': 'success', '90': 'danger' }
return map[String(status)] || ''
},
handleSelectionChange(selection) {
this.multipleSelection = selection
},
openAllocateDialog(row) {
this.currentDemand = { ...row }
this.inventoryList = []
@@ -181,11 +187,12 @@ export default {
if (row.inventoryDis) {
try {
const saved = JSON.parse(row.inventoryDis)
const savedList = Array.isArray(saved) ? saved : [saved]
this.inventoryList.forEach(item => {
const match = saved.find(s => s.houseCode === item.houseCode)
const match = savedList.find(s => (s.horseCode || s.houseCode) === item.houseCode)
if (match) {
item._selected = true
item.allocQty = match.allocQty
item.allocQty = Number(match.qty || match.allocQty || 0)
this.$nextTick(() => {
this.$refs.allocateTable && this.$refs.allocateTable.toggleRowSelection(item, true)
})
@@ -219,16 +226,11 @@ export default {
this.$message.warning(`仓库 ${invalidRow.houseCode} 的分配数量必须大于0`)
return
}
const inventoryDis = JSON.stringify(
this.selectedInventory.map(item => ({
houseCode: item.houseCode,
houseName: item.houseName,
skuCode: item.skuCode,
skuName: item.skuName,
qty: item.qty,
allocQty: item.allocQty
}))
)
const inventoryDisList = this.selectedInventory.map(item => ({
horseCode: item.houseCode,
qty: item.allocQty
}))
const inventoryDis = inventoryDisList.length === 1 ? JSON.stringify(inventoryDisList[0]) : JSON.stringify(inventoryDisList)
this.allocateSaving = true
allocate({ id: this.currentDemand.id, inventoryDis }).then(() => {
this.$message.success('库存分配成功')
@@ -240,17 +242,26 @@ export default {
this.allocateSaving = false
})
},
handlePush(row) {
this.$confirm(`确认下发需求单 "${row.workOrder}" `, '提示', {
handleBatchPush() {
if (!this.multipleSelection.length) {
this.$message.warning('请先勾选要下推的需求单')
return
}
const invalidRows = this.multipleSelection.filter(item => String(item.status) !== '01')
if (invalidRows.length) {
this.$message.warning('仅支持批量下推状态为“分配”的需求单')
return
}
this.$confirm(`确认批量下推已勾选的 ${this.multipleSelection.length} 条需求单吗?`, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
push({ id: row.id, workOrder: row.workOrder }).then(() => {
this.$message.success('下成功')
push(this.multipleSelection).then(() => {
this.$message.success('下成功')
this.crud.toQuery()
}).catch(() => {
this.$message.error('下失败')
this.$message.error('下失败')
})
}).catch(() => {})
}

View File

@@ -128,18 +128,19 @@
:data="form.tableData"
style="width: 100%;"
border
fit
:header-cell-style="{background:'#f5f7fa',color:'#606266'}"
>
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column show-overflow-tooltip width="150" prop="storagevehicle_code" label="批次号" />
<el-table-column show-overflow-tooltip width="150" prop="pcsn" label="批次号" />
<el-table-column show-overflow-tooltip width="150" prop="material_code" label="物料编码" />
<el-table-column show-overflow-tooltip width="150" prop="material_name" label="物料名称" />
<el-table-column show-overflow-tooltip width="170" prop="qty" label="数量" />
<el-table-column show-overflow-tooltip width="170" prop="qty_unit_name" label="计量单位名称" />
<el-table-column show-overflow-tooltip width="150" prop="ext_code" label="源单号" />
<el-table-column show-overflow-tooltip width="150" prop="ext_type" label="源单类型" />
<el-table-column v-if="crud.status.cu > 0" align="center" label="操作" width="120" fixed="right">
<el-table-column show-overflow-tooltip min-width="140" prop="storagevehicle_code" label="载具编码" />
<el-table-column show-overflow-tooltip min-width="140" prop="pcsn" label="批次号" />
<el-table-column show-overflow-tooltip min-width="140" prop="material_code" label="物料编码" />
<el-table-column show-overflow-tooltip min-width="180" prop="material_name" label="物料名称" />
<el-table-column show-overflow-tooltip min-width="110" prop="qty" label="数量" />
<el-table-column show-overflow-tooltip min-width="130" prop="qty_unit_name" label="计量单位名称" />
<el-table-column show-overflow-tooltip min-width="140" prop="ext_code" label="源单号" />
<el-table-column show-overflow-tooltip min-width="120" prop="ext_type" label="源单类型" />
<el-table-column v-if="crud.status.cu > 0" align="center" label="操作" width="100" fixed="right">
<template scope="scope">
<el-button
type="danger"
@@ -309,21 +310,20 @@ export default {
}
},
tableChanged(rows) {
// 对新增的行进行校验不能存在相同物料批次
rows.forEach((item) => {
let same_mater = true
this.form.tableData.forEach((row) => {
if (row.pcsn === item.pcsn && row.material_id === item.material_id && row.storagevehicle_code === item.storagevehicle_code) {
same_mater = false
}
})
if (same_mater) {
const exists = this.form.tableData.some(row => this.isSameMaterialRow(row, item))
if (!exists) {
this.form.total_qty = parseFloat(this.form.total_qty) + parseFloat(item.qty)
this.form.tableData.splice(-1, 0, item)
this.form.tableData.push(item)
}
})
this.form.detail_count = this.form.tableData.length
},
isSameMaterialRow(row, item) {
const rowKey = [row.pcsn || '', row.material_id || row.material_code || '', row.storagevehicle_code || ''].join('_')
const itemKey = [item.pcsn || '', item.material_id || item.material_code || '', item.storagevehicle_code || ''].join('_')
return rowKey === itemKey
},
async insertEvent(row) {
if (this.form.bill_type === '') {
this.crud.notify('请选择业务类型!', CRUD.NOTIFICATION_TYPE.INFO)

View File

@@ -144,13 +144,14 @@ export default {
this.$emit('update:dialogShow', false)
},
submit() {
const selection = this.$refs.multipleTable.selection || []
if (!selection.length) {
this.$message.warning('请至少选择一条数据')
return
}
this.$emit('update:dialogShow', false)
this.rows = this.$refs.multipleTable.selection
console.log('获取的rows:')
console.log(this.rows)
this.$emit('tableChanged', this.rows)
group.getAllGroupInfo(this.rows).then(res => {
this.rows = res.content
group.getAllGroupInfo(selection).then(res => {
this.rows = res.content || []
this.$emit('tableChanged', this.rows)
})
// this.form = this.$options.data().form