优化
This commit is contained in:
+3
-4
@@ -40,19 +40,18 @@ public class ClientFinanceWalletController {
|
||||
return FinanceResponses.success(service.rechargeRequests(user.tenantId(), page, size));
|
||||
}
|
||||
|
||||
@GetMapping("/recharge-channels")
|
||||
@GetMapping("/recharge-channel")
|
||||
@PreAuthorize("hasAuthority('merchant:finance:recharge:create')")
|
||||
public ApiResponse<?> channels() { return FinanceResponses.success(service.channels()); }
|
||||
public ApiResponse<?> channel() { return FinanceResponses.success(service.channel()); }
|
||||
|
||||
@PostMapping(value = "/recharge-requests", consumes = "multipart/form-data")
|
||||
@PreAuthorize("hasAuthority('merchant:finance:recharge:create')")
|
||||
public ApiResponse<?> submit(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestHeader("Idempotency-Key") String idempotencyKey,
|
||||
@RequestParam BigDecimal amount,
|
||||
@RequestParam String paymentMethod,
|
||||
@RequestPart("file") MultipartFile file) {
|
||||
return FinanceResponses.success(service.submitRecharge(user.tenantId(), user.userId(), user.displayName(),
|
||||
idempotencyKey, amount, paymentMethod, file));
|
||||
idempotencyKey, amount, file));
|
||||
}
|
||||
|
||||
@GetMapping("/recharge-requests/{requestId}/voucher")
|
||||
|
||||
@@ -33,13 +33,12 @@ public final class FinanceWalletDtos {
|
||||
String remark, LocalDateTime createdAt) { }
|
||||
|
||||
public record RechargeRequest(long requestId, String requestNo, BigDecimal amount,
|
||||
String paymentMethod, long voucherFileId, String voucherFileName,
|
||||
long voucherFileId, String voucherFileName,
|
||||
String status, int version, String submittedByName,
|
||||
String reviewedByName, String reviewRemark,
|
||||
LocalDateTime createdAt, LocalDateTime reviewedAt) { }
|
||||
|
||||
public record RechargeChannel(String paymentMethod, String displayName,
|
||||
boolean enabled, String qrCodeUrl) { }
|
||||
public record RechargeChannel(boolean enabled, String qrCodeUrl) { }
|
||||
|
||||
public record RechargeReviewRequest(String decision, String remark, int expectedVersion) { }
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class FinanceWalletService {
|
||||
private static final Set<String> PAYMENT_METHODS = Set.of("WECHAT", "ALIPAY");
|
||||
private static final Set<String> ADJUSTMENT_PAYMENT_METHODS = Set.of("BANK_TRANSFER", "CASH", "OTHER");
|
||||
private static final Set<String> IMAGE_TYPES = Set.of("image/jpeg", "image/png");
|
||||
|
||||
@@ -51,15 +50,13 @@ public class FinanceWalletService {
|
||||
private final FinanceFileClient fileClient;
|
||||
private final FinanceDocumentNumberGenerator numberGenerator;
|
||||
private final String internalToken;
|
||||
private final String wechatQrCodeUrl;
|
||||
private final String alipayQrCodeUrl;
|
||||
private final String rechargeQrCodeUrl;
|
||||
|
||||
public FinanceWalletService(JdbcTemplate jdbc, ObjectMapper objectMapper,
|
||||
FinanceFileClient fileClient,
|
||||
FinanceDocumentNumberGenerator numberGenerator,
|
||||
@Value("${baiyue.security.internal-service-token:}") String internalToken,
|
||||
@Value("${baiyue.finance.recharge.wechat-qr-code-url:}") String wechatQrCodeUrl,
|
||||
@Value("${baiyue.finance.recharge.alipay-qr-code-url:}") String alipayQrCodeUrl,
|
||||
@Value("${baiyue.finance.recharge.qr-code-url:}") String rechargeQrCodeUrl,
|
||||
@Value("${spring.profiles.active:}") String activeProfiles,
|
||||
@Value("${DEPLOY_ENV:}") String deployEnvironment) {
|
||||
this.jdbc = jdbc;
|
||||
@@ -69,8 +66,7 @@ public class FinanceWalletService {
|
||||
this.internalToken = internalToken;
|
||||
boolean development = "development".equalsIgnoreCase(deployEnvironment.trim())
|
||||
|| List.of(activeProfiles.split(",")).stream().map(String::trim).anyMatch("dev"::equalsIgnoreCase);
|
||||
this.wechatQrCodeUrl = rechargeQrCode(wechatQrCodeUrl, development);
|
||||
this.alipayQrCodeUrl = rechargeQrCode(alipayQrCodeUrl, development);
|
||||
this.rechargeQrCodeUrl = rechargeQrCode(rechargeQrCodeUrl, development);
|
||||
}
|
||||
|
||||
private static String rechargeQrCode(String configured, boolean development) {
|
||||
@@ -104,22 +100,20 @@ public class FinanceWalletService {
|
||||
return WalletPage.of(rows, total == null ? 0 : total, page, size);
|
||||
}
|
||||
|
||||
public List<RechargeChannel> channels() {
|
||||
return List.of(new RechargeChannel("WECHAT", "微信支付", wechatQrCodeUrl != null, wechatQrCodeUrl),
|
||||
new RechargeChannel("ALIPAY", "支付宝", alipayQrCodeUrl != null, alipayQrCodeUrl));
|
||||
public RechargeChannel channel() {
|
||||
return new RechargeChannel(rechargeQrCodeUrl != null, rechargeQrCodeUrl);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public RechargeRequest submitRecharge(long customerId, long operatorId, String operatorName,
|
||||
String idempotencyKey, BigDecimal amount,
|
||||
String paymentMethod, MultipartFile file) {
|
||||
MultipartFile file) {
|
||||
requirePositive(customerId, "客户"); requirePositive(operatorId, "操作人");
|
||||
BigDecimal normalizedAmount = money(amount);
|
||||
String method = paymentMethod(paymentMethod);
|
||||
RechargeChannel channel = channels().stream().filter(value -> value.paymentMethod().equals(method)).findFirst().orElseThrow();
|
||||
if (!channel.enabled()) throw error("FIN-WALLET-CHANNEL-DISABLED", channel.displayName() + "收款二维码未配置");
|
||||
RechargeChannel channel = channel();
|
||||
if (!channel.enabled()) throw error("FIN-WALLET-CHANNEL-DISABLED", "收款二维码未配置");
|
||||
validateImage(file);
|
||||
String requestHash = hash(Map.of("amount", normalizedAmount.toPlainString(), "paymentMethod", method,
|
||||
String requestHash = hash(Map.of("amount", normalizedAmount.toPlainString(),
|
||||
"fileName", String.valueOf(file.getOriginalFilename()), "contentType", String.valueOf(file.getContentType()),
|
||||
"size", file.getSize(), "fileHash", fileHash(file)));
|
||||
Long replay = reserve(customerId, operatorId, "WALLET_RECHARGE_SUBMIT", idempotencyKey, requestHash);
|
||||
@@ -138,12 +132,12 @@ public class FinanceWalletService {
|
||||
KeyHolder holder = new GeneratedKeyHolder();
|
||||
jdbc.update(connection -> {
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"INSERT INTO fin_recharge_request(customer_id,request_no,amount,payment_method,voucher_file_id,voucher_file_name,status,version,submitted_by,submitted_by_name) VALUES(?,?,?,?,?,?,'PENDING',0,?,?)",
|
||||
"INSERT INTO fin_recharge_request(customer_id,request_no,amount,voucher_file_id,voucher_file_name,status,version,submitted_by,submitted_by_name) VALUES(?,?,?,?,?,'PENDING',0,?,?)",
|
||||
Statement.RETURN_GENERATED_KEYS);
|
||||
statement.setLong(1, customerId); statement.setString(2, requestNo);
|
||||
statement.setBigDecimal(3, normalizedAmount); statement.setString(4, method);
|
||||
statement.setLong(5, upload.data().fileId()); statement.setString(6, upload.data().fileName());
|
||||
statement.setLong(7, operatorId); statement.setString(8, clean(operatorName, 128));
|
||||
statement.setBigDecimal(3, normalizedAmount);
|
||||
statement.setLong(4, upload.data().fileId()); statement.setString(5, upload.data().fileName());
|
||||
statement.setLong(6, operatorId); statement.setString(7, clean(operatorName, 128));
|
||||
return statement;
|
||||
}, holder);
|
||||
long requestId = generatedId(holder);
|
||||
@@ -173,7 +167,7 @@ public class FinanceWalletService {
|
||||
WalletAccount afterAccount = rechargeAccount(account, before.amount());
|
||||
updateAccount(beforeCustomerId(requestId), afterAccount, account.version(), operatorId);
|
||||
insertLedger(beforeCustomerId(requestId), "RECHARGE", before.amount(), afterAccount,
|
||||
"CLIENT_RECHARGE", before.requestNo(), LocalDate.now(), before.paymentMethod(), null,
|
||||
"CLIENT_RECHARGE", before.requestNo(), LocalDate.now(), null, null,
|
||||
operatorId, operatorName, request.remark());
|
||||
}
|
||||
RechargeRequest after = requiredRecharge(requestId, null);
|
||||
@@ -587,7 +581,7 @@ public class FinanceWalletService {
|
||||
|
||||
private RechargeRequest rechargeRow(java.sql.ResultSet rs) throws java.sql.SQLException {
|
||||
return new RechargeRequest(rs.getLong("id"), rs.getString("request_no"), rs.getBigDecimal("amount"),
|
||||
rs.getString("payment_method"), rs.getLong("voucher_file_id"), rs.getString("voucher_file_name"),
|
||||
rs.getLong("voucher_file_id"), rs.getString("voucher_file_name"),
|
||||
rs.getString("status"), rs.getInt("version"), rs.getString("submitted_by_name"),
|
||||
rs.getString("reviewed_by_name"), rs.getString("review_remark"), timestamp(rs.getTimestamp("created_at")),
|
||||
timestamp(rs.getTimestamp("reviewed_at")));
|
||||
@@ -633,11 +627,6 @@ public class FinanceWalletService {
|
||||
if (normalized == null) throw bad("业务单号不能为空");
|
||||
return normalized;
|
||||
}
|
||||
private static String paymentMethod(String value) {
|
||||
String normalized = upper(value);
|
||||
if (!PAYMENT_METHODS.contains(normalized)) throw bad("付款方式无效");
|
||||
return normalized;
|
||||
}
|
||||
private static void validateImage(MultipartFile file) {
|
||||
if (file == null || file.isEmpty()) throw bad("请上传付款截图");
|
||||
if (!IMAGE_TYPES.contains(String.valueOf(file.getContentType()).toLowerCase(Locale.ROOT))) throw bad("付款截图仅支持 JPG 或 PNG");
|
||||
|
||||
Reference in New Issue
Block a user