|
@@ -984,6 +984,7 @@ public class PayScoreServiceImpl implements PayScoreService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 2. 取消 Redis 追踪的预创建订单(之前未完成购物流程留下的)
|
|
// 2. 取消 Redis 追踪的预创建订单(之前未完成购物流程留下的)
|
|
|
|
|
+ // 必须检查关联的本地订单状态,避免误取消已确认/正在扣款的订单
|
|
|
if (stringRedisTemplate != null) {
|
|
if (stringRedisTemplate != null) {
|
|
|
try {
|
|
try {
|
|
|
String trackingKey = REDIS_TRACKING_KEY + userId;
|
|
String trackingKey = REDIS_TRACKING_KEY + userId;
|
|
@@ -992,6 +993,10 @@ public class PayScoreServiceImpl implements PayScoreService {
|
|
|
log.info("[支付分服务] 清理用户 {} 的 {} 笔追踪预创建订单", userId, trackedOrders.size());
|
|
log.info("[支付分服务] 清理用户 {} 的 {} 笔追踪预创建订单", userId, trackedOrders.size());
|
|
|
for (String outOrderNo : trackedOrders) {
|
|
for (String outOrderNo : trackedOrders) {
|
|
|
if (outOrderNo != null && !outOrderNo.isEmpty()) {
|
|
if (outOrderNo != null && !outOrderNo.isEmpty()) {
|
|
|
|
|
+ if (!isPayScoreOrderSafeToCancel(outOrderNo)) {
|
|
|
|
|
+ log.info("[支付分服务] 跳过取消已确认的支付分订单 - outOrderNo: {}", outOrderNo);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
cancelPayScoreOrderByOutOrderNo(outOrderNo, null);
|
|
cancelPayScoreOrderByOutOrderNo(outOrderNo, null);
|
|
|
stringRedisTemplate.opsForSet().remove(trackingKey, outOrderNo);
|
|
stringRedisTemplate.opsForSet().remove(trackingKey, outOrderNo);
|
|
|
}
|
|
}
|
|
@@ -1059,6 +1064,7 @@ public class PayScoreServiceImpl implements PayScoreService {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 取消同设备旧的预创建订单(已被本次新订单替代)
|
|
* 取消同设备旧的预创建订单(已被本次新订单替代)
|
|
|
|
|
+ * 必须检查关联的本地订单状态,避免误取消已确认/正在扣款的订单
|
|
|
*/
|
|
*/
|
|
|
private void cancelOldDeviceOrders(Long userId, String deviceId, String currentOutOrderNo) {
|
|
private void cancelOldDeviceOrders(Long userId, String deviceId, String currentOutOrderNo) {
|
|
|
if (stringRedisTemplate == null) {
|
|
if (stringRedisTemplate == null) {
|
|
@@ -1072,6 +1078,10 @@ public class PayScoreServiceImpl implements PayScoreService {
|
|
|
if (tracked != null) {
|
|
if (tracked != null) {
|
|
|
for (String outOrderNo : tracked) {
|
|
for (String outOrderNo : tracked) {
|
|
|
if (outOrderNo != null && outOrderNo.endsWith(suffix) && !outOrderNo.equals(currentOutOrderNo)) {
|
|
if (outOrderNo != null && outOrderNo.endsWith(suffix) && !outOrderNo.equals(currentOutOrderNo)) {
|
|
|
|
|
+ if (!isPayScoreOrderSafeToCancel(outOrderNo)) {
|
|
|
|
|
+ log.info("[支付分服务] 跳过取消同设备已确认的支付分订单 - outOrderNo: {}, deviceId: {}", outOrderNo, deviceId);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
cancelPayScoreOrderByOutOrderNo(outOrderNo, null);
|
|
cancelPayScoreOrderByOutOrderNo(outOrderNo, null);
|
|
|
stringRedisTemplate.opsForSet().remove(trackingKey, outOrderNo);
|
|
stringRedisTemplate.opsForSet().remove(trackingKey, outOrderNo);
|
|
|
}
|
|
}
|
|
@@ -1081,4 +1091,35 @@ public class PayScoreServiceImpl implements PayScoreService {
|
|
|
log.warn("[支付分服务] 清理设备旧追踪失败 - deviceId: {}", deviceId, e);
|
|
log.warn("[支付分服务] 清理设备旧追踪失败 - deviceId: {}", deviceId, e);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 检查支付分订单是否可以安全取消
|
|
|
|
|
+ * 已确认(DOING)或正在扣款(USER_PAYING)或已完成(DONE)的订单不应被取消
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return true 可以安全取消(本地无订单或仅 CREATED 状态),false 不可取消
|
|
|
|
|
+ */
|
|
|
|
|
+ private boolean isPayScoreOrderSafeToCancel(String outOrderNo) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Order localOrder = orderService.lambdaQuery()
|
|
|
|
|
+ .eq(Order::getPayScoreOrderId, outOrderNo)
|
|
|
|
|
+ .one();
|
|
|
|
|
+ if (localOrder == null) {
|
|
|
|
|
+ // 没有关联的本地订单,可以安全取消(只是预创建的支付分记录)
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ String state = localOrder.getPayScoreState();
|
|
|
|
|
+ if (PayScoreState.CREATED.getCode().equals(state)) {
|
|
|
|
|
+ // CREATED 状态的订单(用户从未确认),可以取消
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ // DOING / USER_PAYING / DONE 状态的订单不可取消
|
|
|
|
|
+ log.warn("[支付分服务] 支付分订单已确认不可取消 - outOrderNo: {}, payScoreState: {}, orderId: {}",
|
|
|
|
|
+ outOrderNo, state, localOrder.getId());
|
|
|
|
|
+ return false;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("[支付分服务] 检查支付分订单状态失败 - outOrderNo: {}", outOrderNo, e);
|
|
|
|
|
+ // 查询失败时保守处理:不取消,避免误伤
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|