优化
This commit is contained in:
+11
@@ -13,10 +13,12 @@ import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
@@ -81,6 +83,15 @@ public class InternalPalletLocationController {
|
||||
return ApiResponse.success(service.settle(request));
|
||||
}
|
||||
|
||||
@GetMapping("/occupied-resources")
|
||||
@Operation(summary = "查询业务当前占用资源", description = "PDA提交前使用的只读实时库存事实")
|
||||
public ApiResponse<List<LocationDtos.OccupiedResource>> occupiedResources(
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
@RequestParam long tenantId, @RequestParam String sourceService, @RequestParam long businessId) {
|
||||
verify(token);
|
||||
return ApiResponse.success(service.occupiedResources(tenantId, sourceService, businessId));
|
||||
}
|
||||
|
||||
@PostMapping("/rebind-temporary-location")
|
||||
@Operation(summary = "A0临时库位换绑", description = "将一条具体A0托盘占用换绑到同仓空闲普通库位")
|
||||
public ApiResponse<PalletAllocationDtos.RebindTemporaryLocationResult> rebindTemporaryLocation(
|
||||
|
||||
@@ -458,6 +458,19 @@ public class LocationResourceService {
|
||||
.toList();
|
||||
}
|
||||
|
||||
/** PDA 提交前读取当前占用事实;只读快照不持有数据库行锁。 */
|
||||
@Transactional(readOnly = true)
|
||||
public List<OccupiedResource> findOccupiedResources(long tenantId, String sourceService, long businessId) {
|
||||
return repository.findOccupanciesByBusiness(tenantId, sourceService, businessId).stream()
|
||||
.filter(item -> "OCCUPIED".equals(item.getOccupancyStatus()))
|
||||
.sorted(Comparator.comparingLong(LocationOccupancyEntity::getReservationId)
|
||||
.thenComparingLong(LocationOccupancyEntity::getId))
|
||||
.map(item -> new OccupiedResource(item.getReservationId(), item.getId(), 0,
|
||||
item.getWarehouseId(), item.getPalletId(), item.getLocationId(), item.getLocationCode(),
|
||||
Boolean.TRUE.equals(item.getSharedOverflow()), requireAllocatedPackageCount(item)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/** 将 A0 的一条托盘占用换绑到同仓空闲普通库位。 */
|
||||
@Transactional
|
||||
public LocationDtos.RebindTemporaryLocationResult rebindTemporaryLocation(
|
||||
|
||||
@@ -153,9 +153,6 @@ public class OverseasStorageFeeService {
|
||||
.thenComparingInt(OverseasStorageFeeDtos.TierRequest::startDay));
|
||||
for (String feeType : List.of("STORAGE", "RETURN_STORAGE")) {
|
||||
List<OverseasStorageFeeDtos.TierRequest> group = tiers.stream().filter(t -> feeType.equals(t.feeType())).toList();
|
||||
if (source.size() == 9 && (("STORAGE".equals(feeType) && group.size() != 5)
|
||||
|| ("RETURN_STORAGE".equals(feeType) && group.size() != 4)))
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "仓租必须5档,退货仓储费必须4档");
|
||||
int expectedStart = 1;
|
||||
for (int i = 0; i < group.size(); i++) {
|
||||
OverseasStorageFeeDtos.TierRequest tier = group.get(i);
|
||||
|
||||
+5
@@ -538,6 +538,11 @@ public class PalletLocationAllocationService {
|
||||
return new ArrayList<>(locationResourceService.findActiveResources(tenantId, sourceService, businessId));
|
||||
}
|
||||
|
||||
public List<LocationDtos.OccupiedResource> occupiedResources(long tenantId, String sourceService,
|
||||
long businessId) {
|
||||
return locationResourceService.findOccupiedResources(tenantId, sourceService, businessId);
|
||||
}
|
||||
|
||||
private static PalletAllocationDtos.BatchResult fromActive(List<LocationDtos.ActiveResource> active,
|
||||
PalletVolumeSplitter.SplitResult split) {
|
||||
if (active.size() != split.palletCount()) {
|
||||
|
||||
+13
@@ -3,6 +3,7 @@ package com.baiyue.warehouse.controller;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.warehouse.dto.PalletAllocationDtos;
|
||||
import com.baiyue.warehouse.dto.LocationDtos;
|
||||
import com.baiyue.warehouse.service.PalletLocationAllocationService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -65,6 +66,18 @@ class InternalPalletLocationControllerTest {
|
||||
verify(service).settle(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
void readsOccupiedResourcesOnlyForInternalCaller() {
|
||||
List<LocationDtos.OccupiedResource> expected = List.of(new LocationDtos.OccupiedResource(
|
||||
101L, 201L, 0, 20L, 30L, 40L, "A-01", false, 5));
|
||||
when(service.occupiedResources(0L, "firstleg-service", 88L)).thenReturn(expected);
|
||||
|
||||
var response = controller.occupiedResources(INTERNAL_TOKEN, 0L, "firstleg-service", 88L);
|
||||
|
||||
assertThat(response.data()).isEqualTo(expected);
|
||||
verify(service).occupiedResources(0L, "firstleg-service", 88L);
|
||||
}
|
||||
|
||||
private static PalletAllocationDtos.TransferRequest request() {
|
||||
return new PalletAllocationDtos.TransferRequest(10001L, "FIRSTLEG", 88L, 89L,
|
||||
"RK-001-S1", "transfer-88-89", 9001L, List.of(new PalletAllocationDtos.TransferItem(40L, 5)));
|
||||
|
||||
@@ -49,6 +49,27 @@ class LocationResourceServiceTest {
|
||||
assertThat(service.findActiveResources(0L, "firstleg-service", 901L)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsOnlyCurrentOccupiedResourcesWithAllocatedPackageCounts() {
|
||||
LocationOccupancyEntity active = occupancy(201L, 101L, 9L, "A1", 501L);
|
||||
active.setTenantId(0L);
|
||||
active.setSourceService("firstleg-service");
|
||||
active.setBusinessId(901L);
|
||||
active.setAllocatedPackageCount(7);
|
||||
LocationOccupancyEntity released = occupancy(202L, 102L, 10L, "A2", 502L);
|
||||
released.setOccupancyStatus("RELEASED");
|
||||
when(repository.findOccupanciesByBusiness(0L, "firstleg-service", 901L))
|
||||
.thenReturn(List.of(released, active));
|
||||
|
||||
var result = service.findOccupiedResources(0L, "firstleg-service", 901L);
|
||||
|
||||
assertThat(result).singleElement().satisfies(item -> {
|
||||
assertThat(item.reservationId()).isEqualTo(101L);
|
||||
assertThat(item.occupancyId()).isEqualTo(201L);
|
||||
assertThat(item.allocatedPackageCount()).isEqualTo(7);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleCase01() {
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse());
|
||||
|
||||
+25
@@ -53,6 +53,26 @@ class OverseasStorageFeeServiceTest {
|
||||
verify(repository, never()).insertRule(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsVariableTierCountsEvenWhenTotalIsNine() {
|
||||
doAnswer(invocation -> {
|
||||
OverseasStorageFeeRuleEntity rule = invocation.getArgument(0);
|
||||
rule.setId(10L);
|
||||
return null;
|
||||
}).when(repository).insertRule(any());
|
||||
List<OverseasStorageFeeDtos.TierRequest> tiers = List.of(
|
||||
typedTier("STORAGE", "CBM", 1, 10), typedTier("STORAGE", "CBM", 11, 20),
|
||||
typedTier("STORAGE", "CBM", 21, 30), typedTier("STORAGE", "CBM", 31, null),
|
||||
typedTier("RETURN_STORAGE", "PALLET", 1, 10), typedTier("RETURN_STORAGE", "PALLET", 11, 20),
|
||||
typedTier("RETURN_STORAGE", "PALLET", 21, 30), typedTier("RETURN_STORAGE", "PALLET", 31, 40),
|
||||
typedTier("RETURN_STORAGE", "PALLET", 41, null));
|
||||
|
||||
Long id = service.create(new OverseasStorageFeeDtos.CreateRequest(10001L, "示例客户", "USD", tiers));
|
||||
|
||||
assertThat(id).isEqualTo(10L);
|
||||
verify(repository).insertTiers(org.mockito.ArgumentMatchers.argThat(list -> list.size() == 9));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsDuplicateCustomer() {
|
||||
when(repository.existsCustomer(10001L, null)).thenReturn(true);
|
||||
@@ -124,6 +144,11 @@ class OverseasStorageFeeServiceTest {
|
||||
return new OverseasStorageFeeDtos.TierRequest(start, end, new BigDecimal(price));
|
||||
}
|
||||
|
||||
private static OverseasStorageFeeDtos.TierRequest typedTier(String feeType, String billingUnit,
|
||||
int start, Integer end) {
|
||||
return new OverseasStorageFeeDtos.TierRequest(feeType, billingUnit, start, end, BigDecimal.ONE);
|
||||
}
|
||||
|
||||
private static OverseasStorageFeeRuleEntity rule() {
|
||||
OverseasStorageFeeRuleEntity rule = new OverseasStorageFeeRuleEntity();
|
||||
rule.setId(10L);
|
||||
|
||||
Reference in New Issue
Block a user