优化
This commit is contained in:
+1
-1
@@ -13,7 +13,7 @@
|
||||
| 目标 | 入口 |
|
||||
|---|---|
|
||||
| 客户资料/审核与企业联系信息 | `controller/PlatformTenantController.java`、`service/TenantService.java`;公司联系电话/邮箱属于企业资料,不作为登录标识且不要求跨企业唯一;审核必填资质仅营业执照与统一社会信用代码,法人身份证选填 |
|
||||
| 客户默认尺寸初始化、重试与补偿 | `service/CustomerDimensionRuleInitializationService.java`、`CustomerDimensionInitializationRelay.java`、`repository/CustomerDimensionInitializationRepository.java`、`client/CustomerDimensionRuleClient.java`、`model/CustomerDimensionInitializationTask.java`;持久任务异步调用 Firstleg `/internal/firstleg/v1/customer-dimension-configs/defaults` |
|
||||
| 客户默认箱规与权重系数初始化、重试及补偿 | `service/CustomerDimensionRuleInitializationService.java`、`CustomerDimensionInitializationRelay.java`、`repository/CustomerDimensionInitializationRepository.java`、`client/CustomerDimensionRuleClient.java`、`model/CustomerDimensionInitializationTask.java`;持久任务异步调用 Firstleg `/internal/firstleg/v1/customer-dimension-configs/defaults`,尺寸配置和默认权重系数规则均返回成功后才标记 `READY` |
|
||||
| 商户成员、登录手机号与个人资料 | `controller/MerchantTenantController.java`、`service/MemberService.java`、`service/PersonalProfileService.java`、`client/AuthAccountClient.java`;成员手机号是可选登录标识,变更时同步 Auth、撤销该账号全部会话并审计,不与公司联系电话联动 |
|
||||
| 平台用户与海外 PDA 仓绑定 | `controller/PlatformUserManagementController.java`、`service/PlatformUserManagementService.java`、`dto/PlatformUserManagementDtos.java`、`entity/IamMembership.java`;`OVERSEAS_WAREHOUSE_PDA_OPERATOR` 必须且只能绑定一个 `overseasWarehouseId` |
|
||||
| 角色/权限/RBAC | `controller/RbacController.java`、`service/RbacService.java` |
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/** Firstleg internal contract for atomically provisioning four default box-size dimension records. */
|
||||
/** Firstleg internal contract for atomically provisioning box-size and weight-coefficient defaults. */
|
||||
@FeignClient(name = "firstleg-service", contextId = "customerDimensionRuleClient",
|
||||
url = "${baiyue.clients.firstleg.url:}",
|
||||
path = "/internal/firstleg/v1/customer-dimension-configs")
|
||||
@@ -24,7 +24,8 @@ public interface CustomerDimensionRuleClient {
|
||||
@RequestParam long tenantId,
|
||||
@RequestParam String initializationKey);
|
||||
|
||||
record InitializationRequest(long tenantId, long operatorId, String initializationKey) { }
|
||||
/** configId is the first record ID retained only for contract compatibility. */
|
||||
record InitializationResponse(Long configId, boolean createdByThisInitialization) { }
|
||||
record InitializationRequest(long tenantId, long operatorId, String initializationKey,
|
||||
String customerName) { }
|
||||
record InitializationResponse(Long configId, Long chargeRuleId,
|
||||
boolean createdByThisInitialization) { }
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ package com.baiyue.iam.model;
|
||||
public record CustomerDimensionInitializationTask(
|
||||
long tenantId,
|
||||
long operatorId,
|
||||
String customerName,
|
||||
String initializationKey,
|
||||
String action,
|
||||
String status,
|
||||
int attemptCount,
|
||||
int taskVersion) {
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -73,11 +73,14 @@ public class CustomerDimensionInitializationRepository {
|
||||
+ "WHERE tenant_id=? AND status='PENDING' AND next_retry_at<=?",
|
||||
workerId, now.plusMinutes(2), now, tenantId, now);
|
||||
if (claimed != 1) return null;
|
||||
return jdbc.queryForObject("SELECT tenant_id,operator_id,initialization_key,action,status,"
|
||||
+ "attempt_count,task_version FROM iam_customer_dimension_initialization_task "
|
||||
+ "WHERE tenant_id=? AND status='SENDING' AND lease_owner=?",
|
||||
return jdbc.queryForObject("SELECT task.tenant_id,task.operator_id,tenant.tenant_name,"
|
||||
+ "task.initialization_key,task.action,task.status,task.attempt_count,task.task_version "
|
||||
+ "FROM iam_customer_dimension_initialization_task task "
|
||||
+ "JOIN iam_tenant tenant ON tenant.id=task.tenant_id "
|
||||
+ "WHERE task.tenant_id=? AND task.status='SENDING' AND task.lease_owner=?",
|
||||
(rs, row) -> new CustomerDimensionInitializationTask(
|
||||
rs.getLong("tenant_id"), rs.getLong("operator_id"), rs.getString("initialization_key"),
|
||||
rs.getLong("tenant_id"), rs.getLong("operator_id"), rs.getString("tenant_name"),
|
||||
rs.getString("initialization_key"),
|
||||
rs.getString("action"), rs.getString("status"), rs.getInt("attempt_count"),
|
||||
rs.getInt("task_version")), tenantId, workerId);
|
||||
}
|
||||
|
||||
@@ -43,10 +43,11 @@ public class CustomerDimensionInitializationRelay {
|
||||
}
|
||||
ApiResponse<CustomerDimensionRuleClient.InitializationResponse> response = client.initialize(
|
||||
internalToken, new CustomerDimensionRuleClient.InitializationRequest(
|
||||
task.tenantId(), task.operatorId(), task.initializationKey()));
|
||||
task.tenantId(), task.operatorId(), task.initializationKey(), task.customerName()));
|
||||
requireSuccess(response, true);
|
||||
if (response.data() == null || response.data().configId() == null) {
|
||||
throw new DeliveryFailure("S0503", "Firstleg 未返回默认尺寸配置ID", false);
|
||||
if (response.data() == null || response.data().configId() == null
|
||||
|| response.data().chargeRuleId() == null) {
|
||||
throw new DeliveryFailure("S0503", "Firstleg 未完整返回默认尺寸和权重系数规则ID", false);
|
||||
}
|
||||
repository.markReady(task, workerId, response.data().configId());
|
||||
} catch (Exception failure) {
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class CustomerDimensionRuleClientContractTest {
|
||||
@Test
|
||||
void usesOneAtomicCallForTheFourDefaultBoxDimensionRecords() throws Exception {
|
||||
void usesOneAtomicCallForBoxDimensionsAndWeightCoefficientRule() throws Exception {
|
||||
FeignClient feign = CustomerDimensionRuleClient.class.getAnnotation(FeignClient.class);
|
||||
PostMapping initialize = CustomerDimensionRuleClient.class
|
||||
.getMethod("initialize", String.class,
|
||||
@@ -25,6 +25,6 @@ class CustomerDimensionRuleClientContractTest {
|
||||
assertThat(compensate.value()).containsExactly("/defaults");
|
||||
assertThat(CustomerDimensionRuleClient.InitializationResponse.class.getRecordComponents())
|
||||
.extracting(java.lang.reflect.RecordComponent::getName)
|
||||
.containsExactly("configId", "createdByThisInitialization");
|
||||
.containsExactly("configId", "chargeRuleId", "createdByThisInitialization");
|
||||
}
|
||||
}
|
||||
|
||||
+20
-2
@@ -43,15 +43,33 @@ class CustomerDimensionInitializationRelayTest {
|
||||
CustomerDimensionInitializationTask task = task("INITIALIZE", 0);
|
||||
when(repository.claim(anyLong(), anyString(), any(LocalDateTime.class))).thenReturn(task);
|
||||
when(client.initialize(anyString(), any())).thenReturn(ApiResponse.success(
|
||||
new CustomerDimensionRuleClient.InitializationResponse(91L, true)));
|
||||
new CustomerDimensionRuleClient.InitializationResponse(91L, 191L, true)));
|
||||
|
||||
relay.deliver(10001L);
|
||||
|
||||
ArgumentCaptor<CustomerDimensionRuleClient.InitializationRequest> request =
|
||||
ArgumentCaptor.forClass(CustomerDimensionRuleClient.InitializationRequest.class);
|
||||
verify(client).initialize(anyString(), request.capture());
|
||||
assertTrue("柏悦物流".equals(request.getValue().customerName()));
|
||||
verify(repository).markReady(task, workerId(), 91L);
|
||||
verify(repository, never()).recordFailure(any(), anyString(), anyInt(), any(), anyString(),
|
||||
anyString(), any(Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingWeightCoefficientRuleKeepsInitializationFromBecomingReady() {
|
||||
CustomerDimensionInitializationTask task = task("INITIALIZE", 0);
|
||||
when(repository.claim(anyLong(), anyString(), any(LocalDateTime.class))).thenReturn(task);
|
||||
when(client.initialize(anyString(), any())).thenReturn(ApiResponse.success(
|
||||
new CustomerDimensionRuleClient.InitializationResponse(91L, null, true)));
|
||||
|
||||
relay.deliver(10001L);
|
||||
|
||||
verify(repository, never()).markReady(any(), anyString(), any());
|
||||
verify(repository).recordFailure(any(), anyString(), anyInt(), any(), anyString(),
|
||||
anyString(), any(Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void transientFailureStaysPendingWithDiagnosticAndBackoff() {
|
||||
CustomerDimensionInitializationTask task = task("INITIALIZE", 0);
|
||||
@@ -95,7 +113,7 @@ class CustomerDimensionInitializationRelayTest {
|
||||
}
|
||||
|
||||
private CustomerDimensionInitializationTask task(String action, int attempts) {
|
||||
return new CustomerDimensionInitializationTask(10001L, 9001L, "iam-customer-create:10001",
|
||||
return new CustomerDimensionInitializationTask(10001L, 9001L, "柏悦物流", "iam-customer-create:10001",
|
||||
action, "SENDING", attempts, 3);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user