This commit is contained in:
2026-10-20 11:33:20 +08:00
parent 16ac817524
commit 6fa5d281ec
61 changed files with 31358 additions and 8 deletions
@@ -34,11 +34,5 @@ public final class CargoDiscardRequests {
public record Query(@Min(1) long page, @Min(1) @Max(200) long size,
String discardNo, String inboundCode, String overseasWarehouseId,
String status, LocalDateTime createdFrom, LocalDateTime createdTo,
LocalDateTime completedFrom, LocalDateTime completedTo) {
/** 未筛完成时间的调用保持创建时间查询语义。 */
public Query(long page, long size, String discardNo, String inboundCode, String overseasWarehouseId,
String status, LocalDateTime createdFrom, LocalDateTime createdTo) {
this(page, size, discardNo, inboundCode, overseasWarehouseId, status, createdFrom, createdTo, null, null);
}
}
LocalDateTime completedFrom, LocalDateTime completedTo) {}
}
@@ -0,0 +1,22 @@
package com.baiyue.lastleg.discard.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/** 只读取废弃明细真实关联的本库托盘身份。 */
@Mapper
public interface CargoDiscardDimensionMapper {
/** 无托盘事实以空串保留,避免把不适用维度伪造为零。 */
@Select("""
SELECT COALESCE(CASE WHEN i.return_carton_id IS NOT NULL THEN r.pallet_code
WHEN i.inventory_position_id IS NOT NULL THEN p.pallet_no ELSE d.pallet_no END,'')
FROM ll_cargo_discard_item i
LEFT JOIN ll_return_inventory_carton r ON r.id=i.return_carton_id AND r.customer_id=i.customer_id
LEFT JOIN ll_inventory_position p ON p.id=i.inventory_position_id AND p.customer_id=i.customer_id
LEFT JOIN ll_dropship_order_profile d ON d.id=i.profile_id AND d.customer_id=i.customer_id
WHERE i.customer_id=#{customerId} AND i.application_id=#{applicationId}
""")
List<String> palletNos(@Param("customerId") String customerId, @Param("applicationId") Long applicationId);
}
@@ -0,0 +1,19 @@
package com.baiyue.lastleg.discard.repository;
import com.baiyue.lastleg.discard.entity.CargoDiscardItem;
import com.baiyue.lastleg.discard.mapper.CargoDiscardItemMapper;
import com.baiyue.lastleg.discard.mapper.CargoDiscardDimensionMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Repository;
import java.util.List;
/** 封装数量统计的明细与来源托盘读取。 */
@Repository
public class CargoDiscardDimensionRepository {
@Resource private CargoDiscardItemMapper items;
@Resource private CargoDiscardDimensionMapper dimensions;
/** 读取一票客户隔离明细。 */
public List<CargoDiscardItem> items(String customer, Long application) { return items.listApplication(customer, application); }
/** 读取一票托盘身份,保留无事实行。 */
public List<String> pallets(String customer, Long application) { return dimensions.palletNos(customer, application); }
}
@@ -0,0 +1,36 @@
package com.baiyue.lastleg.discard.repository;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baiyue.lastleg.discard.dto.CargoDiscardRequests;
import com.baiyue.lastleg.discard.entity.CargoDiscardApplication;
import com.baiyue.lastleg.discard.mapper.CargoDiscardApplicationMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import java.util.List;
/** 列表和全筛选统计共用同一客户及时间过滤条件。 */
@Repository
public class CargoDiscardQueryRepository {
@Resource private CargoDiscardApplicationMapper applications;
/** 返回全部筛选单据,不受页面大小影响。 */
public List<CargoDiscardApplication> list(String customerId, CargoDiscardRequests.Query query) {
return applications.selectList(filter(customerId, query));
}
/** 完成时间使用客户确认时间,与客户端完成时间展示保持一致。 */
public static LambdaQueryWrapper<CargoDiscardApplication> filter(String customerId, CargoDiscardRequests.Query query) {
return new LambdaQueryWrapper<CargoDiscardApplication>()
.eq(StringUtils.hasText(customerId), CargoDiscardApplication::getCustomerId, customerId)
.like(StringUtils.hasText(query.discardNo()), CargoDiscardApplication::getDiscardNo, query.discardNo())
.like(StringUtils.hasText(query.inboundCode()), CargoDiscardApplication::getInboundCodes, query.inboundCode())
.eq(StringUtils.hasText(query.overseasWarehouseId()), CargoDiscardApplication::getOverseasWarehouseId, query.overseasWarehouseId())
.eq(StringUtils.hasText(query.status()), CargoDiscardApplication::getStatus, query.status())
.ge(query.createdFrom() != null, CargoDiscardApplication::getCreatedAt, query.createdFrom())
.le(query.createdTo() != null, CargoDiscardApplication::getCreatedAt, query.createdTo())
.ge(query.completedFrom() != null, CargoDiscardApplication::getCustomerConfirmedAt, query.completedFrom())
.le(query.completedTo() != null, CargoDiscardApplication::getCustomerConfirmedAt, query.completedTo())
.orderByDesc(CargoDiscardApplication::getCreatedAt).orderByDesc(CargoDiscardApplication::getId);
}
}
@@ -0,0 +1,54 @@
package com.baiyue.lastleg.discard.service;
import com.baiyue.lastleg.discard.dto.CargoDiscardRequests;
import com.baiyue.lastleg.discard.model.CargoDiscardQuantities;
import com.baiyue.lastleg.discard.repository.CargoDiscardQueryRepository;
import com.baiyue.lastleg.discard.repository.CargoDiscardDimensionRepository;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.HashSet;
/** 按全部筛选单据统计票、SKU、件、箱和真实来源托盘。 */
@Service
public class CargoDiscardStatisticsService {
@Resource private CargoDiscardQueryRepository queries;
@Resource private CargoDiscardDimensionRepository dimensions;
public record Statistics(long orderCount, int skuCount, long requestedPackages, Long actualPackages,
Long requestedPieces, Long actualPieces, Integer palletCount) {}
/** 已确认实际数独立汇总;缺失件数或托盘事实返回空值,不从箱数换算。 */
public Statistics statistics(String customer, CargoDiscardRequests.Query query) {
var applications = queries.list(customer, query);
var skus = new HashSet<String>(); var pallets = new HashSet<String>();
long boxes = 0, actualBoxes = 0, pieces = 0, actualPieces = 0;
boolean piecesKnown = true, actualPiecesKnown = true, actualKnown = false, palletsKnown = true;
for (var application : applications) {
var lines = dimensions.items(application.getCustomerId(), application.getId());
boxes += lines.isEmpty() ? application.getTotalPackages() : CargoDiscardQuantities.boxes(lines, false);
if (lines.isEmpty()) { piecesKnown = false; palletsKnown = false; }
var confirmed = lines.stream().filter(i -> i.getActualDiscardPackages() != null).toList();
if (!confirmed.isEmpty()) { actualKnown = true; actualBoxes += CargoDiscardQuantities.boxes(confirmed, true); }
for (var line : lines) {
if (line.getSkuCode() != null && !line.getSkuCode().isBlank()) skus.add(line.getSkuCode());
if (line.getReturnCartonId() == null) {
piecesKnown = false;
if (line.getActualDiscardPackages() != null) actualPiecesKnown = false;
} else {
pieces += line.getDiscardPackages();
if (line.getActualDiscardPackages() != null) actualPieces += line.getActualDiscardPackages();
}
}
var sourcePallets = dimensions.pallets(application.getCustomerId(), application.getId());
if (sourcePallets.isEmpty()) palletsKnown = false;
for (var pallet : sourcePallets) {
if (pallet == null || pallet.isBlank() || "散箱".equals(pallet)) palletsKnown = false;
else pallets.add(application.getCustomerId() + ":" + application.getOverseasWarehouseId() + ":" + pallet);
}
}
return new Statistics(applications.size(), skus.size(), boxes, actualKnown ? actualBoxes : null,
!applications.isEmpty() && piecesKnown ? pieces : null,
actualKnown && actualPiecesKnown ? actualPieces : null,
!applications.isEmpty() && palletsKnown ? pallets.size() : null);
}
}