fix(lastleg): preserve warehouse pallet business conflict responses
This commit is contained in:
+13
-5
@@ -179,15 +179,14 @@ public class HttpWarehouseResourceGateway implements WarehouseResourceGateway {
|
||||
.header("X-Internal-Service-Token", internalToken).retrieve()
|
||||
.onStatus(HttpStatusCode::isError, (request, result) -> { throw palletLookupFailure(result.getStatusCode()); })
|
||||
.body(WarehousePalletResponse.class);
|
||||
if (response == null || response.data() == null) throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE,
|
||||
"Warehouse pallet service returned no usable response");
|
||||
requirePalletResponse(response);
|
||||
return new WarehousePalletReference(response.data().id(), response.data().palletCode(), response.data().warehouseId(),
|
||||
response.data().locationId(), response.data().status(), response.data().fbaWarehouseCode(),
|
||||
response.data().unitPrice(), response.data().version());
|
||||
}
|
||||
|
||||
private ResponseStatusException palletLookupFailure(HttpStatusCode status) {
|
||||
return new ResponseStatusException(status.value() == 404 ? HttpStatus.NOT_FOUND
|
||||
return new ResponseStatusException(status.value() == 409 ? HttpStatus.CONFLICT : status.value() == 404 ? HttpStatus.NOT_FOUND
|
||||
: (status.is4xxClientError() ? HttpStatus.BAD_REQUEST : HttpStatus.SERVICE_UNAVAILABLE),
|
||||
status.value() == 404 ? "Warehouse pallet was not found" : "Warehouse pallet lookup failed");
|
||||
}
|
||||
@@ -199,14 +198,23 @@ public class HttpWarehouseResourceGateway implements WarehouseResourceGateway {
|
||||
.retrieve().onStatus(HttpStatusCode::isError, (request, result) -> {
|
||||
throw palletLookupFailure(result.getStatusCode());
|
||||
}).body(WarehousePalletResponse.class);
|
||||
requirePalletResponse(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
/** 托盘状态冲突是业务拒绝,不能把HTTP 200内的A0409误报为仓储服务不可用。 */
|
||||
private void requirePalletResponse(WarehousePalletResponse response) {
|
||||
if (response != null && "A0409".equals(response.code())) {
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT,
|
||||
response.message() == null || response.message().isBlank() ? "Warehouse pallet state conflicts with this operation" : response.message());
|
||||
}
|
||||
if (response != null && "A0404".equals(response.code())) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Warehouse pallet was not found");
|
||||
}
|
||||
if (response == null || response.data() == null) {
|
||||
if (response == null || !"200".equals(response.code()) || response.data() == null) {
|
||||
throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE,
|
||||
"Warehouse pallet service returned no usable response");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private WarehousePalletReference reference(WarehousePalletData pallet) {
|
||||
|
||||
+40
@@ -164,6 +164,46 @@ class HttpWarehouseResourceGatewayTest {
|
||||
server.verify();
|
||||
}
|
||||
|
||||
/** 实际SHIP后报废的原托扫码仍拒绝;保留提供者业务码/原因,不伪装为服务故障或按ID重试。 */
|
||||
@Test
|
||||
void inspectPreservesScrappedPalletBusinessConflictWithoutFallback() {
|
||||
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/D1747-1-001"))
|
||||
.andRespond(withSuccess("""
|
||||
{"code":"A0409","message":"托盘已报废","data":null}
|
||||
""", MediaType.APPLICATION_JSON));
|
||||
assertThatThrownBy(() -> gateway.inspectPallet("D1747-1-001"))
|
||||
.isInstanceOfSatisfying(ResponseStatusException.class, error -> {
|
||||
assertThat(error.getStatusCode()).isEqualTo(HttpStatus.CONFLICT);
|
||||
assertThat(error.getReason()).isEqualTo("托盘已报废");
|
||||
});
|
||||
server.verify();
|
||||
}
|
||||
|
||||
/** 按ID读取使用同一响应边界,错误码即使带data也不能被当作合法实托。 */
|
||||
@Test
|
||||
void idLookupRejectsBusinessConflictEvenWithPayload() {
|
||||
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/id/31"))
|
||||
.andRespond(withSuccess("""
|
||||
{"code":"A0409","message":"托盘状态冲突","data":{"palletId":31,"palletCode":"PAL-1",
|
||||
"warehouseId":88,"locationId":40,"status":"IDLE","version":1}}
|
||||
""", MediaType.APPLICATION_JSON));
|
||||
assertThatThrownBy(() -> gateway.resolvePallet(31L))
|
||||
.isInstanceOfSatisfying(ResponseStatusException.class, error ->
|
||||
assertThat(error.getStatusCode()).isEqualTo(HttpStatus.CONFLICT));
|
||||
server.verify();
|
||||
}
|
||||
|
||||
/** 同一个状态冲突无论通过HTTP状态还是业务信封传输,都不能降为400或503。 */
|
||||
@Test
|
||||
void inspectPreservesHttpConflict() {
|
||||
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/PAL-CONFLICT"))
|
||||
.andRespond(withStatus(HttpStatus.CONFLICT));
|
||||
assertThatThrownBy(() -> gateway.inspectPallet("PAL-CONFLICT"))
|
||||
.isInstanceOfSatisfying(ResponseStatusException.class, error ->
|
||||
assertThat(error.getStatusCode()).isEqualTo(HttpStatus.CONFLICT));
|
||||
server.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveReservedFallsBackToConfirmedPhysicalBindingForEarlierPlanDisplayCode() {
|
||||
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/IP-ACY2-20260909-166786-P001"))
|
||||
|
||||
Reference in New Issue
Block a user