提交
This commit is contained in:
+5
@@ -1,6 +1,7 @@
|
||||
package com.baiyue.lastleg.inventory.query.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public record InventoryBalanceView(
|
||||
Long id,
|
||||
@@ -15,6 +16,10 @@ public record InventoryBalanceView(
|
||||
Long inboundOrderId,
|
||||
String inboundOrderNo,
|
||||
String inboundCode,
|
||||
List<String> skuCodes,
|
||||
List<String> productNames,
|
||||
List<Long> warehouseLocationIds,
|
||||
List<String> warehouseLocationCodes,
|
||||
long totalPackages,
|
||||
long availablePackages,
|
||||
long holdPackages,
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ public record InventoryLedgerView(
|
||||
String palletNo,
|
||||
String batchNo,
|
||||
String warehouseLocationCode,
|
||||
String skuCode,
|
||||
String businessType,
|
||||
String businessOrderNo,
|
||||
String outboundOrderNo,
|
||||
|
||||
+6
@@ -19,6 +19,10 @@ public final class InventoryQueryRequests {
|
||||
String inboundOrderNo,
|
||||
String inboundCode,
|
||||
String businessOrderNo,
|
||||
String skuCode,
|
||||
String productName,
|
||||
String batchNo,
|
||||
String warehouseLocationCode,
|
||||
String inventoryStatus
|
||||
) {
|
||||
public BalanceQuery {
|
||||
@@ -42,6 +46,8 @@ public final class InventoryQueryRequests {
|
||||
String outboundOrderNo,
|
||||
String palletNo,
|
||||
String batchNo,
|
||||
String skuCode,
|
||||
String warehouseLocationCode,
|
||||
LocalDateTime occurredFrom,
|
||||
LocalDateTime occurredTo
|
||||
) {
|
||||
|
||||
+28
@@ -5,6 +5,8 @@ import com.baiyue.lastleg.inventory.entity.InventoryLedger;
|
||||
import com.baiyue.lastleg.inventory.entity.InventoryPosition;
|
||||
import com.baiyue.lastleg.inventory.query.dto.InventoryQueryRequests;
|
||||
import com.baiyue.lastleg.inventory.query.model.InventoryAggregateProjection;
|
||||
import com.baiyue.lastleg.inventory.query.model.InventoryLocationFact;
|
||||
import com.baiyue.lastleg.inventory.query.model.InventorySkuFact;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
@@ -19,6 +21,10 @@ public interface InventoryQueryMapper {
|
||||
"<if test='q.inboundOrderNo != null and q.inboundOrderNo != \"\"'> AND inbound_order_no LIKE CONCAT('%',#{q.inboundOrderNo},'%')</if>" +
|
||||
"<if test='q.inboundCode != null and q.inboundCode != \"\"'> AND inbound_code LIKE CONCAT('%',#{q.inboundCode},'%')</if>" +
|
||||
"<if test='q.businessOrderNo != null and q.businessOrderNo != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_ledger l WHERE l.balance_id=ll_inventory_balance.id AND l.customer_id=#{customerId} AND l.business_order_no LIKE CONCAT('%',#{q.businessOrderNo},'%'))</if>" +
|
||||
"<if test='q.skuCode != null and q.skuCode != \"\"'> AND EXISTS (SELECT 1 FROM ll_order_detail d WHERE d.order_id=ll_inventory_balance.inbound_order_id AND d.sku_code LIKE CONCAT('%',#{q.skuCode},'%'))</if>" +
|
||||
"<if test='q.productName != null and q.productName != \"\"'> AND EXISTS (SELECT 1 FROM ll_order_detail d WHERE d.order_id=ll_inventory_balance.inbound_order_id AND (d.product_name_zh LIKE CONCAT('%',#{q.productName},'%') OR d.product_name_en LIKE CONCAT('%',#{q.productName},'%')))</if>" +
|
||||
"<if test='q.batchNo != null and q.batchNo != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_position p WHERE p.balance_id=ll_inventory_balance.id AND p.customer_id=#{customerId} AND p.batch_no LIKE CONCAT('%',#{q.batchNo},'%'))</if>" +
|
||||
"<if test='q.warehouseLocationCode != null and q.warehouseLocationCode != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_position p WHERE p.balance_id=ll_inventory_balance.id AND p.customer_id=#{customerId} AND p.warehouse_location_code LIKE CONCAT('%',#{q.warehouseLocationCode},'%'))</if>" +
|
||||
"<choose>" +
|
||||
"<when test='q.inventoryStatus == \"AVAILABLE\"'> AND available_packages > 0</when>" +
|
||||
"<when test='q.inventoryStatus == \"HOLD\"'> AND hold_packages > 0</when>" +
|
||||
@@ -37,6 +43,10 @@ public interface InventoryQueryMapper {
|
||||
"<if test='q.inboundOrderNo != null and q.inboundOrderNo != \"\"'> AND b.inbound_order_no LIKE CONCAT('%',#{q.inboundOrderNo},'%')</if>" +
|
||||
"<if test='q.inboundCode != null and q.inboundCode != \"\"'> AND b.inbound_code LIKE CONCAT('%',#{q.inboundCode},'%')</if>" +
|
||||
"<if test='q.businessOrderNo != null and q.businessOrderNo != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_ledger l WHERE l.balance_id=b.id AND l.customer_id=#{customerId} AND l.business_order_no LIKE CONCAT('%',#{q.businessOrderNo},'%'))</if>" +
|
||||
"<if test='q.skuCode != null and q.skuCode != \"\"'> AND EXISTS (SELECT 1 FROM ll_order_detail d WHERE d.order_id=b.inbound_order_id AND d.sku_code LIKE CONCAT('%',#{q.skuCode},'%'))</if>" +
|
||||
"<if test='q.productName != null and q.productName != \"\"'> AND EXISTS (SELECT 1 FROM ll_order_detail d WHERE d.order_id=b.inbound_order_id AND (d.product_name_zh LIKE CONCAT('%',#{q.productName},'%') OR d.product_name_en LIKE CONCAT('%',#{q.productName},'%')))</if>" +
|
||||
"<if test='q.batchNo != null and q.batchNo != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_position p2 WHERE p2.balance_id=b.id AND p2.customer_id=#{customerId} AND p2.batch_no LIKE CONCAT('%',#{q.batchNo},'%'))</if>" +
|
||||
"<if test='q.warehouseLocationCode != null and q.warehouseLocationCode != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_position p2 WHERE p2.balance_id=b.id AND p2.customer_id=#{customerId} AND p2.warehouse_location_code LIKE CONCAT('%',#{q.warehouseLocationCode},'%'))</if>" +
|
||||
"<choose>" +
|
||||
"<when test='q.inventoryStatus == \"AVAILABLE\"'> AND b.available_packages > 0</when>" +
|
||||
"<when test='q.inventoryStatus == \"HOLD\"'> AND b.hold_packages > 0</when>" +
|
||||
@@ -58,6 +68,22 @@ public interface InventoryQueryMapper {
|
||||
long countBalances(@Param("customerId") String customerId,
|
||||
@Param("q") InventoryQueryRequests.BalanceQuery query);
|
||||
|
||||
@Select("<script>SELECT DISTINCT b.id balance_id,d.sku_code," +
|
||||
"COALESCE(NULLIF(d.product_name_zh,''),d.product_name_en) product_name " +
|
||||
"FROM ll_inventory_balance b JOIN ll_order_detail d ON d.order_id=b.inbound_order_id " +
|
||||
"WHERE b.customer_id=#{customerId} AND b.id IN " +
|
||||
"<foreach collection='balanceIds' item='id' open='(' separator=',' close=')'>#{id}</foreach> " +
|
||||
"AND d.sku_code IS NOT NULL AND d.sku_code<>'' ORDER BY b.id,d.sku_code</script>")
|
||||
List<InventorySkuFact> skuFacts(@Param("customerId") String customerId,
|
||||
@Param("balanceIds") List<Long> balanceIds);
|
||||
|
||||
@Select("<script>SELECT DISTINCT balance_id,warehouse_location_id,warehouse_location_code " +
|
||||
"FROM ll_inventory_position WHERE customer_id=#{customerId} AND balance_id IN " +
|
||||
"<foreach collection='balanceIds' item='id' open='(' separator=',' close=')'>#{id}</foreach> " +
|
||||
"ORDER BY balance_id,warehouse_location_code</script>")
|
||||
List<InventoryLocationFact> locationFacts(@Param("customerId") String customerId,
|
||||
@Param("balanceIds") List<Long> balanceIds);
|
||||
|
||||
@Select("<script>SELECT COUNT(*) dimension_count," +
|
||||
"COALESCE(SUM(available_packages),0) available_packages," +
|
||||
"COALESCE(SUM(hold_packages),0) hold_packages," +
|
||||
@@ -103,6 +129,8 @@ public interface InventoryQueryMapper {
|
||||
"<if test='q.outboundOrderNo != null and q.outboundOrderNo != \"\"'> AND outbound_order_no LIKE CONCAT('%',#{q.outboundOrderNo},'%')</if>" +
|
||||
"<if test='q.palletNo != null and q.palletNo != \"\"'> AND pallet_no LIKE CONCAT('%',#{q.palletNo},'%')</if>" +
|
||||
"<if test='q.batchNo != null and q.batchNo != \"\"'> AND batch_no LIKE CONCAT('%',#{q.batchNo},'%')</if>" +
|
||||
"<if test='q.skuCode != null and q.skuCode != \"\"'> AND sku_code LIKE CONCAT('%',#{q.skuCode},'%')</if>" +
|
||||
"<if test='q.warehouseLocationCode != null and q.warehouseLocationCode != \"\"'> AND warehouse_location_code LIKE CONCAT('%',#{q.warehouseLocationCode},'%')</if>" +
|
||||
"<if test='q.occurredFrom != null'> AND occurred_at >=#{q.occurredFrom}</if>" +
|
||||
"<if test='q.occurredTo != null'> AND occurred_at <=#{q.occurredTo}</if>";
|
||||
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.baiyue.lastleg.inventory.query.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class InventoryLocationFact {
|
||||
private Long balanceId;
|
||||
private Long warehouseLocationId;
|
||||
private String warehouseLocationCode;
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.baiyue.lastleg.inventory.query.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class InventorySkuFact {
|
||||
private Long balanceId;
|
||||
private String skuCode;
|
||||
private String productName;
|
||||
}
|
||||
+35
-8
@@ -11,6 +11,8 @@ import com.baiyue.lastleg.inventory.query.dto.InventoryPositionView;
|
||||
import com.baiyue.lastleg.inventory.query.dto.InventoryQueryRequests;
|
||||
import com.baiyue.lastleg.inventory.query.mapper.InventoryQueryMapper;
|
||||
import com.baiyue.lastleg.inventory.query.model.InventoryAggregateProjection;
|
||||
import com.baiyue.lastleg.inventory.query.model.InventoryLocationFact;
|
||||
import com.baiyue.lastleg.inventory.query.model.InventorySkuFact;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -19,7 +21,9 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class InventoryQueryService {
|
||||
@@ -51,8 +55,8 @@ public class InventoryQueryService {
|
||||
public PageResult<InventoryBalanceView> balances(String customerId, InventoryQueryRequests.BalanceQuery query) {
|
||||
validateStatus(query.inventoryStatus(), BALANCE_STATUSES);
|
||||
long total = mapper.countBalances(customerId, query);
|
||||
List<InventoryBalanceView> records = total == 0 ? List.of() : mapper.balances(
|
||||
customerId, query, offset(query.page(), query.size()), query.size()).stream().map(this::balanceView).toList();
|
||||
List<InventoryBalanceView> records = total == 0 ? List.of() : balanceViews(customerId,
|
||||
mapper.balances(customerId, query, offset(query.page(), query.size()), query.size()));
|
||||
return page(records, query.page(), query.size(), total);
|
||||
}
|
||||
|
||||
@@ -78,12 +82,14 @@ public class InventoryQueryService {
|
||||
validateStatus(query.inventoryStatus(), BALANCE_STATUSES);
|
||||
List<String> rows = new ArrayList<>();
|
||||
rows.add("customerId,customerName,overseasWarehouseCode,overseasWarehouseName,destinationWarehouseCode," +
|
||||
"destinationWarehouseName,inboundOrderId,inboundOrderNo,inboundCode,totalPackages,availablePackages," +
|
||||
"destinationWarehouseName,inboundOrderId,inboundOrderNo,inboundCode,skuCodes,productNames," +
|
||||
"warehouseLocationCodes,totalPackages,availablePackages," +
|
||||
"holdPackages,allocatedPackages,pickedPackages,inTransitPackages,receivingPackages,procurementPackages");
|
||||
mapper.balances(customerId, query, 0, EXPORT_LIMIT).stream().map(this::balanceView).forEach(v -> rows.add(
|
||||
balanceViews(customerId, mapper.balances(customerId, query, 0, EXPORT_LIMIT)).forEach(v -> rows.add(
|
||||
String.join(",", csv(v.customerId()), csv(v.customerName()), csv(v.overseasWarehouseCode()), csv(v.overseasWarehouseName()),
|
||||
csv(v.destinationWarehouseCode()), csv(v.destinationWarehouseName()), csv(v.inboundOrderId()),
|
||||
csv(v.inboundOrderNo()), csv(v.inboundCode()),
|
||||
csv(v.inboundOrderNo()), csv(v.inboundCode()), csv(String.join("|", v.skuCodes())),
|
||||
csv(String.join("|", v.productNames())), csv(String.join("|", v.warehouseLocationCodes())),
|
||||
csv(v.totalPackages()), csv(v.availablePackages()), csv(v.holdPackages()), csv(v.allocatedPackages()),
|
||||
csv(v.pickedPackages()), csv(v.inTransitPackages()), csv(v.receivingPackages()),
|
||||
csv(v.procurementPackages()))));
|
||||
@@ -105,7 +111,19 @@ public class InventoryQueryService {
|
||||
return ("\uFEFF" + String.join("\r\n", rows)).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private InventoryBalanceView balanceView(InventoryBalance value) {
|
||||
private List<InventoryBalanceView> balanceViews(String customerId, List<InventoryBalance> balances) {
|
||||
if (balances.isEmpty()) return List.of();
|
||||
List<Long> ids = balances.stream().map(InventoryBalance::getId).toList();
|
||||
Map<Long, List<InventorySkuFact>> skus = mapper.skuFacts(customerId, ids).stream()
|
||||
.collect(Collectors.groupingBy(InventorySkuFact::getBalanceId));
|
||||
Map<Long, List<InventoryLocationFact>> locations = mapper.locationFacts(customerId, ids).stream()
|
||||
.collect(Collectors.groupingBy(InventoryLocationFact::getBalanceId));
|
||||
return balances.stream().map(value -> balanceView(value,
|
||||
skus.getOrDefault(value.getId(), List.of()), locations.getOrDefault(value.getId(), List.of()))).toList();
|
||||
}
|
||||
|
||||
private InventoryBalanceView balanceView(InventoryBalance value, List<InventorySkuFact> skus,
|
||||
List<InventoryLocationFact> locations) {
|
||||
long availablePackages = number(value.getAvailablePackages());
|
||||
long holdPackages = number(value.getHoldPackages());
|
||||
long allocatedPackages = number(value.getAllocatedPackages());
|
||||
@@ -116,7 +134,12 @@ public class InventoryQueryService {
|
||||
return new InventoryBalanceView(value.getId(), value.getCustomerId(), value.getCustomerName(), value.getOverseasWarehouseId(),
|
||||
value.getOverseasWarehouseCode(), value.getOverseasWarehouseName(), value.getDestinationWarehouseId(),
|
||||
value.getDestinationWarehouseCode(), value.getDestinationWarehouseName(), value.getInboundOrderId(),
|
||||
value.getInboundOrderNo(), value.getInboundCode(), availablePackages + holdPackages + allocatedPackages + pickedPackages
|
||||
value.getInboundOrderNo(), value.getInboundCode(),
|
||||
skus.stream().map(InventorySkuFact::getSkuCode).filter(InventoryQueryService::hasText).distinct().toList(),
|
||||
skus.stream().map(InventorySkuFact::getProductName).filter(InventoryQueryService::hasText).distinct().toList(),
|
||||
locations.stream().map(InventoryLocationFact::getWarehouseLocationId).filter(java.util.Objects::nonNull).distinct().toList(),
|
||||
locations.stream().map(InventoryLocationFact::getWarehouseLocationCode).filter(InventoryQueryService::hasText).distinct().toList(),
|
||||
availablePackages + holdPackages + allocatedPackages + pickedPackages
|
||||
+ inTransitPackages + receivingPackages + procurementPackages,
|
||||
availablePackages, holdPackages, allocatedPackages, pickedPackages, inTransitPackages,
|
||||
receivingPackages, procurementPackages, value.getUpdatedAt());
|
||||
@@ -141,7 +164,7 @@ public class InventoryQueryService {
|
||||
return new InventoryLedgerView(value.getId(), value.getCustomerId(), value.getOverseasWarehouseId(),
|
||||
value.getDestinationWarehouseCode(), value.getInboundOrderId(), value.getInboundOrderNo(), value.getInboundCode(),
|
||||
value.getPalletNo(), value.getBatchNo(),
|
||||
value.getWarehouseLocationCode(), value.getBusinessType(), value.getBusinessOrderNo(),
|
||||
value.getWarehouseLocationCode(), value.getSkuCode(), value.getBusinessType(), value.getBusinessOrderNo(),
|
||||
value.getOutboundOrderNo(), value.getStatusFrom(), value.getStatusTo(),
|
||||
number(value.getBeforePackages()), number(value.getDeltaPackages()), number(value.getAfterPackages()),
|
||||
value.getOperatorId(), value.getRemark(), value.getOccurredAt());
|
||||
@@ -168,6 +191,10 @@ public class InventoryQueryService {
|
||||
return value == null ? 0 : value;
|
||||
}
|
||||
|
||||
private static boolean hasText(String value) {
|
||||
return value != null && !value.isBlank();
|
||||
}
|
||||
|
||||
private static <T> PageResult<T> page(List<T> records, long page, long size, long total) {
|
||||
long pages = total == 0 ? 0 : (total + size - 1) / size;
|
||||
return new PageResult<>(records, page, size, total, pages);
|
||||
|
||||
Reference in New Issue
Block a user