|
|
|
|
@ -1,5 +1,6 @@ |
|
|
|
|
package org.springblade.wms.service.impl; |
|
|
|
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
|
import cn.hutool.core.date.DateUtil; |
|
|
|
|
import cn.hutool.core.util.IdUtil; |
|
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
|
@ -11,12 +12,18 @@ import lombok.extern.slf4j.Slf4j; |
|
|
|
|
import org.springblade.core.log.exception.ServiceException; |
|
|
|
|
import org.springblade.core.mp.base.BaseServiceImpl; |
|
|
|
|
import org.springblade.core.secure.BladeUser; |
|
|
|
|
import org.springblade.desk.dashboard.feign.IPartClient; |
|
|
|
|
import org.springblade.desk.dashboard.pojo.entity.DsPartEntity; |
|
|
|
|
import org.springblade.desk.dashboard.pojo.entity.DsPartRelationEntity; |
|
|
|
|
import org.springblade.desk.order.pojo.entity.YieldOrder; |
|
|
|
|
import org.springblade.wms.excel.StGraphiteMoldOutExcel; |
|
|
|
|
import org.springblade.wms.mapper.StGlassCakeOutMapper; |
|
|
|
|
import org.springblade.wms.mapper.StGraphiteMoldOutMapper; |
|
|
|
|
import org.springblade.wms.mapper.StRealtimeStockMapper; |
|
|
|
|
import org.springblade.wms.mapper.StStockInoutRecordMapper; |
|
|
|
|
import org.springblade.wms.pojo.dto.StGraphiteMoldOutDTO; |
|
|
|
|
import org.springblade.wms.pojo.dto.StockOccupyTempDTO; |
|
|
|
|
import org.springblade.wms.pojo.dto.SubItemStockDTO; |
|
|
|
|
import org.springblade.wms.pojo.entity.*; |
|
|
|
|
import org.springblade.wms.pojo.vo.StGraphiteMoldOutVO; |
|
|
|
|
import org.springblade.wms.service.*; |
|
|
|
|
@ -25,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional; |
|
|
|
|
import org.springframework.util.CollectionUtils; |
|
|
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @version 1.0 |
|
|
|
|
@ -52,6 +60,10 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl<StGraphiteMold |
|
|
|
|
IStStorehouseService stStorehouseService; |
|
|
|
|
@Resource |
|
|
|
|
IStStorageLocationService stStorageLocationService; |
|
|
|
|
@Resource |
|
|
|
|
StGlassCakeOutMapper stGlassCakeOutMapper; |
|
|
|
|
@Resource |
|
|
|
|
IPartClient partClient; |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public IPage<StGraphiteMoldOutVO> selectStGraphiteMoldOutPage(IPage<StGraphiteMoldOutVO> page, StGraphiteMoldOutVO stGraphiteMoldOut) { |
|
|
|
|
@ -71,44 +83,108 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl<StGraphiteMold |
|
|
|
|
throw new RuntimeException("根据流程卡号【" + dto.getCardNo() + "】未查询到生产订单信息"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
List<StGraphiteMoldOut> preOutStockList = new ArrayList<>(); |
|
|
|
|
// 整套数量:需要生产多少套
|
|
|
|
|
Double totalNeedSet = faYieldOrder.getYpQty(); |
|
|
|
|
int totalNeedSetInt = Double.valueOf(Math.ceil(totalNeedSet)).intValue(); |
|
|
|
|
|
|
|
|
|
DsPartEntity partOne = partClient.getPart(faYieldOrder.getPartCode(), faYieldOrder.getPartVersion()); |
|
|
|
|
List<DsPartRelationEntity> partRelationEntityList = partClient.getSubPart(partOne.getId()); |
|
|
|
|
List<DsPartEntity> allChildPartList = new ArrayList<>(); |
|
|
|
|
if (!CollectionUtils.isEmpty(partRelationEntityList)) { |
|
|
|
|
// 提取所有非空的childPartId并去重(避免null和重复ID,减少查询压力)
|
|
|
|
|
List<Long> childPartIdList = partRelationEntityList.stream() |
|
|
|
|
.map(DsPartRelationEntity::getChildPartId) // 提取子件ID
|
|
|
|
|
.filter(Objects::nonNull) // 过滤null的ID
|
|
|
|
|
.distinct() // 去重,避免重复查询
|
|
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
|
|
// 批量查询DS_PART表
|
|
|
|
|
if (!CollectionUtils.isEmpty(childPartIdList)) { |
|
|
|
|
// 调用dsPartService的批量查询方法(根据ID列表查DS_PART)
|
|
|
|
|
allChildPartList = partClient.batchParts(childPartIdList); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
List<SubItemStockDTO> sourceSubStockList = new ArrayList<>(); |
|
|
|
|
for (DsPartEntity bom : allChildPartList) { |
|
|
|
|
SubItemStockDTO item = new SubItemStockDTO(); |
|
|
|
|
item.setSubGoodsCode(bom.getPartCode()); |
|
|
|
|
// 单套子件耗用数量
|
|
|
|
|
DsPartRelationEntity dsPartRelation = stGlassCakeOutMapper.getPartQuota(faYieldOrder.getPartCode(), item.getSubGoodsCode()); |
|
|
|
|
item.setSingleUseQty(dsPartRelation.getQuota()); |
|
|
|
|
// 查询该子件所有可用库存
|
|
|
|
|
List<StRealtimeStock> stockAll = stRealtimeStockMapper.selectMaxUsableStockByMoldAttr(item.getSubGoodsCode()); |
|
|
|
|
item.setStockList(stockAll); |
|
|
|
|
// 实时剩余可用总库存(动态变化,逐套消耗)
|
|
|
|
|
double usableTotal = 0D; |
|
|
|
|
if (CollUtil.isNotEmpty(stockAll)) { |
|
|
|
|
usableTotal = stockAll.stream() |
|
|
|
|
.mapToDouble(s -> s.getQuantity() - Optional.ofNullable(s.getOccupyQuantity()).orElse(0D)) |
|
|
|
|
.sum(); |
|
|
|
|
} |
|
|
|
|
item.setRemainUsable(usableTotal); |
|
|
|
|
sourceSubStockList.add(item); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 存放最终要生成的出库明细、占用、锁库数据
|
|
|
|
|
List<StockOccupyTempDTO> needOccupyList = new ArrayList<>(); |
|
|
|
|
// 成功齐套的套数
|
|
|
|
|
int successSet = 0; |
|
|
|
|
|
|
|
|
|
// 2、逐套循环校验,能齐一套算一套
|
|
|
|
|
for (; successSet < totalNeedSetInt; ) { |
|
|
|
|
boolean oneSetAllOk = true; |
|
|
|
|
// 本套需要占用的临时数据
|
|
|
|
|
List<StockOccupyTempDTO> tempOccupy = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
for (SubItemStockDTO sub : sourceSubStockList) { |
|
|
|
|
double needPerSet = sub.getSingleUseQty(); |
|
|
|
|
// 当前子件剩余可用不足单套用量 → 本套不齐套,跳出
|
|
|
|
|
if (sub.getRemainUsable() < needPerSet - 0.001) { |
|
|
|
|
oneSetAllOk = false; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
String goodsCode = faYieldOrder.getPartCode(); |
|
|
|
|
Double requireQty = faYieldOrder.getYpQty(); |
|
|
|
|
System.out.println("石墨模编码:" + goodsCode + ",总需求:" + requireQty); |
|
|
|
|
// 从子件库存里扣对应数量,优先耗前面批次库存
|
|
|
|
|
double surplusNeed = needPerSet; |
|
|
|
|
List<StRealtimeStock> stockList = sub.getStockList(); |
|
|
|
|
for (StRealtimeStock stock : stockList) { |
|
|
|
|
if (surplusNeed <= 0.001) break; |
|
|
|
|
double occ = Optional.ofNullable(stock.getOccupyQuantity()).orElse(0D); |
|
|
|
|
double usable = stock.getQuantity() - occ; |
|
|
|
|
if (usable <= 0) continue; |
|
|
|
|
|
|
|
|
|
List<StRealtimeStock> candidateStockList = new ArrayList<>(); |
|
|
|
|
double totalUsable = 0.0; |
|
|
|
|
List<StRealtimeStock> allUsableStockList = stRealtimeStockMapper.selectMaxUsableStockByMoldAttr(goodsCode); |
|
|
|
|
double takeQty = Math.min(usable, surplusNeed); |
|
|
|
|
// 暂存本次占用信息,齐套成功才真正落库
|
|
|
|
|
StockOccupyTempDTO temp = new StockOccupyTempDTO(); |
|
|
|
|
temp.setStock(stock); |
|
|
|
|
temp.setTakeQty(takeQty); |
|
|
|
|
temp.setSubGoodsCode(sub.getSubGoodsCode()); |
|
|
|
|
tempOccupy.add(temp); |
|
|
|
|
|
|
|
|
|
if (allUsableStockList == null || allUsableStockList.isEmpty()) { |
|
|
|
|
log.info("石墨模【{}】库存不足,无法生成!需求数量:{}", goodsCode, requireQty); |
|
|
|
|
return Collections.emptyList(); |
|
|
|
|
surplusNeed -= takeQty; |
|
|
|
|
} |
|
|
|
|
for (StRealtimeStock stock : allUsableStockList) { |
|
|
|
|
double occupy = Optional.ofNullable(stock.getOccupyQuantity()).orElse(0D); |
|
|
|
|
double usableQty = stock.getQuantity() - occupy; |
|
|
|
|
if (usableQty <= 0) { |
|
|
|
|
continue; |
|
|
|
|
// 子件总可用扣减本套耗用
|
|
|
|
|
sub.setRemainUsable(sub.getRemainUsable() - needPerSet); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidateStockList.add(stock); |
|
|
|
|
totalUsable += usableQty; |
|
|
|
|
|
|
|
|
|
if (totalUsable >= requireQty) { |
|
|
|
|
if (oneSetAllOk) { |
|
|
|
|
// 本套齐套,临时占用转正,加入最终列表
|
|
|
|
|
needOccupyList.addAll(tempOccupy); |
|
|
|
|
successSet++; |
|
|
|
|
} else { |
|
|
|
|
// 任意子件不齐套,终止整套循环,不再尝试后续套数
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// if (totalUsable < requireQty - 0.001) {
|
|
|
|
|
// throw new ServiceException("石墨模【" + goodsCode + "】库存不足,无法生成!需求数量:" + requireQty + ",可用库存:" + totalUsable);
|
|
|
|
|
// }
|
|
|
|
|
if (candidateStockList.isEmpty()) { |
|
|
|
|
log.info("石墨模【{}】库存不足,无法生成!需求数量:{}", goodsCode, requireQty); |
|
|
|
|
if (CollUtil.isEmpty(needOccupyList)) { |
|
|
|
|
log.info("父件{}无任何可齐套库存,需求{}套,生成0套预出库", partOne.getPartCode(), totalNeedSet); |
|
|
|
|
return Collections.emptyList(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
double remainingQty = requireQty; |
|
|
|
|
List<StGraphiteMoldOut> preOutStockList = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
String datePrefix = DateUtil.format(new Date(), "yyyyMMdd"); |
|
|
|
|
// 2. 当天最大序号
|
|
|
|
|
String maxCode = stStockInoutRecordMapper.getMaxCheckCode(datePrefix); |
|
|
|
|
@ -117,23 +193,29 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl<StGraphiteMold |
|
|
|
|
String number = maxCode.substring(datePrefix.length()); |
|
|
|
|
lastNum = Integer.parseInt(number); |
|
|
|
|
} |
|
|
|
|
for (StRealtimeStock maxStock : candidateStockList) { |
|
|
|
|
if (remainingQty <= 0.001) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
int childNum = 1; |
|
|
|
|
|
|
|
|
|
double occupyQty = Optional.ofNullable(maxStock.getOccupyQuantity()).orElse(0D); |
|
|
|
|
double usableQty = maxStock.getQuantity() - occupyQty; |
|
|
|
|
double actualTake = Math.min(usableQty, remainingQty); |
|
|
|
|
// 3、遍历占用明细:更新库存占用、新增锁库、生成预出库单据
|
|
|
|
|
for (StockOccupyTempDTO temp : needOccupyList) { |
|
|
|
|
lastNum++; |
|
|
|
|
StRealtimeStock maxStock = temp.getStock(); |
|
|
|
|
Double takeQty = temp.getTakeQty(); |
|
|
|
|
|
|
|
|
|
StGraphiteMoldOut preOutStock = new StGraphiteMoldOut(); |
|
|
|
|
preOutStock.setYoCode(faYieldOrder.getYoCode()); |
|
|
|
|
preOutStock.setCardNo(dto.getCardNo()); |
|
|
|
|
|
|
|
|
|
String sirCode = datePrefix + StrUtil.padPre(String.valueOf(lastNum), 4, '0'); |
|
|
|
|
preOutStock.setOutCode(sirCode); |
|
|
|
|
String parentOutCode = datePrefix + StrUtil.padPre(String.valueOf(lastNum), 4, '0'); |
|
|
|
|
preOutStock.setParentOutCode(parentOutCode); |
|
|
|
|
String outCode = parentOutCode + "-" + childNum; |
|
|
|
|
preOutStock.setOutCode(outCode); |
|
|
|
|
childNum++; |
|
|
|
|
// preOutStock.setOutCode(stStockInoutRecordService.generateCode());
|
|
|
|
|
preOutStock.setNeedQuantity(requireQty); |
|
|
|
|
SubItemStockDTO currSub = sourceSubStockList.stream() |
|
|
|
|
.filter(s -> s.getSubGoodsCode().equals(temp.getSubGoodsCode())) |
|
|
|
|
.findFirst().get(); |
|
|
|
|
preOutStock.setNeedQuantity(currSub.getSingleUseQty() * totalNeedSet); |
|
|
|
|
preOutStock.setCompleteQuantity(takeQty); |
|
|
|
|
preOutStock.setGoodsId(maxStock.getGoodsId()); |
|
|
|
|
StGoods stGoods = stGoodsService.getById(maxStock.getGoodsId()); |
|
|
|
|
preOutStock.setGoodsName(stGoods.getGoodsName()); |
|
|
|
|
@ -152,22 +234,22 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl<StGraphiteMold |
|
|
|
|
preOutStock.setUpdateTime(now); |
|
|
|
|
|
|
|
|
|
preOutStockList.add(preOutStock); |
|
|
|
|
System.out.println("石墨模[编码:" + goodsCode + "]库存充足,已构建预出库信息,库存ID:" + maxStock.getId()); |
|
|
|
|
System.out.println("石墨模子件[编码:" + preOutStock.getGoodsCode() + "]库存充足,已构建预出库信息,库存ID:" + maxStock.getId()); |
|
|
|
|
|
|
|
|
|
double newOccupy = occupyQty + actualTake; |
|
|
|
|
maxStock.setOccupyQuantity(newOccupy); |
|
|
|
|
// 更新实时库存占用数量
|
|
|
|
|
double oldOccupy = Optional.ofNullable(maxStock.getOccupyQuantity()).orElse(0D); |
|
|
|
|
maxStock.setOccupyQuantity(oldOccupy + takeQty); |
|
|
|
|
stRealtimeStockService.updateById(maxStock); |
|
|
|
|
|
|
|
|
|
StRealtimeStockLock lock = new StRealtimeStockLock(); |
|
|
|
|
lock.setId(IdUtil.getSnowflake().nextId()); |
|
|
|
|
lock.setRlsId(maxStock.getId()); |
|
|
|
|
lock.setWoNo(preOutStock.getCardNo()); |
|
|
|
|
lock.setOccupyQuantity(actualTake); |
|
|
|
|
lock.setOccupyQuantity(takeQty); |
|
|
|
|
lock.setStatus(0); |
|
|
|
|
stRealtimeStockMapper.insertStockLock(lock); |
|
|
|
|
remainingQty -= actualTake; |
|
|
|
|
} |
|
|
|
|
System.out.println("石墨模[编码:" + goodsCode + "] 预出库全部完成!"); |
|
|
|
|
System.out.println("石墨模子件预出库全部完成!"); |
|
|
|
|
|
|
|
|
|
this.saveBatch(preOutStockList); |
|
|
|
|
return preOutStockList; |
|
|
|
|
@ -302,7 +384,7 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl<StGraphiteMold |
|
|
|
|
stockList.add(realtimeStock); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (param.getOutedQuantity() > realtimeStock.getQuantity()) { |
|
|
|
|
if (param.getOutedQuantity() > realtimeStock.getQuantity() - realtimeStock.getOccupyQuantity()) { |
|
|
|
|
throw new ServiceException("流程卡号【"+outEntity.getCardNo()+"】出库数量不能大于库存总数量,库存数量为:" + realtimeStock.getQuantity()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -320,7 +402,7 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl<StGraphiteMold |
|
|
|
|
this.updateById(outEntity); |
|
|
|
|
|
|
|
|
|
StStockInoutRecord inoutRecord = new StStockInoutRecord(); |
|
|
|
|
inoutRecord.setCheckNo(outEntity.getCardNo()); |
|
|
|
|
inoutRecord.setCardNo(outEntity.getCardNo()); |
|
|
|
|
inoutRecord.setSirCode(outEntity.getOutCode()); |
|
|
|
|
inoutRecord.setSlId(outEntity.getSlId()); |
|
|
|
|
inoutRecord.setRlsId(outEntity.getRlsId()); |
|
|
|
|
@ -350,6 +432,14 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl<StGraphiteMold |
|
|
|
|
outEntity.setSirId(inoutRecord.getId()); |
|
|
|
|
this.updateById(outEntity); |
|
|
|
|
resultList.add(outEntity); |
|
|
|
|
|
|
|
|
|
if (outEntity.getOutedQuantity() < outEntity.getCompleteQuantity()) { |
|
|
|
|
Double resOccupyQty = outEntity.getCompleteQuantity() - outEntity.getOutedQuantity(); |
|
|
|
|
realtimeStock.setOccupyQuantity(realtimeStock.getOccupyQuantity() - resOccupyQty); |
|
|
|
|
stRealtimeStockService.updateById(realtimeStock); |
|
|
|
|
|
|
|
|
|
stRealtimeStockMapper.updateRealTimeLock(outEntity.getCardNo(), String.valueOf(realtimeStock.getId()), -resOccupyQty); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!allInoutList.isEmpty() && !stockList.isEmpty()) { |
|
|
|
|
|