优化
This commit is contained in:
+65
@@ -0,0 +1,65 @@
|
||||
package com.baiyue.finance.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.finance.client.FinanceFileClient;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.ContentDisposition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/finance/v1/vouchers")
|
||||
@PreAuthorize("hasAuthority('platform:finance:customer-arap:list')")
|
||||
public class PlatformFinanceVoucherController {
|
||||
private final FinanceFileClient files;
|
||||
private final String token;
|
||||
|
||||
public PlatformFinanceVoucherController(FinanceFileClient files,
|
||||
@Value("${baiyue.security.internal-service-token:}") String token) {
|
||||
this.files = files;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public record Voucher(String fileId, String fileName, String contentType, Long sizeBytes) {}
|
||||
|
||||
@GetMapping("/{fileId}")
|
||||
public ApiResponse<Voucher> metadata(@PathVariable long fileId, @RequestParam long customerId) {
|
||||
var file = scopedFile(customerId, fileId);
|
||||
return FinanceResponses.success(new Voucher(String.valueOf(fileId), file.fileName(), file.contentType(), file.sizeBytes()));
|
||||
}
|
||||
|
||||
@GetMapping("/{fileId}/content")
|
||||
public ResponseEntity<byte[]> content(@PathVariable long fileId, @RequestParam long customerId) {
|
||||
var file = scopedFile(customerId, fileId);
|
||||
var response = files.download(token, customerId, customerId, fileId);
|
||||
if (response == null || !response.getStatusCode().is2xxSuccessful() || response.getBody() == null) {
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "付款凭证读取失败,请稍后重试");
|
||||
}
|
||||
return ResponseEntity.ok().cacheControl(CacheControl.noStore())
|
||||
.header("X-Content-Type-Options", "nosniff")
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment()
|
||||
.filename(file.fileName() == null ? "付款凭证" : file.fileName(), StandardCharsets.UTF_8).build().toString())
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM).body(response.getBody());
|
||||
}
|
||||
|
||||
private FinanceFileClient.Metadata scopedFile(long customerId, long fileId) {
|
||||
if (customerId <= 0 || fileId <= 0) throw new BizException(ResultCode.BAD_REQUEST, "客户或付款凭证无效");
|
||||
var response = files.metadata(token, customerId, customerId, fileId);
|
||||
var file = response == null ? null : response.data();
|
||||
if (file == null || !Long.valueOf(fileId).equals(file.fileId())
|
||||
|| !Long.valueOf(customerId).equals(file.tenantId())
|
||||
|| !"FINANCE_VOUCHER".equals(file.businessType())
|
||||
|| !String.valueOf(customerId).equals(file.businessId())) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "付款凭证不存在或不属于当前客户");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
+10
-1
@@ -115,6 +115,13 @@ public class BusinessFeeSourceEventService {
|
||||
|| blank(value.feeItemName()) || !DIRECTIONS.contains(value.direction())
|
||||
|| value.businessDate() == null || !"CNY".equals(value.currency())
|
||||
|| value.totalAmount() == null || value.totalAmount().signum() <= 0
|
||||
|| !Set.of("CNY", "USD").contains(value.originalCurrency())
|
||||
|| value.originalAmount() == null || value.originalAmount().signum() <= 0
|
||||
|| value.exchangeRate() == null || value.exchangeRate().signum() <= 0
|
||||
|| blank(value.exchangeRateMonth())
|
||||
|| (value.periodStart() == null) != (value.periodEnd() == null)
|
||||
|| value.periodStart() != null && value.periodStart().isAfter(value.periodEnd())
|
||||
|| (value.chargeableQuantity() == null) != blank(value.quantityUnit())
|
||||
|| !"APPROVED".equals(value.reviewStatus()) || blank(value.sourceHash())) {
|
||||
throw error("FIN-EVT-012", "跨区费用来源快照字段不完整");
|
||||
}
|
||||
@@ -148,7 +155,9 @@ public class BusinessFeeSourceEventService {
|
||||
value.warehouseId(), value.feeItemCode(), value.feeItemName(), value.direction(), value.supplierId(),
|
||||
value.supplierName(), value.supplierCategory(), value.settlementMode(), value.paidAt(), value.paymentMethod(),
|
||||
value.paymentReferenceNo(), value.paymentVoucherFileIds(), value.businessDate(), value.currency(),
|
||||
value.totalAmount(), value.reviewStatus(), "PUBLISHED", "ACTIVE", null);
|
||||
value.totalAmount(), value.originalCurrency(), value.originalAmount(), value.exchangeRate(),
|
||||
value.exchangeRateMonth(), value.chargeableQuantity(), value.quantityUnit(), value.unitPrice(),
|
||||
value.periodStart(), value.periodEnd(), value.reviewStatus(), "PUBLISHED", "ACTIVE", null);
|
||||
String expected = EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(objectMapper.valueToTree(unsigned)));
|
||||
if (!expected.equals(value.sourceHash())) throw error("FIN-EVT-004", "费用来源快照哈希不一致");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user