|
|
|
|
@ -4,17 +4,37 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPackagingSchemeRespVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockStatisticsRespVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutItemMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.framework.bean.ProductTypeEnum;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
import org.springframework.context.annotation.Lazy;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
import org.springframework.validation.annotation.Validated;
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.time.LocalDate;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
|
|
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE;
|
|
|
|
|
@ -42,6 +62,14 @@ public class ErpStockServiceImpl implements ErpStockService {
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpStockMapper stockMapper;
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpStockInMapper stockInMapper;
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpStockInItemMapper stockInItemMapper;
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpStockOutMapper stockOutMapper;
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpStockOutItemMapper stockOutItemMapper;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public ErpStockDO getStock(Long id) {
|
|
|
|
|
@ -93,6 +121,21 @@ public class ErpStockServiceImpl implements ErpStockService {
|
|
|
|
|
return stockMapper.selectPage(pageReqVO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public ErpStockStatisticsRespVO getStockStatistics() {
|
|
|
|
|
ErpStockStatisticsRespVO respVO = new ErpStockStatisticsRespVO();
|
|
|
|
|
List<ErpStockDO> stockList = stockMapper.selectList(new LambdaQueryWrapper<ErpStockDO>());
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(stockList.stream()
|
|
|
|
|
.map(ErpStockDO::getProductId).collect(Collectors.toSet()));
|
|
|
|
|
fillStockCards(respVO, stockList, productMap);
|
|
|
|
|
|
|
|
|
|
LocalDateTime beginTime = LocalDate.now().atStartOfDay();
|
|
|
|
|
LocalDateTime endTime = beginTime.plusDays(1);
|
|
|
|
|
fillTodayInCard(respVO, beginTime, endTime, productMap);
|
|
|
|
|
fillTodayOutCard(respVO, beginTime, endTime, productMap);
|
|
|
|
|
return respVO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public BigDecimal updateStockCountIncrement(Long categoryId, Long productId, Long warehouseId, Long areaId,
|
|
|
|
|
String areaName, BigDecimal count) {
|
|
|
|
|
@ -140,6 +183,480 @@ public class ErpStockServiceImpl implements ErpStockService {
|
|
|
|
|
return stock.getCount().add(count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillStockCards(ErpStockStatisticsRespVO respVO, List<ErpStockDO> stockList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
List<ErpStockDO> productStockList = filterStockByCategory(stockList, productMap, ProductTypeEnum.ITEM.getTypeId());
|
|
|
|
|
List<ErpStockDO> materialStockList = filterStockByCategory(stockList, productMap, ProductTypeEnum.PRODUCT.getTypeId());
|
|
|
|
|
List<ErpStockDO> sparePartStockList = filterStockByCategory(stockList, productMap, ProductTypeEnum.BEIJIAN.getTypeId());
|
|
|
|
|
|
|
|
|
|
respVO.setProductStock(buildProductStockCard(productStockList, productMap));
|
|
|
|
|
|
|
|
|
|
respVO.setMaterialStock(buildUnitGroupedStockCard(materialStockList));
|
|
|
|
|
respVO.setSparePartStock(buildUnitGroupedStockCard(sparePartStockList));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillTodayInCard(ErpStockStatisticsRespVO respVO, LocalDateTime beginTime, LocalDateTime endTime,
|
|
|
|
|
Map<Long, ErpProductRespVO> stockProductMap) {
|
|
|
|
|
ErpStockStatisticsRespVO.TodayInCard todayInCard = new ErpStockStatisticsRespVO.TodayInCard();
|
|
|
|
|
List<ErpStockInDO> stockInList = stockInMapper.selectList(new LambdaQueryWrapper<ErpStockInDO>()
|
|
|
|
|
.eq(ErpStockInDO::getStatus, ErpAuditStatus.APPROVE.getStatus())
|
|
|
|
|
.between(ErpStockInDO::getInTime, beginTime, endTime));
|
|
|
|
|
List<Long> stockInIds = stockInList.stream().map(ErpStockInDO::getId).collect(Collectors.toList());
|
|
|
|
|
List<ErpStockInItemDO> itemList = stockInIds.isEmpty() ? Collections.emptyList()
|
|
|
|
|
: stockInItemMapper.selectListByInIds(stockInIds);
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap = buildProductMap(itemList.stream()
|
|
|
|
|
.map(ErpStockInItemDO::getProductId).collect(Collectors.toSet()), stockProductMap);
|
|
|
|
|
|
|
|
|
|
todayInCard.setOrderCount((long) stockInIds.size());
|
|
|
|
|
todayInCard.setItemCount((long) itemList.size());
|
|
|
|
|
todayInCard.setProductStock(buildInItemProductStockCard(filterInItemByCategory(itemList, productMap, ProductTypeEnum.ITEM.getTypeId()), productMap));
|
|
|
|
|
todayInCard.setMaterialStock(buildInItemUnitGroupedStockCard(filterInItemByCategory(itemList, productMap, ProductTypeEnum.PRODUCT.getTypeId()), productMap));
|
|
|
|
|
todayInCard.setSparePartStock(buildInItemUnitGroupedStockCard(filterInItemByCategory(itemList, productMap, ProductTypeEnum.BEIJIAN.getTypeId()), productMap));
|
|
|
|
|
respVO.setTodayIn(todayInCard);
|
|
|
|
|
respVO.getProductStock().setTodayFinishedInDisplay(todayInCard.getProductStock().getStockDisplay());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillTodayOutCard(ErpStockStatisticsRespVO respVO, LocalDateTime beginTime, LocalDateTime endTime,
|
|
|
|
|
Map<Long, ErpProductRespVO> stockProductMap) {
|
|
|
|
|
ErpStockStatisticsRespVO.TodayOutCard todayOutCard = new ErpStockStatisticsRespVO.TodayOutCard();
|
|
|
|
|
List<ErpStockOutDO> stockOutList = stockOutMapper.selectList(new LambdaQueryWrapper<ErpStockOutDO>()
|
|
|
|
|
.eq(ErpStockOutDO::getStatus, ErpAuditStatus.APPROVE.getStatus())
|
|
|
|
|
.between(ErpStockOutDO::getOutTime, beginTime, endTime));
|
|
|
|
|
List<Long> stockOutIds = stockOutList.stream().map(ErpStockOutDO::getId).collect(Collectors.toList());
|
|
|
|
|
List<ErpStockOutItemDO> itemList = stockOutIds.isEmpty() ? Collections.emptyList()
|
|
|
|
|
: stockOutItemMapper.selectListByOutIds(stockOutIds);
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap = buildProductMap(itemList.stream()
|
|
|
|
|
.map(ErpStockOutItemDO::getProductId).collect(Collectors.toSet()), stockProductMap);
|
|
|
|
|
|
|
|
|
|
todayOutCard.setOrderCount((long) stockOutIds.size());
|
|
|
|
|
todayOutCard.setItemCount((long) itemList.size());
|
|
|
|
|
todayOutCard.setProductStock(buildOutItemProductStockCard(filterOutItemByCategory(itemList, productMap, ProductTypeEnum.ITEM.getTypeId()), productMap));
|
|
|
|
|
todayOutCard.setMaterialStock(buildOutItemUnitGroupedStockCard(filterOutItemByCategory(itemList, productMap, ProductTypeEnum.PRODUCT.getTypeId()), productMap));
|
|
|
|
|
todayOutCard.setSparePartStock(buildOutItemUnitGroupedStockCard(filterOutItemByCategory(itemList, productMap, ProductTypeEnum.BEIJIAN.getTypeId()), productMap));
|
|
|
|
|
respVO.setTodayOut(todayOutCard);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Map<Long, ErpProductRespVO> buildProductMap(Set<Long> productIds, Map<Long, ErpProductRespVO> stockProductMap) {
|
|
|
|
|
Set<Long> missingProductIds = new HashSet<>(productIds);
|
|
|
|
|
missingProductIds.removeAll(stockProductMap.keySet());
|
|
|
|
|
if (missingProductIds.isEmpty()) {
|
|
|
|
|
return stockProductMap;
|
|
|
|
|
}
|
|
|
|
|
Map<Long, ErpProductRespVO> resultMap = productService.getProductVOMap(productIds);
|
|
|
|
|
resultMap.putAll(stockProductMap);
|
|
|
|
|
return resultMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<ErpStockDO> filterStockByCategory(List<ErpStockDO> stockList, Map<Long, ErpProductRespVO> productMap,
|
|
|
|
|
Integer categoryType) {
|
|
|
|
|
return stockList.stream()
|
|
|
|
|
.filter(stock -> categoryType.equals(resolveCategoryType(stock, productMap)))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<ErpStockInItemDO> filterInItemByCategory(List<ErpStockInItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap,
|
|
|
|
|
Integer categoryType) {
|
|
|
|
|
return itemList.stream()
|
|
|
|
|
.filter(item -> categoryType.equals(resolveCategoryType(item.getProductId(), productMap)))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<ErpStockOutItemDO> filterOutItemByCategory(List<ErpStockOutItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap,
|
|
|
|
|
Integer categoryType) {
|
|
|
|
|
return itemList.stream()
|
|
|
|
|
.filter(item -> categoryType.equals(resolveCategoryType(item.getProductId(), productMap)))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.UnitGroupedStockCard buildUnitGroupedStockCard(List<ErpStockDO> stockList) {
|
|
|
|
|
ErpStockStatisticsRespVO.UnitGroupedStockCard card = new ErpStockStatisticsRespVO.UnitGroupedStockCard();
|
|
|
|
|
card.setSkuCount(countDistinctProduct(stockList));
|
|
|
|
|
List<ErpStockStatisticsRespVO.UnitStock> unitStocks = stockList.stream()
|
|
|
|
|
.collect(Collectors.groupingBy(stock -> buildUnitKey(stock.getUnitId(), stock.getUnitName())))
|
|
|
|
|
.values().stream()
|
|
|
|
|
.map(this::buildUnitStock)
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
card.setUnitStocks(unitStocks);
|
|
|
|
|
card.setStockDisplay(unitStocks.stream()
|
|
|
|
|
.map(ErpStockStatisticsRespVO.UnitStock::getStockDisplay)
|
|
|
|
|
.collect(Collectors.joining(" / ")));
|
|
|
|
|
return card;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.UnitStock buildUnitStock(List<ErpStockDO> stockList) {
|
|
|
|
|
ErpStockDO firstStock = stockList.get(0);
|
|
|
|
|
BigDecimal count = stockList.stream().map(stock -> defaultZero(stock.getCount()))
|
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
return buildUnitStock(firstStock.getUnitId(), firstStock.getUnitName(), count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.ProductStockCard buildProductStockCard(List<ErpStockDO> stockList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockStatisticsRespVO.ProductStockCard card = new ErpStockStatisticsRespVO.ProductStockCard();
|
|
|
|
|
BigDecimal totalCount = sumStockCount(stockList);
|
|
|
|
|
String unitName = resolveStockUnitName(stockList, productMap);
|
|
|
|
|
card.setSkuCount(countDistinctProduct(stockList));
|
|
|
|
|
card.setTotalCount(totalCount);
|
|
|
|
|
card.setUnitName(unitName);
|
|
|
|
|
card.setStockDisplay(formatNumber(totalCount) + nullToEmpty(unitName));
|
|
|
|
|
card.setPackagingStocks(buildStockPackagingStocks(stockList, productMap));
|
|
|
|
|
card.setTodayFinishedInDisplay(formatNumber(BigDecimal.ZERO) + nullToEmpty(unitName));
|
|
|
|
|
return card;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.ProductStockCard buildInItemProductStockCard(List<ErpStockInItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockStatisticsRespVO.ProductStockCard card = new ErpStockStatisticsRespVO.ProductStockCard();
|
|
|
|
|
BigDecimal totalCount = sumInItemCount(itemList);
|
|
|
|
|
String unitName = resolveInItemUnitName(itemList, productMap);
|
|
|
|
|
card.setSkuCount(itemList.stream().map(ErpStockInItemDO::getProductId).distinct().count());
|
|
|
|
|
card.setTotalCount(totalCount);
|
|
|
|
|
card.setUnitName(unitName);
|
|
|
|
|
card.setStockDisplay(formatNumber(totalCount) + nullToEmpty(unitName));
|
|
|
|
|
card.setPackagingStocks(buildInItemPackagingStocks(itemList, productMap));
|
|
|
|
|
return card;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.ProductStockCard buildOutItemProductStockCard(List<ErpStockOutItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockStatisticsRespVO.ProductStockCard card = new ErpStockStatisticsRespVO.ProductStockCard();
|
|
|
|
|
BigDecimal totalCount = sumOutItemCount(itemList);
|
|
|
|
|
String unitName = resolveOutItemUnitName(itemList, productMap);
|
|
|
|
|
card.setSkuCount(itemList.stream().map(ErpStockOutItemDO::getProductId).distinct().count());
|
|
|
|
|
card.setTotalCount(totalCount);
|
|
|
|
|
card.setUnitName(unitName);
|
|
|
|
|
card.setStockDisplay(formatNumber(totalCount) + nullToEmpty(unitName));
|
|
|
|
|
card.setPackagingStocks(buildOutItemPackagingStocks(itemList, productMap));
|
|
|
|
|
return card;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildUnitKey(Long unitId, String unitName) {
|
|
|
|
|
return String.valueOf(unitId) + "_" + String.valueOf(unitName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.UnitGroupedStockCard buildInItemUnitGroupedStockCard(List<ErpStockInItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockStatisticsRespVO.UnitGroupedStockCard card = new ErpStockStatisticsRespVO.UnitGroupedStockCard();
|
|
|
|
|
card.setSkuCount(itemList.stream().map(ErpStockInItemDO::getProductId).distinct().count());
|
|
|
|
|
List<ErpStockStatisticsRespVO.UnitStock> unitStocks = itemList.stream()
|
|
|
|
|
.collect(Collectors.groupingBy(item -> buildInItemUnitKey(item, productMap)))
|
|
|
|
|
.values().stream()
|
|
|
|
|
.map(items -> buildInItemUnitStock(items, productMap))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
card.setUnitStocks(unitStocks);
|
|
|
|
|
card.setStockDisplay(unitStocks.stream()
|
|
|
|
|
.map(ErpStockStatisticsRespVO.UnitStock::getStockDisplay)
|
|
|
|
|
.collect(Collectors.joining(" / ")));
|
|
|
|
|
return card;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.UnitGroupedStockCard buildOutItemUnitGroupedStockCard(List<ErpStockOutItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockStatisticsRespVO.UnitGroupedStockCard card = new ErpStockStatisticsRespVO.UnitGroupedStockCard();
|
|
|
|
|
card.setSkuCount(itemList.stream().map(ErpStockOutItemDO::getProductId).distinct().count());
|
|
|
|
|
List<ErpStockStatisticsRespVO.UnitStock> unitStocks = itemList.stream()
|
|
|
|
|
.collect(Collectors.groupingBy(item -> buildOutItemUnitKey(item, productMap)))
|
|
|
|
|
.values().stream()
|
|
|
|
|
.map(items -> buildOutItemUnitStock(items, productMap))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
card.setUnitStocks(unitStocks);
|
|
|
|
|
card.setStockDisplay(unitStocks.stream()
|
|
|
|
|
.map(ErpStockStatisticsRespVO.UnitStock::getStockDisplay)
|
|
|
|
|
.collect(Collectors.joining(" / ")));
|
|
|
|
|
return card;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.UnitStock buildInItemUnitStock(List<ErpStockInItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockInItemDO firstItem = itemList.get(0);
|
|
|
|
|
BigDecimal count = itemList.stream().map(item -> defaultZero(item.getCount()))
|
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
return buildUnitStock(resolveInItemUnitId(firstItem, productMap), resolveInItemUnitName(firstItem, productMap), count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.UnitStock buildOutItemUnitStock(List<ErpStockOutItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockOutItemDO firstItem = itemList.get(0);
|
|
|
|
|
BigDecimal count = itemList.stream().map(item -> defaultZero(item.getCount()))
|
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
return buildUnitStock(resolveOutItemUnitId(firstItem, productMap), resolveOutItemUnitName(firstItem, productMap), count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.UnitStock buildUnitStock(Long unitId, String unitName, BigDecimal count) {
|
|
|
|
|
ErpStockStatisticsRespVO.UnitStock unitStock = new ErpStockStatisticsRespVO.UnitStock();
|
|
|
|
|
unitStock.setUnitId(unitId);
|
|
|
|
|
unitStock.setUnitName(unitName);
|
|
|
|
|
unitStock.setCount(count);
|
|
|
|
|
unitStock.setStockDisplay(formatNumber(count) + nullToEmpty(unitName));
|
|
|
|
|
return unitStock;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildInItemUnitKey(ErpStockInItemDO item, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
return buildUnitKey(resolveInItemUnitId(item, productMap), resolveInItemUnitName(item, productMap));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildOutItemUnitKey(ErpStockOutItemDO item, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
return buildUnitKey(resolveOutItemUnitId(item, productMap), resolveOutItemUnitName(item, productMap));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Long resolveInItemUnitId(ErpStockInItemDO item, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
if (item.getProductUnitId() != null) {
|
|
|
|
|
return item.getProductUnitId();
|
|
|
|
|
}
|
|
|
|
|
ErpProductRespVO product = productMap.get(item.getProductId());
|
|
|
|
|
return product != null ? product.getUnitId() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveInItemUnitName(ErpStockInItemDO item, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
if (item.getProductUnitName() != null) {
|
|
|
|
|
return item.getProductUnitName();
|
|
|
|
|
}
|
|
|
|
|
return resolveCurrentProductUnitName(item.getProductId(), item.getProductUnitId(), productMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Long resolveOutItemUnitId(ErpStockOutItemDO item, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
if (item.getProductUnitId() != null) {
|
|
|
|
|
return item.getProductUnitId();
|
|
|
|
|
}
|
|
|
|
|
ErpProductRespVO product = productMap.get(item.getProductId());
|
|
|
|
|
return product != null ? product.getUnitId() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveOutItemUnitName(ErpStockOutItemDO item, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
if (item.getProductUnitName() != null) {
|
|
|
|
|
return item.getProductUnitName();
|
|
|
|
|
}
|
|
|
|
|
return resolveCurrentProductUnitName(item.getProductId(), item.getProductUnitId(), productMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveCurrentProductUnitName(Long productId, Long unitId, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpProductRespVO product = productMap.get(productId);
|
|
|
|
|
if (product == null || (unitId != null && !Objects.equals(unitId, product.getUnitId()))) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return product.getUnitName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<ErpStockStatisticsRespVO.ProductPackagingStock> buildStockPackagingStocks(List<ErpStockDO> stockList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
return stockList.stream()
|
|
|
|
|
.collect(Collectors.groupingBy(this::buildStockPackagingKey))
|
|
|
|
|
.values().stream()
|
|
|
|
|
.map(items -> buildStockPackagingStock(items, productMap))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.ProductPackagingStock buildStockPackagingStock(List<ErpStockDO> stockList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockDO firstStock = stockList.get(0);
|
|
|
|
|
BigDecimal totalCount = sumStockCount(stockList);
|
|
|
|
|
String unitName = firstStock.getUnitName();
|
|
|
|
|
ErpStockStatisticsRespVO.ProductPackagingStock detail = buildProductPackagingStock(
|
|
|
|
|
firstStock.getProductId(), resolveProductName(firstStock.getProductId(), productMap),
|
|
|
|
|
firstStock.getDefaultPackagingSchemeId(), firstStock.getDefaultPackagingSchemeName(),
|
|
|
|
|
totalCount, unitName, firstStock.getPackageQuantity(), firstStock.getPalletPackageQuantity(),
|
|
|
|
|
firstStock.getPalletTotalQuantity());
|
|
|
|
|
return detail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<ErpStockStatisticsRespVO.ProductPackagingStock> buildInItemPackagingStocks(List<ErpStockInItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
return itemList.stream()
|
|
|
|
|
.collect(Collectors.groupingBy(this::buildInItemPackagingKey))
|
|
|
|
|
.values().stream()
|
|
|
|
|
.map(items -> buildInItemPackagingStock(items, productMap))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.ProductPackagingStock buildInItemPackagingStock(List<ErpStockInItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockInItemDO firstItem = itemList.get(0);
|
|
|
|
|
BigDecimal totalCount = sumInItemCount(itemList);
|
|
|
|
|
return buildProductPackagingStock(firstItem.getProductId(), resolveProductName(firstItem.getProductId(), productMap),
|
|
|
|
|
firstItem.getPackagingSchemeId(), firstItem.getPackagingSchemeName(), totalCount,
|
|
|
|
|
resolveInItemUnitName(firstItem, productMap), firstItem.getPackageQuantity(),
|
|
|
|
|
firstItem.getPalletPackageQuantity(), firstItem.getPalletTotalQuantity());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<ErpStockStatisticsRespVO.ProductPackagingStock> buildOutItemPackagingStocks(List<ErpStockOutItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
return itemList.stream()
|
|
|
|
|
.collect(Collectors.groupingBy(this::buildOutItemPackagingKey))
|
|
|
|
|
.values().stream()
|
|
|
|
|
.map(items -> buildOutItemPackagingStock(items, productMap))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.ProductPackagingStock buildOutItemPackagingStock(List<ErpStockOutItemDO> itemList,
|
|
|
|
|
Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpStockOutItemDO firstItem = itemList.get(0);
|
|
|
|
|
BigDecimal totalCount = sumOutItemCount(itemList);
|
|
|
|
|
return buildProductPackagingStock(firstItem.getProductId(), resolveProductName(firstItem.getProductId(), productMap),
|
|
|
|
|
firstItem.getPackagingSchemeId(), firstItem.getPackagingSchemeName(), totalCount,
|
|
|
|
|
resolveOutItemUnitName(firstItem, productMap), firstItem.getPackageQuantity(),
|
|
|
|
|
firstItem.getPalletPackageQuantity(), firstItem.getPalletTotalQuantity());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ErpStockStatisticsRespVO.ProductPackagingStock buildProductPackagingStock(Long productId, String productName,
|
|
|
|
|
Long packagingSchemeId, String packagingSchemeName,
|
|
|
|
|
BigDecimal totalCount, String unitName,
|
|
|
|
|
BigDecimal packageQuantity,
|
|
|
|
|
BigDecimal palletPackageQuantity,
|
|
|
|
|
BigDecimal palletTotalQuantity) {
|
|
|
|
|
ErpStockStatisticsRespVO.ProductPackagingStock detail = new ErpStockStatisticsRespVO.ProductPackagingStock();
|
|
|
|
|
detail.setProductId(productId);
|
|
|
|
|
detail.setProductName(productName);
|
|
|
|
|
detail.setPackagingSchemeId(packagingSchemeId);
|
|
|
|
|
detail.setPackagingSchemeName(packagingSchemeName);
|
|
|
|
|
detail.setTotalCount(totalCount);
|
|
|
|
|
detail.setUnitName(unitName);
|
|
|
|
|
detail.setStockDisplay(formatNumber(totalCount) + nullToEmpty(unitName));
|
|
|
|
|
detail.setPackagingDisplay(formatProductQuantity(calculateProductQuantity(totalCount, palletTotalQuantity, packageQuantity)));
|
|
|
|
|
detail.setPackageQuantity(packageQuantity);
|
|
|
|
|
detail.setPalletPackageQuantity(palletPackageQuantity);
|
|
|
|
|
detail.setPalletTotalQuantity(palletTotalQuantity);
|
|
|
|
|
return detail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildStockPackagingKey(ErpStockDO stock) {
|
|
|
|
|
return buildProductPackagingKey(stock.getProductId(), stock.getDefaultPackagingSchemeId(), stock.getPackageQuantity(),
|
|
|
|
|
stock.getPalletPackageQuantity(), stock.getPalletTotalQuantity(), stock.getUnitId(), stock.getUnitName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildInItemPackagingKey(ErpStockInItemDO item) {
|
|
|
|
|
return buildProductPackagingKey(item.getProductId(), item.getPackagingSchemeId(), item.getPackageQuantity(),
|
|
|
|
|
item.getPalletPackageQuantity(), item.getPalletTotalQuantity(), item.getProductUnitId(), item.getProductUnitName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildOutItemPackagingKey(ErpStockOutItemDO item) {
|
|
|
|
|
return buildProductPackagingKey(item.getProductId(), item.getPackagingSchemeId(), item.getPackageQuantity(),
|
|
|
|
|
item.getPalletPackageQuantity(), item.getPalletTotalQuantity(), item.getProductUnitId(), item.getProductUnitName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildProductPackagingKey(Long productId, Long packagingSchemeId, BigDecimal packageQuantity,
|
|
|
|
|
BigDecimal palletPackageQuantity, BigDecimal palletTotalQuantity,
|
|
|
|
|
Long unitId, String unitName) {
|
|
|
|
|
return String.valueOf(productId) + "_" + String.valueOf(packagingSchemeId) + "_"
|
|
|
|
|
+ String.valueOf(packageQuantity) + "_" + String.valueOf(palletPackageQuantity) + "_"
|
|
|
|
|
+ String.valueOf(palletTotalQuantity) + "_" + buildUnitKey(unitId, unitName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BigDecimal sumStockCount(List<ErpStockDO> stockList) {
|
|
|
|
|
return stockList.stream().map(stock -> defaultZero(stock.getCount()))
|
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BigDecimal sumInItemCount(List<ErpStockInItemDO> itemList) {
|
|
|
|
|
return itemList.stream().map(item -> defaultZero(item.getCount()))
|
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BigDecimal sumOutItemCount(List<ErpStockOutItemDO> itemList) {
|
|
|
|
|
return itemList.stream().map(item -> defaultZero(item.getCount()))
|
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveStockUnitName(List<ErpStockDO> stockList, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
return stockList.stream().map(ErpStockDO::getUnitName).filter(Objects::nonNull).findFirst()
|
|
|
|
|
.orElseGet(() -> stockList.stream().map(stock -> resolveCurrentProductUnitName(stock.getProductId(), stock.getUnitId(), productMap))
|
|
|
|
|
.filter(Objects::nonNull).findFirst().orElse(null));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveInItemUnitName(List<ErpStockInItemDO> itemList, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
return itemList.stream().map(item -> resolveInItemUnitName(item, productMap)).filter(Objects::nonNull).findFirst().orElse(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveOutItemUnitName(List<ErpStockOutItemDO> itemList, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
return itemList.stream().map(item -> resolveOutItemUnitName(item, productMap)).filter(Objects::nonNull).findFirst().orElse(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveProductName(Long productId, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpProductRespVO product = productMap.get(productId);
|
|
|
|
|
return product != null ? product.getName() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Integer resolveCategoryType(ErpStockDO stock, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
if (stock.getCategoryType() != null) {
|
|
|
|
|
return stock.getCategoryType();
|
|
|
|
|
}
|
|
|
|
|
return resolveCategoryType(stock.getProductId(), productMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Integer resolveCategoryType(Long productId, Map<Long, ErpProductRespVO> productMap) {
|
|
|
|
|
ErpProductRespVO product = productMap.get(productId);
|
|
|
|
|
return product != null ? product.getCategoryType() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Long countDistinctProduct(List<ErpStockDO> stockList) {
|
|
|
|
|
return stockList.stream().map(ErpStockDO::getProductId).distinct().count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String formatProductStockDisplay(List<ErpStockDO> stockList) {
|
|
|
|
|
BigDecimal palletCount = BigDecimal.ZERO;
|
|
|
|
|
BigDecimal packageCount = BigDecimal.ZERO;
|
|
|
|
|
BigDecimal pieceCount = BigDecimal.ZERO;
|
|
|
|
|
for (ErpStockDO stock : stockList) {
|
|
|
|
|
ProductQuantity quantity = calculateProductQuantity(stock.getCount(), stock.getPalletTotalQuantity(), stock.getPackageQuantity());
|
|
|
|
|
palletCount = palletCount.add(quantity.getPalletCount());
|
|
|
|
|
packageCount = packageCount.add(quantity.getPackageCount());
|
|
|
|
|
pieceCount = pieceCount.add(quantity.getPieceCount());
|
|
|
|
|
}
|
|
|
|
|
return formatProductQuantity(palletCount, packageCount, pieceCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ProductQuantity calculateProductQuantity(BigDecimal count, BigDecimal palletTotalQuantity, BigDecimal packageQuantity) {
|
|
|
|
|
BigDecimal safeCount = defaultZero(count);
|
|
|
|
|
BigDecimal palletCount = BigDecimal.ZERO;
|
|
|
|
|
BigDecimal packageCount = BigDecimal.ZERO;
|
|
|
|
|
BigDecimal pieceCount = safeCount;
|
|
|
|
|
if (palletTotalQuantity != null && palletTotalQuantity.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
|
|
palletCount = safeCount.divideToIntegralValue(palletTotalQuantity);
|
|
|
|
|
pieceCount = safeCount.remainder(palletTotalQuantity);
|
|
|
|
|
}
|
|
|
|
|
if (packageQuantity != null && packageQuantity.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
|
|
packageCount = pieceCount.divideToIntegralValue(packageQuantity);
|
|
|
|
|
pieceCount = pieceCount.remainder(packageQuantity);
|
|
|
|
|
}
|
|
|
|
|
return new ProductQuantity(palletCount, packageCount, pieceCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String formatProductQuantity(BigDecimal palletCount, BigDecimal packageCount, BigDecimal pieceCount) {
|
|
|
|
|
StringBuilder display = new StringBuilder();
|
|
|
|
|
appendDisplay(display, palletCount, "托", false);
|
|
|
|
|
appendDisplay(display, packageCount, "包", false);
|
|
|
|
|
appendDisplay(display, pieceCount, "个", display.length() == 0);
|
|
|
|
|
return display.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String formatProductQuantity(ProductQuantity quantity) {
|
|
|
|
|
return formatProductQuantity(quantity.getPalletCount(), quantity.getPackageCount(), quantity.getPieceCount());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void appendDisplay(StringBuilder display, BigDecimal quantity, String unitName, boolean keepZero) {
|
|
|
|
|
if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
|
|
if (!keepZero) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
display.append("0").append(unitName);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
display.append(formatNumber(quantity)).append(unitName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BigDecimal defaultZero(BigDecimal value) {
|
|
|
|
|
return value != null ? value : BigDecimal.ZERO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String nullToEmpty(String value) {
|
|
|
|
|
return value != null ? value : "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String formatNumber(BigDecimal value) {
|
|
|
|
|
return value == null ? "0" : value.stripTrailingZeros().toPlainString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillStockSnapshot(ErpStockDO stock, ErpProductRespVO product,
|
|
|
|
|
ProductPackagingSchemeRespVO defaultPackagingScheme) {
|
|
|
|
|
if (product == null) {
|
|
|
|
|
@ -196,4 +713,16 @@ public class ErpStockServiceImpl implements ErpStockService {
|
|
|
|
|
.setPalletTotalQuantity(stock.getPalletTotalQuantity());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@lombok.Data
|
|
|
|
|
@lombok.AllArgsConstructor
|
|
|
|
|
private static class ProductQuantity {
|
|
|
|
|
|
|
|
|
|
private BigDecimal palletCount;
|
|
|
|
|
|
|
|
|
|
private BigDecimal packageCount;
|
|
|
|
|
|
|
|
|
|
private BigDecimal pieceCount;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|