|
|
@@ -401,9 +401,23 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
|
|
|
/**
|
|
|
* 处理无消费场景
|
|
|
+ * 用户开门但未取货:标记 DoorRecord、关门、取消关联的支付分订单、清理 Redis
|
|
|
*/
|
|
|
private void handleNoConsume(String activityId) {
|
|
|
log.info("用户打开柜门但未消费,无需创建订单 - activityId: {}", activityId);
|
|
|
+
|
|
|
+ // 取消关联的支付分订单(用户在微信侧已确认但未取货)
|
|
|
+ try {
|
|
|
+ DoorRecord record = doorRecordService.getByActivityId(activityId);
|
|
|
+ if (record != null && record.getPayScoreOrderId() != null && payScoreService != null) {
|
|
|
+ ((com.haha.service.payment.payscore.impl.PayScoreServiceImpl) payScoreService)
|
|
|
+ .cancelPayScoreForNoConsume(record.getPayScoreOrderId(),
|
|
|
+ record.getUserId(), record.getDeviceId());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("无消费场景取消支付分订单失败 - activityId: {}", activityId, e);
|
|
|
+ }
|
|
|
+
|
|
|
doorRecordService.markNoConsume(activityId);
|
|
|
doorRecordService.updateDoorClosed(activityId);
|
|
|
}
|
|
|
@@ -1803,14 +1817,20 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
log.info("支付分订单ID已从追踪SET恢复 - orderId: {}, payScoreOrderId: {}",
|
|
|
order.getId(), recovered);
|
|
|
} else {
|
|
|
+ // tracking SET 未命中,尝试从 DoorRecord 恢复(scan-open 时持久化的)
|
|
|
+ if (!tryRecoverFromDoorRecord(order)) {
|
|
|
+ log.debug("订单未使用支付分,跳过扣费 - orderId: {}, payChannel: {}",
|
|
|
+ order.getId(), order.getPayChannel());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // payScoreService 未初始化,尝试从 DoorRecord 恢复
|
|
|
+ if (!tryRecoverFromDoorRecord(order)) {
|
|
|
log.debug("订单未使用支付分,跳过扣费 - orderId: {}, payChannel: {}",
|
|
|
order.getId(), order.getPayChannel());
|
|
|
return;
|
|
|
}
|
|
|
- } else {
|
|
|
- log.debug("订单未使用支付分,跳过扣费 - orderId: {}, payChannel: {}",
|
|
|
- order.getId(), order.getPayChannel());
|
|
|
- return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1879,6 +1899,50 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 从 DoorRecord 恢复支付分订单ID(多层恢复的最后一道防线)
|
|
|
+ * 当 Redis preauth key 过期 + tracking SET 也被清理时,DoorRecord 上仍有 scan-open 时持久化的信息
|
|
|
+ *
|
|
|
+ * @return true 恢复成功并已回写 DB,false 未找到
|
|
|
+ */
|
|
|
+ private boolean tryRecoverFromDoorRecord(Order order) {
|
|
|
+ if (order.getActivityId() == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ DoorRecord record = doorRecordService.getByActivityId(order.getActivityId());
|
|
|
+ if (record != null && record.getPayScoreOrderId() != null) {
|
|
|
+ String recovered = record.getPayScoreOrderId();
|
|
|
+ String svcId = record.getServiceId();
|
|
|
+
|
|
|
+ order.setPayScoreOrderId(recovered);
|
|
|
+ order.setPayChannel(PaymentChannel.WECHAT_PAYSCORE.getCode());
|
|
|
+ order.setPayType("微信支付分");
|
|
|
+ order.setPayScoreState(PayScoreState.CREATED.getCode());
|
|
|
+ if (svcId != null) {
|
|
|
+ order.setServiceId(svcId);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 回写到数据库
|
|
|
+ orderService.lambdaUpdate()
|
|
|
+ .set(Order::getPayScoreOrderId, recovered)
|
|
|
+ .set(Order::getPayChannel, PaymentChannel.WECHAT_PAYSCORE.getCode())
|
|
|
+ .set(Order::getPayType, "微信支付分")
|
|
|
+ .set(Order::getPayScoreState, PayScoreState.CREATED.getCode())
|
|
|
+ .set(svcId != null, Order::getServiceId, svcId)
|
|
|
+ .eq(Order::getId, order.getId())
|
|
|
+ .update();
|
|
|
+ log.info("支付分订单ID已从DoorRecord恢复 - orderId: {}, payScoreOrderId: {}, activityId: {}",
|
|
|
+ order.getId(), recovered, order.getActivityId());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("从DoorRecord恢复支付分订单ID失败 - orderId: {}, activityId: {}",
|
|
|
+ order.getId(), order.getActivityId(), e);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 同步支付状态到哈哈平台
|
|
|
* 告知哈哈平台该订单已完成支付
|