This commit is contained in:
wujinliang
2026-09-18 09:16:02 +08:00
parent 522afd0185
commit 6be4e764a9
11 changed files with 211 additions and 27 deletions
@@ -33,6 +33,7 @@ public class CustomerAddressService {
@Transactional
public Long create(long tenantId, long userId, CustomerAddressDtos.SaveRequest request) {
ensureNoDuplicate(tenantId, request, null);
CustomerAddressEntity value = new CustomerAddressEntity();
value.setId(IdWorker.getId());
value.setTenantId(tenantId);
@@ -51,6 +52,7 @@ public class CustomerAddressService {
if (!value.getAddressType().equals(request.addressType())) {
throw new BizException(ResultCode.VALIDATION_FAILED, "地址类型创建后不可修改");
}
ensureNoDuplicate(tenantId, request, id);
if (request.defaultAddress()) clearDefault(tenantId, request.addressType(), id);
apply(value, request);
value.setUpdatedBy(userId);
@@ -99,6 +101,25 @@ public class CustomerAddressService {
.set(CustomerAddressEntity::getDefaultAddress, false));
}
private void ensureNoDuplicate(long tenantId, CustomerAddressDtos.SaveRequest request, Long excludedId) {
boolean duplicate = mapper.selectList(new LambdaQueryWrapper<CustomerAddressEntity>()
.eq(CustomerAddressEntity::getTenantId, tenantId)
.eq(CustomerAddressEntity::getActive, true)
.eq(CustomerAddressEntity::getAddressType, request.addressType())
.eq(CustomerAddressEntity::getCompanyName, request.companyName().trim())
.eq(CustomerAddressEntity::getContactName, request.contactName().trim())
.eq(CustomerAddressEntity::getPhone, request.phone().trim())
.eq(CustomerAddressEntity::getCountryCode, request.countryCode().trim().toUpperCase())
.eq(CustomerAddressEntity::getCity, request.city().trim())
.eq(CustomerAddressEntity::getAddressLine, request.addressLine().trim())
.ne(excludedId != null, CustomerAddressEntity::getId, excludedId))
.stream().findAny().isPresent();
if (duplicate) {
throw new BizException(ResultCode.CONFLICT, "PICKUP".equals(request.addressType())
? "相同的企业提货地址已存在" : "相同的企业私人仓地址已存在");
}
}
private static void apply(CustomerAddressEntity value, CustomerAddressDtos.SaveRequest source) {
value.setAddressType(source.addressType()); value.setAddressName(source.addressName().trim());
value.setCompanyName(source.companyName().trim()); value.setContactName(source.contactName().trim());
@@ -324,11 +324,11 @@ public class UnifiedOrderQueryService {
order.getDestinationWarehouseId(), order.getDestinationWarehouseName(), null, null,
order.getInboundCode(),
order.getExpectedShipDate(), null, null, totalPackageCount(cargo), null, null,
order.getEstimatedVolumeCbm(), volumeCbm(cargo), null, null,
order.getEstimatedVolumeCbm(), volumeCbm(cargo), grossWeightKg(cargo), volumeCbm(cargo),
order.getExpectedArrivalAt(), null, null, null, order.getFulfillmentType(), order.getLxCode(),
order.getPickupMethod(), order.getTaxMode(), order.getContainerMode(),
order.getCustomsInspection(), order.getDestinationType(), order.getAmazonWarehouseCode(),
null, null, null, null, null, null, null, order.getExpressCompany(), order.getExpressTrackingNo(),
null, null, null, null, netWeightKg(cargo), null, null, order.getExpressCompany(), order.getExpressTrackingNo(),
StringUtils.hasText(creatorName) ? creatorName : string(order.getCreatedBy()), skuNos(cargo), totalQuantity(cargo), shipmentId(order, cargo), referenceId(order, cargo),
null, null, null, null, null, coLoadGroup,
order.getCustomerRemark(), latestInternalNote, order.getWarehouseRemark(), order.getCustomerServiceRemark(),
@@ -348,13 +348,14 @@ public class UnifiedOrderQueryService {
displayedPackageCount(order, cargo, inbound), null,
distinctLocationCodes(inbound.locationCodes()),
order.getEstimatedVolumeCbm(), volumeCbm(cargo),
inbound.actualGrossWeightKg(), inbound.actualVolumeCbm(),
measuredOrDeclared(inbound.actualGrossWeightKg(), grossWeightKg(cargo)),
measuredOrDeclared(inbound.actualVolumeCbm(), volumeCbm(cargo)),
order.getExpectedArrivalAt() != null ? order.getExpectedArrivalAt() : inbound.expectedArrivalAt(), inbound.feeReviewStatus(),
inbound.companyName(), inbound.businessType(), inbound.fulfillmentType(), inbound.lxCode(),
order.getPickupMethod(), inbound.taxMode(), inbound.containerMode(),
inbound.customsInspection(), inbound.destinationType(), inbound.destinationCode(), inbound.palletCount(),
inbound.chargeableWeightKg(), inbound.chargeableVolumeCbm(), inbound.volumeWeightKg(),
inbound.actualNetWeightKg(),
measuredOrDeclared(inbound.actualNetWeightKg(), netWeightKg(cargo)),
inbound.measureCompletedAt(), inbound.inboundedAt(), inbound.expressCompanyName(), inbound.expressTrackingNo(),
StringUtils.hasText(creatorName) ? creatorName : inbound.createdByName(), skuNos(cargo), totalQuantity(cargo), shipmentId(order, cargo), referenceId(order, cargo), measurement(inbound),
preload(summary.preload()), loading(summary.loading()),
@@ -378,13 +379,14 @@ public class UnifiedOrderQueryService {
inbound.id(), inbound.version(), inbound.inboundCode(), null, inbound.holdFlag(), inbound.currentHoldReason(),
displayedPackageCount(order, cargo, inbound), null, distinctLocationCodes(inbound.locationCodes()),
order == null ? null : order.getEstimatedVolumeCbm(), volumeCbm(cargo),
inbound.actualGrossWeightKg(), inbound.actualVolumeCbm(),
measuredOrDeclared(inbound.actualGrossWeightKg(), grossWeightKg(cargo)),
measuredOrDeclared(inbound.actualVolumeCbm(), volumeCbm(cargo)),
order != null && order.getExpectedArrivalAt() != null ? order.getExpectedArrivalAt() : inbound.expectedArrivalAt(), inbound.feeReviewStatus(), inbound.companyName(),
inbound.businessType(), inbound.fulfillmentType(), inbound.lxCode(),
order == null ? null : order.getPickupMethod(), inbound.taxMode(), inbound.containerMode(),
inbound.customsInspection(), inbound.destinationType(), inbound.destinationCode(), inbound.palletCount(),
inbound.chargeableWeightKg(), inbound.chargeableVolumeCbm(), inbound.volumeWeightKg(),
inbound.actualNetWeightKg(),
measuredOrDeclared(inbound.actualNetWeightKg(), netWeightKg(cargo)),
inbound.measureCompletedAt(), inbound.inboundedAt(), inbound.expressCompanyName(), inbound.expressTrackingNo(),
inbound.createdByName(), skuNos(cargo), totalQuantity(cargo), shipmentId(order, cargo), referenceId(order, cargo),
measurement(inbound), preload(summary.preload()), loading(summary.loading()),
@@ -490,6 +492,10 @@ public class UnifiedOrderQueryService {
return cargo == null ? null : cargo.volumeCbm();
}
private BigDecimal measuredOrDeclared(BigDecimal measured, BigDecimal declared) {
return measured == null ? declared : measured;
}
private record CargoSummary(List<String> skuNos, List<String> shipmentIds, List<String> referenceIds,
Integer totalQuantity, Integer totalPackageCount, BigDecimal grossWeightKg,
BigDecimal netWeightKg, BigDecimal volumeCbm) {
@@ -7,9 +7,12 @@ import com.baiyue.order.mapper.CustomerAddressMapper;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -38,4 +41,21 @@ class CustomerAddressServiceTest {
assertThatThrownBy(() -> service.required(10001L, 90001L, "PICKUP"))
.isInstanceOf(BizException.class).hasMessage("客户地址不存在或已停用");
}
@Test
void rejectsDuplicatePickupAddressBeforeCreatingAnotherRecord() {
CustomerAddressMapper mapper = mock(CustomerAddressMapper.class);
CustomerAddressEntity duplicate = new CustomerAddressEntity();
duplicate.setId(90001L);
when(mapper.selectList(any())).thenReturn(List.of(duplicate));
CustomerAddressService service = new CustomerAddressService();
ReflectionTestUtils.setField(service, "mapper", mapper);
var request = new CustomerAddressDtos.SaveRequest("PICKUP", "深圳工厂", "柏悦物流",
"惠万昌", "13229608341", null, "CN", "江西省", "抚州市", null,
"崇仁县三山乡长仁大队廉家村", null, false);
assertThatThrownBy(() -> service.create(10001L, 20001L, request))
.isInstanceOf(BizException.class).hasMessage("相同的企业提货地址已存在");
verify(mapper, never()).insert(any(CustomerAddressEntity.class));
}
}
@@ -127,7 +127,7 @@ class UnifiedOrderQueryServiceTest {
}
@Test
void newlyCreatedOrderUsesItsOwnCargoPackageCountBeforeInboundExists() {
void newlyCreatedOrderUsesItsOwnCargoTotalsBeforeInboundExists() {
UnifiedOrderQuery query = query(null);
OrderEntity order = order(OrderStatus.APPROVED);
OrderCargoEntity cargo = new OrderCargoEntity();
@@ -144,13 +144,39 @@ class UnifiedOrderQueryServiceTest {
assertThat(service.page(10001L, query).records()).singleElement().satisfies(row -> {
assertThat(row.totalPackageCount()).isEqualTo(100);
assertThat(row.expectedVolumeCbm()).isEqualByComparingTo("0.375");
assertThat(row.actualGrossWeightKg()).isNull();
assertThat(row.totalNetWeightKg()).isNull();
assertThat(row.actualVolumeCbm()).isNull();
assertThat(row.actualGrossWeightKg()).isEqualByComparingTo("12.5");
assertThat(row.totalNetWeightKg()).isEqualByComparingTo("11.2");
assertThat(row.actualVolumeCbm()).isEqualByComparingTo("0.375");
});
verify(orders).findCargoByOrderIds(10001L, List.of(77L));
}
@Test
void unmeasuredInboundFallsBackToDeclaredCargoTotals() {
UnifiedOrderQuery query = query(null);
OrderEntity order = order(OrderStatus.APPROVED);
OrderCargoEntity cargo = new OrderCargoEntity();
cargo.setOrderId(77L);
cargo.setPackageCount(50);
cargo.setGrossWeightKg(new BigDecimal("1500"));
cargo.setNetWeightKg(new BigDecimal("25"));
cargo.setVolumeCbm(new BigDecimal("7.5"));
var summary = summary("WAIT_MEASURE", null);
when(summary.inbound().actualGrossWeightKg()).thenReturn(null);
when(summary.inbound().actualNetWeightKg()).thenReturn(null);
when(summary.inbound().actualVolumeCbm()).thenReturn(null);
when(orders.unifiedPage(eq(10001L), eq(query), any()))
.thenReturn(new PageResult<>(List.of(order), 1, 20, 1, 1));
when(firstleg.summaries(eq("internal-token"), any())).thenReturn(ApiResponse.success(List.of(summary)));
when(orders.findCargoByOrderIds(10001L, List.of(77L))).thenReturn(List.of(cargo));
assertThat(service.page(10001L, query).records()).singleElement().satisfies(row -> {
assertThat(row.actualGrossWeightKg()).isEqualByComparingTo("1500");
assertThat(row.totalNetWeightKg()).isEqualByComparingTo("25");
assertThat(row.actualVolumeCbm()).isEqualByComparingTo("7.5");
});
}
@Test
void dropshipMixedSkuRowsCountSharedCartonVolumeOnlyOnce() {
UnifiedOrderQuery query = query(null);