fix(overseas): price generated receiving pallets
This commit is contained in:
@@ -62,6 +62,7 @@ test('PDA module covers the container-number receiving contract and excludes out
|
|||||||
assert.doesNotMatch(source, /requestOverseas\('POST', '\/api\/platform\/v1\/warehouse-admin'/)
|
assert.doesNotMatch(source, /requestOverseas\('POST', '\/api\/platform\/v1\/warehouse-admin'/)
|
||||||
assert.doesNotMatch(source, /requestOverseas\('GET', '\/api\/platform\/v1\/warehouse-admin'/)
|
assert.doesNotMatch(source, /requestOverseas\('GET', '\/api\/platform\/v1\/warehouse-admin'/)
|
||||||
assert.match(source, /receiving-containers\/current\/pallets\/resolve/)
|
assert.match(source, /receiving-containers\/current\/pallets\/resolve/)
|
||||||
|
assert.match(source, /const locationCode = resolvedPallet\.data\?\.locationCode \|\| pallet\.locationCode/)
|
||||||
assert.match(source, /overseasWarehouseId, password/)
|
assert.match(source, /overseasWarehouseId, password/)
|
||||||
assert.match(source, /inbound\?\.overseasWarehouseId/)
|
assert.match(source, /inbound\?\.overseasWarehouseId/)
|
||||||
assert.doesNotMatch(source, /const warehouseId = id\(inbound\?\.destinationWarehouseId\)/)
|
assert.doesNotMatch(source, /const warehouseId = id\(inbound\?\.destinationWarehouseId\)/)
|
||||||
|
|||||||
@@ -203,14 +203,6 @@ async function verifyWarehouseQueries(context, token, inboundCode, pallet, desti
|
|||||||
&& inventoryItems.every((item) => nonBlank(item?.skuCode) && Number(item?.availablePackages) > 0),
|
&& inventoryItems.every((item) => nonBlank(item?.skuCode) && Number(item?.availablePackages) > 0),
|
||||||
`skuCodes=${[...new Set(inventoryItems.map((item) => item?.skuCode).filter(nonBlank))].join('|') || 'missing'}, availablePackages=${inventoryItems.reduce((total, item) => total + Number(item?.availablePackages || 0), 0)}; ${trace(inventory.response)}`, OPTIONS)
|
`skuCodes=${[...new Set(inventoryItems.map((item) => item?.skuCode).filter(nonBlank))].join('|') || 'missing'}, availablePackages=${inventoryItems.reduce((total, item) => total + Number(item?.availablePackages || 0), 0)}; ${trace(inventory.response)}`, OPTIONS)
|
||||||
|
|
||||||
const location = await pda(context, token, 'POST', '完成入库后扫码查询库位',
|
|
||||||
'/api/pda/v1/last-leg/locations/resolve', { code: pallet.locationCode })
|
|
||||||
context.assert(MODULE, '库位查询返回当前仓真实占用汇总', location.response,
|
|
||||||
success(location.response) && id(location.data?.locationId) === pallet.locationId
|
|
||||||
&& location.data?.locationCode === pallet.locationCode
|
|
||||||
&& Number(location.data?.occupiedPackages) > 0 && Number(location.data?.inventoryPositionCount) > 0,
|
|
||||||
`locationId=${id(location.data?.locationId) || 'missing'}; ${trace(location.response)}`, OPTIONS)
|
|
||||||
|
|
||||||
const resolvedPallet = await pda(context, token, 'POST', '完成入库后扫码查询托盘内容',
|
const resolvedPallet = await pda(context, token, 'POST', '完成入库后扫码查询托盘内容',
|
||||||
'/api/pda/v1/last-leg/pallets/resolve', { code: pallet.palletCode })
|
'/api/pda/v1/last-leg/pallets/resolve', { code: pallet.palletCode })
|
||||||
context.assert(MODULE, '托盘查询返回当前位置与库存明细', resolvedPallet.response,
|
context.assert(MODULE, '托盘查询返回当前位置与库存明细', resolvedPallet.response,
|
||||||
@@ -220,6 +212,15 @@ async function verifyWarehouseQueries(context, token, inboundCode, pallet, desti
|
|||||||
&& Number(resolvedPallet.data?.occupiedPackages) > 0,
|
&& Number(resolvedPallet.data?.occupiedPackages) > 0,
|
||||||
`palletId=${id(resolvedPallet.data?.palletId) || 'missing'}; ${trace(resolvedPallet.response)}`, OPTIONS)
|
`palletId=${id(resolvedPallet.data?.palletId) || 'missing'}; ${trace(resolvedPallet.response)}`, OPTIONS)
|
||||||
|
|
||||||
|
const locationCode = resolvedPallet.data?.locationCode || pallet.locationCode
|
||||||
|
const location = await pda(context, token, 'POST', '完成入库后扫码查询库位',
|
||||||
|
'/api/pda/v1/last-leg/locations/resolve', { code: locationCode })
|
||||||
|
context.assert(MODULE, '库位查询返回当前仓真实占用汇总', location.response,
|
||||||
|
success(location.response) && id(location.data?.locationId) === pallet.locationId
|
||||||
|
&& location.data?.locationCode === locationCode
|
||||||
|
&& Number(location.data?.occupiedPackages) > 0 && Number(location.data?.inventoryPositionCount) > 0,
|
||||||
|
`locationId=${id(location.data?.locationId) || 'missing'}; ${trace(location.response)}`, OPTIONS)
|
||||||
|
|
||||||
const history = await pda(context, token, 'GET', '查询当前仓管PDA作业历史',
|
const history = await pda(context, token, 'GET', '查询当前仓管PDA作业历史',
|
||||||
'/api/pda/v1/last-leg/operations?page=1&size=50')
|
'/api/pda/v1/last-leg/operations?page=1&size=50')
|
||||||
const historyRows = records(history.data)
|
const historyRows = records(history.data)
|
||||||
|
|||||||
+12
-1
@@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -46,6 +47,8 @@ public class WarehousePalletBatchService {
|
|||||||
@Resource private WarehouseResourceLockRepository lockRecords;
|
@Resource private WarehouseResourceLockRepository lockRecords;
|
||||||
@Resource private WarehouseResourceRepository repository;
|
@Resource private WarehouseResourceRepository repository;
|
||||||
@Resource private ObjectMapper objectMapper;
|
@Resource private ObjectMapper objectMapper;
|
||||||
|
@Value("${baiyue.pallet.auto-created-unit-price:1.00}")
|
||||||
|
private BigDecimal autoCreatedPalletUnitPrice;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public WarehousePalletBatchResponse ensureReserved(WarehousePalletBatchRequests.EnsureReserved request) {
|
public WarehousePalletBatchResponse ensureReserved(WarehousePalletBatchRequests.EnsureReserved request) {
|
||||||
@@ -81,7 +84,8 @@ public class WarehousePalletBatchService {
|
|||||||
for (WarehousePalletBatchRequests.Item requested : normalized.items()) {
|
for (WarehousePalletBatchRequests.Item requested : normalized.items()) {
|
||||||
Long palletId = resources.createPallet(WarehouseResourceService.PUBLIC_RESOURCE_SCOPE,
|
Long palletId = resources.createPallet(WarehouseResourceService.PUBLIC_RESOURCE_SCOPE,
|
||||||
normalized.warehouseId(), new PalletRequests.SaveRequest(null, requested.palletType(), null,
|
normalized.warehouseId(), new PalletRequests.SaveRequest(null, requested.palletType(), null,
|
||||||
BigDecimal.ZERO, "IDLE", null, "Auto-created for inbound plan " + requested.inboundPlanNo(),
|
requiredAutoCreatedPalletUnitPrice(), "IDLE", null,
|
||||||
|
"Auto-created for inbound plan " + requested.inboundPlanNo(),
|
||||||
requested.fbaWarehouseCode()));
|
requested.fbaWarehouseCode()));
|
||||||
WarehousePalletEntity pallet = resources.pallet(WarehouseResourceService.PUBLIC_RESOURCE_SCOPE,
|
WarehousePalletEntity pallet = resources.pallet(WarehouseResourceService.PUBLIC_RESOURCE_SCOPE,
|
||||||
normalized.warehouseId(), palletId);
|
normalized.warehouseId(), palletId);
|
||||||
@@ -110,6 +114,13 @@ public class WarehousePalletBatchService {
|
|||||||
return response(batch, created, false);
|
return response(batch, created, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BigDecimal requiredAutoCreatedPalletUnitPrice() {
|
||||||
|
if (autoCreatedPalletUnitPrice == null || autoCreatedPalletUnitPrice.signum() <= 0) {
|
||||||
|
throw new IllegalStateException("Auto-created pallet unit price must be greater than zero");
|
||||||
|
}
|
||||||
|
return autoCreatedPalletUnitPrice.setScale(2, java.math.RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public WarehousePalletBatchResponse confirm(WarehousePalletBatchRequests.Confirm request) {
|
public WarehousePalletBatchResponse confirm(WarehousePalletBatchRequests.Confirm request) {
|
||||||
WarehousePalletBatchRequests.Confirm normalized = normalize(request);
|
WarehousePalletBatchRequests.Confirm normalized = normalize(request);
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ spring:
|
|||||||
management.endpoints.web.exposure.include: health,info,prometheus
|
management.endpoints.web.exposure.include: health,info,prometheus
|
||||||
|
|
||||||
baiyue:
|
baiyue:
|
||||||
|
pallet:
|
||||||
|
auto-created-unit-price: ${AUTO_CREATED_PALLET_UNIT_PRICE:1.00}
|
||||||
clients:
|
clients:
|
||||||
domestic-warehouse:
|
domestic-warehouse:
|
||||||
url: ${DOMESTIC_WAREHOUSE_URL:}
|
url: ${DOMESTIC_WAREHOUSE_URL:}
|
||||||
|
|||||||
+6
-1
@@ -26,6 +26,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
|||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ class WarehousePalletBatchServiceTest {
|
|||||||
ReflectionTestUtils.setField(service, "lockRecords", lockRecords);
|
ReflectionTestUtils.setField(service, "lockRecords", lockRecords);
|
||||||
ReflectionTestUtils.setField(service, "repository", repository);
|
ReflectionTestUtils.setField(service, "repository", repository);
|
||||||
ReflectionTestUtils.setField(service, "objectMapper", new ObjectMapper());
|
ReflectionTestUtils.setField(service, "objectMapper", new ObjectMapper());
|
||||||
|
ReflectionTestUtils.setField(service, "autoCreatedPalletUnitPrice", new BigDecimal("1.00"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -74,8 +76,11 @@ class WarehousePalletBatchServiceTest {
|
|||||||
assertThat(response.status()).isEqualTo("RESERVED");
|
assertThat(response.status()).isEqualTo("RESERVED");
|
||||||
assertThat(response.items()).extracting(item -> item.customerId()).containsExactly(CUSTOMER_A, CUSTOMER_B);
|
assertThat(response.items()).extracting(item -> item.customerId()).containsExactly(CUSTOMER_A, CUSTOMER_B);
|
||||||
ArgumentCaptor<Long> scope = ArgumentCaptor.forClass(Long.class);
|
ArgumentCaptor<Long> scope = ArgumentCaptor.forClass(Long.class);
|
||||||
verify(resources, times(2)).createPallet(scope.capture(), anyLong(), any(PalletRequests.SaveRequest.class));
|
ArgumentCaptor<PalletRequests.SaveRequest> palletRequests = ArgumentCaptor.forClass(PalletRequests.SaveRequest.class);
|
||||||
|
verify(resources, times(2)).createPallet(scope.capture(), anyLong(), palletRequests.capture());
|
||||||
assertThat(scope.getAllValues()).containsOnly(WarehouseResourceService.PUBLIC_RESOURCE_SCOPE);
|
assertThat(scope.getAllValues()).containsOnly(WarehouseResourceService.PUBLIC_RESOURCE_SCOPE);
|
||||||
|
assertThat(palletRequests.getAllValues()).extracting(PalletRequests.SaveRequest::unitPrice)
|
||||||
|
.containsOnly(new BigDecimal("1.00"));
|
||||||
verify(batches, never()).lockByKey(WAREHOUSE, "container-1");
|
verify(batches, never()).lockByKey(WAREHOUSE, "container-1");
|
||||||
ArgumentCaptor<WarehouseResourceLockRequests.ReserveRequest> reservations =
|
ArgumentCaptor<WarehouseResourceLockRequests.ReserveRequest> reservations =
|
||||||
ArgumentCaptor.forClass(WarehouseResourceLockRequests.ReserveRequest.class);
|
ArgumentCaptor.forClass(WarehouseResourceLockRequests.ReserveRequest.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user