fix:修改盘点执行相关接口及添加库存总览接口
parent
48e624ace6
commit
e3d1dac817
@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.erp.enums.stock;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum ErpStockCheckSourceTypeEnum implements IntArrayValuable {
|
||||
|
||||
BY_LOCATION(1, "按库存"),
|
||||
BY_PRODUCT(2, "按产品");
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpStockCheckSourceTypeEnum::getType).toArray();
|
||||
|
||||
private final Integer type;
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - ERP 仓库总览 Response VO")
|
||||
@Data
|
||||
public class ErpWarehouseSummaryRespVO {
|
||||
|
||||
@Schema(description = "仓库编号", example = "1")
|
||||
private Long warehouseId;
|
||||
|
||||
@Schema(description = "仓库名称", example = "A仓")
|
||||
private String warehouseName;
|
||||
|
||||
@Schema(description = "产品库存量", example = "1000")
|
||||
private BigDecimal productStockCount;
|
||||
|
||||
@Schema(description = "产品库存展示", example = "2托3包4个")
|
||||
private String productStockDisplay;
|
||||
|
||||
@Schema(description = "物料库存量", example = "1000")
|
||||
private BigDecimal materialStockCount;
|
||||
|
||||
@Schema(description = "物料库存展示", example = "10采购单位20库存单位")
|
||||
private String materialStockDisplay;
|
||||
|
||||
@Schema(description = "备件库存量", example = "1000")
|
||||
private BigDecimal sparePartStockCount;
|
||||
|
||||
@Schema(description = "备件库存展示", example = "10采购单位20库存单位")
|
||||
private String sparePartStockDisplay;
|
||||
|
||||
@Schema(description = "今日入库单数量", example = "5")
|
||||
private Long todayStockInOrderCount;
|
||||
|
||||
@Schema(description = "今日入库明细行数量", example = "18")
|
||||
private Long todayStockInItemCount;
|
||||
|
||||
@Schema(description = "今日入库产成品展示", example = "2托3包4个")
|
||||
private String todayProductStockInDisplay;
|
||||
|
||||
@Schema(description = "今日入库物料展示", example = "100个")
|
||||
private String todayMaterialStockInDisplay;
|
||||
|
||||
@Schema(description = "今日入库备件展示", example = "100个")
|
||||
private String todaySparePartStockInDisplay;
|
||||
|
||||
@Schema(description = "今日出库单数量", example = "3")
|
||||
private Long todayStockOutOrderCount;
|
||||
|
||||
@Schema(description = "今日出库明细行数量", example = "10")
|
||||
private Long todayStockOutItemCount;
|
||||
|
||||
@Schema(description = "今日出库产成品展示", example = "2托3包4个")
|
||||
private String todayProductStockOutDisplay;
|
||||
|
||||
@Schema(description = "今日出库物料展示", example = "100个")
|
||||
private String todayMaterialStockOutDisplay;
|
||||
|
||||
@Schema(description = "今日出库备件展示", example = "100个")
|
||||
private String todaySparePartStockOutDisplay;
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package cn.iocoder.yudao.module.erp.service.stock;
|
||||
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSummaryRespVO;
|
||||
|
||||
public interface ErpWarehouseSummaryService {
|
||||
|
||||
ErpWarehouseSummaryRespVO getWarehouseSummary(Long warehouseId);
|
||||
|
||||
}
|
||||
@ -0,0 +1,261 @@
|
||||
package cn.iocoder.yudao.module.erp.service.stock;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSummaryRespVO;
|
||||
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
|
||||
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.dataobject.stock.ErpWarehouseDO;
|
||||
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.service.product.ErpProductService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
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.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Validated
|
||||
public class ErpWarehouseSummaryServiceImpl implements ErpWarehouseSummaryService {
|
||||
|
||||
@Resource
|
||||
private ErpWarehouseService warehouseService;
|
||||
@Resource
|
||||
private ErpStockMapper stockMapper;
|
||||
@Resource
|
||||
private ErpStockInMapper stockInMapper;
|
||||
@Resource
|
||||
private ErpStockInItemMapper stockInItemMapper;
|
||||
@Resource
|
||||
private ErpStockOutMapper stockOutMapper;
|
||||
@Resource
|
||||
private ErpStockOutItemMapper stockOutItemMapper;
|
||||
@Resource
|
||||
private ErpProductService productService;
|
||||
|
||||
@Override
|
||||
public ErpWarehouseSummaryRespVO getWarehouseSummary(Long warehouseId) {
|
||||
ErpWarehouseDO warehouse = warehouseService.getWarehouse(warehouseId);
|
||||
ErpWarehouseSummaryRespVO respVO = new ErpWarehouseSummaryRespVO();
|
||||
respVO.setWarehouseId(warehouseId);
|
||||
respVO.setWarehouseName(warehouse != null ? warehouse.getName() : null);
|
||||
|
||||
List<ErpStockDO> stockList = stockMapper.selectListByWarehouseIdsAndAreaIds(Collections.singletonList(warehouseId), null);
|
||||
fillStockSummary(respVO, stockList);
|
||||
|
||||
LocalDateTime beginTime = LocalDate.now().atStartOfDay();
|
||||
LocalDateTime endTime = beginTime.plusDays(1);
|
||||
fillTodayInSummary(respVO, warehouseId, beginTime, endTime);
|
||||
fillTodayOutSummary(respVO, warehouseId, beginTime, endTime);
|
||||
return respVO;
|
||||
}
|
||||
|
||||
private void fillStockSummary(ErpWarehouseSummaryRespVO respVO, List<ErpStockDO> stockList) {
|
||||
if (CollUtil.isEmpty(stockList)) {
|
||||
respVO.setProductStockCount(BigDecimal.ZERO);
|
||||
respVO.setMaterialStockCount(BigDecimal.ZERO);
|
||||
respVO.setSparePartStockCount(BigDecimal.ZERO);
|
||||
respVO.setProductStockDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null));
|
||||
respVO.setMaterialStockDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
|
||||
respVO.setSparePartStockDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, List<ErpStockDO>> categoryMap = stockList.stream().collect(Collectors.groupingBy(this::resolveCategoryType));
|
||||
BigDecimal productCount = sumCount(categoryMap.get(1));
|
||||
BigDecimal materialCount = sumCount(categoryMap.get(2));
|
||||
BigDecimal sparePartCount = sumCount(categoryMap.get(3));
|
||||
|
||||
respVO.setProductStockCount(productCount);
|
||||
respVO.setMaterialStockCount(materialCount);
|
||||
respVO.setSparePartStockCount(sparePartCount);
|
||||
|
||||
ErpStockDO productStock = firstStock(categoryMap.get(1));
|
||||
ErpStockDO materialStock = firstStock(categoryMap.get(2));
|
||||
ErpStockDO sparePartStock = firstStock(categoryMap.get(3));
|
||||
respVO.setProductStockDisplay(formatProductDisplay(productCount,
|
||||
productStock != null ? productStock.getPalletTotalQuantity() : null,
|
||||
productStock != null ? productStock.getPalletPackageQuantity() : null,
|
||||
productStock != null ? productStock.getPackageQuantity() : null));
|
||||
respVO.setMaterialStockDisplay(formatUnitDisplay(materialCount,
|
||||
materialStock != null ? materialStock.getPurchaseUnitConvertQuantity() : null,
|
||||
materialStock != null ? materialStock.getPurchaseUnitName() : null,
|
||||
materialStock != null ? materialStock.getUnitName() : null));
|
||||
respVO.setSparePartStockDisplay(formatUnitDisplay(sparePartCount,
|
||||
sparePartStock != null ? sparePartStock.getPurchaseUnitConvertQuantity() : null,
|
||||
sparePartStock != null ? sparePartStock.getPurchaseUnitName() : null,
|
||||
sparePartStock != null ? sparePartStock.getUnitName() : null));
|
||||
}
|
||||
|
||||
private void fillTodayInSummary(ErpWarehouseSummaryRespVO respVO, Long warehouseId, LocalDateTime beginTime, LocalDateTime endTime) {
|
||||
List<ErpStockInDO> stockInList = stockInMapper.selectList(new LambdaQueryWrapper<ErpStockInDO>()
|
||||
.eq(ErpStockInDO::getStatus, 20)
|
||||
.between(ErpStockInDO::getInTime, beginTime, endTime));
|
||||
List<Long> inIds = stockInList.stream()
|
||||
.filter(stockIn -> hasWarehouseIn(stockIn.getId(), warehouseId))
|
||||
.map(ErpStockInDO::getId)
|
||||
.collect(Collectors.toList());
|
||||
respVO.setTodayStockInOrderCount((long) inIds.size());
|
||||
|
||||
List<ErpStockInItemDO> itemList = stockInItemMapper.selectListByInIds(inIds);
|
||||
respVO.setTodayStockInItemCount((long) itemList.size());
|
||||
fillInOutDisplay(respVO, true, itemList);
|
||||
}
|
||||
|
||||
private void fillTodayOutSummary(ErpWarehouseSummaryRespVO respVO, Long warehouseId, LocalDateTime beginTime, LocalDateTime endTime) {
|
||||
List<ErpStockOutDO> stockOutList = stockOutMapper.selectList(new LambdaQueryWrapper<ErpStockOutDO>()
|
||||
.eq(ErpStockOutDO::getStatus, 20)
|
||||
.between(ErpStockOutDO::getOutTime, beginTime, endTime));
|
||||
List<Long> outIds = stockOutList.stream()
|
||||
.filter(stockOut -> hasWarehouseOut(stockOut.getId(), warehouseId))
|
||||
.map(ErpStockOutDO::getId)
|
||||
.collect(Collectors.toList());
|
||||
respVO.setTodayStockOutOrderCount((long) outIds.size());
|
||||
|
||||
List<ErpStockOutItemDO> itemList = stockOutItemMapper.selectListByOutIds(outIds);
|
||||
respVO.setTodayStockOutItemCount((long) itemList.size());
|
||||
fillInOutDisplay(respVO, false, itemList);
|
||||
}
|
||||
|
||||
private void fillInOutDisplay(ErpWarehouseSummaryRespVO respVO, boolean inbound, List<?> itemList) {
|
||||
if (CollUtil.isEmpty(itemList)) {
|
||||
if (inbound) {
|
||||
respVO.setTodayProductStockInDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null));
|
||||
respVO.setTodayMaterialStockInDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
|
||||
respVO.setTodaySparePartStockInDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
|
||||
} else {
|
||||
respVO.setTodayProductStockOutDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null));
|
||||
respVO.setTodayMaterialStockOutDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
|
||||
respVO.setTodaySparePartStockOutDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Set<Long> productIds = itemList.stream()
|
||||
.map(item -> item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getProductId() : ((ErpStockOutItemDO) item).getProductId())
|
||||
.collect(Collectors.toSet());
|
||||
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(productIds);
|
||||
|
||||
BigDecimal productCount = BigDecimal.ZERO;
|
||||
BigDecimal materialCount = BigDecimal.ZERO;
|
||||
BigDecimal sparePartCount = BigDecimal.ZERO;
|
||||
|
||||
for (Object item : itemList) {
|
||||
Long productId = item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getProductId() : ((ErpStockOutItemDO) item).getProductId();
|
||||
BigDecimal count = item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getCount() : ((ErpStockOutItemDO) item).getCount();
|
||||
ErpProductRespVO product = productMap.get(productId);
|
||||
Integer categoryType = product != null ? product.getCategoryType() : null;
|
||||
if (Integer.valueOf(1).equals(categoryType)) {
|
||||
productCount = productCount.add(safeCount(count));
|
||||
} else if (Integer.valueOf(2).equals(categoryType)) {
|
||||
materialCount = materialCount.add(safeCount(count));
|
||||
} else if (Integer.valueOf(3).equals(categoryType)) {
|
||||
sparePartCount = sparePartCount.add(safeCount(count));
|
||||
}
|
||||
}
|
||||
|
||||
if (inbound) {
|
||||
respVO.setTodayProductStockInDisplay(formatProductDisplay(productCount, null, null, null));
|
||||
respVO.setTodayMaterialStockInDisplay(formatUnitDisplay(materialCount, null, null, null));
|
||||
respVO.setTodaySparePartStockInDisplay(formatUnitDisplay(sparePartCount, null, null, null));
|
||||
} else {
|
||||
respVO.setTodayProductStockOutDisplay(formatProductDisplay(productCount, null, null, null));
|
||||
respVO.setTodayMaterialStockOutDisplay(formatUnitDisplay(materialCount, null, null, null));
|
||||
respVO.setTodaySparePartStockOutDisplay(formatUnitDisplay(sparePartCount, null, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasWarehouseIn(Long inId, Long warehouseId) {
|
||||
return stockInItemMapper.selectListByInId(inId).stream().anyMatch(item -> warehouseId.equals(item.getWarehouseId()));
|
||||
}
|
||||
|
||||
private boolean hasWarehouseOut(Long outId, Long warehouseId) {
|
||||
return stockOutItemMapper.selectListByOutId(outId).stream().anyMatch(item -> warehouseId.equals(item.getWarehouseId()));
|
||||
}
|
||||
|
||||
private Integer resolveCategoryType(ErpStockDO stock) {
|
||||
if (stock.getCategoryType() != null) {
|
||||
return stock.getCategoryType();
|
||||
}
|
||||
ErpProductRespVO product = productService.getProductVOMap(Collections.singleton(stock.getProductId())).get(stock.getProductId());
|
||||
return product != null ? product.getCategoryType() : null;
|
||||
}
|
||||
|
||||
private ErpStockDO firstStock(List<ErpStockDO> list) {
|
||||
return CollUtil.isEmpty(list) ? null : list.get(0);
|
||||
}
|
||||
|
||||
private BigDecimal sumCount(List<ErpStockDO> list) {
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal total = BigDecimal.ZERO;
|
||||
for (ErpStockDO stock : list) {
|
||||
total = total.add(safeCount(stock.getCount()));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private BigDecimal safeCount(BigDecimal count) {
|
||||
return count == null ? BigDecimal.ZERO : count;
|
||||
}
|
||||
|
||||
private String formatProductDisplay(BigDecimal count, BigDecimal palletTotalQuantity, BigDecimal palletPackageQuantity,
|
||||
BigDecimal packageQuantity) {
|
||||
BigDecimal safeCount = safeCount(count);
|
||||
if (palletTotalQuantity == null || palletTotalQuantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return formatNumber(safeCount) + "个";
|
||||
}
|
||||
BigDecimal palletCount = safeCount.divideToIntegralValue(palletTotalQuantity);
|
||||
BigDecimal remainAfterPallet = safeCount.remainder(palletTotalQuantity);
|
||||
if (palletPackageQuantity == null || palletPackageQuantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return formatNumber(palletCount) + "托" + formatNumber(remainAfterPallet) + "个";
|
||||
}
|
||||
BigDecimal packageCount = remainAfterPallet.divideToIntegralValue(palletPackageQuantity);
|
||||
BigDecimal remainAfterPackage = remainAfterPallet.remainder(palletPackageQuantity);
|
||||
if (packageQuantity == null || packageQuantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return formatNumber(palletCount) + "托" + formatNumber(packageCount) + "包" + formatNumber(remainAfterPackage) + "个";
|
||||
}
|
||||
BigDecimal unitCount = remainAfterPackage.divideToIntegralValue(packageQuantity);
|
||||
return formatNumber(palletCount) + "托" + formatNumber(packageCount) + "包" + formatNumber(unitCount) + "个";
|
||||
}
|
||||
|
||||
private String formatUnitDisplay(BigDecimal count, BigDecimal purchaseUnitConvertQuantity, String purchaseUnitName, String unitName) {
|
||||
BigDecimal safeCount = safeCount(count);
|
||||
if (purchaseUnitConvertQuantity == null || purchaseUnitConvertQuantity.compareTo(BigDecimal.ZERO) <= 0
|
||||
|| purchaseUnitName == null || unitName == null) {
|
||||
return formatNumber(safeCount) + (unitName != null ? unitName : "个");
|
||||
}
|
||||
BigDecimal purchaseCount = safeCount.divideToIntegralValue(purchaseUnitConvertQuantity);
|
||||
BigDecimal unitCount = safeCount.remainder(purchaseUnitConvertQuantity);
|
||||
StringBuilder display = new StringBuilder();
|
||||
if (purchaseCount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
display.append(formatNumber(purchaseCount)).append(purchaseUnitName);
|
||||
}
|
||||
if (unitCount.compareTo(BigDecimal.ZERO) > 0 || display.length() == 0) {
|
||||
display.append(formatNumber(unitCount)).append(unitName);
|
||||
}
|
||||
return display.toString();
|
||||
}
|
||||
|
||||
private String formatNumber(BigDecimal value) {
|
||||
return value == null ? "0" : value.stripTrailingZeros().toPlainString();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue