114 lines
6.1 KiB
Java
114 lines
6.1 KiB
Java
package com.baiyue.file.controller;
|
||
|
||
import com.baiyue.common.core.api.ApiResponse;
|
||
import com.baiyue.common.core.api.ResultCode;
|
||
import com.baiyue.common.core.exception.BizException;
|
||
import com.baiyue.common.security.AuthenticatedUser;
|
||
import com.baiyue.file.client.IamQualificationClient;
|
||
import com.baiyue.file.service.LocalQualificationStorage;
|
||
import com.baiyue.file.service.QualificationPackageService;
|
||
import jakarta.annotation.Resource;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
import org.springframework.beans.factory.annotation.Value;
|
||
import org.springframework.http.CacheControl;
|
||
import org.springframework.http.MediaType;
|
||
import org.springframework.http.ResponseEntity;
|
||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||
import org.springframework.security.access.prepost.PreAuthorize;
|
||
import org.springframework.web.bind.annotation.*;
|
||
import org.springframework.web.multipart.MultipartFile;
|
||
|
||
import java.time.LocalDate;
|
||
|
||
@RestController
|
||
@RequestMapping("/api/merchant/v1/files/qualifications")
|
||
public class QualificationFileController {
|
||
private static final Logger LOGGER = LoggerFactory.getLogger(QualificationFileController.class);
|
||
@Resource private LocalQualificationStorage storage;
|
||
@Resource private IamQualificationClient iamClient;
|
||
@Resource private QualificationPackageService packageService;
|
||
@Value("${baiyue.security.internal-service-token}") private String internalToken;
|
||
|
||
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||
@PreAuthorize("hasAuthority('merchant:qualification:upload')")
|
||
public ApiResponse<UploadResponse> upload(
|
||
@AuthenticationPrincipal AuthenticatedUser user,
|
||
@RequestPart("file") MultipartFile file,
|
||
@RequestParam String qualificationType,
|
||
@RequestParam(value = "certificateNo", required = false) String certificateNo,
|
||
@RequestParam(required = false) LocalDate validTo,
|
||
@RequestParam(defaultValue = "false") boolean replace) {
|
||
long tenantId = merchantTenant(user);
|
||
qualificationType = QualificationTypes.requireSingleUpload(qualificationType);
|
||
var stored = storage.store(tenantId, file);
|
||
try {
|
||
var response = iamClient.submit(internalToken,
|
||
new IamQualificationClient.QualificationRequest(tenantId, qualificationType,
|
||
certificateNo, stored.documentUrl(), validTo, replace));
|
||
if (response == null) {
|
||
throw new IllegalStateException("IAM qualification response is empty");
|
||
}
|
||
if (!response.successful()) {
|
||
ResultCode code = ResultCode.of(response.code());
|
||
String message = response.message() == null || response.message().isBlank()
|
||
? code.message() : response.message();
|
||
storage.delete(stored);
|
||
throw new BizException(code, message);
|
||
}
|
||
if (response.data() == null) {
|
||
throw new IllegalStateException("IAM qualification response data is empty");
|
||
}
|
||
var data = response.data();
|
||
if (!stored.documentUrl().equals(data.replacedDocumentUrl())) {
|
||
storage.deleteByDocumentUrl(tenantId, data.replacedDocumentUrl());
|
||
}
|
||
return ApiResponse.success(new UploadResponse(data.qualificationId(), data.reviewId(),
|
||
data.tenantStatus(), stored.documentUrl()));
|
||
} catch (BizException exception) {
|
||
throw exception;
|
||
} catch (RuntimeException exception) {
|
||
LOGGER.error("IAM 资质登记结果未知,保留已写入文件等待重试或对账,tenantId={},documentUrl={}",
|
||
tenantId, stored.documentUrl(), exception);
|
||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "IAM qualification service is unavailable");
|
||
}
|
||
}
|
||
|
||
@PostMapping(value = "/required-package", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||
@PreAuthorize("hasAuthority('merchant:qualification:upload')")
|
||
public ApiResponse<QualificationPackageService.PackageUploadResult> uploadRequiredPackage(
|
||
@AuthenticationPrincipal AuthenticatedUser user,
|
||
@RequestPart(value = "businessLicense", required = false) MultipartFile businessLicense,
|
||
@RequestPart(value = "legalPersonId", required = false) MultipartFile legalPersonId,
|
||
@RequestParam String unifiedSocialCreditCode,
|
||
@RequestParam(required = false) LocalDate businessLicenseValidTo,
|
||
@RequestParam(required = false) LocalDate legalPersonIdValidTo,
|
||
@RequestParam(defaultValue = "false") boolean replaceBusinessLicense,
|
||
@RequestParam(defaultValue = "false") boolean replaceLegalPersonId) {
|
||
return ApiResponse.success(packageService.upload(merchantTenant(user), businessLicense, legalPersonId,
|
||
unifiedSocialCreditCode, businessLicenseValidTo, legalPersonIdValidTo,
|
||
replaceBusinessLicense, replaceLegalPersonId, false));
|
||
}
|
||
|
||
@GetMapping("/{fileName}")
|
||
public ResponseEntity<org.springframework.core.io.Resource> download(
|
||
@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String fileName) {
|
||
var resource = storage.load(merchantTenant(user), fileName);
|
||
String mediaType = fileName.endsWith(".png") ? MediaType.IMAGE_PNG_VALUE
|
||
: (fileName.endsWith(".pdf") ? MediaType.APPLICATION_PDF_VALUE : MediaType.IMAGE_JPEG_VALUE);
|
||
return ResponseEntity.ok().cacheControl(CacheControl.noStore())
|
||
.contentType(MediaType.parseMediaType(mediaType)).body(resource);
|
||
}
|
||
|
||
private long merchantTenant(AuthenticatedUser user) {
|
||
if (user == null || !"MERCHANT".equalsIgnoreCase(user.appCode())
|
||
|| user.tenantId() == null || user.tenantId() <= 0) {
|
||
throw new BizException(ResultCode.FORBIDDEN, "Merchant identity is required");
|
||
}
|
||
return user.tenantId();
|
||
}
|
||
|
||
public record UploadResponse(Long qualificationId, Long reviewId,
|
||
String tenantStatus, String documentUrl) { }
|
||
}
|