提交
This commit is contained in:
+100
-1
@@ -4,6 +4,7 @@ import com.baiyue.warehouse.dto.LocationDtos.ConfirmCommand;
|
||||
import com.baiyue.warehouse.dto.LocationDtos.OccupancyTarget;
|
||||
import com.baiyue.warehouse.dto.LocationDtos.ReservationTarget;
|
||||
import com.baiyue.warehouse.dto.LocationDtos.ReserveCommand;
|
||||
import com.baiyue.warehouse.dto.LocationDtos.SelectiveReleaseCommand;
|
||||
import com.baiyue.warehouse.entity.LocationEntity;
|
||||
import com.baiyue.warehouse.entity.LocationOccupancyEntity;
|
||||
import com.baiyue.warehouse.entity.LocationReservationEntity;
|
||||
@@ -20,6 +21,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
@@ -29,7 +31,7 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(LocationResourceService.class)
|
||||
@SpringJUnitConfig(classes = {LocationResourceService.class, PickingPackageAllocator.class})
|
||||
class LocationResourceServiceTest {
|
||||
@MockBean private LocationRepository repository;
|
||||
@Resource private LocationResourceService service;
|
||||
@@ -138,6 +140,79 @@ class LocationResourceServiceTest {
|
||||
verify(repository).insertOccupancy(any(LocationOccupancyEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReleaseOnlyExplicitlySelectedLocations() {
|
||||
List<LocationOccupancyEntity> active = List.of(
|
||||
occupancy(201L, 101L, 9L, "A1", 501L),
|
||||
occupancy(202L, 102L, 10L, "A2", 502L),
|
||||
occupancy(203L, 103L, 11L, "A3", 503L));
|
||||
when(repository.lockOccupiedByBusiness(10001L, "FIRSTLEG", 301L)).thenReturn(active);
|
||||
when(repository.findOwned(10001L, 88L, 10L)).thenReturn(occupiedLocation(10L, "A2"));
|
||||
when(repository.releaseOccupancy(active.get(1), "PDA partial pick")).thenReturn(1);
|
||||
when(repository.changeStatus(10001L, 88L, 10L, "OCCUPIED", "AVAILABLE", 0, 7L)).thenReturn(1);
|
||||
|
||||
var result = service.releaseSelected(new SelectiveReleaseCommand(10001L, "FIRSTLEG", 301L, 7L,
|
||||
"PDA partial pick", 10, List.of(10L), null));
|
||||
|
||||
assertThat(result).singleElement().satisfies(item -> {
|
||||
assertThat(item.allocationNo()).isEqualTo(2);
|
||||
assertThat(item.locationId()).isEqualTo(10L);
|
||||
assertThat(item.releasedPackageCount()).isEqualTo(4);
|
||||
});
|
||||
verify(repository, never()).releaseOccupancy(active.get(0), "PDA partial pick");
|
||||
verify(repository, never()).releaseOccupancy(active.get(2), "PDA partial pick");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReleaseFirstNAllocationsWhenLocationsAreNotSpecified() {
|
||||
List<LocationOccupancyEntity> active = List.of(
|
||||
occupancy(201L, 101L, 9L, "A1", 501L),
|
||||
occupancy(202L, 102L, 10L, "A2", 502L),
|
||||
occupancy(203L, 103L, 11L, "A3", 503L));
|
||||
when(repository.lockOccupiedByBusiness(10001L, "FIRSTLEG", 301L)).thenReturn(active);
|
||||
for (int index = 0; index < 2; index++) {
|
||||
LocationOccupancyEntity item = active.get(index);
|
||||
when(repository.findOwned(10001L, 88L, item.getLocationId()))
|
||||
.thenReturn(occupiedLocation(item.getLocationId(), item.getLocationCode()));
|
||||
when(repository.releaseOccupancy(item, "PDA default pick")).thenReturn(1);
|
||||
when(repository.changeStatus(10001L, 88L, item.getLocationId(), "OCCUPIED", "AVAILABLE", 0, 7L))
|
||||
.thenReturn(1);
|
||||
}
|
||||
|
||||
var result = service.releaseSelected(new SelectiveReleaseCommand(10001L, "FIRSTLEG", 301L, 7L,
|
||||
"PDA default pick", 10, List.of(), 2));
|
||||
|
||||
assertThat(result).extracting(item -> item.allocationNo()).containsExactly(1, 2);
|
||||
assertThat(result).extracting(item -> item.locationCode()).containsExactly("A1", "A2");
|
||||
assertThat(result).extracting(item -> item.releasedPackageCount()).containsExactly(4, 4);
|
||||
verify(repository, never()).releaseOccupancy(active.get(2), "PDA default pick");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectLocationOwnedByAnotherInboundOrder() {
|
||||
when(repository.lockOccupiedByBusiness(10001L, "FIRSTLEG", 301L)).thenReturn(List.of(
|
||||
occupancy(201L, 101L, 9L, "A1", 501L)));
|
||||
|
||||
assertThatThrownBy(() -> service.releaseSelected(new SelectiveReleaseCommand(
|
||||
10001L, "FIRSTLEG", 301L, 7L, "PDA partial pick", 10, List.of(99L), null)))
|
||||
.isInstanceOf(com.baiyue.common.core.exception.BizException.class);
|
||||
verify(repository, never()).releaseOccupancy(any(), any(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFailOnConcurrentOccupancyUpdate() {
|
||||
LocationOccupancyEntity active = occupancy(201L, 101L, 9L, "A1", 501L);
|
||||
when(repository.lockOccupiedByBusiness(10001L, "FIRSTLEG", 301L)).thenReturn(List.of(active));
|
||||
when(repository.findOwned(10001L, 88L, 9L)).thenReturn(occupiedLocation(9L, "A1"));
|
||||
when(repository.releaseOccupancy(active, "PDA pick")).thenReturn(0);
|
||||
|
||||
assertThatThrownBy(() -> service.releaseSelected(new SelectiveReleaseCommand(
|
||||
10001L, "FIRSTLEG", 301L, 7L, "PDA pick", 10, List.of(), 1)))
|
||||
.isInstanceOf(com.baiyue.common.core.exception.BizException.class);
|
||||
verify(repository, never()).changeStatus(anyLong(), anyLong(), anyLong(),
|
||||
any(String.class), any(String.class), anyInt(), anyLong());
|
||||
}
|
||||
|
||||
private static ReserveCommand reserveCommand() {
|
||||
return new ReserveCommand(10001L, 88L, "FIRSTLEG", 301L, "RK001", 7L,
|
||||
LocalDateTime.now().plusMinutes(30), List.of(
|
||||
@@ -176,6 +251,30 @@ class LocationResourceServiceTest {
|
||||
return location;
|
||||
}
|
||||
|
||||
private static LocationEntity occupiedLocation(long id, String code) {
|
||||
LocationEntity location = location(id, code);
|
||||
location.setStatus("OCCUPIED");
|
||||
return location;
|
||||
}
|
||||
|
||||
private static LocationOccupancyEntity occupancy(long id, long reservationId, long locationId,
|
||||
String locationCode, long palletId) {
|
||||
LocationOccupancyEntity occupancy = new LocationOccupancyEntity();
|
||||
occupancy.setId(id);
|
||||
occupancy.setTenantId(10001L);
|
||||
occupancy.setReservationId(reservationId);
|
||||
occupancy.setSourceService("FIRSTLEG");
|
||||
occupancy.setBusinessId(301L);
|
||||
occupancy.setWarehouseId(88L);
|
||||
occupancy.setPalletId(palletId);
|
||||
occupancy.setLocationId(locationId);
|
||||
occupancy.setLocationCode(locationCode);
|
||||
occupancy.setSharedOverflow(false);
|
||||
occupancy.setOccupancyStatus("OCCUPIED");
|
||||
occupancy.setVersion(0);
|
||||
return occupancy;
|
||||
}
|
||||
|
||||
private static LocationReservationEntity reservation(String status) {
|
||||
LocationReservationEntity reservation = new LocationReservationEntity();
|
||||
reservation.setId(101L);
|
||||
|
||||
+19
@@ -104,6 +104,25 @@ class PalletLocationAllocationServiceTest {
|
||||
verify(pallets, never()).findAvailable(any(Long.class), any(Long.class), any(), any(), any(Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReleaseOnlyPalletsReturnedBySelectedLocationRelease() {
|
||||
var resource = new LocationDtos.SelectiveReleaseResult(
|
||||
102L, 202L, 2, 20L, 30L, 40L, "A-02", 4);
|
||||
when(locations.releaseSelected(any())).thenReturn(List.of(resource));
|
||||
when(pallets.transitionStatus(10001L, 20L, 30L, List.of("OCCUPIED"), "AVAILABLE"))
|
||||
.thenReturn(1);
|
||||
|
||||
var result = service.releaseSelected(new PalletAllocationDtos.SelectiveReleaseRequest(
|
||||
10001L, "FIRSTLEG", 88L, 9001L, "PDA partial pick", 10, List.of(40L), null));
|
||||
|
||||
assertThat(result).singleElement().satisfies(item -> {
|
||||
assertThat(item.allocationNo()).isEqualTo(2);
|
||||
assertThat(item.locationId()).isEqualTo(40L);
|
||||
assertThat(item.releasedPackageCount()).isEqualTo(4);
|
||||
});
|
||||
verify(pallets).transitionStatus(10001L, 20L, 30L, List.of("OCCUPIED"), "AVAILABLE");
|
||||
}
|
||||
|
||||
private static PalletAllocationDtos.ReserveRequest reserve(long businessId) {
|
||||
return new PalletAllocationDtos.ReserveRequest(10001, 20, "FIRSTLEG", businessId, "RK-001", "measure-001",
|
||||
9001, new BigDecimal("2"), new BigDecimal("2"), "木托盘", LocalDateTime.now().plusMinutes(30), true);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.baiyue.warehouse.service;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PickingPackageAllocatorTest {
|
||||
private final PickingPackageAllocator allocator = new PickingPackageAllocator();
|
||||
|
||||
@Test
|
||||
void shouldUseCeilingShareAndCapFinalLocation() {
|
||||
assertThat(allocator.allocate(10, 3)).containsExactly(4, 4, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleExactDivision() {
|
||||
assertThat(allocator.allocate(12, 3)).containsExactly(4, 4, 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNeverAllocateMoreThanRemainingPackages() {
|
||||
assertThat(allocator.allocate(2, 3)).containsExactly(1, 1, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user