fix: carry package count into inbound snapshot
This commit is contained in:
+2
-1
@@ -55,7 +55,8 @@ public class InternalInboundOrderController {
|
|||||||
if (command.tenantId() <= 0 || command.orderId() <= 0 || command.warehouseId() == null
|
if (command.tenantId() <= 0 || command.orderId() <= 0 || command.warehouseId() == null
|
||||||
|| command.warehouseId() <= 0 || command.customerName() == null || command.customerName().isBlank()
|
|| command.warehouseId() <= 0 || command.customerName() == null || command.customerName().isBlank()
|
||||||
|| command.inboundCode() == null || command.inboundCode().isBlank()
|
|| command.inboundCode() == null || command.inboundCode().isBlank()
|
||||||
|| command.inboundCode().length() > 40) {
|
|| command.inboundCode().length() > 40
|
||||||
|
|| command.totalPackageCount() != null && command.totalPackageCount() < 1) {
|
||||||
throw new BizException(ResultCode.BAD_REQUEST, "订单入库快照不完整");
|
throw new BizException(ResultCode.BAD_REQUEST, "订单入库快照不完整");
|
||||||
}
|
}
|
||||||
return ApiResponse.success(service.createFromApprovedOrder(command));
|
return ApiResponse.success(service.createFromApprovedOrder(command));
|
||||||
|
|||||||
@@ -30,8 +30,25 @@ public record OrderApprovedInboundCommand(
|
|||||||
String destinationName,
|
String destinationName,
|
||||||
String publicRemark,
|
String publicRemark,
|
||||||
String expressCompanyName,
|
String expressCompanyName,
|
||||||
String expressTrackingNo
|
String expressTrackingNo,
|
||||||
|
Integer totalPackageCount
|
||||||
) {
|
) {
|
||||||
|
/** 兼容尚未携带订单总箱数的历史事件。 */
|
||||||
|
public OrderApprovedInboundCommand(
|
||||||
|
long tenantId, long orderId, String orderNo, String inboundCode, Long customerId, String customerName,
|
||||||
|
Long warehouseId, String warehouseName, Long deliveryWarehouseId, String deliveryWarehouseName,
|
||||||
|
LocalDateTime expectedArrivalAt, String businessType, String channelCode, String channelName,
|
||||||
|
Long carrierId, String carrierName, String taxMode, String pricingTaxMode, String containerMode,
|
||||||
|
Boolean customsInspection, String destinationType, Long destinationWarehouseId, String destinationCode,
|
||||||
|
String destinationName, String publicRemark, String expressCompanyName, String expressTrackingNo
|
||||||
|
) {
|
||||||
|
this(tenantId, orderId, orderNo, inboundCode, customerId, customerName, warehouseId, warehouseName,
|
||||||
|
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
||||||
|
carrierId, carrierName, taxMode, pricingTaxMode, containerMode, customsInspection, destinationType,
|
||||||
|
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
||||||
|
expressTrackingNo, null);
|
||||||
|
}
|
||||||
|
|
||||||
/** 兼容未携带报价包税维度的历史调用方。 */
|
/** 兼容未携带报价包税维度的历史调用方。 */
|
||||||
public OrderApprovedInboundCommand(
|
public OrderApprovedInboundCommand(
|
||||||
long tenantId, long orderId, String orderNo, String inboundCode, Long customerId, String customerName,
|
long tenantId, long orderId, String orderNo, String inboundCode, Long customerId, String customerName,
|
||||||
@@ -45,6 +62,6 @@ public record OrderApprovedInboundCommand(
|
|||||||
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
||||||
carrierId, carrierName, taxMode, null, containerMode, customsInspection, destinationType,
|
carrierId, carrierName, taxMode, null, containerMode, customsInspection, destinationType,
|
||||||
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
||||||
expressTrackingNo);
|
expressTrackingNo, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public class InboundOrderCreationService {
|
|||||||
inbound.setDestinationName(command.destinationName());
|
inbound.setDestinationName(command.destinationName());
|
||||||
inbound.setExpressCompanyName(command.expressCompanyName());
|
inbound.setExpressCompanyName(command.expressCompanyName());
|
||||||
inbound.setExpressTrackingNo(command.expressTrackingNo());
|
inbound.setExpressTrackingNo(command.expressTrackingNo());
|
||||||
|
inbound.setTotalPackageCount(command.totalPackageCount());
|
||||||
inbound.setPublicRemark(command.publicRemark());
|
inbound.setPublicRemark(command.publicRemark());
|
||||||
inbound.setCreatedBy(0L);
|
inbound.setCreatedBy(0L);
|
||||||
inbound.setUpdatedBy(0L);
|
inbound.setUpdatedBy(0L);
|
||||||
|
|||||||
+2
-1
@@ -53,6 +53,7 @@ class InboundOrderCreationServiceTest {
|
|||||||
assertThat(inboundCaptor.getValue().getCarrierId()).isNull();
|
assertThat(inboundCaptor.getValue().getCarrierId()).isNull();
|
||||||
assertThat(inboundCaptor.getValue().getTaxMode()).isEqualTo("BUY_DECLARATION");
|
assertThat(inboundCaptor.getValue().getTaxMode()).isEqualTo("BUY_DECLARATION");
|
||||||
assertThat(inboundCaptor.getValue().getPricingTaxMode()).isEqualTo("TAX_EXCLUDED");
|
assertThat(inboundCaptor.getValue().getPricingTaxMode()).isEqualTo("TAX_EXCLUDED");
|
||||||
|
assertThat(inboundCaptor.getValue().getTotalPackageCount()).isEqualTo(4);
|
||||||
assertThat(createdId).isEqualTo(inboundCaptor.getValue().getId());
|
assertThat(createdId).isEqualTo(inboundCaptor.getValue().getId());
|
||||||
assertThat(replayedId).isEqualTo(900L);
|
assertThat(replayedId).isEqualTo(900L);
|
||||||
}
|
}
|
||||||
@@ -97,6 +98,6 @@ class InboundOrderCreationServiceTest {
|
|||||||
return new OrderApprovedInboundCommand(
|
return new OrderApprovedInboundCommand(
|
||||||
10001L, 77L, "FL-77", inboundCode, 7L, "测试客户", 9L, "义乌仓",
|
10001L, 77L, "FL-77", inboundCode, 7L, "测试客户", 9L, "义乌仓",
|
||||||
null, null, null, "FBA", "AIR", "空运", null, null,
|
null, null, null, "FBA", "AIR", "空运", null, null,
|
||||||
"BUY_DECLARATION", "TAX_EXCLUDED", null, null, null, null, null, null, null, null, null);
|
"BUY_DECLARATION", "TAX_EXCLUDED", null, null, null, null, null, null, null, null, null, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public interface FirstlegInboundClient {
|
|||||||
Long carrierId, String carrierName, String taxMode, String pricingTaxMode, String containerMode,
|
Long carrierId, String carrierName, String taxMode, String pricingTaxMode, String containerMode,
|
||||||
Boolean customsInspection, String destinationType, Long destinationWarehouseId,
|
Boolean customsInspection, String destinationType, Long destinationWarehouseId,
|
||||||
String destinationCode, String destinationName, String publicRemark,
|
String destinationCode, String destinationName, String publicRemark,
|
||||||
String expressCompanyName, String expressTrackingNo
|
String expressCompanyName, String expressTrackingNo, Integer totalPackageCount
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ public class OrderApplicationService {
|
|||||||
event.setEventType(target == OrderStatus.APPROVED ? "FIRST_LEG_ORDER_APPROVED" : "FIRST_LEG_ORDER_CANCELLED");
|
event.setEventType(target == OrderStatus.APPROVED ? "FIRST_LEG_ORDER_APPROVED" : "FIRST_LEG_ORDER_CANCELLED");
|
||||||
try {
|
try {
|
||||||
event.setPayloadJson(target == OrderStatus.APPROVED
|
event.setPayloadJson(target == OrderStatus.APPROVED
|
||||||
? json.writeValueAsString(inboundCommand(order))
|
? json.writeValueAsString(inboundCommand(order, totalPackageCount(order)))
|
||||||
: json.writeValueAsString(Map.of("tenantId", order.getTenantId(), "orderId", order.getId(),
|
: json.writeValueAsString(Map.of("tenantId", order.getTenantId(), "orderId", order.getId(),
|
||||||
"orderNo", order.getOrderNo(), "status", target.name())));
|
"orderNo", order.getOrderNo(), "status", target.name())));
|
||||||
} catch (JsonProcessingException exception) { throw new BizException("Cannot serialize order event"); }
|
} catch (JsonProcessingException exception) { throw new BizException("Cannot serialize order event"); }
|
||||||
@@ -433,6 +433,10 @@ public class OrderApplicationService {
|
|||||||
repository.insertOutbox(event);
|
repository.insertOutbox(event);
|
||||||
}
|
}
|
||||||
static FirstlegInboundClient.OrderApprovedInboundCommand inboundCommand(OrderEntity order) {
|
static FirstlegInboundClient.OrderApprovedInboundCommand inboundCommand(OrderEntity order) {
|
||||||
|
return inboundCommand(order, null);
|
||||||
|
}
|
||||||
|
static FirstlegInboundClient.OrderApprovedInboundCommand inboundCommand(OrderEntity order,
|
||||||
|
Integer totalPackageCount) {
|
||||||
return new FirstlegInboundClient.OrderApprovedInboundCommand(
|
return new FirstlegInboundClient.OrderApprovedInboundCommand(
|
||||||
order.getTenantId(), order.getId(), order.getOrderNo(), order.getInboundCode(),
|
order.getTenantId(), order.getId(), order.getOrderNo(), order.getInboundCode(),
|
||||||
order.getCustomerId(), order.getCustomerName(),
|
order.getCustomerId(), order.getCustomerName(),
|
||||||
@@ -443,7 +447,18 @@ public class OrderApplicationService {
|
|||||||
order.getTaxMode(), order.getPricingTaxMode(),
|
order.getTaxMode(), order.getPricingTaxMode(),
|
||||||
order.getContainerMode(), order.getCustomsInspection(), order.getDestinationType(),
|
order.getContainerMode(), order.getCustomsInspection(), order.getDestinationType(),
|
||||||
order.getDestinationWarehouseId(), order.getAmazonWarehouseCode(), order.getDestinationWarehouseName(),
|
order.getDestinationWarehouseId(), order.getAmazonWarehouseCode(), order.getDestinationWarehouseName(),
|
||||||
order.getCustomerRemark(), order.getExpressCompany(), order.getExpressTrackingNo());
|
order.getCustomerRemark(), order.getExpressCompany(), order.getExpressTrackingNo(), totalPackageCount);
|
||||||
|
}
|
||||||
|
private int totalPackageCount(OrderEntity order) {
|
||||||
|
long total = repository.findCargo(order.getTenantId(), order.getId()).stream()
|
||||||
|
.map(com.baiyue.order.entity.OrderCargoEntity::getPackageCount)
|
||||||
|
.filter(java.util.Objects::nonNull)
|
||||||
|
.mapToLong(Integer::longValue)
|
||||||
|
.sum();
|
||||||
|
if (total < 1 || total > 1_000_000) {
|
||||||
|
throw new BizException("订单货物总箱数必须为1至1000000箱");
|
||||||
|
}
|
||||||
|
return (int) total;
|
||||||
}
|
}
|
||||||
private String nextNo(long orderId) {
|
private String nextNo(long orderId) {
|
||||||
return "FL" + orderId;
|
return "FL" + orderId;
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class OrderInboundOutboxPublisher {
|
|||||||
failPermanently(event, "order snapshot is unavailable");
|
failPermanently(event, "order snapshot is unavailable");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
command = OrderApplicationService.inboundCommand(order);
|
command = OrderApplicationService.inboundCommand(order, totalPackageCount(order));
|
||||||
if (incomplete(command)) {
|
if (incomplete(command)) {
|
||||||
failPermanently(event, "rebuilt order snapshot is incomplete");
|
failPermanently(event, "rebuilt order snapshot is incomplete");
|
||||||
continue;
|
continue;
|
||||||
@@ -77,7 +77,17 @@ public class OrderInboundOutboxPublisher {
|
|||||||
return command.orderNo() == null || command.orderNo().isBlank()
|
return command.orderNo() == null || command.orderNo().isBlank()
|
||||||
|| command.inboundCode() == null || command.inboundCode().isBlank()
|
|| command.inboundCode() == null || command.inboundCode().isBlank()
|
||||||
|| command.customerName() == null || command.customerName().isBlank()
|
|| command.customerName() == null || command.customerName().isBlank()
|
||||||
|| command.warehouseId() == null || command.warehouseId() <= 0;
|
|| command.warehouseId() == null || command.warehouseId() <= 0
|
||||||
|
|| command.totalPackageCount() == null || command.totalPackageCount() < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int totalPackageCount(com.baiyue.order.entity.OrderEntity order) {
|
||||||
|
long total = repository.findCargo(order.getTenantId(), order.getId()).stream()
|
||||||
|
.map(com.baiyue.order.entity.OrderCargoEntity::getPackageCount)
|
||||||
|
.filter(java.util.Objects::nonNull)
|
||||||
|
.mapToLong(Integer::longValue)
|
||||||
|
.sum();
|
||||||
|
return total > 0 && total <= 1_000_000 ? (int) total : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void failPermanently(OutboxEventEntity event, String reason) {
|
private void failPermanently(OutboxEventEntity event, String reason) {
|
||||||
|
|||||||
@@ -217,13 +217,17 @@ class OrderApplicationServiceStateTest {
|
|||||||
order.setInboundCode("RK-1");
|
order.setInboundCode("RK-1");
|
||||||
when(repository.findOwned(10001L, 1L)).thenReturn(order);
|
when(repository.findOwned(10001L, 1L)).thenReturn(order);
|
||||||
when(repository.saveOrder(10001L, order)).thenReturn(1);
|
when(repository.saveOrder(10001L, order)).thenReturn(1);
|
||||||
|
OrderCargoEntity cargo = new OrderCargoEntity();
|
||||||
|
cargo.setPackageCount(4);
|
||||||
|
when(repository.findCargo(10001L, 1L)).thenReturn(List.of(cargo));
|
||||||
|
|
||||||
service(repository, mock(OrderEligibilityGuard.class), mock(OrderMasterDataGuard.class))
|
service(repository, mock(OrderEligibilityGuard.class), mock(OrderMasterDataGuard.class))
|
||||||
.transit(10001L, 2L, "u", 1L, OrderStatus.APPROVED, null);
|
.transit(10001L, 2L, "u", 1L, OrderStatus.APPROVED, null);
|
||||||
|
|
||||||
assertThat(order.getStatus()).isEqualTo(OrderStatus.APPROVED);
|
assertThat(order.getStatus()).isEqualTo(OrderStatus.APPROVED);
|
||||||
verify(repository).insertOutbox(argThat(event -> event.getPayloadJson().contains("\"inboundCode\":\"RK-1\"")
|
verify(repository).insertOutbox(argThat(event -> event.getPayloadJson().contains("\"inboundCode\":\"RK-1\"")
|
||||||
&& event.getPayloadJson().contains("\"carrierId\":null")));
|
&& event.getPayloadJson().contains("\"carrierId\":null")
|
||||||
|
&& event.getPayloadJson().contains("\"totalPackageCount\":4")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -290,10 +294,11 @@ class OrderApplicationServiceStateTest {
|
|||||||
order.setTaxMode("BUY_DECLARATION");
|
order.setTaxMode("BUY_DECLARATION");
|
||||||
order.setPricingTaxMode("TAX_EXCLUDED");
|
order.setPricingTaxMode("TAX_EXCLUDED");
|
||||||
|
|
||||||
var command = OrderApplicationService.inboundCommand(order);
|
var command = OrderApplicationService.inboundCommand(order, 4);
|
||||||
|
|
||||||
assertThat(command.taxMode()).isEqualTo("BUY_DECLARATION");
|
assertThat(command.taxMode()).isEqualTo("BUY_DECLARATION");
|
||||||
assertThat(command.pricingTaxMode()).isEqualTo("TAX_EXCLUDED");
|
assertThat(command.pricingTaxMode()).isEqualTo("TAX_EXCLUDED");
|
||||||
|
assertThat(command.totalPackageCount()).isEqualTo(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class OrderInboundOutboxPublisherTest {
|
|||||||
org.assertj.core.api.Assertions.assertThat(command.getValue().warehouseId()).isEqualTo(31L);
|
org.assertj.core.api.Assertions.assertThat(command.getValue().warehouseId()).isEqualTo(31L);
|
||||||
org.assertj.core.api.Assertions.assertThat(command.getValue().taxMode()).isEqualTo("BUY_DECLARATION");
|
org.assertj.core.api.Assertions.assertThat(command.getValue().taxMode()).isEqualTo("BUY_DECLARATION");
|
||||||
org.assertj.core.api.Assertions.assertThat(command.getValue().pricingTaxMode()).isEqualTo("TAX_EXCLUDED");
|
org.assertj.core.api.Assertions.assertThat(command.getValue().pricingTaxMode()).isEqualTo("TAX_EXCLUDED");
|
||||||
|
org.assertj.core.api.Assertions.assertThat(command.getValue().totalPackageCount()).isEqualTo(4);
|
||||||
verify(fixture.repository).markOutboxPublished(eq(11L), eq(41L), any(LocalDateTime.class));
|
verify(fixture.repository).markOutboxPublished(eq(11L), eq(41L), any(LocalDateTime.class));
|
||||||
verify(fixture.repository, never()).markOutboxRetry(anyLong(), anyLong(), any());
|
verify(fixture.repository, never()).markOutboxRetry(anyLong(), anyLong(), any());
|
||||||
verify(fixture.repository, never()).markOutboxFailed(any(), anyLong());
|
verify(fixture.repository, never()).markOutboxFailed(any(), anyLong());
|
||||||
@@ -114,6 +115,12 @@ class OrderInboundOutboxPublisherTest {
|
|||||||
order.setTaxMode("BUY_DECLARATION");
|
order.setTaxMode("BUY_DECLARATION");
|
||||||
order.setPricingTaxMode("TAX_EXCLUDED");
|
order.setPricingTaxMode("TAX_EXCLUDED");
|
||||||
when(repository.findOwned(event.getTenantId(), event.getAggregateId())).thenReturn(order);
|
when(repository.findOwned(event.getTenantId(), event.getAggregateId())).thenReturn(order);
|
||||||
|
var firstCargo = new com.baiyue.order.entity.OrderCargoEntity();
|
||||||
|
firstCargo.setPackageCount(1);
|
||||||
|
var secondCargo = new com.baiyue.order.entity.OrderCargoEntity();
|
||||||
|
secondCargo.setPackageCount(3);
|
||||||
|
when(repository.findCargo(event.getTenantId(), event.getAggregateId()))
|
||||||
|
.thenReturn(List.of(firstCargo, secondCargo));
|
||||||
}
|
}
|
||||||
OrderInboundOutboxPublisher publisher = new OrderInboundOutboxPublisher();
|
OrderInboundOutboxPublisher publisher = new OrderInboundOutboxPublisher();
|
||||||
ReflectionTestUtils.setField(publisher, "repository", repository);
|
ReflectionTestUtils.setField(publisher, "repository", repository);
|
||||||
|
|||||||
Reference in New Issue
Block a user