暂存提交
This commit is contained in:
@@ -11,9 +11,12 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Service
|
||||
public class OrderMasterDataGuard {
|
||||
private static final Logger log = LoggerFactory.getLogger(OrderMasterDataGuard.class);
|
||||
private final WarehouseClient warehouses;
|
||||
private final PartnerClient partners;
|
||||
private final String token;
|
||||
@@ -37,13 +40,15 @@ public class OrderMasterDataGuard {
|
||||
}
|
||||
return new Snapshots(partner,receiving,destination);
|
||||
} catch (FeignException.NotFound exception) {
|
||||
throw new BizException(ResultCode.NOT_FOUND,"往来单位或仓库不存在、已停用或不属于当前企业");
|
||||
throw new BizException(ResultCode.NOT_FOUND,"往来单位或仓库不存在或不属于当前企业");
|
||||
} catch (FeignException.Conflict exception) {
|
||||
throw new BizException(ResultCode.CONFLICT,"往来单位或仓库已停用");
|
||||
} catch (FeignException exception) {
|
||||
throw unavailable("主数据");
|
||||
throw downstreamFailure(exception);
|
||||
} catch (BizException exception) {
|
||||
throw exception;
|
||||
} catch (RuntimeException exception) {
|
||||
throw unavailable("主数据");
|
||||
throw downstreamFailure(exception);
|
||||
}
|
||||
}
|
||||
public void validatePersisted(long tenantId, Long partnerId, Long receivingWarehouseId, Long destinationWarehouseId) {
|
||||
@@ -54,13 +59,15 @@ public class OrderMasterDataGuard {
|
||||
loadWarehouse(tenantId,receivingWarehouseId,"收货仓库");
|
||||
if (destinationWarehouseId!=null) loadWarehouse(tenantId,destinationWarehouseId,"目的仓库");
|
||||
} catch (FeignException.NotFound exception) {
|
||||
throw new BizException(ResultCode.NOT_FOUND,"往来单位或仓库已停用、越权或不存在");
|
||||
throw new BizException(ResultCode.NOT_FOUND,"往来单位或仓库不存在或不属于当前企业");
|
||||
} catch (FeignException.Conflict exception) {
|
||||
throw new BizException(ResultCode.CONFLICT,"往来单位或仓库已停用");
|
||||
} catch (FeignException exception) {
|
||||
throw unavailable("主数据");
|
||||
throw downstreamFailure(exception);
|
||||
} catch (BizException exception) {
|
||||
throw exception;
|
||||
} catch (RuntimeException exception) {
|
||||
throw unavailable("主数据");
|
||||
throw downstreamFailure(exception);
|
||||
}
|
||||
}
|
||||
private PartnerClient.Partner loadPartner(long tenantId,long id) {
|
||||
@@ -68,8 +75,10 @@ public class OrderMasterDataGuard {
|
||||
if (response==null || !response.successful() || response.data()==null)
|
||||
throw unavailable("往来单位");
|
||||
var value=response.data();
|
||||
if (!Long.valueOf(tenantId).equals(value.tenantId()) || !"ACTIVE".equals(value.status()))
|
||||
throw new BizException(ResultCode.FORBIDDEN,"往来单位不属于当前企业或已停用");
|
||||
if (!Long.valueOf(tenantId).equals(value.tenantId()))
|
||||
throw new BizException(ResultCode.FORBIDDEN,"往来单位不属于当前企业");
|
||||
if (!"ACTIVE".equals(value.status()))
|
||||
throw new BizException(ResultCode.CONFLICT,"往来单位已停用");
|
||||
if (!StringUtils.hasText(value.partnerName())) throw unavailable("往来单位");
|
||||
return value;
|
||||
}
|
||||
@@ -78,8 +87,10 @@ public class OrderMasterDataGuard {
|
||||
if (response==null || !response.successful() || response.data()==null || response.data().warehouse()==null)
|
||||
throw unavailable(name);
|
||||
var value=response.data();
|
||||
if (!Long.valueOf(tenantId).equals(value.warehouse().tenantId()) || !"ACTIVE".equals(value.warehouse().status()))
|
||||
throw new BizException(ResultCode.FORBIDDEN,name+"不属于当前企业或已停用");
|
||||
if (!Long.valueOf(tenantId).equals(value.warehouse().tenantId()))
|
||||
throw new BizException(ResultCode.FORBIDDEN,name+"不属于当前企业");
|
||||
if (!"ACTIVE".equals(value.warehouse().status()))
|
||||
throw new BizException(ResultCode.CONFLICT,name+"已停用");
|
||||
if (!Long.valueOf(id).equals(value.warehouse().id()) || !StringUtils.hasText(value.warehouse().warehouseName())) {
|
||||
throw unavailable(name);
|
||||
}
|
||||
@@ -88,6 +99,27 @@ public class OrderMasterDataGuard {
|
||||
private BizException unavailable(String name) {
|
||||
return new BizException(ResultCode.SERVICE_UNAVAILABLE,name+"服务暂时不可用");
|
||||
}
|
||||
private BizException downstreamFailure(RuntimeException exception) {
|
||||
FeignException feignException = findFeignException(exception);
|
||||
if (feignException != null) {
|
||||
if (feignException.status() == 404)
|
||||
return new BizException(ResultCode.NOT_FOUND,"往来单位或仓库不存在或不属于当前企业");
|
||||
if (feignException.status() == 409)
|
||||
return new BizException(ResultCode.CONFLICT,"往来单位或仓库已停用");
|
||||
if (feignException.status() == 403)
|
||||
return new BizException(ResultCode.SERVICE_UNAVAILABLE,
|
||||
"主数据内部服务凭证不一致,请检查 INTERNAL_SERVICE_TOKEN");
|
||||
}
|
||||
log.warn("订单主数据内部调用失败,已转换为 S0503", exception);
|
||||
return unavailable("主数据");
|
||||
}
|
||||
private FeignException findFeignException(Throwable exception) {
|
||||
Throwable current = exception;
|
||||
for (int depth = 0; current != null && depth < 10; depth++, current = current.getCause()) {
|
||||
if (current instanceof FeignException feignException) return feignException;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public record Snapshots(PartnerClient.Partner partner, WarehouseClient.Detail receiving,
|
||||
WarehouseClient.Detail destination) { }
|
||||
}
|
||||
|
||||
@@ -31,3 +31,14 @@ baiyue:
|
||||
url: ${IAM_SERVICE_URL:}
|
||||
warehouse:
|
||||
url: ${WAREHOUSE_SERVICE_URL:}
|
||||
|
||||
logging:
|
||||
file:
|
||||
name: "${LOGGING_FILE_NAME:${LOG_PATH:./logs}/${spring.application.name}.log}"
|
||||
logback:
|
||||
rollingpolicy:
|
||||
file-name-pattern: "${LOGGING_ROLLING_FILE_NAME_PATTERN:${LOG_PATH:./logs}/${spring.application.name}.%d{yyyy-MM-dd}.%i.log.gz}"
|
||||
max-file-size: "${LOGGING_ROLLING_MAX_FILE_SIZE:100MB}"
|
||||
max-history: "${LOGGING_ROLLING_MAX_HISTORY:30}"
|
||||
total-size-cap: "${LOGGING_ROLLING_TOTAL_SIZE_CAP:5GB}"
|
||||
clean-history-on-start: "${LOGGING_ROLLING_CLEAN_HISTORY_ON_START:false}"
|
||||
|
||||
@@ -6,11 +6,16 @@ import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.client.PartnerClient;
|
||||
import com.baiyue.order.client.WarehouseClient;
|
||||
import com.baiyue.order.dto.OrderRequests;
|
||||
import feign.FeignException;
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@@ -71,6 +76,67 @@ class OrderMasterDataGuardTest {
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
@Test
|
||||
void downstreamForbiddenExplainsInternalCredentialMismatch() {
|
||||
WarehouseClient warehouses=mock(WarehouseClient.class); PartnerClient partners=mock(PartnerClient.class);
|
||||
when(partners.active("token",10001,7)).thenThrow(feign(403));
|
||||
|
||||
assertThatThrownBy(() -> new OrderMasterDataGuard(warehouses,partners,"token").validate(10001,request(7L,8L)))
|
||||
.isInstanceOf(BizException.class)
|
||||
.satisfies(exception -> {
|
||||
BizException businessException = (BizException) exception;
|
||||
assertThat(businessException.getResultCode()).isEqualTo(ResultCode.SERVICE_UNAVAILABLE);
|
||||
assertThat(businessException.getMessage()).contains("内部服务凭证");
|
||||
});
|
||||
}
|
||||
@Test
|
||||
void downstreamNotFoundMapsToBusinessNotFound() {
|
||||
WarehouseClient warehouses=mock(WarehouseClient.class); PartnerClient partners=mock(PartnerClient.class);
|
||||
when(partners.active("token",10001,7)).thenThrow(feign(404));
|
||||
|
||||
assertThatThrownBy(() -> new OrderMasterDataGuard(warehouses,partners,"token").validate(10001,request(7L,8L)))
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.NOT_FOUND);
|
||||
}
|
||||
@Test
|
||||
void wrappedDownstreamConflictMapsToBusinessConflict() {
|
||||
WarehouseClient warehouses=mock(WarehouseClient.class); PartnerClient partners=mock(PartnerClient.class);
|
||||
when(partners.active("token",10001,7)).thenThrow(new IllegalStateException("wrapped", feign(409)));
|
||||
|
||||
assertThatThrownBy(() -> new OrderMasterDataGuard(warehouses,partners,"token").validate(10001,request(7L,8L)))
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.CONFLICT);
|
||||
}
|
||||
@Test
|
||||
void downstreamServerErrorMapsToServiceUnavailable() {
|
||||
WarehouseClient warehouses=mock(WarehouseClient.class); PartnerClient partners=mock(PartnerClient.class);
|
||||
when(partners.active("token",10001,7)).thenThrow(feign(500));
|
||||
|
||||
assertThatThrownBy(() -> new OrderMasterDataGuard(warehouses,partners,"token").validate(10001,request(7L,8L)))
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
@Test
|
||||
void inactiveMasterDataInSuccessfulResponseMapsToConflict() {
|
||||
WarehouseClient warehouses=mock(WarehouseClient.class); PartnerClient partners=mock(PartnerClient.class);
|
||||
when(partners.active("token",10001,7))
|
||||
.thenReturn(ApiResponse.success(new PartnerClient.Partner(7L,10001L,"客户","INACTIVE")));
|
||||
|
||||
assertThatThrownBy(() -> new OrderMasterDataGuard(warehouses,partners,"token").validate(10001,request(7L,8L)))
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.CONFLICT);
|
||||
}
|
||||
private FeignException feign(int status) {
|
||||
Request request = Request.create(Request.HttpMethod.GET, "http://warehouse-service/internal/test",
|
||||
Map.of(), null, StandardCharsets.UTF_8, null);
|
||||
Response response = Response.builder().status(status).reason("test").request(request)
|
||||
.headers(Map.of()).build();
|
||||
return FeignException.errorStatus("masterData", response);
|
||||
}
|
||||
private OrderRequests.SaveRequest request(Long partner,Long warehouse) {
|
||||
var party=new OrderRequests.Party("公司","联系人","13800138000",null,"CN",null,"深圳",null,"地址",null);
|
||||
var cargo=new OrderRequests.Cargo("货物",null,"CARTON",1,BigDecimal.ONE,BigDecimal.ONE,
|
||||
|
||||
Reference in New Issue
Block a user