This commit is contained in:
2026-08-25 11:54:19 +08:00
parent 322de03312
commit d9c8cc478e
9 changed files with 36 additions and 28 deletions
@@ -18,7 +18,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
"com.baiyue.firstleg.outbound.dispatch.mapper",
"com.baiyue.firstleg.portschedule.mapper",
"com.baiyue.firstleg.customs.mapper",
"com.baiyue.firstleg.customerstatistics.mapper"
"com.baiyue.firstleg.customerstatistics.adapter.out.persistence"
})
@EnableFeignClients(basePackages = "com.baiyue.firstleg")
@EnableScheduling
@@ -1,9 +1,9 @@
package com.baiyue.firstleg.customerstatistics.controller;
package com.baiyue.firstleg.customerstatistics.adapter.in.web;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.security.AuthenticatedUser;
import com.baiyue.firstleg.customerstatistics.dto.CustomerTransitStatisticsDtos.TransitSummary;
import com.baiyue.firstleg.customerstatistics.service.CustomerTransitStatisticsService;
import com.baiyue.firstleg.customerstatistics.application.CustomerTransitStatisticsService;
import com.baiyue.firstleg.customerstatistics.application.model.CustomerTransitStatisticsDtos.TransitSummary;
import com.baiyue.firstleg.service.FirstlegScopeGuard;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Positive;
@@ -1,14 +1,13 @@
package com.baiyue.firstleg.customerstatistics.mapper;
package com.baiyue.firstleg.customerstatistics.adapter.out.persistence;
import com.baiyue.firstleg.customerstatistics.application.port.out.CustomerTransitStatisticsReader;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Mapper
public interface CustomerTransitStatisticsMapper {
public interface CustomerTransitStatisticsMapper extends CustomerTransitStatisticsReader {
@Override
@Select("""
SELECT #{customerId} AS customerId,
COUNT(*) AS containerCount,
@@ -49,8 +48,5 @@ public interface CustomerTransitStatisticsMapper {
WHERE x.customer_id = #{customerId}
) scoped
""")
SummaryRow summarize(@Param("customerId") long customerId);
record SummaryRow(Long customerId, Long containerCount, BigDecimal totalTeu,
Long unknownContainerCount, LocalDateTime asOf) {}
SummaryProjection summarize(@Param("customerId") long customerId);
}
@@ -1,9 +1,9 @@
package com.baiyue.firstleg.customerstatistics.service;
package com.baiyue.firstleg.customerstatistics.application;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.firstleg.customerstatistics.dto.CustomerTransitStatisticsDtos.TransitSummary;
import com.baiyue.firstleg.customerstatistics.mapper.CustomerTransitStatisticsMapper;
import com.baiyue.firstleg.customerstatistics.application.model.CustomerTransitStatisticsDtos.TransitSummary;
import com.baiyue.firstleg.customerstatistics.application.port.out.CustomerTransitStatisticsReader;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@@ -12,11 +12,11 @@ import java.math.BigDecimal;
@Service
public class CustomerTransitStatisticsService {
private static final String DEFINITION = "actual_sailing_at IS NOT NULL 且 actual_warehouse_arrival_at IS NULL;排除取消/失败订舱;客户+containerBookingId去重;拼柜按active LoadingPlanItem.accountId归属,整柜按OceanBooking.customerId归属。TEU:20*=1,40*=2,45*=2.25,未知箱型不计totalTeu。";
@Resource private CustomerTransitStatisticsMapper mapper;
@Resource private CustomerTransitStatisticsReader reader;
public TransitSummary summarize(long customerId) {
if (customerId <= 0) throw new BizException(ResultCode.BAD_REQUEST, "customerId必须为正数");
var row = mapper.summarize(customerId);
var row = reader.summarize(customerId);
return new TransitSummary(customerId,
value(row == null ? null : row.containerCount()),
row == null || row.totalTeu() == null ? BigDecimal.ZERO : row.totalTeu(),
@@ -1,4 +1,4 @@
package com.baiyue.firstleg.customerstatistics.dto;
package com.baiyue.firstleg.customerstatistics.application.model;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -0,0 +1,11 @@
package com.baiyue.firstleg.customerstatistics.application.port.out;
import java.math.BigDecimal;
import java.time.LocalDateTime;
public interface CustomerTransitStatisticsReader {
SummaryProjection summarize(long customerId);
record SummaryProjection(Long customerId, Long containerCount, BigDecimal totalTeu,
Long unknownContainerCount, LocalDateTime asOf) {}
}
@@ -20,7 +20,8 @@ class BaiyueFirstlegApplicationContractTest {
.contains("com.baiyue.firstleg.outbound.dispatch.mapper")
.contains("com.baiyue.firstleg.portschedule.mapper")
.contains("com.baiyue.firstleg.customs.mapper")
.contains("com.baiyue.firstleg.customerstatistics.mapper");
.contains("com.baiyue.firstleg.customerstatistics.adapter.out.persistence")
.doesNotContain("com.baiyue.firstleg.customerstatistics.mapper");
}
@Test
@@ -1,8 +1,8 @@
package com.baiyue.firstleg.customerstatistics;
import com.baiyue.firstleg.customerstatistics.controller.PlatformCustomerTransitStatisticsController;
import com.baiyue.firstleg.customerstatistics.mapper.CustomerTransitStatisticsMapper;
import com.baiyue.firstleg.customerstatistics.service.CustomerTransitStatisticsService;
import com.baiyue.firstleg.customerstatistics.adapter.in.web.PlatformCustomerTransitStatisticsController;
import com.baiyue.firstleg.customerstatistics.adapter.out.persistence.CustomerTransitStatisticsMapper;
import com.baiyue.firstleg.customerstatistics.application.CustomerTransitStatisticsService;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -1,8 +1,8 @@
package com.baiyue.firstleg.customerstatistics;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.firstleg.customerstatistics.mapper.CustomerTransitStatisticsMapper;
import com.baiyue.firstleg.customerstatistics.service.CustomerTransitStatisticsService;
import com.baiyue.firstleg.customerstatistics.application.CustomerTransitStatisticsService;
import com.baiyue.firstleg.customerstatistics.application.port.out.CustomerTransitStatisticsReader;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -19,12 +19,12 @@ import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class CustomerTransitStatisticsServiceTest {
@Mock CustomerTransitStatisticsMapper mapper;
@Mock CustomerTransitStatisticsReader reader;
@InjectMocks CustomerTransitStatisticsService service;
@Test void preservesDecimalTeuAndUnknownCount() {
var asOf = LocalDateTime.of(2026, 8, 13, 12, 0);
when(mapper.summarize(88L)).thenReturn(new CustomerTransitStatisticsMapper.SummaryRow(
when(reader.summarize(88L)).thenReturn(new CustomerTransitStatisticsReader.SummaryProjection(
88L, 4L, new BigDecimal("6.25"), 1L, asOf));
var result = service.summarize(88L);
@@ -35,7 +35,7 @@ class CustomerTransitStatisticsServiceTest {
assertThat(result.unknownContainerCount()).isEqualTo(1);
assertThat(result.asOf()).isEqualTo(asOf);
assertThat(result.definition()).contains("20*=1", "40*=2", "45*=2.25", "未知箱型");
verify(mapper).summarize(88L);
verify(reader).summarize(88L);
}
@Test void rejectsInvalidCustomerBeforeQuery() {