完成一键登录和支付功能
This commit was merged in pull request #43.
This commit is contained in:
+4
-2
@@ -10,20 +10,22 @@ import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDeta
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = "cn.novalon.gym.manage", exclude = {
|
||||
ReactiveUserDetailsServiceAutoConfiguration.class })
|
||||
//@EnableScheduling
|
||||
@EnableScheduling
|
||||
@EnableR2dbcRepositories(basePackages = {
|
||||
"cn.novalon.gym.manage.db.dao",
|
||||
"cn.novalon.gym.manage.sys.audit.repository" ,
|
||||
"cn.novalon.gym.manage.gymmembercard.dao",
|
||||
"cn.novalon.gym.manage.member.repository",
|
||||
"cn.novalon.gym.manage.groupcourse.dao",
|
||||
"cn.novalon.gym.manage.checkIn.repository"
|
||||
"cn.novalon.gym.manage.checkIn.repository",
|
||||
"cn.novalon.gym.manage.payment.repository"
|
||||
})
|
||||
@EnableReactiveElasticsearchRepositories(basePackages = "cn.novalon.gym.manage.member.es.repository")
|
||||
public class ManageApplication {
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package cn.novalon.gym.manage.app.config;
|
||||
|
||||
import cn.novalon.gym.manage.app.handler.PaymentWebSocketHandler;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.reactive.socket.WebSocketHandler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class PaymentWebSocketConfig {
|
||||
|
||||
private final PaymentWebSocketHandler paymentWebSocketHandler;
|
||||
|
||||
@Bean
|
||||
public HandlerMapping paymentWebSocketHandlerMapping() {
|
||||
Map<String, WebSocketHandler> map = new HashMap<>();
|
||||
map.put("/ws/payment/{orderNo}", paymentWebSocketHandler);
|
||||
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(map);
|
||||
mapping.setOrder(-1);
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
+32
-1
@@ -14,9 +14,11 @@ import cn.novalon.gym.manage.member.handler.MemberCardHandler;
|
||||
import cn.novalon.gym.manage.member.handler.MemberCardRecordHandler;
|
||||
import cn.novalon.gym.manage.member.handler.MemberCardTransactionHandler;
|
||||
import cn.novalon.gym.manage.member.handler.MemberHandler;
|
||||
import cn.novalon.gym.manage.member.handler.MemberStoredCardHandler;
|
||||
import cn.novalon.gym.manage.member.handler.WechatAuthHandler;
|
||||
import cn.novalon.gym.manage.notify.handler.SysNoticeHandler;
|
||||
import cn.novalon.gym.manage.notify.handler.SysUserMessageHandler;
|
||||
import cn.novalon.gym.manage.payment.handler.PaymentHandler;
|
||||
import cn.novalon.gym.manage.sys.handler.auth.PasswordDiagnosticHandler;
|
||||
import cn.novalon.gym.manage.sys.handler.auth.SysAuthHandler;
|
||||
import cn.novalon.gym.manage.sys.handler.config.SysConfigHandler;
|
||||
@@ -71,6 +73,7 @@ public class SystemRouter {
|
||||
MemberCardHandler memberCardHandler,
|
||||
MemberCardRecordHandler memberCardRecordHandler,
|
||||
MemberCardTransactionHandler memberCardTransactionHandler,
|
||||
MemberStoredCardHandler memberStoredCardHandler,
|
||||
GroupCourseHandler groupCourseHandler,
|
||||
GroupCourseBookingHandler groupCourseBookingHandler,
|
||||
GroupCourseRecommendHandler groupCourseRecommendHandler,
|
||||
@@ -78,7 +81,8 @@ public class SystemRouter {
|
||||
CourseLabelHandler courseLabelHandler,
|
||||
CheckInHandler checkInHandler,
|
||||
DataStatisticsHandler dataStatisticsHandler,
|
||||
PhoneAuthHandler phoneAuthHandler) {
|
||||
PhoneAuthHandler phoneAuthHandler,
|
||||
PaymentHandler paymentHandler) {
|
||||
|
||||
return route()
|
||||
// ========== 诊断路由 ==========
|
||||
@@ -262,6 +266,8 @@ public class SystemRouter {
|
||||
.POST("/api/member-card-records/{recordId}/use", memberCardRecordHandler::useCard)
|
||||
.POST("/api/member-card-records/{recordId}/refund", memberCardRecordHandler::refundCard)
|
||||
.GET("/api/member-card-records/my-cards/{memberId}", memberCardRecordHandler::getMyCards)
|
||||
.GET("/api/member-card-records/my-cards-with-status/{memberId}", memberCardRecordHandler::getMyCardsWithStatus)
|
||||
.GET("/api/member-card-records/primary/{memberId}", memberCardRecordHandler::getPrimaryCard)
|
||||
.GET("/api/member-card-records/{recordId}", memberCardRecordHandler::getMemberCardRecordById)
|
||||
.POST("/api/member-card-records/process-expired", memberCardRecordHandler::processExpiredCards)
|
||||
|
||||
@@ -270,10 +276,20 @@ public class SystemRouter {
|
||||
.GET("/api/member-card-transactions", memberCardTransactionHandler::getTransactionsWithConditions)
|
||||
.GET("/api/member-card-transactions/member/{memberId}", memberCardTransactionHandler::getMemberTransactions)
|
||||
.GET("/api/member-card-transactions/card/{cardId}", memberCardTransactionHandler::getTransactionsByCardId)
|
||||
.GET("/api/member-card-transactions/record/{recordId}", memberCardTransactionHandler::getTransactionsByRecordId)
|
||||
.GET("/api/member-card-transactions/statistics/deduct/{cardId}", memberCardTransactionHandler::getDeductCountByCardId)
|
||||
.GET("/api/member-card-transactions/statistics/renew", memberCardTransactionHandler::getRenewAmountByTimeRange)
|
||||
.GET("/api/member-card-transactions/statistics/purchase/{memberId}", memberCardTransactionHandler::getPurchaseAmountByMember)
|
||||
|
||||
// ===== 储值卡管理(包含支付密码) =====
|
||||
.GET("/api/stored-card/{memberId}", memberStoredCardHandler::getStoredCardInfo)
|
||||
.GET("/api/stored-card/{memberId}/balance", memberStoredCardHandler::getBalance)
|
||||
.GET("/api/stored-card/{memberId}/recharges", memberStoredCardHandler::getRechargeRecords)
|
||||
.GET("/api/pay-password/check/{memberId}", memberStoredCardHandler::checkPasswordSet)
|
||||
.POST("/api/pay-password/set/{memberId}", memberStoredCardHandler::setPassword)
|
||||
.POST("/api/pay-password/verify/{memberId}", memberStoredCardHandler::verifyPassword)
|
||||
.POST("/api/stored-card/pay/{memberId}", memberStoredCardHandler::payWithStoredCard)
|
||||
|
||||
// ========================================
|
||||
// ========== 团课管理路由 =================
|
||||
// ========================================
|
||||
@@ -360,6 +376,21 @@ public class SystemRouter {
|
||||
.GET("/api/datacount/history", dataStatisticsHandler::queryHistoricalStatistics)
|
||||
.GET("/api/datacount/export", dataStatisticsHandler::exportStatistics)
|
||||
|
||||
// ========================================
|
||||
// ========== 支付模块路由 ================
|
||||
// ========================================
|
||||
|
||||
.POST("/api/payment/create", paymentHandler::createPayment)
|
||||
.POST("/api/payment/qrcode/create", paymentHandler::createQrCodePayment)
|
||||
.GET("/api/payment/all", paymentHandler::getAllPaymentOrders)
|
||||
.GET("/api/payment/huifu/list", paymentHandler::queryHuifuTradeList)
|
||||
.GET("/api/payment/huifu/query", paymentHandler::queryHuifuTradeByOrderId)
|
||||
.GET("/api/payment/notify/huifu", paymentHandler::huifuNotify)
|
||||
.GET("/api/payment/pending/{memberId}", paymentHandler::getPendingOrder)
|
||||
.GET("/api/payment/{orderId}", paymentHandler::getPaymentStatus)
|
||||
.POST("/api/payment/{orderId}/refund", paymentHandler::refundPayment)
|
||||
.POST("/api/payment/{orderId}/close", paymentHandler::closeOrder)
|
||||
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package cn.novalon.gym.manage.app.handler;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.socket.WebSocketHandler;
|
||||
import org.springframework.web.reactive.socket.WebSocketSession;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.Sinks;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PaymentWebSocketHandler implements WebSocketHandler {
|
||||
|
||||
private static final Map<String, Sinks.Many<String>> sessionSinks = new ConcurrentHashMap<>();
|
||||
|
||||
public static void sendMessage(String orderNo, String status) {
|
||||
Sinks.Many<String> sink = sessionSinks.get(orderNo);
|
||||
if (sink != null) {
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("orderId", orderNo);
|
||||
message.put("status", status);
|
||||
message.put("timestamp", System.currentTimeMillis());
|
||||
sink.tryEmitNext(message.toJSONString());
|
||||
log.info("[WebSocket] 推送支付状态, orderNo={}, status={}", orderNo, status);
|
||||
} else {
|
||||
log.warn("[WebSocket] 未找到连接, orderNo={}", orderNo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(WebSocketSession session) {
|
||||
String path = session.getHandshakeInfo().getUri().getPath();
|
||||
String orderNo = extractOrderNo(path);
|
||||
|
||||
log.info("[WebSocket] 客户端连接, orderNo={}", orderNo);
|
||||
|
||||
Sinks.Many<String> sink = Sinks.many().multicast().onBackpressureBuffer();
|
||||
sessionSinks.put(orderNo, sink);
|
||||
|
||||
Mono<Void> heartbeat = Mono.delay(Duration.ofSeconds(30))
|
||||
.repeat(() -> true)
|
||||
.then()
|
||||
.onErrorResume(e -> Mono.empty());
|
||||
|
||||
Mono<Void> send = session.send(
|
||||
sink.asFlux()
|
||||
.map(session::textMessage)
|
||||
.mergeWith(
|
||||
Flux.interval(Duration.ofSeconds(25))
|
||||
.map(tick -> {
|
||||
JSONObject ping = new JSONObject();
|
||||
ping.put("type", "ping");
|
||||
ping.put("timestamp", System.currentTimeMillis());
|
||||
return session.textMessage(ping.toJSONString());
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
Mono<Void> receive = session.receive()
|
||||
.doOnNext(message -> {
|
||||
log.debug("[WebSocket] 收到消息, orderNo={}, msg={}", orderNo, message.getPayloadAsText());
|
||||
})
|
||||
.then();
|
||||
|
||||
return Mono.zip(send, receive, heartbeat)
|
||||
.then()
|
||||
.doFinally(signal -> {
|
||||
sessionSinks.remove(orderNo);
|
||||
log.info("[WebSocket] 连接关闭, orderNo={}, signal={}", orderNo, signal);
|
||||
});
|
||||
}
|
||||
|
||||
private String extractOrderNo(String path) {
|
||||
if (path.startsWith("/ws/payment/")) {
|
||||
return path.substring("/ws/payment/".length());
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
package cn.novalon.gym.manage.app.service;
|
||||
|
||||
import cn.novalon.gym.manage.app.handler.PaymentWebSocketHandler;
|
||||
import cn.novalon.gym.manage.member.repository.MemberStoredCardRechargeRepository;
|
||||
import cn.novalon.gym.manage.member.repository.MemberStoredCardRepository;
|
||||
import cn.novalon.gym.manage.member.service.IMemberCardService;
|
||||
import cn.novalon.gym.manage.payment.entity.PaymentOrder;
|
||||
import cn.novalon.gym.manage.payment.repository.PaymentOrderRepository;
|
||||
import cn.novalon.gym.manage.payment.service.PaymentNotifyService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class PaymentNotifyServiceImpl implements PaymentNotifyService {
|
||||
|
||||
private final PaymentOrderRepository paymentOrderRepository;
|
||||
private final MemberStoredCardRepository memberStoredCardRepository;
|
||||
private final MemberStoredCardRechargeRepository memberStoredCardRechargeRepository;
|
||||
private final IMemberCardService memberCardService;
|
||||
private Long memberIdGlob;
|
||||
|
||||
public PaymentNotifyServiceImpl(PaymentOrderRepository paymentOrderRepository,
|
||||
MemberStoredCardRepository memberStoredCardRepository,
|
||||
MemberStoredCardRechargeRepository memberStoredCardRechargeRepository,
|
||||
IMemberCardService memberCardService) {
|
||||
this.paymentOrderRepository = paymentOrderRepository;
|
||||
this.memberStoredCardRepository = memberStoredCardRepository;
|
||||
this.memberStoredCardRechargeRepository = memberStoredCardRechargeRepository;
|
||||
this.memberCardService = memberCardService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> notifyPaymentStatus(String orderNo, String status,Long memberId) {
|
||||
memberIdGlob = memberId;
|
||||
return paymentOrderRepository.findByOrderNo(orderNo)
|
||||
.flatMap(order -> {
|
||||
log.info("[PaymentNotify] 支付通知: orderNo={}, status={}, orderType={}", orderNo, status, order.getOrderType());
|
||||
|
||||
if ("SUCCESS".equals(status)) {
|
||||
return handlePaymentSuccess(order);
|
||||
}
|
||||
|
||||
return Mono.empty();
|
||||
})
|
||||
.doOnSuccess(v -> {
|
||||
try {
|
||||
PaymentWebSocketHandler.sendMessage(orderNo, status);
|
||||
} catch (Exception e) {
|
||||
log.error("[PaymentNotify] WebSocket推送失败, orderNo={}, status={}", orderNo, status, e);
|
||||
}
|
||||
})
|
||||
.then();
|
||||
}
|
||||
|
||||
private Mono<Void> handlePaymentSuccess(PaymentOrder order) {
|
||||
String orderType = order.getOrderType();
|
||||
|
||||
if ("STORED_CARD_RECHARGE".equals(orderType)) {
|
||||
return handleStoredCardRecharge(order);
|
||||
}
|
||||
|
||||
if ("MEMBER_CARD".equals(orderType)) {
|
||||
return handleMemberCardPurchase(order);
|
||||
}
|
||||
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
private Mono<Void> handleMemberCardPurchase(PaymentOrder order) {
|
||||
String remark = order.getRemark();
|
||||
log.info("[PaymentNotify] 开始处理会员卡购买, orderNo={}, memberId={}, remark={}",
|
||||
order.getOrderNo(), order.getMemberId(), remark);
|
||||
|
||||
if (remark == null || remark.isEmpty()) {
|
||||
log.warn("[PaymentNotify] 会员卡购买订单缺少remark, orderNo={}", order.getOrderNo());
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
Long memberCardId = null;
|
||||
Integer count = 1;
|
||||
|
||||
try {
|
||||
String[] items = remark.split(";");
|
||||
for (String item : items) {
|
||||
String[] params = item.split(",");
|
||||
for (String param : params) {
|
||||
String[] keyValue = param.split(":");
|
||||
if (keyValue.length == 2) {
|
||||
String key = keyValue[0].trim();
|
||||
String value = keyValue[1].trim();
|
||||
if ("会员卡类型ID".equals(key)) {
|
||||
memberCardId = Long.parseLong(value);
|
||||
} else if ("数量".equals(key)) {
|
||||
count = Integer.parseInt(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[PaymentNotify] 解析会员卡购买参数异常, orderNo={}, remark={}", order.getOrderNo(), remark, e);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
if (memberCardId == null) {
|
||||
log.warn("[PaymentNotify] 会员卡购买参数不完整, orderNo={}, remark={}", order.getOrderNo(), remark);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
final Long finalMemberCardId = memberCardId;
|
||||
final int finalCount = count;
|
||||
final Long sourceOrderId = order.getId();
|
||||
|
||||
log.info("[PaymentNotify] 处理会员卡购买: orderNo={}, memberId={}, memberCardId={}, count={}",
|
||||
order.getOrderNo(), memberIdGlob, finalMemberCardId, finalCount);
|
||||
|
||||
return memberCardService.purchaseCard(memberIdGlob, finalMemberCardId, sourceOrderId)
|
||||
.doOnSuccess(record -> log.info("[PaymentNotify] 会员卡购买完成: orderNo={}, memberId={}, memberCardRecordId={}",
|
||||
order.getOrderNo(), memberIdGlob, record.getMemberCardRecordId()))
|
||||
.doOnError(e -> log.error("[PaymentNotify] 会员卡购买异常, orderNo={}", order.getOrderNo(), e))
|
||||
.onErrorResume(e -> Mono.empty())
|
||||
.then();
|
||||
}
|
||||
|
||||
private Mono<Void> handleStoredCardRecharge(PaymentOrder order) {
|
||||
String remark = order.getRemark();
|
||||
log.info("[PaymentNotify] 开始处理储值卡充值, orderNo={}, memberId={}, orderType={}, remark={}",
|
||||
order.getOrderNo(), order.getMemberId(), order.getOrderType(), remark);
|
||||
|
||||
if (remark == null || remark.isEmpty()) {
|
||||
log.warn("[PaymentNotify] 储值卡充值订单缺少remark, orderNo={}", order.getOrderNo());
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
BigDecimal rechargeAmount = null;
|
||||
BigDecimal bonus = null;
|
||||
|
||||
try {
|
||||
String[] params = remark.split("&");
|
||||
for (String param : params) {
|
||||
String[] keyValue = param.split("=");
|
||||
if (keyValue.length == 2) {
|
||||
String key = keyValue[0];
|
||||
String value = keyValue[1];
|
||||
if ("rechargeAmount".equals(key)) {
|
||||
rechargeAmount = new BigDecimal(value);
|
||||
} else if ("bonus".equals(key)) {
|
||||
bonus = new BigDecimal(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[PaymentNotify] 解析充值参数异常, orderNo={}, remark={}", order.getOrderNo(), remark, e);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
if (rechargeAmount == null) {
|
||||
log.warn("[PaymentNotify] 储值卡充值参数不完整, orderNo={}, remark={}", order.getOrderNo(), remark);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
final BigDecimal finalRechargeAmount = rechargeAmount;
|
||||
final BigDecimal finalBonus = bonus != null ? bonus : BigDecimal.ZERO;
|
||||
final BigDecimal totalAddAmount = finalRechargeAmount.add(finalBonus);
|
||||
Long memberId = memberIdGlob;
|
||||
final String orderNo = order.getOrderNo();
|
||||
final BigDecimal payAmount = order.getTransAmt();
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
log.info("[PaymentNotify] 处理储值卡充值: orderNo={}, memberId={}, rechargeAmount={}, bonus={}, total={}, payAmount={}",
|
||||
orderNo, memberId, finalRechargeAmount, finalBonus, totalAddAmount, payAmount);
|
||||
|
||||
return memberStoredCardRepository.findByMemberId(memberId)
|
||||
.flatMap(card -> {
|
||||
log.info("[PaymentNotify] 会员 {} 已有储值卡(cardId={}),直接充值", memberId, card.getId());
|
||||
return doRecharge(memberId, orderNo, finalRechargeAmount, finalBonus, totalAddAmount, payAmount, now);
|
||||
})
|
||||
.switchIfEmpty(Mono.defer(() -> {
|
||||
log.info("[PaymentNotify] 会员 {} 首次充值,创建储值卡并充值", memberId);
|
||||
return memberStoredCardRepository.createStoredCard(memberId)
|
||||
.doOnSuccess(rows -> log.info("[PaymentNotify] 创建储值卡结果: memberId={}, affectedRows={}", memberId, rows))
|
||||
.then(doRecharge(memberId, orderNo, finalRechargeAmount, finalBonus, totalAddAmount, payAmount, now));
|
||||
}))
|
||||
.doOnError(e -> log.error("[PaymentNotify] 处理储值卡充值异常, orderNo={}", orderNo, e))
|
||||
.onErrorResume(e -> Mono.empty());
|
||||
}
|
||||
|
||||
private Mono<Void> doRecharge(Long memberId, String orderNo, BigDecimal rechargeAmount, BigDecimal bonusAmount,
|
||||
BigDecimal totalAmount, BigDecimal payAmount, LocalDateTime now) {
|
||||
log.info("[PaymentNotify] 开始充值: memberId={}, orderNo={}, rechargeAmount={}, bonusAmount={}, totalAmount={}, payAmount={}",
|
||||
memberId, orderNo, rechargeAmount, bonusAmount, totalAmount, payAmount);
|
||||
|
||||
return memberStoredCardRepository.rechargeBalance(memberId, totalAmount)
|
||||
.flatMap(rows -> {
|
||||
log.info("[PaymentNotify] 充值结果: memberId={}, orderNo={}, affectedRows={}", memberId, orderNo, rows);
|
||||
if (rows != null && rows > 0) {
|
||||
log.info("[PaymentNotify] 储值卡余额更新成功: memberId={}, addedAmount={}", memberId, totalAmount);
|
||||
return memberStoredCardRechargeRepository.createRechargeRecord(
|
||||
memberId, orderNo, rechargeAmount, bonusAmount, totalAmount, payAmount
|
||||
).doOnSuccess(recordRows -> log.info("[PaymentNotify] 创建充值记录结果: orderNo={}, affectedRows={}", orderNo, recordRows))
|
||||
.then(
|
||||
memberStoredCardRechargeRepository.markSuccess(orderNo, now)
|
||||
.doOnSuccess(markRows -> log.info("[PaymentNotify] 标记充值成功结果: orderNo={}, affectedRows={}", orderNo, markRows))
|
||||
)
|
||||
.doOnSuccess(r -> {
|
||||
log.info("[PaymentNotify] 储值卡充值完成: orderNo={}, memberId={}, totalAmount={}", orderNo, memberId, totalAmount);
|
||||
}).then();
|
||||
} else {
|
||||
log.warn("[PaymentNotify] 储值卡余额更新失败(rows=0): memberId={}, orderNo={}", memberId, orderNo);
|
||||
return memberStoredCardRechargeRepository.createRechargeRecord(
|
||||
memberId, orderNo, rechargeAmount, bonusAmount, totalAmount, payAmount
|
||||
).then(
|
||||
memberStoredCardRechargeRepository.markFailed(orderNo)
|
||||
).then();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,13 @@ jwt:
|
||||
secret: novalon-gym-manage-jwt-secret-key-for-development-only-2026
|
||||
expiration: 86400000
|
||||
|
||||
dcloud:
|
||||
univerify:
|
||||
appid: __UNI__52E2F0D
|
||||
appkey: IKsoDGSM9l8pIws9gXtyp4
|
||||
api-secret: ${DCLOUD_API_SECRET:}
|
||||
api-url: https://fc-mp-339e2e1b-0096-4ddd-952d-c4e6b88048e4.next.bspapp.com/getPhoneByUniverify
|
||||
|
||||
rate:
|
||||
limit:
|
||||
limit-for-period: 10000
|
||||
|
||||
@@ -10,3 +10,12 @@ logging:
|
||||
level:
|
||||
cn.novalon.manage: INFO
|
||||
org.springframework.r2dbc: INFO
|
||||
|
||||
dcloud:
|
||||
univerify:
|
||||
appid: ${DCLOUD_APPID:__UNI__52E2F0D}
|
||||
appkey: ${DCLOUD_APPKEY:IKsoDGSM9l8pIws9gXtyp4}
|
||||
api-url: ${DCLOUD_API_URL:https://developer.dcloud.net.cn/api/client/univerify/getPhoneNumber}
|
||||
timeout: ${DCLOUD_TIMEOUT:10000}
|
||||
proxy-host: ${DCLOUD_PROXY_HOST:}
|
||||
proxy-port: ${DCLOUD_PROXY_PORT:}
|
||||
|
||||
@@ -104,3 +104,29 @@ alibaba:
|
||||
template-code: 100001
|
||||
code-length: 6
|
||||
code-expire-seconds: 300
|
||||
|
||||
dcloud:
|
||||
univerify:
|
||||
appid: __UNI__52E2F0D
|
||||
appkey: IKsoDGSM9l8pIws9gXtyp4
|
||||
api-url: https://developer.dcloud.net.cn/api/client/univerify/getPhoneNumber
|
||||
|
||||
huifu:
|
||||
mode: prod
|
||||
skill-source: hfps/1.3.0
|
||||
channel:
|
||||
sys-id: 6666000207573586
|
||||
product-id: XLSISV
|
||||
huifu-id: 6666000207573586
|
||||
rsa-private-key: ${HUIFU_CHANNEL_PRIVATE_KEY:MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCNUdQE59I4bV1dIgLs2IRN3Wl8KI2yS4KpTUQWrvvlUcBTztB8rIeN5lr6Yv4VsZ1TG0FAb0D80JjxEQ1+0HizYNOQ1h2935v2r8h7rx3VTLbMOkmsg8Lb8LQRTbPaJOZfsIZMzBytYiRzWunHaMlCr800EA3q5NMj9VjHQuamxKqyzyHqfkIjA/sZ8q9atVjn8ahUjPKdrGA8b79HexHhCgOSLdK+fWw0eMCsWWYP2qECLsvZ+tjfvqSBXx1kg7womwT1VBCf+0Dx+jJPKR3mxQfz2szoucJYuXRo55kA6yCwoeNsjanLDRkPBSy3NHdKrffP6YODhRHG6KHyayyNAgMBAAECggEATIR69TEETVNCEzRgOxe9A2AYRoa6ukhSdhMFA/c5IuCR747yqh7MwtNwfVRuWRazpZUDTr0uhfT4asad9QUx5YZO54RX1EAn9XkWZ4nY8G46J/iDfapWLrp09U2KTVpfdn5hKWH3QRX7wI4AON2O49HGnSL4NjAx9q1YpYOe2bqevxmB4uD9vR/FHMjZ2qWzPaL7pId98x4DCJCiZctBQqb7gxR8EseD1Ddn2HbH5DEUjoxz2umtL+zrcGKDFBy4kM3r+10FP5jFG4fJfZFQwrzMTEkXJriau9DMRTQ83rWHzNvhdTNUuyqah74ez5V1piVEOXCPudzFsMttD2DyzQKBgQDokQH3WtcQqwFTUo+uWVVup4NoQzNZpEGIHK17afRsf9YnkoJVqjhywq1dhQT+yuyW9geJJKWpHQIAS4gGudhNK+j6d//bbvvbkOmtsdWyZ6Z2EmY8JrPkHdHAcadNJX7vrIc1xPeyci4AHhErDHc3hhD5njuSLx3DUp4iODNxKwKBgQCbjyHvP90YGjh49DWklh2NJgR2+OR6Fd0afdmwtGKeCUP5l2To6rfLBbcSRIWCON4iLME5wLLdHcm5wAQukC4dsUB5iZffp21+7hrrwUw/G0MUzFudfhZkjsDU5i+FwnVMqmsLJPUsjJTOfKsJdA2DjnwfMcgxw9FeClGveSFNJwKBgQDCpjuDECDY7oeZeYyQXGzIxKOTbEtaR8Qha/83QCM3fHd9f35evK2qP45iq6bWqnkCkMEV4/pTZNf77zvWhU2oqYvBtxYKTwW1a8BphGJbg60rPZMb3TjLQLoB3B4uz6dCaqBwPH8kd7RQnNm5siFF84vZoLozTAQZKtj3wxorKQKBgQCGKnEONHqwaw0B5T7O8VoTfxKiug/07B6C1sCGk03rF/q0rkquSKK0S/2Vl9u+cOXFe+w7r2OVKjfuKRpyPpBHs7T0HiQLFhBuRVaat2DXnN/CdG8f6rvNhwHxnYanSwx4TxN7zShYf/doEEZEJP/y01ViYkFUCpvtC+FgAo0iSQKBgFrkJGxPo6T7i5ZF7VoZWdARnypfbOl4gF9GMrXykk0fnKBDTof9Bg34a8OX54cf4yEH1ifZzVtNyzPTH9FxV88TksWRouqi1Uo6///kJI6gXROspE91TpNtNGHPgLhebA83WlFtS/H7i5G6RO+6KO0uflSImfy3Owp/ChyFUGmn}
|
||||
rsa-public-key: ${HUIFU_CHANNEL_PUBLIC_KEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjVHUBOfSOG1dXSIC7NiETd1pfCiNskuCqU1EFq775VHAU87QfKyHjeZa+mL+FbGdUxtBQG9A/NCY8RENftB4s2DTkNYdvd+b9q/Ie68d1Uy2zDpJrIPC2/C0EU2z2iTmX7CGTMwcrWIkc1rpx2jJQq/NNBAN6uTTI/VYx0LmpsSqss8h6n5CIwP7GfKvWrVY5/GoVIzynaxgPG+/R3sR4QoDki3Svn1sNHjArFlmD9qhAi7L2frY376kgV8dZIO8KJsE9VQQn/tA8foyTykd5sUH89rM6LnCWLl0aOeZAOsgsKHjbI2pyw0ZDwUstzR3Sq33z+mDg4URxuih8mssjQIDAQAB}
|
||||
huifu-public-key: ${HUIFU_CHANNEL_HUIFU_PUBLIC_KEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7PYy64gcO1Y44ntGFRdHzDJy6KnNoMLB6H5ZyCvqB2m2Bvzx18TMCjwevt5A4XF0ke9HfXRvZOL8TOaHdeiSbXWVBEpNsbQr0612U41cN688uHk4ShtoYuvSAbT0SuQULPh90BthzBrxrIuduex7qISk4d4mKvfM+tMTBQPWJc2au2yfTpisZPlKS5jg5xUCxG4UIze/xC4I92rVyVfziMm19Tzh1EXq4Hm1nXmRejgE2o2Hi/wu8Et6hj5UjZzPu3DPvzDN4AP372DP6EREYrVGYiD9qDqxx63jDqlGsdKmENXPp27gUqXX4vGD5xn0lOSXMHUQ5NUcXzdGbpWBBwIDAQAB}
|
||||
merchant:
|
||||
sys-id: 6666000207581039
|
||||
product-id: XLSISV
|
||||
huifu-id: 6666000207581039
|
||||
rsa-private-key: ${HUIFU_MERCHANT_PRIVATE_KEY:MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcxAwrhZF+izz1gxQKOr4jnC05obIBHbl0DzHOcd4CaaDV7Kv1NRJKi33JhdDsW4JGgu16e5Rtzq1VzU5VWz5EKgGL46maOFwCkngJUTP/LC3JVf/wtJmYCm8xNE8C7GNNIqKzYEvUOEfXqagpVvVrGsQ9FpzFp2rP9hBmHY3yizVyPX/uT9S+af5TRxiaItj3SSJGgloaEMrnKOpb/EH7JwPSS0liAyT/NxPfOyyZHc22AvaAIOE5y+0PMUCKPuIdfpOrej3LVpO1Arc2hSgmdB+YIPSiBVYPXa6AuAmil9mpbtSikQJ7Uu7lX4JyTW4QxQ06rPFKnFWVKkzivAElAgMBAAECggEAJd0AJ37iTlMpDQ90xqe7hvRQxAu256gbQ9nrqLY97g0/KIw6WEZSPakFX6gvdvb/NzKmUyAIEKGLoh6tXdZk6qfOqc/6BeK47nIcBfwT9/zerjNUVvn34w4aHyNINieMMHQ+Id8PUZmqWH+Euz9ilVTosuyEPwUZulLvUQqwXzU5VnwVghURbUhDd+ecBJACWgemRun6d5241PQXNYAdH1k7cETd8GfIi3qclhhJrxi7tu5tq4YGCXQIoz7HCLim7GIvT0M+FRgSw2EOrHnAQNFeQ/vQbP71ttLoTxehL6Se9dfWrV5OI+Y/T7vR2F84Qt0iNbaxyJGir7siKDFIwQKBgQDXDzinx3/TasplM78pR/0CtuuKr1Ch02LOPrTosJ1qf1OohxQThowhOTxMsBlgYSKu9s1QRffUUXEqYXxd2B6lzDKfggwO6U2XxIcxWeNow0xoFfqcXYSg7Ga2sCr9uhdwxIdFQNF7SNBpT8ht4fJrRX6mWY1nHybpyTDQ4xoQNQKBgQC6m+yiOoi5JD3zVSSJq/iq5DJPA5B4aoP+t5u9lp2Q7iVO0QI5ilBlEKGE4VOU0glnXlDTfuqEYooMY85ekl4WGb3AOT0PhLL2i+gO2nlWBzf4HPzB/hibjfyPyniRM03cHkG3HXucL7Sne6FwERcfjEqjUd2cdP1l89PNrq4rMQKBgQCMmjABSWYh8/y1I5rEQ4OAJdVjC3GdC1Xa35ZpVybjvLEWSpHunhW5lvD8dllw8LC7UTI0XDpGPqTM/4VO2YBYB2PFc0Gs8g0/v0ZgFpOeJ6kpl80MM/wFNemFYTIKRoMSv/psZY9PmfBgGcBBTuquBXZjDcNr+yr2yAm5V/DvTQKBgHqRi94KoF8q5N39IKCkqhJlDH5FkxDktYoKw2rFkPzuzuZz9gghRyj6wXxsG9/2DWMt2dzw0czehFoa/CO188KEadPmRKr6uCmkP2nyKhxNZX+8WnB5G2Sg4DD6BjMpBYz8+qDx5ozx8LDJTYI0V4HLPgMD9JGdbgsXGhlREOkhAoGALr6IQOXnviWNAhCdc7rrsaMLMPbLZ1wqzWtQUG1JxDobbpzEP4CW/mvW5pMn58mSBg5qbXhyDI4fFP0CPb98QIz2tGnIzYyFzdKmF5Z1N7X1OF9O+tsSqASoBZzTqB4fr/o4mz0s9JCeriBR2LWjsbsDU13DTLsfQpWbtOnIy70=}
|
||||
rsa-public-key: ${HUIFU_MERCHANT_PUBLIC_KEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnMQMK4WRfos89YMUCjq+I5wtOaGyAR25dA8xznHeAmmg1eyr9TUSSot9yYXQ7FuCRoLtenuUbc6tVc1OVVs+RCoBi+OpmjhcApJ4CVEz/ywtyVX/8LSZmApvMTRPAuxjTSKis2BL1DhH16moKVb1axrEPRacxadqz/YQZh2N8os1cj1/7k/Uvmn+U0cYmiLY90kiRoJaGhDK5yjqW/xB+ycD0ktJYgMk/zcT3zssmR3NtgL2gCDhOcvtDzFAij7iHX6Tq3o9y1aTtQK3NoUoJnQfmCD0ogVWD12ugLgJopfZqW7UopECe1Lu5V+Cck1uEMUNOqzxSpxVlSpM4rwBJQIDAQAB}
|
||||
huifu-public-key: ${HUIFU_MERCHANT_HUIFU_PUBLIC_KEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuqolFneAH66z3/3gaIYIaRZOIk/UYzdsXIm0RyawYBYAOu/NJ7ul8CRIrRlt5vd98HodW2yPrXA4+VHF3AS9UE4WTDpo9qV5brhqQSr/lAuZtEwMZwUWwgdnGFMkUFd9RvyGXAqY0bsQrcQgQ6zGjZHzlMljogDR3iblG0ak5ssD2TSC2W+1cxu+id+FP6onZXlXizuClTyIRh17m7CbS6rl0P3M96MlTdCzTeBw/Y54CiegBJI2wOrm2Qa6Dg6KRc+YkaJWjuRJVJkwjk8JhSyALno9oEzuDKaAXlsQlxeIhmAy4esRrZGrMV8SG0gwUZIP8lduPjQE95lCqqJ0gQIDAQAB}
|
||||
notify:
|
||||
url: ${HUIFU_NOTIFY_URL:https://your-domain.com/api/payment/notify/huifu}
|
||||
|
||||
@@ -14,10 +14,10 @@ wechat:
|
||||
aes-key: ${WECHAT_MP_AESKEY}
|
||||
callback-url: ${WECHAT_MP_CALLBACK_URL}
|
||||
|
||||
# 手机号加密配置
|
||||
# 手机号加密配置(AES-128-CBC,16字节密钥和IV,Base64编码)
|
||||
phone-encryption:
|
||||
secret-key: ${PHONE_ENCRYPTION_SECRET_KEY}
|
||||
iv: ${PHONE_ENCRYPTION_IV}
|
||||
secret-key: ${PHONE_ENCRYPTION_SECRET_KEY:MTIzNDU2Nzg5MDEyMzQ1Ng==}
|
||||
iv: ${PHONE_ENCRYPTION_IV:MTIzNDU2Nzg5MDEyMzQ1Ng==}
|
||||
|
||||
spring:
|
||||
elasticsearch:
|
||||
|
||||
Reference in New Issue
Block a user