|
|
@@ -1,16 +1,33 @@
|
|
|
package cn.iocoder.yudao.module.pms.service.iotprodinventoryaging;
|
|
|
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import cn.hutool.core.util.ObjUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
|
+import cn.iocoder.yudao.module.pms.controller.admin.iotprodinventoryaging.vo.IotInventoryAgingStatisticsRespVO;
|
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotprodinventoryaging.vo.IotProdInventoryAgingPageReqVO;
|
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotprodinventoryaging.vo.IotProdInventoryAgingSaveReqVO;
|
|
|
import cn.iocoder.yudao.module.pms.dal.dataobject.iotprodinventoryaging.IotProdInventoryAgingDO;
|
|
|
import cn.iocoder.yudao.module.pms.dal.mysql.iotprodinventoryaging.IotProdInventoryAgingMapper;
|
|
|
+import cn.iocoder.yudao.module.system.api.saporg.SapOrgApi;
|
|
|
+import cn.iocoder.yudao.module.system.api.saporg.dto.SapOrgRespDTO;
|
|
|
+import cn.iocoder.yudao.module.system.controller.admin.saporg.vo.SapOrgSimpleReqVO;
|
|
|
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
|
|
|
+import cn.iocoder.yudao.module.system.dal.dataobject.saporg.SapOrgDO;
|
|
|
+import cn.iocoder.yudao.module.system.service.dept.DeptService;
|
|
|
+import cn.iocoder.yudao.module.system.service.saporg.SapOrgService;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.validation.annotation.Validated;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.*;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_PROD_INVENTORY_AGING_NOT_EXISTS;
|
|
|
|
|
|
@@ -25,6 +42,12 @@ public class IotProdInventoryAgingServiceImpl implements IotProdInventoryAgingSe
|
|
|
|
|
|
@Resource
|
|
|
private IotProdInventoryAgingMapper iotProdInventoryAgingMapper;
|
|
|
+ @Autowired
|
|
|
+ private SapOrgApi sapOrgApi;
|
|
|
+ @Autowired
|
|
|
+ private DeptService deptService;
|
|
|
+ @Autowired
|
|
|
+ private SapOrgService sapOrgService;
|
|
|
|
|
|
@Override
|
|
|
public Long createIotProdInventoryAging(IotProdInventoryAgingSaveReqVO createReqVO) {
|
|
|
@@ -68,4 +91,177 @@ public class IotProdInventoryAgingServiceImpl implements IotProdInventoryAgingSe
|
|
|
return iotProdInventoryAgingMapper.selectPage(pageReqVO);
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public IotInventoryAgingStatisticsRespVO inventoryStatus(IotProdInventoryAgingPageReqVO pageReqVO) {
|
|
|
+ // 库龄数据量大 必须选择日期
|
|
|
+ if (StrUtil.isBlank(pageReqVO.getFdate())) {
|
|
|
+ throw exception(IOT_PROD_INVENTORY_AGING_NOT_EXISTS);
|
|
|
+ }
|
|
|
+ String deptIdStr = pageReqVO.getDept();
|
|
|
+ if (StrUtil.isBlank(deptIdStr)) {
|
|
|
+ throw exception(IOT_PROD_INVENTORY_AGING_NOT_EXISTS);
|
|
|
+ }
|
|
|
+ IotInventoryAgingStatisticsRespVO result = new IotInventoryAgingStatisticsRespVO();
|
|
|
+ // 查询当前公司对应的 库存地点 标识 名称 按照各库存地点统计 存货及积压金额
|
|
|
+ Long deptId = Long.valueOf(deptIdStr);
|
|
|
+ DeptDO dept = deptService.getDept(deptId);
|
|
|
+ Set<Long> factoryIds = dept.getFactoryIds();
|
|
|
+ List<SapOrgRespDTO> sapOrganizations = sapOrgApi.getSapOrgList(factoryIds);
|
|
|
+ if (CollUtil.isEmpty(sapOrganizations)) {
|
|
|
+ throw exception(IOT_PROD_INVENTORY_AGING_NOT_EXISTS);
|
|
|
+ }
|
|
|
+ // key工厂编码 value工厂名称
|
|
|
+ Map<String, String> factoryPair = new HashMap<>();
|
|
|
+ sapOrganizations.forEach(org -> {
|
|
|
+ factoryPair.put(org.getFactoryCode(), org.getFactoryName());
|
|
|
+ });
|
|
|
+ // 需要查询库龄的工厂
|
|
|
+ List<String> factoryCodes = sapOrganizations.stream()
|
|
|
+ .filter(dto -> "age".equals(dto.getCreator()))
|
|
|
+ .map(SapOrgRespDTO::getFactoryCode)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ // 查询工厂下所有库存地点信息
|
|
|
+ // key工厂编辑-库存地点编码 value库存地点名称
|
|
|
+ Map<String, String> storageLocationPair = new HashMap<>();
|
|
|
+ SapOrgSimpleReqVO reqVO = new SapOrgSimpleReqVO();
|
|
|
+ reqVO.setType(3);
|
|
|
+ reqVO.setFactoryCodes(factoryCodes);
|
|
|
+ List<SapOrgDO> storageLocations = sapOrgService.getSelectedList(reqVO);
|
|
|
+ if (CollUtil.isNotEmpty(storageLocations)) {
|
|
|
+ storageLocations.forEach(location -> {
|
|
|
+ String factoryCode = location.getFactoryCode();
|
|
|
+ String storageLocationCode = location.getStorageLocationCode();
|
|
|
+ String uniqueKey = StrUtil.join("-", factoryCode, storageLocationCode);
|
|
|
+ storageLocationPair.put(uniqueKey, location.getStorageLocationName());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 查询帆软数仓中的库龄数据
|
|
|
+ List<IotProdInventoryAgingDO> stockAges = iotProdInventoryAgingMapper.InventoryAges(pageReqVO);
|
|
|
+ if (CollUtil.isEmpty(stockAges)) {
|
|
|
+ throw exception(IOT_PROD_INVENTORY_AGING_NOT_EXISTS);
|
|
|
+ }
|
|
|
+ // 总库存
|
|
|
+ BigDecimal amtSummary = stockAges.stream()
|
|
|
+ .map(IotProdInventoryAgingDO::getAmttotal)
|
|
|
+ // null值转为0
|
|
|
+ .map(val -> ObjUtil.isEmpty(val) ? BigDecimal.ZERO : val)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ // 1年以内的库存总额
|
|
|
+ BigDecimal amtSummaryOneYear = stockAges.stream()
|
|
|
+ .map(IotProdInventoryAgingDO::getAmt1)
|
|
|
+ // null值转为0
|
|
|
+ .map(val -> ObjUtil.isEmpty(val) ? BigDecimal.ZERO : val)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ // 按工厂‑库存地点分组
|
|
|
+ Map<String, List<IotProdInventoryAgingDO>> groupMap = stockAges.stream()
|
|
|
+ .collect(Collectors.groupingBy(age -> StrUtil.join("-", age.getWerks(), age.getLgort())));
|
|
|
+ // 按工厂‑库存地点分组
|
|
|
+ Map<String, List<IotProdInventoryAgingDO>> facotryGroupMap = stockAges.stream()
|
|
|
+ .collect(Collectors.groupingBy(age -> age.getWerks()));
|
|
|
+
|
|
|
+ // 积压库存 = 总库存 - 1年以内的库存总额
|
|
|
+ BigDecimal overstockInventory = amtSummary.subtract(amtSummaryOneYear);
|
|
|
+
|
|
|
+ // 各工厂的总库存 key工厂编码 value
|
|
|
+ Map<String, BigDecimal> factoryInventoryPair = new HashMap<>();
|
|
|
+ // 各工厂的积压库存 key工厂编码
|
|
|
+ Map<String, BigDecimal> factoryOverStockPair = new HashMap<>();
|
|
|
+ // 各工厂的总库存 key工厂编码 value
|
|
|
+ Map<String, BigDecimal> factoryNameInventoryPair = new HashMap<>();
|
|
|
+ // 各工厂的积压库存 key工厂编码
|
|
|
+ Map<String, BigDecimal> factoryNameOverStockPair = new HashMap<>();
|
|
|
+
|
|
|
+ // 循环分组统计总库存、积压库存 按照库存地点统计
|
|
|
+ facotryGroupMap.forEach((factoryCode, ages) -> {
|
|
|
+ BigDecimal sumTotal = ages.stream()
|
|
|
+ .map(IotProdInventoryAgingDO::getAmttotal)
|
|
|
+ .map(val -> ObjUtil.isEmpty(val) ? BigDecimal.ZERO : val)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+
|
|
|
+ BigDecimal sumOneYear = ages.stream()
|
|
|
+ .map(IotProdInventoryAgingDO::getAmt1)
|
|
|
+ .map(val -> ObjUtil.isEmpty(val) ? BigDecimal.ZERO : val)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+
|
|
|
+ BigDecimal sumOverStock = sumTotal.subtract(sumOneYear);
|
|
|
+
|
|
|
+ factoryInventoryPair.put(factoryCode, sumTotal);
|
|
|
+ factoryOverStockPair.put(factoryCode, sumOverStock);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成 storageNameInventoryPair
|
|
|
+ factoryNameInventoryPair = factoryInventoryPair.entrySet().stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ e -> factoryPair.getOrDefault(e.getKey(), "未知"),
|
|
|
+ Map.Entry::getValue,
|
|
|
+ (v1, v2) -> v1 // 若键冲突(例如多个“未知”),保留第一个值
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 生成 storageNameOverStockPair
|
|
|
+ factoryNameOverStockPair = factoryOverStockPair.entrySet().stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ e -> factoryPair.getOrDefault(e.getKey(), "未知"),
|
|
|
+ Map.Entry::getValue,
|
|
|
+ (v1, v2) -> v1
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 各库存地点的总库存 key工厂编码-库存地点编码 value
|
|
|
+ Map<String, BigDecimal> storageInventoryPair = new HashMap<>();
|
|
|
+ // 各库存地点的积压库存 key工厂编码-库存地点编码
|
|
|
+ Map<String, BigDecimal> storageOverStockPair = new HashMap<>();
|
|
|
+ // 循环分组统计总库存、积压库存 按照库存地点统计
|
|
|
+ groupMap.forEach((uniqueKey, list) -> {
|
|
|
+ BigDecimal sumTotal = list.stream()
|
|
|
+ .map(IotProdInventoryAgingDO::getAmttotal)
|
|
|
+ .map(val -> ObjUtil.isEmpty(val) ? BigDecimal.ZERO : val)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+
|
|
|
+ BigDecimal sumOneYear = list.stream()
|
|
|
+ .map(IotProdInventoryAgingDO::getAmt1)
|
|
|
+ .map(val -> ObjUtil.isEmpty(val) ? BigDecimal.ZERO : val)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+
|
|
|
+ BigDecimal sumOverStock = sumTotal.subtract(sumOneYear);
|
|
|
+
|
|
|
+ storageInventoryPair.put(uniqueKey, sumTotal);
|
|
|
+ storageOverStockPair.put(uniqueKey, sumOverStock);
|
|
|
+ });
|
|
|
+ // 各库存地点的总库存 key工厂编码-库存地点名称 value
|
|
|
+ Map<String, BigDecimal> storageNameInventoryPair = new HashMap<>();
|
|
|
+ // 各库存地点的积压库存 key工厂编辑-库存地点编码
|
|
|
+ Map<String, BigDecimal> storageNameOverStockPair = new HashMap<>();
|
|
|
+ Function<String, String> keyMapper = uniqueKey -> {
|
|
|
+ String locationName = storageLocationPair.get(uniqueKey);
|
|
|
+ if (StrUtil.isBlank(locationName)) {
|
|
|
+ return "未知";
|
|
|
+ }
|
|
|
+ String factoryCode = StrUtil.subBefore(uniqueKey, "-", false);
|
|
|
+ return StrUtil.join("-", factoryCode, locationName);
|
|
|
+ };
|
|
|
+ // 生成 storageNameInventoryPair
|
|
|
+ storageNameInventoryPair = storageInventoryPair.entrySet().stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ e -> keyMapper.apply(e.getKey()),
|
|
|
+ Map.Entry::getValue,
|
|
|
+ (v1, v2) -> v1 // 若键冲突(例如多个“未知”),保留第一个值
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 生成 storageNameOverStockPair
|
|
|
+ storageNameOverStockPair = storageOverStockPair.entrySet().stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ e -> keyMapper.apply(e.getKey()),
|
|
|
+ Map.Entry::getValue,
|
|
|
+ (v1, v2) -> v1
|
|
|
+ ));
|
|
|
+ result.setTotalInventory(amtSummary);
|
|
|
+ result.setTotalOverStock(overstockInventory);
|
|
|
+
|
|
|
+ result.setFactoryNameInventoryPair(factoryNameInventoryPair);
|
|
|
+ result.setFactoryNameOverStockPair(factoryNameOverStockPair);
|
|
|
+
|
|
|
+ result.setStorageNameInventoryPair(storageInventoryPair);
|
|
|
+ result.setStorageNameOverStockPair(storageOverStockPair);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
}
|