提交代码

This commit is contained in:
2026-08-03 15:46:50 +08:00
parent 8f5201112d
commit 9e69eff1c5
26 changed files with 383 additions and 58 deletions
@@ -9,6 +9,7 @@ import com.baiyue.iam.dto.OnboardingDtos.OrderEligibilityResponse;
import com.baiyue.iam.dto.OnboardingDtos.QualificationSubmissionRequest;
import com.baiyue.iam.dto.OnboardingDtos.QualificationSubmissionResponse;
import com.baiyue.iam.dto.OnboardingDtos.PlatformQualificationRegistrationRequest;
import com.baiyue.iam.dto.OnboardingDtos.PlatformQualificationRegistrationResponse;
import com.baiyue.iam.service.MerchantOnboardingService;
import com.baiyue.iam.service.ProfileResourceService;
import com.baiyue.iam.service.TenantService;
@@ -50,7 +51,7 @@ public class InternalTenantController {
}
@PostMapping("/platform-qualifications")
public ApiResponse<QualificationSubmissionResponse> registerPlatformQualification(
public ApiResponse<PlatformQualificationRegistrationResponse> registerPlatformQualification(
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
@Valid @RequestBody PlatformQualificationRegistrationRequest request) {
verify(token);
@@ -36,7 +36,15 @@ public final class OnboardingDtos {
@NotBlank @Pattern(regexp = "BUSINESS_LICENSE|LEGAL_PERSON_ID|FREIGHT_FORWARDER_CERTIFICATE|BANK_ACCOUNT_LICENSE") String qualificationType,
String certificateNo,
@NotBlank String documentUrl,
LocalDate validTo
LocalDate validTo,
boolean replace
) { }
public record PlatformQualificationRegistrationResponse(
Long qualificationId,
Long reviewId,
String tenantStatus,
String replacedDocumentUrl
) { }
public record OrderEligibilityResponse(boolean eligible, String tenantStatus, String reason) { }
@@ -34,6 +34,12 @@ public class ProfileResourceRepository {
public void saveQualification(IamTenantQualification qualification) { qualificationMapper.updateById(qualification); }
public List<IamTenantAddress> findAddresses(long tenantId) { return addressMapper.selectList(new LambdaQueryWrapper<IamTenantAddress>().eq(IamTenantAddress::getTenantId, tenantId)); }
public List<IamTenantQualification> findQualifications(long tenantId) { return qualificationMapper.selectList(new LambdaQueryWrapper<IamTenantQualification>().eq(IamTenantQualification::getTenantId, tenantId)); }
public List<IamTenantQualification> findQualificationsForUpdate(long tenantId) {
return qualificationMapper.selectList(new LambdaQueryWrapper<IamTenantQualification>()
.eq(IamTenantQualification::getTenantId, tenantId)
.orderByAsc(IamTenantQualification::getId)
.last("FOR UPDATE"));
}
public long countApprovedQualifications(long tenantId) {
return qualificationMapper.selectCount(new LambdaQueryWrapper<IamTenantQualification>()
.eq(IamTenantQualification::getTenantId, tenantId)
@@ -6,6 +6,7 @@ import com.baiyue.common.core.exception.BizException;
import com.baiyue.iam.dto.OnboardingDtos.QualificationSubmissionRequest;
import com.baiyue.iam.dto.OnboardingDtos.QualificationSubmissionResponse;
import com.baiyue.iam.dto.OnboardingDtos.PlatformQualificationRegistrationRequest;
import com.baiyue.iam.dto.OnboardingDtos.PlatformQualificationRegistrationResponse;
import com.baiyue.iam.dto.ProfileDtos.AddressRequest;
import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.entity.IamTenantAddress;
@@ -92,7 +93,7 @@ public class ProfileResourceService {
@Transactional
@BusinessAudit(event = "PLATFORM_TENANT_QUALIFICATION_UPLOAD", resourceType = "TENANT_QUALIFICATION",
resourceId = "#request.tenantId", description = "平台代客户上传资质", captureAfter = false)
public QualificationSubmissionResponse registerPlatformQualification(PlatformQualificationRegistrationRequest request) {
public PlatformQualificationRegistrationResponse registerPlatformQualification(PlatformQualificationRegistrationRequest request) {
IamTenant tenant = tenantRepository.findTenant(request.tenantId());
if (tenant == null || !"MERCHANT".equals(tenant.getTenantType())) {
throw new BizException(ResultCode.NOT_FOUND, "Enterprise not found / 企业客户不存在");
@@ -100,15 +101,26 @@ public class ProfileResourceService {
if (!"PROFILE_REQUIRED".equals(tenant.getStatus()) && !"REJECTED".equals(tenant.getStatus())) {
throw new BizException(ResultCode.CONFLICT, "Qualifications can only be uploaded before review / 仅待完善或已驳回客户可上传资质");
}
if (repository.findQualifications(tenant.getId()).stream().anyMatch(item ->
request.qualificationType().equals(item.getQualificationType()) && !"REJECTED".equals(item.getStatus()))) {
IamTenantQualification existing = repository.findQualificationsForUpdate(tenant.getId()).stream()
.filter(item -> request.qualificationType().equals(item.getQualificationType())
&& !"REJECTED".equals(item.getStatus()))
.findFirst().orElse(null);
if (existing != null && !request.replace()) {
throw new BizException(ResultCode.CONFLICT, "Qualification type already uploaded / 该类资质已上传");
}
String replacedDocumentUrl = null;
if (existing != null) {
replacedDocumentUrl = existing.getDocumentUrl();
existing.setStatus("REJECTED");
existing.setReviewComment("平台在送审前替换文件");
repository.saveQualification(existing);
}
IamTenantQualification qualification = createQualification(tenant.getId(), request.qualificationType(),
request.certificateNo(), request.documentUrl());
qualification.setValidTo(request.validTo());
repository.saveQualification(qualification);
return new QualificationSubmissionResponse(qualification.getId(), null, tenant.getStatus());
return new PlatformQualificationRegistrationResponse(
qualification.getId(), null, tenant.getStatus(), replacedDocumentUrl);
}
private IamTenantQualification createQualification(long tenant, String type, String certificateNo, String url) {
@@ -15,6 +15,7 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -29,11 +30,11 @@ class PlatformQualificationRegistrationTest {
IamTenant tenant = new IamTenant();
tenant.setId(10001L); tenant.setTenantType("MERCHANT"); tenant.setStatus("PROFILE_REQUIRED");
when(tenantRepository.findTenant(10001L)).thenReturn(tenant);
when(repository.findQualifications(10001L)).thenReturn(List.of());
when(repository.findQualificationsForUpdate(10001L)).thenReturn(List.of());
var response = service.registerPlatformQualification(new PlatformQualificationRegistrationRequest(
10001L, "LEGAL_PERSON_ID", null, "/api/merchant/v1/files/qualifications/file.pdf",
LocalDate.of(2030, 12, 31)));
LocalDate.of(2030, 12, 31), false));
ArgumentCaptor<IamTenantQualification> captor = ArgumentCaptor.forClass(IamTenantQualification.class);
verify(repository).insertQualification(captor.capture());
@@ -42,5 +43,34 @@ class PlatformQualificationRegistrationTest {
assertEquals(LocalDate.of(2030, 12, 31), captor.getValue().getValidTo());
assertEquals("PROFILE_REQUIRED", response.tenantStatus());
assertNull(response.reviewId());
assertNull(response.replacedDocumentUrl());
}
@Test
void platformCanReplaceAnUploadedQualificationBeforeReview() {
ProfileResourceRepository repository = mock(ProfileResourceRepository.class);
TenantRepository tenantRepository = mock(TenantRepository.class);
ProfileResourceService service = new ProfileResourceService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "tenantRepository", tenantRepository);
IamTenant tenant = new IamTenant();
tenant.setId(10001L); tenant.setTenantType("MERCHANT"); tenant.setStatus("PROFILE_REQUIRED");
IamTenantQualification existing = new IamTenantQualification();
existing.setId(88L); existing.setTenantId(10001L); existing.setQualificationType("LEGAL_PERSON_ID");
existing.setStatus("PENDING");
existing.setDocumentUrl("/api/merchant/v1/files/qualifications/old-file.pdf");
when(tenantRepository.findTenant(10001L)).thenReturn(tenant);
when(repository.findQualificationsForUpdate(10001L)).thenReturn(List.of(existing));
var response = service.registerPlatformQualification(new PlatformQualificationRegistrationRequest(
10001L, "LEGAL_PERSON_ID", null, "/api/merchant/v1/files/qualifications/new-file.pdf",
LocalDate.of(2031, 12, 31), true));
ArgumentCaptor<IamTenantQualification> captor = ArgumentCaptor.forClass(IamTenantQualification.class);
verify(repository, times(2)).saveQualification(captor.capture());
assertEquals("REJECTED", existing.getStatus());
assertEquals("平台在送审前替换文件", existing.getReviewComment());
assertEquals(existing.getDocumentUrl(), response.replacedDocumentUrl());
assertEquals("PENDING", captor.getAllValues().get(1).getStatus());
}
}