From 8385196b384f9d5f62fb3b9144b51e1322a92a13 Mon Sep 17 00:00:00 2001
From: zhaogd
Date: Thu, 6 Aug 2026 13:43:34 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E7=A7=BB=E9=99=A4mock=E6=94=AF?=
=?UTF-8?q?=E4=BB=98=E3=80=81=E5=8D=A1=E4=B8=8D=E5=8F=AF=E5=A4=8D=E7=94=A8?=
=?UTF-8?q?=E3=80=81=E6=96=B0=E5=A2=9E=E8=AE=BE=E5=A4=87=E7=AB=AF=E5=8F=96?=
=?UTF-8?q?=E6=B6=88=E8=AE=A2=E5=8D=95=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 移除所有mock支付逻辑,订单强制走微信支付
2. 卡状态流转改为单向:UNUSED->RESERVED->USED(终态不可复用)
3. 解绑接口改为仅清除device_id,卡状态保持USED
4. 新增设备端取消订单接口 POST /api/jst/daycard/cancel/{orderNo}
5. 修复微信回调验签header大小写问题
6. 临时注释分账标记(商户号未开通分账权限)
7. 删除多余的App UI辅助接口(ApiJstUiController)
8. 清理application.yml中无用UI配置
---
.../daycard/constants/DayCardConstants.java | 2 -
.../controller/DayCardManageController.java | 2 +-
.../daycard/entity/DayCardOrderEntity.java | 2 +-
.../daycard/service/DayCardOrderService.java | 11 +-
.../service/impl/DayCardOrderServiceImpl.java | 122 ++++-----
.../impl/DayCardRefundServiceImpl.java | 32 +--
.../openapi/controller/ApiJstController.java | 22 ++
.../controller/ApiJstUiController.java | 253 ------------------
.../payment/controller/PaymentController.java | 39 +--
.../payment/service/WechatPayService.java | 5 -
.../service/impl/WechatPayServiceImpl.java | 55 +---
src/main/resources/application.yml | 8 -
.../mapper/daycard/DayCardPoolDao.xml | 9 +-
13 files changed, 100 insertions(+), 462 deletions(-)
delete mode 100644 src/main/java/io/as/modules/openapi/controller/ApiJstUiController.java
diff --git a/src/main/java/io/as/modules/daycard/constants/DayCardConstants.java b/src/main/java/io/as/modules/daycard/constants/DayCardConstants.java
index d64ab23..95c394a 100644
--- a/src/main/java/io/as/modules/daycard/constants/DayCardConstants.java
+++ b/src/main/java/io/as/modules/daycard/constants/DayCardConstants.java
@@ -159,8 +159,6 @@ public final class DayCardConstants {
public static final String REFUND_STATUS_CLOSED = "CLOSED";
// ==================== 支付渠道 ====================
- /** Mock支付 */
- public static final String PAY_CHANNEL_MOCK = "MOCK";
/** 微信支付 */
public static final String PAY_CHANNEL_WECHAT = "WECHAT";
}
diff --git a/src/main/java/io/as/modules/daycard/controller/DayCardManageController.java b/src/main/java/io/as/modules/daycard/controller/DayCardManageController.java
index 3000f42..6edfca2 100644
--- a/src/main/java/io/as/modules/daycard/controller/DayCardManageController.java
+++ b/src/main/java/io/as/modules/daycard/controller/DayCardManageController.java
@@ -125,7 +125,7 @@ public class DayCardManageController {
/**
* 解绑设备天卡权益(Web端手动操作)
- * 将设备绑定的 USED 卡转为 REUSABLE,释放设备。橘视厅权益保留,后续新设备下单可复用此卡。
+ * 清除卡上的 device_id 绑定,卡状态保持 USED 不变,不可被其他设备复用。
*/
@AuditAction(value = "DAYCARD_DEVICE_UNBIND", description = "解绑设备天卡权益")
@PostMapping("/device/unbind")
diff --git a/src/main/java/io/as/modules/daycard/entity/DayCardOrderEntity.java b/src/main/java/io/as/modules/daycard/entity/DayCardOrderEntity.java
index ab87c05..91390a8 100644
--- a/src/main/java/io/as/modules/daycard/entity/DayCardOrderEntity.java
+++ b/src/main/java/io/as/modules/daycard/entity/DayCardOrderEntity.java
@@ -56,7 +56,7 @@ public class DayCardOrderEntity implements Serializable {
private Date createdAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updatedAt;
- /** 支付渠道 MOCK/WECHAT */
+ /** 支付渠道 WECHAT */
private String payChannel;
/** 微信预支付ID */
private String prepayId;
diff --git a/src/main/java/io/as/modules/daycard/service/DayCardOrderService.java b/src/main/java/io/as/modules/daycard/service/DayCardOrderService.java
index 982125a..217cbc5 100644
--- a/src/main/java/io/as/modules/daycard/service/DayCardOrderService.java
+++ b/src/main/java/io/as/modules/daycard/service/DayCardOrderService.java
@@ -66,6 +66,15 @@ public interface DayCardOrderService extends IService {
*/
DayCardOrderEntity getByOrderNo(String orderNo);
+ /**
+ * 设备端取消未支付订单
+ * 校验订单归属设备后,关单微信支付、释放卡、更新订单CANCELLED、清理Redis锁
+ *
+ * @param orderNo 订单号
+ * @param deviceId 设备ID(从 sign 解析,校验订单归属)
+ */
+ void cancelOrder(String orderNo, Long deviceId);
+
/**
* 查询设备的天卡权益(激活后 App 获取播放凭证)
* 从 day_card_pool 表查询 status=USED 且 expire_at > NOW() 的卡,返回 thirdCardNo 和 expireAt
@@ -86,7 +95,7 @@ public interface DayCardOrderService extends IService {
/**
* 解绑设备天卡权益(Web端手动操作)
- * 将 USED 卡转为 REUSABLE,释放设备绑定,保留橘视厅权益供后续设备复用
+ * 清除卡上的 device_id 绑定,卡状态保持 USED 不变,不可被其他设备复用
*
* @param deviceId 设备ID
*/
diff --git a/src/main/java/io/as/modules/daycard/service/impl/DayCardOrderServiceImpl.java b/src/main/java/io/as/modules/daycard/service/impl/DayCardOrderServiceImpl.java
index 5da3d37..d46c51a 100644
--- a/src/main/java/io/as/modules/daycard/service/impl/DayCardOrderServiceImpl.java
+++ b/src/main/java/io/as/modules/daycard/service/impl/DayCardOrderServiceImpl.java
@@ -165,7 +165,7 @@ public class DayCardOrderServiceImpl extends ServiceImpl payUpdate = new UpdateWrapper<>();
- payUpdate.eq("id", order.getId())
- .set("code_url", codeUrl)
- .set("pay_channel", "WECHAT");
- baseMapper.update(null, payUpdate);
- } catch (Exception e) {
- logger.warn("微信下单失败,回退到MOCK模式: orderNo={}", orderNo, e);
- order.setPayChannel("MOCK");
- order.setCodeUrl("mock://pay?orderNo=" + orderNo);
- UpdateWrapper payUpdate = new UpdateWrapper<>();
- payUpdate.eq("id", order.getId())
- .set("code_url", order.getCodeUrl())
- .set("pay_channel", "MOCK");
- baseMapper.update(null, payUpdate);
- }
- } else {
- order.setPayChannel("MOCK");
- order.setCodeUrl("mock://pay?orderNo=" + orderNo);
- UpdateWrapper payUpdate = new UpdateWrapper<>();
- payUpdate.eq("id", order.getId())
- .set("code_url", order.getCodeUrl())
- .set("pay_channel", "MOCK");
- baseMapper.update(null, payUpdate);
- }
+ String codeUrl = wechatPayService.createNativePay(orderNo, "天卡订单", amount, channelOrgId, agentOrgId, storeOrgId);
+ order.setCodeUrl(codeUrl);
+ UpdateWrapper payUpdate = new UpdateWrapper<>();
+ payUpdate.eq("id", order.getId())
+ .set("code_url", codeUrl);
+ baseMapper.update(null, payUpdate);
// 8. SKIP LOCKED 抢卡(通用池,不按 partner 过滤)
DayCardPoolEntity pool = dayCardPoolDao.selectOneForUpdateSkipLocked();
@@ -219,7 +196,7 @@ public class DayCardOrderServiceImpl extends ServiceImpl RESERVED
UpdateWrapper poolUpdate = new UpdateWrapper<>();
poolUpdate.eq("id", pool.getId())
- .in("status", DayCardConstants.POOL_STATUS_UNUSED, DayCardConstants.POOL_STATUS_REUSABLE)
+ .eq("status", DayCardConstants.POOL_STATUS_UNUSED)
.eq("delete_flag", DayCardConstants.DELETE_FLAG_UNDEL)
.set("status", DayCardConstants.POOL_STATUS_RESERVED)
.set("order_no", orderNo)
@@ -298,7 +275,7 @@ public class DayCardOrderServiceImpl extends ServiceImpl payUpdate = new UpdateWrapper<>();
- payUpdate.eq("id", order.getId())
- .set("code_url", codeUrl)
- .set("pay_channel", "WECHAT");
- baseMapper.update(null, payUpdate);
- } catch (Exception e) {
- logger.warn("微信下单失败,回退到MOCK模式: orderNo={}", orderNo, e);
- order.setPayChannel("MOCK");
- order.setCodeUrl("mock://pay?orderNo=" + orderNo);
- UpdateWrapper payUpdate = new UpdateWrapper<>();
- payUpdate.eq("id", order.getId())
- .set("code_url", order.getCodeUrl())
- .set("pay_channel", "MOCK");
- baseMapper.update(null, payUpdate);
- }
- } else {
- // 开发模式:使用 Mock 支付
- order.setPayChannel("MOCK");
- order.setCodeUrl("mock://pay?orderNo=" + orderNo);
- UpdateWrapper payUpdate = new UpdateWrapper<>();
- payUpdate.eq("id", order.getId())
- .set("code_url", order.getCodeUrl())
- .set("pay_channel", "MOCK");
- baseMapper.update(null, payUpdate);
- }
+ String codeUrl = wechatPayService.createNativePay(orderNo, "天卡订单", amount, channelOrgId, agentOrgId, storeOrgId);
+ order.setCodeUrl(codeUrl);
+ UpdateWrapper payUpdate = new UpdateWrapper<>();
+ payUpdate.eq("id", order.getId())
+ .set("code_url", codeUrl);
+ baseMapper.update(null, payUpdate);
// 7. SKIP LOCKED 抢卡
DayCardPoolEntity pool = dayCardPoolDao.selectOneForUpdateSkipLocked();
@@ -355,7 +308,7 @@ public class DayCardOrderServiceImpl extends ServiceImpl RESERVED
UpdateWrapper poolUpdate = new UpdateWrapper<>();
poolUpdate.eq("id", pool.getId())
- .in("status", DayCardConstants.POOL_STATUS_UNUSED, DayCardConstants.POOL_STATUS_REUSABLE)
+ .eq("status", DayCardConstants.POOL_STATUS_UNUSED)
.eq("delete_flag", DayCardConstants.DELETE_FLAG_UNDEL)
.set("status", DayCardConstants.POOL_STATUS_RESERVED)
.set("order_no", orderNo)
@@ -444,12 +397,12 @@ public class DayCardOrderServiceImpl extends ServiceImpl orderUpdate = new UpdateWrapper<>();
orderUpdate.eq("id", order.getId())
- .eq("status", DayCardConstants.ORDER_STATUS_CREATED)
+ .in("status", DayCardConstants.ORDER_STATUS_CREATED, DayCardConstants.ORDER_STATUS_PAYING)
.set("status", DayCardConstants.ORDER_STATUS_CANCELLED)
.set("cancel_time", now)
.set("updated_at", now);
@@ -672,6 +625,29 @@ public class DayCardOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>();
@@ -706,7 +682,6 @@ public class DayCardOrderServiceImpl extends ServiceImpl update = new UpdateWrapper<>();
update.eq("id", pool.getId())
.eq("status", DayCardConstants.POOL_STATUS_USED)
- .set("status", DayCardConstants.POOL_STATUS_REUSABLE)
.set("device_id", null)
.set("updated_at", new Date());
int updated = dayCardPoolDao.update(null, update);
@@ -723,17 +698,16 @@ public class DayCardOrderServiceImpl extends ServiceImpl REUSABLE,清卡上的 device_id
+ // 1. 解绑设备当前天卡权益(若有):清除 device_id,卡状态保持 USED 不变
DayCardPoolEntity pool = getDeviceBenefits(deviceId);
if (pool != null) {
UpdateWrapper poolUpdate = new UpdateWrapper<>();
poolUpdate.eq("id", pool.getId())
.eq("status", DayCardConstants.POOL_STATUS_USED)
- .set("status", DayCardConstants.POOL_STATUS_REUSABLE)
.set("device_id", null)
.set("updated_at", now);
dayCardPoolDao.update(null, poolUpdate);
- logger.info("设备组织解绑-释放天卡权益: deviceId={}, poolId={}, cardCode={}",
+ logger.info("设备组织解绑-解除天卡权益绑定: deviceId={}, poolId={}, cardCode={}",
deviceId, pool.getId(), pool.getCardCode());
}
// 2. 清除设备的门店组织关联(storeOrgId),设备可在新场所用新激活码重新绑定
diff --git a/src/main/java/io/as/modules/daycard/service/impl/DayCardRefundServiceImpl.java b/src/main/java/io/as/modules/daycard/service/impl/DayCardRefundServiceImpl.java
index 60f12a7..20823e0 100644
--- a/src/main/java/io/as/modules/daycard/service/impl/DayCardRefundServiceImpl.java
+++ b/src/main/java/io/as/modules/daycard/service/impl/DayCardRefundServiceImpl.java
@@ -157,18 +157,13 @@ public class DayCardRefundServiceImpl extends ServiceImplMock 支付的 payNo 以 "MOCK_" 开头,其余视为微信支付
- *
- * @param payNo 支付单号
- * @return true=微信支付
- */
- private boolean isWechatPayment(String payNo) {
- if (StringUtils.isBlank(payNo)) {
- // 没有支付单号,默认视为微信支付
- return true;
- }
- return !payNo.startsWith(DayCardConstants.PAY_CHANNEL_MOCK + "_");
- }
-
/**
* 生成退款单号:REFUND + yyyyMMddHHmmss + 6位随机数
*/
diff --git a/src/main/java/io/as/modules/openapi/controller/ApiJstController.java b/src/main/java/io/as/modules/openapi/controller/ApiJstController.java
index d12af24..1eca4e4 100644
--- a/src/main/java/io/as/modules/openapi/controller/ApiJstController.java
+++ b/src/main/java/io/as/modules/openapi/controller/ApiJstController.java
@@ -195,6 +195,28 @@ public class ApiJstController {
return buildSuccessResponse(data);
}
+ /**
+ * 取消天卡订单(用户放弃支付时调用)
+ */
+ @ApiOperation(value = "取消天卡订单",
+ notes = "请求头必传 sign。用户取消支付时调用,取消订单并释放卡,允许设备重新下单。")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "sign", value = "设备签名", required = true, paramType = "header", dataType = "string")
+ })
+ @PostMapping("/daycard/cancel/{orderNo}")
+ public Map cancelDayCard(@PathVariable("orderNo") String orderNo, HttpServletRequest request) {
+ try {
+ Long deviceId = deviceIdFrom(request);
+ dayCardOrderService.cancelOrder(orderNo, deviceId);
+ Map data = new HashMap<>();
+ data.put("orderNo", orderNo);
+ data.put("status", "CANCELLED");
+ return buildSuccessResponse(data);
+ } catch (ASException e) {
+ return rrExceptionResponse(e);
+ }
+ }
+
/**
* 设备心跳:更新设备心跳时间,续期 sign
*/
diff --git a/src/main/java/io/as/modules/openapi/controller/ApiJstUiController.java b/src/main/java/io/as/modules/openapi/controller/ApiJstUiController.java
deleted file mode 100644
index bfc4ee1..0000000
--- a/src/main/java/io/as/modules/openapi/controller/ApiJstUiController.java
+++ /dev/null
@@ -1,253 +0,0 @@
-package io.as.modules.openapi.controller;
-
-import io.as.modules.device.dto.DeviceOrgContext;
-import io.as.modules.device.service.DeviceResolveService;
-import io.as.modules.openapi.filter.ApiDeviceSignFilter;
-import io.as.modules.sys.entity.SysOrgEntity;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 橘视听 App UI 数据接口
- * 提供顶栏按钮、筛选分类、筛选内容列表、独立配置等 App 展示所需数据
- * 所有接口均需请求头 sign(由 ApiDeviceSignFilter 校验)
- * 返回格式:{code:0, msg:"success", data:{...}}
- */
-@RestController
-@RequestMapping("/api/jst")
-public class ApiJstUiController {
-
- private static final Logger logger = LoggerFactory.getLogger(ApiJstUiController.class);
-
- @Autowired
- private DeviceResolveService deviceResolveService;
-
- @Value("${renren.daycard.ui.logo-url:https://daycard.oss.cn/logo.png}")
- private String defaultLogoUrl;
-
- @Value("${renren.daycard.ui.login-bg-url:https://daycard.oss.cn/login_bg.png}")
- private String defaultLoginBgUrl;
-
- @Value("${renren.daycard.ui.search-normal-url:https://daycard.oss.cn/search_normal.png}")
- private String searchNormalUrl;
-
- @Value("${renren.daycard.ui.search-focus-url:https://daycard.oss.cn/search_focus.png}")
- private String searchFocusUrl;
-
- @Value("${renren.daycard.ui.help-normal-url:https://daycard.oss.cn/help_normal.png}")
- private String helpNormalUrl;
-
- @Value("${renren.daycard.ui.help-focus-url:https://daycard.oss.cn/help_focus.png}")
- private String helpFocusUrl;
-
- // ==================== 1. 顶栏按钮 ====================
-
- /**
- * 顶栏按钮数据:返回 logo + 搜索 + 帮助
- * logo 优先取设备所属渠道的 brand_logo_url,无则用全局默认
- */
- @PostMapping("/topButtons")
- public Map topButtons(@RequestBody(required = false) Map body,
- HttpServletRequest request) {
- Long deviceId = deviceIdFrom(request);
- String logoUrl = resolveLogoUrl(deviceId);
-
- List