diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java index 3c0c69df0..334ab92e9 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java @@ -356,8 +356,8 @@ public class ErpStockController { if (stock.getUnitName() == null || stock.getPurchaseUnitName() == null || stock.getPurchaseUnitConvertQuantity() == null) { return null; } - return "1" + stock.getUnitName() + "=" + formatNumber(stock.getPurchaseUnitConvertQuantity()) - + stock.getPurchaseUnitName(); + return "1" + stock.getPurchaseUnitName() + "=" + formatNumber(stock.getPurchaseUnitConvertQuantity()) + + stock.getUnitName(); } private String buildStockDisplay(ErpStockRespVO stock) { @@ -383,12 +383,12 @@ public class ErpStockController { private String buildPurchaseUnitDisplay(ErpStockRespVO stock, BigDecimal count) { if (stock.getPurchaseUnitConvertQuantity() == null || stock.getPurchaseUnitConvertQuantity().compareTo(BigDecimal.ZERO) <= 0 || stock.getUnitName() == null || stock.getPurchaseUnitName() == null) { - return formatNumber(count) + nullToEmpty(stock.getPurchaseUnitName()); + return formatNumber(count) + nullToEmpty(stock.getUnitName()); } - BigDecimal unitCount = defaultZero(count).divideToIntegralValue(stock.getPurchaseUnitConvertQuantity()); - BigDecimal purchaseUnitCount = defaultZero(count).remainder(stock.getPurchaseUnitConvertQuantity()); - return formatNumber(unitCount) + stock.getUnitName() - + formatNumber(purchaseUnitCount) + stock.getPurchaseUnitName(); + BigDecimal purchaseUnitCount = defaultZero(count).divideToIntegralValue(stock.getPurchaseUnitConvertQuantity()); + BigDecimal unitCount = defaultZero(count).remainder(stock.getPurchaseUnitConvertQuantity()); + return formatNumber(purchaseUnitCount) + stock.getPurchaseUnitName() + + formatNumber(unitCount) + stock.getUnitName(); } private void appendQuantity(StringBuilder display, BigDecimal quantity, String unitName, boolean keepZero) { diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java index 789bac398..1524b65d6 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java @@ -315,7 +315,9 @@ public class ErpStockInController { item.setPallets(buildStockInPalletRespList(itemPalletMap.get(item.getId()), palletMap)); MapUtils.findAndThen(productMap, item.getProductId(), product -> { item.setProductBarCode(product.getBarCode()); - item.setProductUnitName(product.getUnitName()); + if (StringUtils.isBlank(item.getProductUnitName())) { + item.setProductUnitName(product.getUnitName()); + } item.setCategoryType(product.getCategoryType()); if (item.getSupplierId() == null) { item.setSupplierId(product.getDefaultSupplierId()); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java index e51995f0b..6d7104710 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java @@ -329,7 +329,9 @@ public class ErpStockOutController { item.setPallets(buildStockOutPalletRespList(itemPalletMap.get(item.getId()), palletMap)); MapUtils.findAndThen(productMap, item.getProductId(), product -> { item.setProductBarCode(product.getBarCode()); - item.setProductUnitName(product.getUnitName()); + if (StringUtils.isBlank(item.getProductUnitName())) { + item.setProductUnitName(product.getUnitName()); + } item.setCategoryType(product.getCategoryType()); item.setSupplierId(product.getDefaultSupplierId()); if (product.getDefaultSupplierId() != null && CollUtil.isNotEmpty(product.getSuppliers())) { diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockStatisticsRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockStatisticsRespVO.java index 36be1bfc7..801e6afde 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockStatisticsRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockStatisticsRespVO.java @@ -36,9 +36,42 @@ public class ErpStockStatisticsRespVO { private String stockDisplay; @Schema(description = "今日完工入库", example = "12托8包") + private BigDecimal totalCount; + + private String unitName; + + private List packagingStocks; + private String todayFinishedInDisplay; } + @Schema(description = "产成品包装方案库存明细") + @Data + public static class ProductPackagingStock { + + private Long productId; + + private String productName; + + private Long packagingSchemeId; + + private String packagingSchemeName; + + private BigDecimal totalCount; + + private String unitName; + + private String stockDisplay; + + private String packagingDisplay; + + private BigDecimal packageQuantity; + + private BigDecimal palletPackageQuantity; + + private BigDecimal palletTotalQuantity; + } + @Schema(description = "按单位分组库存卡片") @Data public static class UnitGroupedStockCard { @@ -81,7 +114,7 @@ public class ErpStockStatisticsRespVO { private Long itemCount; @Schema(description = "产品品入库") - private UnitGroupedStockCard productStock; + private ProductStockCard productStock; @Schema(description = "原材料入库") private UnitGroupedStockCard materialStock; @@ -107,7 +140,7 @@ public class ErpStockStatisticsRespVO { private UnitGroupedStockCard sparePartStock; @Schema(description = "产品品发货") - private UnitGroupedStockCard productStock; + private ProductStockCard productStock; } } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java index 32c59fbf4..9973c9a36 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java @@ -70,6 +70,10 @@ public class ErpStockInItemDO extends BaseDO { * 冗余 {@link ErpProductDO#getUnitId()} */ private Long productUnitId; + /** + * 产品单位名称快照 + */ + private String productUnitName; /** * 产品单价 */ diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java index e207772c3..c5f6721e8 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java @@ -101,6 +101,10 @@ public class ErpStockOutItemDO extends BaseDO { * 冗余 {@link ErpProductDO#getUnitId()} */ private Long productUnitId; + /** + * 产品单位名称快照 + */ + private String productUnitName; /** * 产品单价 */ diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 8f1bf3710..7f6719120 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -556,6 +556,7 @@ public class ErpStockInServiceImpl implements ErpStockInService { .setProductName(productMap.get(target.getProductId()).getName()) .setSupplierName(resolveStockInItemSupplierName(item, supplierMap, inType)) .setProductUnitId(productMap.get(target.getProductId()).getUnitId()) + .setProductUnitName(productMap.get(target.getProductId()).getUnitName()) .setTotalPrice(MoneyUtils.priceMultiply(target.getProductPrice(), target.getCount())))); } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java index 17d80ffca..e268924bd 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java @@ -640,6 +640,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { .setAreaName(areaMap.containsKey(target.getAreaId()) ? areaMap.get(target.getAreaId()).getAreaName() : null) .setProductName(productMap.get(target.getProductId()).getName()) .setProductUnitId(productMap.get(target.getProductId()).getUnitId()) + .setProductUnitName(productMap.get(target.getProductId()).getUnitName()) .setTotalPrice(MoneyUtils.priceMultiply(target.getProductPrice(), target.getCount())) .setOutUsageType(item.getOutUsageType()) .setOutUsageTypeName(ErpStockOutUsageTypeEnum.getNameByType(item.getOutUsageType())) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java index d15042b41..e9718beb2 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java @@ -32,6 +32,7 @@ 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; @@ -184,16 +185,11 @@ public class ErpStockServiceImpl implements ErpStockService { private void fillStockCards(ErpStockStatisticsRespVO respVO, List stockList, Map productMap) { - ErpStockStatisticsRespVO.ProductStockCard productStockCard = new ErpStockStatisticsRespVO.ProductStockCard(); - List productStockList = filterStockByCategory(stockList, productMap, ProductTypeEnum.ITEM.getTypeId()); List materialStockList = filterStockByCategory(stockList, productMap, ProductTypeEnum.PRODUCT.getTypeId()); List sparePartStockList = filterStockByCategory(stockList, productMap, ProductTypeEnum.BEIJIAN.getTypeId()); - productStockCard.setSkuCount(countDistinctProduct(productStockList)); - productStockCard.setStockDisplay(formatProductStockDisplay(productStockList)); - productStockCard.setTodayFinishedInDisplay(formatProductStockDisplay(Collections.emptyList())); - respVO.setProductStock(productStockCard); + respVO.setProductStock(buildProductStockCard(productStockList, productMap)); respVO.setMaterialStock(buildUnitGroupedStockCard(materialStockList)); respVO.setSparePartStock(buildUnitGroupedStockCard(sparePartStockList)); @@ -213,7 +209,7 @@ public class ErpStockServiceImpl implements ErpStockService { todayInCard.setOrderCount((long) stockInIds.size()); todayInCard.setItemCount((long) itemList.size()); - todayInCard.setProductStock(buildInItemUnitGroupedStockCard(filterInItemByCategory(itemList, productMap, ProductTypeEnum.ITEM.getTypeId()), productMap)); + 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); @@ -234,7 +230,7 @@ public class ErpStockServiceImpl implements ErpStockService { todayOutCard.setOrderCount((long) stockOutIds.size()); todayOutCard.setItemCount((long) itemList.size()); - todayOutCard.setProductStock(buildOutItemUnitGroupedStockCard(filterOutItemByCategory(itemList, productMap, ProductTypeEnum.ITEM.getTypeId()), productMap)); + 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); @@ -296,6 +292,46 @@ public class ErpStockServiceImpl implements ErpStockService { return buildUnitStock(firstStock.getUnitId(), firstStock.getUnitName(), count); } + private ErpStockStatisticsRespVO.ProductStockCard buildProductStockCard(List stockList, + Map 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 itemList, + Map 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 itemList, + Map 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); } @@ -305,7 +341,7 @@ public class ErpStockServiceImpl implements ErpStockService { ErpStockStatisticsRespVO.UnitGroupedStockCard card = new ErpStockStatisticsRespVO.UnitGroupedStockCard(); card.setSkuCount(itemList.stream().map(ErpStockInItemDO::getProductId).distinct().count()); List unitStocks = itemList.stream() - .collect(Collectors.groupingBy(item -> buildProductUnitKey(item.getProductId(), productMap))) + .collect(Collectors.groupingBy(item -> buildInItemUnitKey(item, productMap))) .values().stream() .map(items -> buildInItemUnitStock(items, productMap)) .collect(Collectors.toList()); @@ -321,7 +357,7 @@ public class ErpStockServiceImpl implements ErpStockService { ErpStockStatisticsRespVO.UnitGroupedStockCard card = new ErpStockStatisticsRespVO.UnitGroupedStockCard(); card.setSkuCount(itemList.stream().map(ErpStockOutItemDO::getProductId).distinct().count()); List unitStocks = itemList.stream() - .collect(Collectors.groupingBy(item -> buildProductUnitKey(item.getProductId(), productMap))) + .collect(Collectors.groupingBy(item -> buildOutItemUnitKey(item, productMap))) .values().stream() .map(items -> buildOutItemUnitStock(items, productMap)) .collect(Collectors.toList()); @@ -335,21 +371,17 @@ public class ErpStockServiceImpl implements ErpStockService { private ErpStockStatisticsRespVO.UnitStock buildInItemUnitStock(List itemList, Map productMap) { ErpStockInItemDO firstItem = itemList.get(0); - ErpProductRespVO product = productMap.get(firstItem.getProductId()); BigDecimal count = itemList.stream().map(item -> defaultZero(item.getCount())) .reduce(BigDecimal.ZERO, BigDecimal::add); - return buildUnitStock(product != null ? product.getUnitId() : null, - product != null ? product.getUnitName() : null, count); + return buildUnitStock(resolveInItemUnitId(firstItem, productMap), resolveInItemUnitName(firstItem, productMap), count); } private ErpStockStatisticsRespVO.UnitStock buildOutItemUnitStock(List itemList, Map productMap) { ErpStockOutItemDO firstItem = itemList.get(0); - ErpProductRespVO product = productMap.get(firstItem.getProductId()); BigDecimal count = itemList.stream().map(item -> defaultZero(item.getCount())) .reduce(BigDecimal.ZERO, BigDecimal::add); - return buildUnitStock(product != null ? product.getUnitId() : null, - product != null ? product.getUnitName() : null, count); + return buildUnitStock(resolveOutItemUnitId(firstItem, productMap), resolveOutItemUnitName(firstItem, productMap), count); } private ErpStockStatisticsRespVO.UnitStock buildUnitStock(Long unitId, String unitName, BigDecimal count) { @@ -361,9 +393,188 @@ public class ErpStockServiceImpl implements ErpStockService { return unitStock; } - private String buildProductUnitKey(Long productId, Map productMap) { + private String buildInItemUnitKey(ErpStockInItemDO item, Map productMap) { + return buildUnitKey(resolveInItemUnitId(item, productMap), resolveInItemUnitName(item, productMap)); + } + + private String buildOutItemUnitKey(ErpStockOutItemDO item, Map productMap) { + return buildUnitKey(resolveOutItemUnitId(item, productMap), resolveOutItemUnitName(item, productMap)); + } + + private Long resolveInItemUnitId(ErpStockInItemDO item, Map 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 productMap) { + if (item.getProductUnitName() != null) { + return item.getProductUnitName(); + } + return resolveCurrentProductUnitName(item.getProductId(), item.getProductUnitId(), productMap); + } + + private Long resolveOutItemUnitId(ErpStockOutItemDO item, Map 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 productMap) { + if (item.getProductUnitName() != null) { + return item.getProductUnitName(); + } + return resolveCurrentProductUnitName(item.getProductId(), item.getProductUnitId(), productMap); + } + + private String resolveCurrentProductUnitName(Long productId, Long unitId, Map productMap) { ErpProductRespVO product = productMap.get(productId); - return product != null ? buildUnitKey(product.getUnitId(), product.getUnitName()) : buildUnitKey(null, null); + if (product == null || (unitId != null && !Objects.equals(unitId, product.getUnitId()))) { + return null; + } + return product.getUnitName(); + } + + private List buildStockPackagingStocks(List stockList, + Map productMap) { + return stockList.stream() + .collect(Collectors.groupingBy(this::buildStockPackagingKey)) + .values().stream() + .map(items -> buildStockPackagingStock(items, productMap)) + .collect(Collectors.toList()); + } + + private ErpStockStatisticsRespVO.ProductPackagingStock buildStockPackagingStock(List stockList, + Map 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 buildInItemPackagingStocks(List itemList, + Map productMap) { + return itemList.stream() + .collect(Collectors.groupingBy(this::buildInItemPackagingKey)) + .values().stream() + .map(items -> buildInItemPackagingStock(items, productMap)) + .collect(Collectors.toList()); + } + + private ErpStockStatisticsRespVO.ProductPackagingStock buildInItemPackagingStock(List itemList, + Map 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 buildOutItemPackagingStocks(List itemList, + Map productMap) { + return itemList.stream() + .collect(Collectors.groupingBy(this::buildOutItemPackagingKey)) + .values().stream() + .map(items -> buildOutItemPackagingStock(items, productMap)) + .collect(Collectors.toList()); + } + + private ErpStockStatisticsRespVO.ProductPackagingStock buildOutItemPackagingStock(List itemList, + Map 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 stockList) { + return stockList.stream().map(stock -> defaultZero(stock.getCount())) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + private BigDecimal sumInItemCount(List itemList) { + return itemList.stream().map(item -> defaultZero(item.getCount())) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + private BigDecimal sumOutItemCount(List itemList) { + return itemList.stream().map(item -> defaultZero(item.getCount())) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + private String resolveStockUnitName(List stockList, Map 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 itemList, Map productMap) { + return itemList.stream().map(item -> resolveInItemUnitName(item, productMap)).filter(Objects::nonNull).findFirst().orElse(null); + } + + private String resolveOutItemUnitName(List itemList, Map productMap) { + return itemList.stream().map(item -> resolveOutItemUnitName(item, productMap)).filter(Objects::nonNull).findFirst().orElse(null); + } + + private String resolveProductName(Long productId, Map productMap) { + ErpProductRespVO product = productMap.get(productId); + return product != null ? product.getName() : null; } private Integer resolveCategoryType(ErpStockDO stock, Map productMap) { @@ -419,6 +630,10 @@ public class ErpStockServiceImpl implements ErpStockService { 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) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DevicePageReqVO.java index 3b592f9c0..7823c8c49 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DevicePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DevicePageReqVO.java @@ -27,6 +27,9 @@ public class DevicePageReqVO extends PageParam { @Schema(description = "状态", example = "1") private String status; + @Schema(description = "运行状态", example = "1") + private String operatingStatus; + @Schema(description = "读主题") private String readTopic; @@ -80,4 +83,4 @@ public class DevicePageReqVO extends PageParam { @Schema(description = "mqtt订阅主题") private String topic; -} \ No newline at end of file +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java index d8f8f4295..a1d3fd804 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java @@ -84,6 +84,7 @@ public interface DeviceMapper extends BaseMapperX { return selectList(new LambdaQueryWrapperX() .eqIfPresent(DeviceDO::getDeviceCode, reqVO.getDeviceCode()) .likeIfPresent(DeviceDO::getDeviceName, reqVO.getDeviceName()) + .likeIfPresent(DeviceDO::getTopic, reqVO.getTopic()) .eqIfPresent(DeviceDO::getDeviceType, reqVO.getDeviceType()) .eqIfPresent(DeviceDO::getStatus, reqVO.getStatus()) .eqIfPresent(DeviceDO::getReadTopic, reqVO.getReadTopic()) @@ -94,6 +95,7 @@ public interface DeviceMapper extends BaseMapperX { .betweenIfPresent(DeviceDO::getLastOnlineTime, reqVO.getLastOnlineTime()) .eqIfPresent(DeviceDO::getRemark, reqVO.getRemark()) .eqIfPresent(DeviceDO::getIsEnable, reqVO.getIsEnable()) + .betweenIfPresent(DeviceDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(DeviceDO::getId)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java index 446faace5..a219ccd99 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -357,6 +357,10 @@ public class DeviceServiceImpl implements DeviceService { public PageResult getDevicePage(DevicePageReqVO pageReqVO) { // 1. 查询分页设备 + if (StringUtils.isNotBlank(pageReqVO.getOperatingStatus())) { + return getDevicePageByOperatingStatus(pageReqVO); + } + PageResult deviceDOPageResult = deviceMapper.selectPage(pageReqVO); List deviceIds = deviceDOPageResult.getList().stream() .map(DeviceDO::getId) @@ -414,6 +418,69 @@ public class DeviceServiceImpl implements DeviceService { return deviceRespVOPageResult; } + private PageResult getDevicePageByOperatingStatus(DevicePageReqVO pageReqVO) { + List deviceList = deviceMapper.selectList(pageReqVO); + List deviceRespVOList = BeanUtils.toBean(deviceList, DeviceRespVO.class); + + List deviceIds = deviceRespVOList.stream() + .map(DeviceRespVO::getId) + .collect(Collectors.toList()); + Map latestTsMap = tdengineService.newSelectLatestTsBatch(deviceIds); + Map latestRecordMap = tdengineService.selectLatestByDeviceAndRuleMinimal(deviceIds, null).stream() + .collect(Collectors.toMap( + DeviceOperationRecordDO::getDeviceId, + r -> r, + (r1, r2) -> r1.getCreateTime().isAfter(r2.getCreateTime()) ? r1 : r2 + )); + + for (DeviceRespVO deviceRespVO : deviceRespVOList) { + Long deviceId = deviceRespVO.getId(); + if (latestTsMap.get(deviceId) != null) { + deviceRespVO.setCollectionTime(latestTsMap.get(deviceId)); + } + deviceRespVO.setOperatingStatus(resolveDeviceOperatingStatus(latestRecordMap.get(deviceId))); + } + + List filteredList = deviceRespVOList.stream() + .filter(device -> matchesOperatingStatus(device.getOperatingStatus(), pageReqVO.getOperatingStatus())) + .collect(Collectors.toList()); + return new PageResult<>(subPage(filteredList, pageReqVO), (long) filteredList.size()); + } + + private String resolveDeviceOperatingStatus(DeviceOperationRecordDO record) { + if (record == null) { + return DeviceStatusEnum.OFFLINE.getName(); + } + DeviceStatusEnum status = DeviceStatusEnum.getByCode(record.getRule()); + return status != null ? status.getName() : DeviceStatusEnum.OFFLINE.getName(); + } + + private boolean matchesOperatingStatus(String actualStatus, String expectedStatus) { + if (StringUtils.equals(actualStatus, expectedStatus)) { + return true; + } + for (DeviceStatusEnum status : DeviceStatusEnum.values()) { + if ((StringUtils.equals(status.getCode(), expectedStatus) + || StringUtils.equals(status.getName(), expectedStatus) + || StringUtils.equalsIgnoreCase(status.name(), expectedStatus)) + && StringUtils.equals(status.getName(), actualStatus)) { + return true; + } + } + return false; + } + + private List subPage(List list, DevicePageReqVO pageReqVO) { + if (Objects.equals(pageReqVO.getPageSize(), PageParam.PAGE_SIZE_NONE)) { + return list; + } + int pageNo = pageReqVO.getPageNo() != null ? pageReqVO.getPageNo() : 1; + int pageSize = pageReqVO.getPageSize() != null ? pageReqVO.getPageSize() : 10; + int fromIndex = Math.min((pageNo - 1) * pageSize, list.size()); + int toIndex = Math.min(fromIndex + pageSize, list.size()); + return list.subList(fromIndex, toIndex); + } + @Override public List selectList(DevicePageReqVO reqVO){ return deviceMapper.selectList(reqVO);